From: Stefan Monnier Date: Tue, 15 May 2012 16:58:35 +0000 (-0400) Subject: Only handle ".." and '..' quoting in shell-mode. X-Git-Tag: emacs-24.2.90~471^2~78 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=2473256d7b660edc5c1525163b2e9917d6ebf18d;p=emacs.git Only handle ".." and '..' quoting in shell-mode. * lisp/shell.el (shell--unquote&requote-argument, shell--unquote-argument) (shell--requote-argument): New functions. (shell-completion-vars): Use them. (shell--parse-pcomplete-arguments): Rename from shell-parse-pcomplete-arguments. * lisp/comint.el (comint-word): Obey comint-file-name-quote-list. Simplify. (comint--unquote&requote-argument): Don't handle ".." and '..' quoting. Obey comint-file-name-quote-list. Fixes: debbugs:11466 --- diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 865bdd7c6a3..de2cfc6f0ac 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,5 +1,15 @@ 2012-05-15 Stefan Monnier + Only handle ".." and '..' quoting in shell-mode (bug#11466). + * shell.el (shell--unquote&requote-argument, shell--unquote-argument) + (shell--requote-argument): New functions. + (shell-completion-vars): Use them. + (shell--parse-pcomplete-arguments): Rename from + shell-parse-pcomplete-arguments. + * comint.el (comint-word): Obey comint-file-name-quote-list. Simplify. + (comint--unquote&requote-argument): Don't handle ".." and '..' quoting. + Obey comint-file-name-quote-list. + * emacs-lisp/smie.el (smie-indent--bolp-1): New function. (smie-indent-keyword): Use it. diff --git a/lisp/comint.el b/lisp/comint.el index 43e42c87be7..db0f5b8b460 100644 --- a/lisp/comint.el +++ b/lisp/comint.el @@ -2968,19 +2968,20 @@ This is a good thing to set in mode hooks.") "Return the word of WORD-CHARS at point, or nil if none is found. Word constituents are considered to be those in WORD-CHARS, which is like the inside of a \"[...]\" (see `skip-chars-forward'), plus all non-ASCII characters." + ;; FIXME: Need to handle "..." and '...' quoting in shell.el! + ;; This should be combined with pomplete-parsing somehow. (save-excursion (let ((here (point)) giveup) (while (not giveup) (let ((startpoint (point))) (skip-chars-backward (concat "\\\\" word-chars)) - ;; Fixme: This isn't consistent with Bash, at least -- not - ;; all non-ASCII chars should be word constituents. - (if (and (> (- (point) 2) (point-min)) - (= (char-after (- (point) 2)) ?\\)) + (if (and comint-file-name-quote-list + (eq (char-before (1- (point))) ?\\)) (forward-char -2)) - (if (and (> (- (point) 1) (point-min)) - (>= (char-after (- (point) 1)) 128)) + ;; FIXME: This isn't consistent with Bash, at least -- not + ;; all non-ASCII chars should be word constituents. + (if (and (not (bobp)) (>= (char-before) 128)) (forward-char -1)) (if (= (point) startpoint) (setq giveup t)))) @@ -3012,14 +3013,14 @@ See `comint-word'." (defun comint--unquote&requote-argument (qstr &optional upos) (unless upos (setq upos 0)) (let* ((qpos 0) - (dquotes nil) (ustrs '()) (re (concat - "[\"']\\|\\\\\\(.\\)" - "\\|\\$\\(?:\\([[:alpha:]][[:alnum:]]*\\)" - "\\|{\\(?2:[^{}]+\\)}\\)" + "\\$\\(?:\\([[:alpha:]][[:alnum:]]*\\)" + "\\|{\\(?1:[^{}]+\\)}\\)" (when (memq system-type '(ms-dos windows-nt)) - "\\|%\\(?2:[^\\\\/]*\\)%"))) + "\\|%\\(?1:[^\\\\/]*\\)%") + (when comint-file-name-quote-list + "\\|\\\\\\(.\\)"))) (qupos nil) (push (lambda (str end) (push str ustrs) @@ -3030,18 +3031,9 @@ See `comint-word'." (while (setq match (string-match re qstr qpos)) (funcall push (substring qstr qpos match) match) (cond - ((match-beginning 1) (funcall push (match-string 1 qstr) (match-end 0))) - ((match-beginning 2) (funcall push (getenv (match-string 2 qstr)) + ((match-beginning 2) (funcall push (match-string 2 qstr) (match-end 0))) + ((match-beginning 1) (funcall push (getenv (match-string 1 qstr)) (- (match-end 0)))) - ((eq (aref qstr match) ?\") (setq dquotes (not dquotes))) - ((eq (aref qstr match) ?\') - (cond - (dquotes (funcall push "'" (match-end 0))) - ((< match (1+ (length qstr))) - (let ((end (string-match "'" qstr (1+ match)))) - (funcall push (substring qstr (1+ match) end) - (or end (length qstr))))) - (t nil))) (t (error "Unexpected case in comint--unquote&requote-argument!"))) (setq qpos (match-end 0))) (funcall push (substring qstr qpos) (length qstr)) @@ -3140,7 +3132,7 @@ Returns t if successful." See `completion-table-with-quoting' and `comint-requote-function'.") (defvar comint-requote-function #'comint--requote-argument "Function to use for completion of quoted data. -See `completion-table-with-quoting' and `comint-requote-function'.") +See `completion-table-with-quoting' and `comint-unquote-function'.") (defun comint--complete-file-name-data () "Return the completion data for file name at point." diff --git a/lisp/shell.el b/lisp/shell.el index 1784188f6ad..ca238a443f3 100644 --- a/lisp/shell.el +++ b/lisp/shell.el @@ -372,8 +372,57 @@ Thus, this does not include the shell's current directory.") ;;; Basic Procedures -(defun shell-parse-pcomplete-arguments () +(defun shell--unquote&requote-argument (qstr &optional upos) + (unless upos (setq upos 0)) + (let* ((qpos 0) + (dquotes nil) + (ustrs '()) + (re (concat + "[\"']" + "\\|\\$\\(?:\\([[:alpha:]][[:alnum:]]*\\)" + "\\|{\\(?1:[^{}]+\\)}\\)" + (when (memq system-type '(ms-dos windows-nt)) + "\\|%\\(?1:[^\\\\/]*\\)%") + (when comint-file-name-quote-list + "\\|\\\\\\(.\\)"))) + (qupos nil) + (push (lambda (str end) + (push str ustrs) + (setq upos (- upos (length str))) + (unless (or qupos (> upos 0)) + (setq qupos (if (< end 0) (- end) (+ upos end)))))) + match) + (while (setq match (string-match re qstr qpos)) + (funcall push (substring qstr qpos match) match) + (cond + ((match-beginning 2) (funcall push (match-string 2 qstr) (match-end 0))) + ((match-beginning 1) (funcall push (getenv (match-string 1 qstr)) + (- (match-end 0)))) + ((eq (aref qstr match) ?\") (setq dquotes (not dquotes))) + ((eq (aref qstr match) ?\') + (cond + (dquotes (funcall push "'" (match-end 0))) + ((< match (1+ (length qstr))) + (let ((end (string-match "'" qstr (1+ match)))) + (funcall push (substring qstr (1+ match) end) + (or end (length qstr))))) + (t nil))) + (t (error "Unexpected case in shell--unquote&requote-argument!"))) + (setq qpos (match-end 0))) + (funcall push (substring qstr qpos) (length qstr)) + (list (mapconcat #'identity (nreverse ustrs) "") + qupos #'comint-quote-filename))) + +(defun shell--unquote-argument (str) + (car (shell--unquote&requote-argument str))) +(defun shell--requote-argument (upos qstr) + ;; See `completion-table-with-quoting'. + (let ((res (shell--unquote&requote-argument qstr upos))) + (cons (nth 1 res) (nth 2 res)))) + +(defun shell--parse-pcomplete-arguments () "Parse whitespace separated arguments in the current region." + ;; FIXME: share code with shell--unquote&requote-argument. (let ((begin (save-excursion (shell-backward-command 1) (point))) (end (point)) begins args) @@ -394,13 +443,13 @@ Thus, this does not include the shell's current directory.") (cond ((match-beginning 3) ;Backslash escape. (push (cond - ((null pcomplete-arg-quote-list) + ((null comint-file-name-quote-list) (goto-char (match-beginning 3)) "\\") ((= (match-beginning 3) (match-end 3)) "\\") (t (match-string 3))) arg)) ((match-beginning 2) ;Double quote. - (push (if (null pcomplete-arg-quote-list) (match-string 2) + (push (if (null comint-file-name-quote-list) (match-string 2) (replace-regexp-in-string "\\\\\\(.\\)" "\\1" (match-string 2))) arg)) @@ -430,10 +479,10 @@ Shell buffers. It implements `shell-completion-execonly' for shell-file-name-quote-list) (set (make-local-variable 'comint-dynamic-complete-functions) shell-dynamic-complete-functions) + (setq-local comint-unquote-function #'shell--unquote-argument) + (setq-local comint-requote-function #'shell--requote-argument) (set (make-local-variable 'pcomplete-parse-arguments-function) - #'shell-parse-pcomplete-arguments) - (set (make-local-variable 'pcomplete-arg-quote-list) - comint-file-name-quote-list) + #'shell--parse-pcomplete-arguments) (set (make-local-variable 'pcomplete-termination-string) (cond ((not comint-completion-addsuffix) "") ((stringp comint-completion-addsuffix)