Fix grep-like functions when running on a remote host
* doc/lispref/processes.texi (Shell Arguments): * etc/NEWS: Describe change in 'shell-quote-argument'. Fix typos. * lisp/subr.el (shell-quote-argument): New optional argument POSIX. * lisp/progmodes/grep.el (grep-compute-defaults) (grep-default-command, grep-expand-keywords, lgrep) (rgrep-default-command): Use POSIX argument in `shell-quote-argument'. (Bug#54487)
This commit is contained in:
parent
7872d496d5
commit
0094dde11d
4 changed files with 97 additions and 73 deletions
|
@ -197,7 +197,7 @@ gives special treatment to certain characters, and if these characters
|
|||
occur in the file name, they will confuse the shell. To handle these
|
||||
characters, use the function @code{shell-quote-argument}:
|
||||
|
||||
@defun shell-quote-argument argument
|
||||
@defun shell-quote-argument argument &optional posix
|
||||
This function returns a string that represents, in shell syntax,
|
||||
an argument whose actual contents are @var{argument}. It should
|
||||
work reliably to concatenate the return value into a shell command
|
||||
|
@ -227,6 +227,15 @@ a shell command:
|
|||
" "
|
||||
(shell-quote-argument newfile))
|
||||
@end example
|
||||
|
||||
If the optional @var{posix} argument is non-@code{nil}, @var{argument}
|
||||
is quoted according to POSIX shell quoting rules, regardless of the
|
||||
system’s shell. This is useful when your shell could run on a remote
|
||||
host, which requires a POSIX shell in general.
|
||||
|
||||
@example
|
||||
(shell-quote-argument "foo > bar" (file-remote-p default-directory))
|
||||
@end example
|
||||
@end defun
|
||||
|
||||
@cindex quoting and unquoting command-line arguments
|
||||
|
|
34
etc/NEWS
34
etc/NEWS
|
@ -578,9 +578,9 @@ the "*Completions*" buffer. Available styles are no sorting,
|
|||
alphabetical (the default), or a custom sort function.
|
||||
|
||||
+++
|
||||
*** New values for the 'completion-auto-help' option.
|
||||
*** New values for the 'completion-auto-help' user option.
|
||||
There are two new values to control the way "*Completions*" behave after
|
||||
a <tab> if completion is not unique. 'always' updates or shows
|
||||
a 'TAB' if completion is not unique. 'always' updates or shows
|
||||
the "*Completions*" buffer after any attempt to complete. 'visual' is
|
||||
like 'always', but only update the completions if they are already
|
||||
visible. The default value 't' always hides the completion buffer after
|
||||
|
@ -591,16 +591,16 @@ some completion is made.
|
|||
This option limits the height of the "*Completions*" buffer.
|
||||
|
||||
+++
|
||||
*** New option 'completions-header-format'
|
||||
*** New user option 'completions-header-format'
|
||||
This is a string to control the message to show before completions.
|
||||
It may contain a "%s" to show the total number of completions. If nil no
|
||||
It may contain a "%s" to show the total number of completions. If nil no
|
||||
completions are shown.
|
||||
|
||||
+++
|
||||
*** New option 'completions-highlight-face'.
|
||||
When this variable is a face name, it highlights the current candidate
|
||||
in the "*Completions*" buffer with that face. When the value is nil,
|
||||
no highlighting is performed at all.
|
||||
*** New user option 'completions-highlight-face'.
|
||||
When this user option is a face name, it highlights the current
|
||||
candidate in the "*Completions*" buffer with that face. When the
|
||||
value is nil, no highlighting is performed at all.
|
||||
|
||||
** Isearch and Replace
|
||||
|
||||
|
@ -1207,7 +1207,7 @@ like:
|
|||
---
|
||||
** The 'inhibit-changing-match-data' variable is now obsolete.
|
||||
Instead, functions like 'string-match' and 'looking-at' now take an
|
||||
optional 'inhibit-modify' argument.
|
||||
optional INHIBIT-MODIFY argument.
|
||||
|
||||
---
|
||||
** 'gnus-define-keys' is now obsolete.
|
||||
|
@ -1330,7 +1330,7 @@ This allows setting a minimum display width for a region of text.
|
|||
** New 'cursor-face' text property.
|
||||
This uses 'cursor-face' instead of the default face when cursor is on or
|
||||
near the character and 'cursor-face-highlight-mode' is enabled. The
|
||||
variable 'cursor-face-highlight-nonselected-window' is similar to
|
||||
user option 'cursor-face-highlight-nonselected-window' is similar to
|
||||
'highlight-nonselected-windows', but for this property.
|
||||
|
||||
+++
|
||||
|
@ -1470,8 +1470,8 @@ This command lets you examine all data in the current selection and
|
|||
the clipboard, and insert it into the buffer.
|
||||
|
||||
---
|
||||
** New hook 'minibuffer-lazy-highlight-setup'.
|
||||
This hook is intended to be added to 'minibuffer-setup-hook'.
|
||||
** New function 'minibuffer-lazy-highlight-setup'.
|
||||
This function is intended to be added to 'minibuffer-setup-hook'.
|
||||
It sets up the minibuffer for lazy highlighting of matches
|
||||
in the original window.
|
||||
|
||||
|
@ -1542,8 +1542,7 @@ from a specified amount of pixels above or below a position.
|
|||
---
|
||||
** 'eshell-eval-using-options' now follows POSIX/GNU argument syntax conventions.
|
||||
Built-in commands in Eshell now accept command-line options with
|
||||
values passed as a single token, such as '-oVALUE' or
|
||||
'--option=VALUE'.
|
||||
values passed as a single token, such as '-oVALUE' or '--option=VALUE'.
|
||||
|
||||
** XDG support
|
||||
|
||||
|
@ -1748,11 +1747,16 @@ This is recorded in the `function-history` symbol property.
|
|||
** 'indian-tml-base-table' no longer translates digits.
|
||||
Use 'indian-tml-base-digits-table' if you want digits translation.
|
||||
|
||||
--
|
||||
---
|
||||
** 'indian-tml-itrans-v5-hash' no longer translates digits.
|
||||
Use 'indian-tml-itrans-digits-v5-hash' if you want digits
|
||||
translation.
|
||||
|
||||
+++
|
||||
** 'shell-quote-argument' has a new optional parameter POSIX.
|
||||
This is useful when quoting shell arguments for a remote shell
|
||||
invocation. Such shells are POSIX conform by default.
|
||||
|
||||
|
||||
* Changes in Emacs 29.1 on Non-Free Operating Systems
|
||||
|
||||
|
|
|
@ -632,12 +632,12 @@ The value depends on `grep-command', `grep-template',
|
|||
,grep-use-null-filename-separator)
|
||||
(grep-find-use-xargs ,grep-find-use-xargs)
|
||||
(grep-highlight-matches ,grep-highlight-matches)))))
|
||||
(let* ((host-id
|
||||
(intern (or (file-remote-p default-directory) "localhost")))
|
||||
(let* ((remote (file-remote-p default-directory))
|
||||
(host-id (intern (or remote "localhost")))
|
||||
(host-defaults (assq host-id grep-host-defaults-alist))
|
||||
(defaults (assq nil grep-host-defaults-alist))
|
||||
(quot-braces (shell-quote-argument "{}"))
|
||||
(quot-scolon (shell-quote-argument ";")))
|
||||
(quot-braces (shell-quote-argument "{}" remote))
|
||||
(quot-scolon (shell-quote-argument ";" remote)))
|
||||
;; There are different defaults on different hosts. They must be
|
||||
;; computed for every host once.
|
||||
(dolist (setting '(grep-command grep-template
|
||||
|
@ -820,7 +820,9 @@ The value depends on `grep-command', `grep-template',
|
|||
|
||||
(defun grep-default-command ()
|
||||
"Compute the default grep command for \\[universal-argument] \\[grep] to offer."
|
||||
(let ((tag-default (shell-quote-argument (grep-tag-default)))
|
||||
(let ((tag-default
|
||||
(shell-quote-argument
|
||||
(grep-tag-default) (file-remote-p default-directory)))
|
||||
;; This a regexp to match single shell arguments.
|
||||
;; Could someone please add comments explaining it?
|
||||
(sh-arg-re
|
||||
|
@ -963,7 +965,8 @@ easily repeat a find command."
|
|||
("<F>" . files)
|
||||
("<N>" . (null-device))
|
||||
("<X>" . excl)
|
||||
("<R>" . (shell-quote-argument (or regexp ""))))
|
||||
("<R>" . (shell-quote-argument
|
||||
(or regexp "") (file-remote-p (expand-file-name (or dir "."))))))
|
||||
"List of substitutions performed by `grep-expand-template'.
|
||||
If car of an element matches, the cdr is evalled in order to get the
|
||||
substitution string.
|
||||
|
@ -1112,11 +1115,12 @@ command before it's run."
|
|||
(when (and (stringp regexp) (> (length regexp) 0))
|
||||
(unless (and dir (file-accessible-directory-p dir))
|
||||
(setq dir default-directory))
|
||||
(let ((command regexp))
|
||||
(let ((command regexp) remote)
|
||||
(if (null files)
|
||||
(if (string= command grep-command)
|
||||
(setq command nil))
|
||||
(setq dir (file-name-as-directory (expand-file-name dir)))
|
||||
(setq dir (file-name-as-directory (expand-file-name dir))
|
||||
remote (file-remote-p dir))
|
||||
(unless (or (not grep-use-directories-skip)
|
||||
(eq grep-use-directories-skip t))
|
||||
(setq grep-use-directories-skip
|
||||
|
@ -1134,11 +1138,12 @@ command before it's run."
|
|||
(mapconcat
|
||||
(lambda (ignore)
|
||||
(cond ((stringp ignore)
|
||||
(shell-quote-argument ignore))
|
||||
(shell-quote-argument
|
||||
ignore remote))
|
||||
((consp ignore)
|
||||
(and (funcall (car ignore) dir)
|
||||
(shell-quote-argument
|
||||
(cdr ignore))))))
|
||||
(cdr ignore) remote)))))
|
||||
grep-find-ignored-files
|
||||
" --exclude=")))
|
||||
(and (eq grep-use-directories-skip t)
|
||||
|
@ -1242,48 +1247,50 @@ command before it's run."
|
|||
(defun rgrep-default-command (regexp files dir)
|
||||
"Compute the command for \\[rgrep] to use by default."
|
||||
(require 'find-dired) ; for `find-name-arg'
|
||||
(grep-expand-template
|
||||
grep-find-template
|
||||
regexp
|
||||
(concat (shell-quote-argument "(")
|
||||
" " find-name-arg " "
|
||||
(mapconcat
|
||||
#'shell-quote-argument
|
||||
(split-string files)
|
||||
(concat " -o " find-name-arg " "))
|
||||
" "
|
||||
(shell-quote-argument ")"))
|
||||
dir
|
||||
(concat
|
||||
(and grep-find-ignored-directories
|
||||
(concat "-type d "
|
||||
(shell-quote-argument "(")
|
||||
;; we should use shell-quote-argument here
|
||||
" -path "
|
||||
(mapconcat (lambda (d) (shell-quote-argument (concat "*/" d)))
|
||||
(rgrep-find-ignored-directories dir)
|
||||
" -o -path ")
|
||||
" "
|
||||
(shell-quote-argument ")")
|
||||
" -prune -o "))
|
||||
(and grep-find-ignored-files
|
||||
(concat (shell-quote-argument "!") " -type d "
|
||||
(shell-quote-argument "(")
|
||||
;; we should use shell-quote-argument here
|
||||
" -name "
|
||||
(mapconcat
|
||||
(lambda (ignore)
|
||||
(cond ((stringp ignore)
|
||||
(shell-quote-argument ignore))
|
||||
((consp ignore)
|
||||
(and (funcall (car ignore) dir)
|
||||
(shell-quote-argument
|
||||
(cdr ignore))))))
|
||||
grep-find-ignored-files
|
||||
" -o -name ")
|
||||
" "
|
||||
(shell-quote-argument ")")
|
||||
" -prune -o ")))))
|
||||
(let ((remote (file-remote-p (or dir default-directory))))
|
||||
(grep-expand-template
|
||||
grep-find-template
|
||||
regexp
|
||||
(concat (shell-quote-argument "(" remote)
|
||||
" " find-name-arg " "
|
||||
(mapconcat
|
||||
(lambda (x) (shell-quote-argument x remote))
|
||||
(split-string files)
|
||||
(concat " -o " find-name-arg " "))
|
||||
" "
|
||||
(shell-quote-argument ")" remote))
|
||||
dir
|
||||
(concat
|
||||
(and grep-find-ignored-directories
|
||||
(concat "-type d "
|
||||
(shell-quote-argument "(" remote)
|
||||
;; we should use shell-quote-argument here
|
||||
" -path "
|
||||
(mapconcat
|
||||
(lambda (d) (shell-quote-argument (concat "*/" d) remote))
|
||||
(rgrep-find-ignored-directories dir)
|
||||
" -o -path ")
|
||||
" "
|
||||
(shell-quote-argument ")" remote)
|
||||
" -prune -o "))
|
||||
(and grep-find-ignored-files
|
||||
(concat (shell-quote-argument "!" remote) " -type d "
|
||||
(shell-quote-argument "(" remote)
|
||||
;; we should use shell-quote-argument here
|
||||
" -name "
|
||||
(mapconcat
|
||||
(lambda (ignore)
|
||||
(cond ((stringp ignore)
|
||||
(shell-quote-argument ignore remote))
|
||||
((consp ignore)
|
||||
(and (funcall (car ignore) dir)
|
||||
(shell-quote-argument
|
||||
(cdr ignore) remote)))))
|
||||
grep-find-ignored-files
|
||||
" -o -name ")
|
||||
" "
|
||||
(shell-quote-argument ")" remote)
|
||||
" -prune -o "))))))
|
||||
|
||||
(defun grep-find-toggle-abbreviation ()
|
||||
"Toggle showing the hidden part of rgrep/lgrep/zrgrep command line."
|
||||
|
|
14
lisp/subr.el
14
lisp/subr.el
|
@ -3760,14 +3760,18 @@ Note: :data and :device are currently not supported on Windows."
|
|||
|
||||
(declare-function w32-shell-dos-semantics "w32-fns" nil)
|
||||
|
||||
(defun shell-quote-argument (argument)
|
||||
(defun shell-quote-argument (argument &optional posix)
|
||||
"Quote ARGUMENT for passing as argument to an inferior shell.
|
||||
|
||||
This function is designed to work with the syntax of your system's
|
||||
standard shell, and might produce incorrect results with unusual shells.
|
||||
See Info node `(elisp)Security Considerations'."
|
||||
(cond
|
||||
((eq system-type 'ms-dos)
|
||||
See Info node `(elisp)Security Considerations'.
|
||||
|
||||
If the optional POSIX argument is non-nil, ARGUMENT is quoted
|
||||
according to POSIX shell quoting rules, regardless of the
|
||||
system's shell."
|
||||
(cond
|
||||
((and (not posix) (eq system-type 'ms-dos))
|
||||
;; Quote using double quotes, but escape any existing quotes in
|
||||
;; the argument with backslashes.
|
||||
(let ((result "")
|
||||
|
@ -3782,7 +3786,7 @@ See Info node `(elisp)Security Considerations'."
|
|||
start (1+ end))))
|
||||
(concat "\"" result (substring argument start) "\"")))
|
||||
|
||||
((and (eq system-type 'windows-nt) (w32-shell-dos-semantics))
|
||||
((and (not posix) (eq system-type 'windows-nt) (w32-shell-dos-semantics))
|
||||
|
||||
;; First, quote argument so that CommandLineToArgvW will
|
||||
;; understand it. See
|
||||
|
|
Loading…
Add table
Reference in a new issue