diff options
| author | Stefan Monnier | 2012-04-25 14:53:57 -0400 |
|---|---|---|
| committer | Stefan Monnier | 2012-04-25 14:53:57 -0400 |
| commit | b4ff4f1fcb552dab77d4312f9adb9f290782fa98 (patch) | |
| tree | ed23ce73595490f9587bf179bad6b8797b13529a /lisp/comint.el | |
| parent | 79c4eeb45046eca02bd4a5daad1b673eb48377a1 (diff) | |
| download | emacs-b4ff4f1fcb552dab77d4312f9adb9f290782fa98.tar.gz emacs-b4ff4f1fcb552dab77d4312f9adb9f290782fa98.zip | |
Use completion-table-with-quoting for comint and pcomplete.
* lisp/comint.el (comint--unquote&requote-argument)
(comint--unquote-argument, comint--requote-argument): New functions.
(comint--unquote&expand-filename, comint-unquote-filename): Obsolete.
(comint-quote-filename): Use regexp-opt-charset.
(comint--common-suffix, comint--common-quoted-suffix)
(comint--table-subvert): Remove.
(comint-unquote-function, comint-requote-function): New vars.
(comint--complete-file-name-data): Use them with
completion-table-with-quoting.
* lisp/pcmpl-unix.el (pcomplete/scp): Use completion-table-subvert.
* lisp/pcomplete.el (pcomplete-arg-quote-list)
(pcomplete-quote-arg-hook, pcomplete-quote-argument): Obsolete.
(pcomplete-unquote-argument-function): Default to non-nil.
(pcomplete-unquote-argument): Simplify.
(pcomplete--common-quoted-suffix): Remove.
(pcomplete-requote-argument-function): New var.
(pcomplete--common-suffix): New function.
(pcomplete-completions-at-point): Use completion-table-with-quoting
and completion-table-subvert.
Diffstat (limited to 'lisp/comint.el')
| -rw-r--r-- | lisp/comint.el | 160 |
1 files changed, 63 insertions, 97 deletions
diff --git a/lisp/comint.el b/lisp/comint.el index 10981675971..2f8d7bd850c 100644 --- a/lisp/comint.el +++ b/lisp/comint.el | |||
| @@ -104,6 +104,7 @@ | |||
| 104 | (eval-when-compile (require 'cl)) | 104 | (eval-when-compile (require 'cl)) |
| 105 | (require 'ring) | 105 | (require 'ring) |
| 106 | (require 'ansi-color) | 106 | (require 'ansi-color) |
| 107 | (require 'regexp-opt) ;For regexp-opt-charset. | ||
| 107 | 108 | ||
| 108 | ;; Buffer Local Variables: | 109 | ;; Buffer Local Variables: |
| 109 | ;;============================================================================ | 110 | ;;============================================================================ |
| @@ -3000,26 +3001,62 @@ interpreter (e.g., the percent notation of cmd.exe on Windows)." | |||
| 3000 | See `comint-word'." | 3001 | See `comint-word'." |
| 3001 | (comint-word comint-file-name-chars)) | 3002 | (comint-word comint-file-name-chars)) |
| 3002 | 3003 | ||
| 3003 | (defun comint--unquote&expand-filename (filename) | 3004 | (defun comint--unquote&requote-argument (qstr &optional upos) |
| 3004 | ;; FIXME: The code below does unquote-then-expand which means that "\\$HOME" | 3005 | (unless upos (setq upos 0)) |
| 3005 | ;; gets expanded to the same as "$HOME" | 3006 | (let* ((qpos 0) |
| 3006 | (comint-substitute-in-file-name | 3007 | (dquotes nil) |
| 3007 | (comint-unquote-filename filename))) | 3008 | (ustrs '()) |
| 3009 | (re (concat | ||
| 3010 | "[\"']\\|\\\\\\(.\\)" | ||
| 3011 | "\\|\\$\\(?:\\([[:alpha:]][[:alnum:]]*\\)" | ||
| 3012 | "\\|{\\(?2:[^{}]+\\)}\\)" | ||
| 3013 | (when (memq system-type '(ms-dos windows-nt)) | ||
| 3014 | "\\|%\\(?2:[^\\\\/]*\\)%"))) | ||
| 3015 | (qupos nil) | ||
| 3016 | (push (lambda (str end) | ||
| 3017 | (push str ustrs) | ||
| 3018 | (setq upos (- upos (length str))) | ||
| 3019 | (unless (or qupos (> upos 0)) | ||
| 3020 | (setq qupos (if (< end 0) (- end) (+ upos end)))))) | ||
| 3021 | match) | ||
| 3022 | (while (setq match (string-match re qstr qpos)) | ||
| 3023 | (funcall push (substring qstr qpos match) match) | ||
| 3024 | (cond | ||
| 3025 | ((match-beginning 1) (funcall push (match-string 1 qstr) (match-end 0))) | ||
| 3026 | ((match-beginning 2) (funcall push (getenv (match-string 2 qstr)) | ||
| 3027 | (- (match-end 0)))) | ||
| 3028 | ((eq (aref qstr match) ?\") (setq dquotes (not dquotes))) | ||
| 3029 | ((eq (aref qstr match) ?\') | ||
| 3030 | (cond | ||
| 3031 | (dquotes (funcall push "'" (match-end 0))) | ||
| 3032 | ((< match (1+ (length qstr))) | ||
| 3033 | (let ((end (string-match "'" qstr (1+ match)))) | ||
| 3034 | (funcall push (substring qstr (1+ match) end) | ||
| 3035 | (or end (length qstr))))) | ||
| 3036 | (t nil))) | ||
| 3037 | (t (error "Unexpected case in comint--unquote&requote-argument!"))) | ||
| 3038 | (setq qpos (match-end 0))) | ||
| 3039 | (funcall push (substring qstr qpos) (length qstr)) | ||
| 3040 | (list (mapconcat #'identity (nreverse ustrs) "") | ||
| 3041 | qupos #'comint-quote-filename))) | ||
| 3042 | |||
| 3043 | (defun comint--unquote-argument (str) | ||
| 3044 | (car (comint--unquote&requote-argument str))) | ||
| 3045 | (define-obsolete-function-alias 'comint--unquote&expand-filename | ||
| 3046 | #'comint--unquote-argument "24.2") | ||
| 3008 | 3047 | ||
| 3009 | (defun comint-match-partial-filename () | 3048 | (defun comint-match-partial-filename () |
| 3010 | "Return the unquoted&expanded filename at point, or nil if none is found. | 3049 | "Return the unquoted&expanded filename at point, or nil if none is found. |
| 3011 | Environment variables are substituted. See `comint-word'." | 3050 | Environment variables are substituted. See `comint-word'." |
| 3012 | (let ((filename (comint--match-partial-filename))) | 3051 | (let ((filename (comint--match-partial-filename))) |
| 3013 | (and filename (comint--unquote&expand-filename filename)))) | 3052 | (and filename (comint--unquote-argument filename)))) |
| 3014 | 3053 | ||
| 3015 | (defun comint-quote-filename (filename) | 3054 | (defun comint-quote-filename (filename) |
| 3016 | "Return FILENAME with magic characters quoted. | 3055 | "Return FILENAME with magic characters quoted. |
| 3017 | Magic characters are those in `comint-file-name-quote-list'." | 3056 | Magic characters are those in `comint-file-name-quote-list'." |
| 3018 | (if (null comint-file-name-quote-list) | 3057 | (if (null comint-file-name-quote-list) |
| 3019 | filename | 3058 | filename |
| 3020 | (let ((regexp | 3059 | (let ((regexp (regexp-opt-charset comint-file-name-quote-list))) |
| 3021 | (format "[%s]" | ||
| 3022 | (mapconcat 'char-to-string comint-file-name-quote-list "")))) | ||
| 3023 | (save-match-data | 3060 | (save-match-data |
| 3024 | (let ((i 0)) | 3061 | (let ((i 0)) |
| 3025 | (while (string-match regexp filename i) | 3062 | (while (string-match regexp filename i) |
| @@ -3033,6 +3070,12 @@ Magic characters are those in `comint-file-name-quote-list'." | |||
| 3033 | filename | 3070 | filename |
| 3034 | (save-match-data | 3071 | (save-match-data |
| 3035 | (replace-regexp-in-string "\\\\\\(.\\)" "\\1" filename t)))) | 3072 | (replace-regexp-in-string "\\\\\\(.\\)" "\\1" filename t)))) |
| 3073 | (make-obsolete 'comint-unquote-filename nil "24.2") | ||
| 3074 | |||
| 3075 | (defun comint--requote-argument (upos qstr) | ||
| 3076 | ;; See `completion-table-with-quoting'. | ||
| 3077 | (let ((res (comint--unquote&requote-argument qstr upos))) | ||
| 3078 | (cons (nth 1 res) (nth 2 res)))) | ||
| 3036 | 3079 | ||
| 3037 | (defun comint-completion-at-point () | 3080 | (defun comint-completion-at-point () |
| 3038 | (run-hook-with-args-until-success 'comint-dynamic-complete-functions)) | 3081 | (run-hook-with-args-until-success 'comint-dynamic-complete-functions)) |
| @@ -3066,87 +3109,6 @@ Returns t if successful." | |||
| 3066 | (when (comint--match-partial-filename) | 3109 | (when (comint--match-partial-filename) |
| 3067 | (comint--complete-file-name-data))) | 3110 | (comint--complete-file-name-data))) |
| 3068 | 3111 | ||
| 3069 | ;; FIXME: comint--common-suffix, comint--common-quoted-suffix, and | ||
| 3070 | ;; comint--table-subvert don't fully solve the problem, since | ||
| 3071 | ;; selecting a file from *Completions* won't quote it, among several | ||
| 3072 | ;; other problems. | ||
| 3073 | |||
| 3074 | (defun comint--common-suffix (s1 s2) | ||
| 3075 | (assert (not (or (string-match "\n" s1) (string-match "\n" s2)))) | ||
| 3076 | ;; Since S2 is expected to be the "unquoted/expanded" version of S1, | ||
| 3077 | ;; there shouldn't be any case difference, even if the completion is | ||
| 3078 | ;; case-insensitive. | ||
| 3079 | (let ((case-fold-search nil)) | ||
| 3080 | (string-match ".*?\\(.*\\)\n.*\\1\\'" (concat s1 "\n" s2)) | ||
| 3081 | (- (match-end 1) (match-beginning 1)))) | ||
| 3082 | |||
| 3083 | (defun comint--common-quoted-suffix (s1 s2) | ||
| 3084 | ;; FIXME: Copied in pcomplete.el. | ||
| 3085 | "Find the common suffix between S1 and S2 where S1 is the expanded S2. | ||
| 3086 | S1 is expected to be the unquoted and expanded version of S2. | ||
| 3087 | Returns (PS1 . PS2), i.e. the shortest prefixes of S1 and S2, such that | ||
| 3088 | S1 = (concat PS1 SS1) and S2 = (concat PS2 SS2) and | ||
| 3089 | SS1 = (unquote SS2)." | ||
| 3090 | (let* ((cs (comint--common-suffix s1 s2)) | ||
| 3091 | (ss1 (substring s1 (- (length s1) cs))) | ||
| 3092 | (qss1 (comint-quote-filename ss1)) | ||
| 3093 | qc s2b) | ||
| 3094 | (if (and (not (equal ss1 qss1)) | ||
| 3095 | (setq qc (comint-quote-filename (substring ss1 0 1))) | ||
| 3096 | (setq s2b (- (length s2) cs (length qc) -1)) | ||
| 3097 | (>= s2b 0) ;bug#11158. | ||
| 3098 | (eq t (compare-strings s2 s2b (- (length s2) cs -1) | ||
| 3099 | qc nil nil))) | ||
| 3100 | ;; The difference found is just that one char is quoted in S2 | ||
| 3101 | ;; but not in S1, keep looking before this difference. | ||
| 3102 | (comint--common-quoted-suffix | ||
| 3103 | (substring s1 0 (- (length s1) cs)) | ||
| 3104 | (substring s2 0 s2b)) | ||
| 3105 | (cons (substring s1 0 (- (length s1) cs)) | ||
| 3106 | (substring s2 0 (- (length s2) cs)))))) | ||
| 3107 | |||
| 3108 | (defun comint--table-subvert (table s1 s2 &optional quote-fun unquote-fun) | ||
| 3109 | "Completion table that replaces the prefix S1 with S2 in STRING. | ||
| 3110 | The result is a completion table which completes strings of the | ||
| 3111 | form (concat S1 S) in the same way as TABLE completes strings of | ||
| 3112 | the form (concat S2 S)." | ||
| 3113 | (lambda (string pred action) | ||
| 3114 | (let* ((str (if (eq t (compare-strings string 0 (length s1) s1 nil nil | ||
| 3115 | completion-ignore-case)) | ||
| 3116 | (let ((rest (substring string (length s1)))) | ||
| 3117 | (concat s2 (if unquote-fun | ||
| 3118 | (funcall unquote-fun rest) rest))))) | ||
| 3119 | (res (if str (complete-with-action action table str pred)))) | ||
| 3120 | (when res | ||
| 3121 | (cond | ||
| 3122 | ((and (eq (car-safe action) 'boundaries)) | ||
| 3123 | (let ((beg (or (and (eq (car-safe res) 'boundaries) (cadr res)) 0))) | ||
| 3124 | (list* 'boundaries | ||
| 3125 | (max (length s1) | ||
| 3126 | ;; FIXME: Adjust because of quoting/unquoting. | ||
| 3127 | (+ beg (- (length s1) (length s2)))) | ||
| 3128 | (and (eq (car-safe res) 'boundaries) (cddr res))))) | ||
| 3129 | ((stringp res) | ||
| 3130 | (if (eq t (compare-strings res 0 (length s2) s2 nil nil | ||
| 3131 | completion-ignore-case)) | ||
| 3132 | (let ((rest (substring res (length s2)))) | ||
| 3133 | (concat s1 (if quote-fun (funcall quote-fun rest) rest))))) | ||
| 3134 | ((eq action t) | ||
| 3135 | (let ((bounds (completion-boundaries str table pred ""))) | ||
| 3136 | (if (>= (car bounds) (length s2)) | ||
| 3137 | (if quote-fun (mapcar quote-fun res) res) | ||
| 3138 | (let ((re (concat "\\`" | ||
| 3139 | (regexp-quote (substring s2 (car bounds)))))) | ||
| 3140 | (delq nil | ||
| 3141 | (mapcar (lambda (c) | ||
| 3142 | (if (string-match re c) | ||
| 3143 | (let ((str (substring c (match-end 0)))) | ||
| 3144 | (if quote-fun | ||
| 3145 | (funcall quote-fun str) str)))) | ||
| 3146 | res)))))) | ||
| 3147 | ;; E.g. action=nil and it's the only completion. | ||
| 3148 | (res)))))) | ||
| 3149 | |||
| 3150 | (defun comint-completion-file-name-table (string pred action) | 3112 | (defun comint-completion-file-name-table (string pred action) |
| 3151 | (if (not (file-name-absolute-p string)) | 3113 | (if (not (file-name-absolute-p string)) |
| 3152 | (completion-file-name-table string pred action) | 3114 | (completion-file-name-table string pred action) |
| @@ -3165,6 +3127,13 @@ the form (concat S2 S)." | |||
| 3165 | res))) | 3127 | res))) |
| 3166 | (t (completion-file-name-table string pred action))))) | 3128 | (t (completion-file-name-table string pred action))))) |
| 3167 | 3129 | ||
| 3130 | (defvar comint-unquote-function #'comint--unquote-argument | ||
| 3131 | "Function to use for completion of quoted data. | ||
| 3132 | See `completion-table-with-quoting' and `comint-requote-function'.") | ||
| 3133 | (defvar comint-requote-function #'comint--requote-argument | ||
| 3134 | "Function to use for completion of quoted data. | ||
| 3135 | See `completion-table-with-quoting' and `comint-requote-function'.") | ||
| 3136 | |||
| 3168 | (defun comint--complete-file-name-data () | 3137 | (defun comint--complete-file-name-data () |
| 3169 | "Return the completion data for file name at point." | 3138 | "Return the completion data for file name at point." |
| 3170 | (let* ((filesuffix (cond ((not comint-completion-addsuffix) "") | 3139 | (let* ((filesuffix (cond ((not comint-completion-addsuffix) "") |
| @@ -3175,14 +3144,11 @@ the form (concat S2 S)." | |||
| 3175 | (filename (comint--match-partial-filename)) | 3144 | (filename (comint--match-partial-filename)) |
| 3176 | (filename-beg (if filename (match-beginning 0) (point))) | 3145 | (filename-beg (if filename (match-beginning 0) (point))) |
| 3177 | (filename-end (if filename (match-end 0) (point))) | 3146 | (filename-end (if filename (match-end 0) (point))) |
| 3178 | (unquoted (if filename (comint--unquote&expand-filename filename) "")) | ||
| 3179 | (table | 3147 | (table |
| 3180 | (let ((prefixes (comint--common-quoted-suffix | 3148 | (completion-table-with-quoting |
| 3181 | unquoted filename))) | 3149 | #'comint-completion-file-name-table |
| 3182 | (comint--table-subvert | 3150 | comint-unquote-function |
| 3183 | #'comint-completion-file-name-table | 3151 | comint-requote-function))) |
| 3184 | (cdr prefixes) (car prefixes) | ||
| 3185 | #'comint-quote-filename #'comint-unquote-filename)))) | ||
| 3186 | (nconc | 3152 | (nconc |
| 3187 | (list | 3153 | (list |
| 3188 | filename-beg filename-end | 3154 | filename-beg filename-end |