aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Monnier2011-04-20 16:05:50 -0300
committerStefan Monnier2011-04-20 16:05:50 -0300
commit2dbaa0806bb585dec7d678bc2bdf842847514097 (patch)
tree6e5bc80a84ed8a88baaf3af1b18e7fb367d36a9a
parentc79a6f38ab49050faa0d33e57d0c606bd9ea0e1a (diff)
downloademacs-2dbaa0806bb585dec7d678bc2bdf842847514097.tar.gz
emacs-2dbaa0806bb585dec7d678bc2bdf842847514097.zip
* lisp/comint.el: Use lexical-binding. Use std completion UI. Require CL.
(comint-dynamic-complete-functions): Use comint-filename-completion. (comint-completion-addsuffix): Tweak custom type. (comint-filename-completion, comint--common-suffix) (comint--common-quoted-suffix, comint--table-subvert) (comint--complete-file-name-data): New functions. (comint-dynamic-complete-as-filename, comint-dynamic-complete-filename) (comint-dynamic-list-filename-completions): Use them. (comint-dynamic-simple-complete): Make obsolete. * lisp/minibuffer.el (completion-in-region-mode): Keep completion-in-region-mode--predicate global. (completion-in-region--postch): Assume completion-in-region-mode--predicate is not null.
-rw-r--r--lisp/ChangeLog14
-rw-r--r--lisp/comint.el230
-rw-r--r--lisp/minibuffer.el13
3 files changed, 158 insertions, 99 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index 64ca1027ca4..214376b817c 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,5 +1,19 @@
12011-04-20 Stefan Monnier <monnier@iro.umontreal.ca> 12011-04-20 Stefan Monnier <monnier@iro.umontreal.ca>
2 2
3 * comint.el: Use lexical-binding. Require CL.
4 (comint-dynamic-complete-functions): Use comint-filename-completion.
5 (comint-completion-addsuffix): Tweak custom type.
6 (comint-filename-completion, comint--common-suffix)
7 (comint--common-quoted-suffix, comint--table-subvert)
8 (comint--complete-file-name-data): New functions.
9 (comint-dynamic-complete-as-filename, comint-dynamic-complete-filename)
10 (comint-dynamic-list-filename-completions): Use them.
11 (comint-dynamic-simple-complete): Make obsolete.
12 * minibuffer.el (completion-in-region-mode):
13 Keep completion-in-region-mode--predicate global.
14 (completion-in-region--postch):
15 Assume completion-in-region-mode--predicate is not null.
16
3 * progmodes/flymake.el (flymake-start-syntax-check-process): 17 * progmodes/flymake.el (flymake-start-syntax-check-process):
4 Obey `dir'. Simplify. 18 Obey `dir'. Simplify.
5 19
diff --git a/lisp/comint.el b/lisp/comint.el
index 64ed32dd2b3..735770a8908 100644
--- a/lisp/comint.el
+++ b/lisp/comint.el
@@ -1,4 +1,4 @@
1;;; comint.el --- general command interpreter in a window stuff 1;;; comint.el --- general command interpreter in a window stuff -*- lexical-binding: t -*-
2 2
3;; Copyright (C) 1988, 1990, 1992-2011 Free Software Foundation, Inc. 3;; Copyright (C) 1988, 1990, 1992-2011 Free Software Foundation, Inc.
4 4
@@ -101,6 +101,7 @@
101 101
102;;; Code: 102;;; Code:
103 103
104(eval-when-compile (require 'cl))
104(require 'ring) 105(require 'ring)
105 106
106;; Buffer Local Variables: 107;; Buffer Local Variables:
@@ -366,7 +367,7 @@ text matching `comint-prompt-regexp', depending on the value of
366`comint-use-prompt-regexp'.") 367`comint-use-prompt-regexp'.")
367 368
368(defvar comint-dynamic-complete-functions 369(defvar comint-dynamic-complete-functions
369 '(comint-replace-by-expanded-history comint-dynamic-complete-filename) 370 '(comint-replace-by-expanded-history comint-filename-completion)
370 "List of functions called to perform completion. 371 "List of functions called to perform completion.
371Works like `completion-at-point-functions'. 372Works like `completion-at-point-functions'.
372See also `comint-dynamic-complete'. 373See also `comint-dynamic-complete'.
@@ -2831,10 +2832,9 @@ its response can be seen."
2831;; comint-dynamic-list-filename-completions List completions in help buffer. 2832;; comint-dynamic-list-filename-completions List completions in help buffer.
2832;; comint-replace-by-expanded-filename Expand and complete filename at point; 2833;; comint-replace-by-expanded-filename Expand and complete filename at point;
2833;; replace with expanded/completed name. 2834;; replace with expanded/completed name.
2834;; comint-dynamic-simple-complete Complete stub given candidates.
2835 2835
2836;; These are not installed in the comint-mode keymap. But they are 2836;; These are not installed in the comint-mode keymap. But they are
2837;; available for people who want them. Shell-mode installs them: 2837;; available for people who want them. Shell-mode installs them:
2838;; (define-key shell-mode-map "\t" 'comint-dynamic-complete) 2838;; (define-key shell-mode-map "\t" 'comint-dynamic-complete)
2839;; (define-key shell-mode-map "\M-?" 2839;; (define-key shell-mode-map "\M-?"
2840;; 'comint-dynamic-list-filename-completions))) 2840;; 'comint-dynamic-list-filename-completions)))
@@ -2849,14 +2849,16 @@ This mirrors the optional behavior of tcsh."
2849 :group 'comint-completion) 2849 :group 'comint-completion)
2850 2850
2851(defcustom comint-completion-addsuffix t 2851(defcustom comint-completion-addsuffix t
2852 "If non-nil, add a `/' to completed directories, ` ' to file names. 2852 "If non-nil, add ` ' to file names.
2853If a cons pair, it should be of the form (DIRSUFFIX . FILESUFFIX) where 2853It can either be a string FILESUFFIX or a cons (DIRSUFFIX . FILESUFFIX)
2854DIRSUFFIX and FILESUFFIX are strings added on unambiguous or exact completion. 2854where DIRSUFFIX is ignored and FILESUFFIX is a string added on unambiguous
2855or exact completion.
2855This mirrors the optional behavior of tcsh." 2856This mirrors the optional behavior of tcsh."
2856 :type '(choice (const :tag "None" nil) 2857 :type '(choice (const :tag "None" nil)
2857 (const :tag "Add /" t) 2858 (const :tag "Add SPC" t)
2858 (cons :tag "Suffix pair" 2859 (string :tag "File suffix")
2859 (string :tag "Directory suffix") 2860 (cons :tag "Obsolete suffix pair"
2861 (string :tag "Ignored")
2860 (string :tag "File suffix"))) 2862 (string :tag "File suffix")))
2861 :group 'comint-completion) 2863 :group 'comint-completion)
2862 2864
@@ -3016,73 +3018,125 @@ Returns t if successful."
3016 (when (comint--match-partial-filename) 3018 (when (comint--match-partial-filename)
3017 (unless (window-minibuffer-p (selected-window)) 3019 (unless (window-minibuffer-p (selected-window))
3018 (message "Completing file name...")) 3020 (message "Completing file name..."))
3019 (comint-dynamic-complete-as-filename))) 3021 (apply #'completion-in-region (comint--complete-file-name-data))))
3020 3022
3021(defun comint-dynamic-complete-as-filename () 3023(defun comint-filename-completion ()
3022 "Dynamically complete at point as a filename. 3024 "Return completion data for filename at point, if any."
3023See `comint-dynamic-complete-filename'. Returns t if successful." 3025 (when (comint--match-partial-filename)
3024 (let* ((completion-ignore-case read-file-name-completion-ignore-case) 3026 (comint--complete-file-name-data)))
3025 (completion-ignored-extensions comint-completion-fignore) 3027
3026 ;; If we bind this, it breaks remote directory tracking in rlogin.el. 3028;; FIXME: comint--common-suffix, comint--common-quoted-suffix, and
3027 ;; I think it was originally bound to solve file completion problems, 3029;; comint--table-subvert copied from pcomplete. And they don't fully solve
3028 ;; but subsequent changes may have made this unnecessary. sm. 3030;; the problem, since selecting a file from *Completions* won't quote it.
3029 ;;(file-name-handler-alist nil) 3031
3030 (minibuffer-p (window-minibuffer-p (selected-window))) 3032(defun comint--common-suffix (s1 s2)
3031 (success t) 3033 (assert (not (or (string-match "\n" s1) (string-match "\n" s2))))
3032 (dirsuffix (cond ((not comint-completion-addsuffix) "") 3034 ;; Since S2 is expected to be the "unquoted/expanded" version of S1,
3033 ((not (consp comint-completion-addsuffix)) "/") 3035 ;; there shouldn't be any case difference, even if the completion is
3034 (t (car comint-completion-addsuffix)))) 3036 ;; case-insensitive.
3035 (filesuffix (cond ((not comint-completion-addsuffix) "") 3037 (let ((case-fold-search nil))
3038 (string-match ".*?\\(.*\\)\n.*\\1\\'" (concat s1 "\n" s2))
3039 (- (match-end 1) (match-beginning 1))))
3040
3041(defun comint--common-quoted-suffix (s1 s2)
3042 "Find the common suffix between S1 and S2 where S1 is the expanded S2.
3043S1 is expected to be the unquoted and expanded version of S1.
3044Returns (PS1 . PS2), i.e. the shortest prefixes of S1 and S2, such that
3045S1 = (concat PS1 SS1) and S2 = (concat PS2 SS2) and
3046SS1 = (unquote SS2)."
3047 (let* ((cs (comint--common-suffix s1 s2))
3048 (ss1 (substring s1 (- (length s1) cs)))
3049 (qss1 (comint-quote-filename ss1))
3050 qc)
3051 (if (and (not (equal ss1 qss1))
3052 (setq qc (comint-quote-filename (substring ss1 0 1)))
3053 (eq t (compare-strings s2 (- (length s2) cs (length qc) -1)
3054 (- (length s2) cs -1)
3055 qc nil nil)))
3056 ;; The difference found is just that one char is quoted in S2
3057 ;; but not in S1, keep looking before this difference.
3058 (comint--common-quoted-suffix
3059 (substring s1 0 (- (length s1) cs))
3060 (substring s2 0 (- (length s2) cs (length qc) -1)))
3061 (cons (substring s1 0 (- (length s1) cs))
3062 (substring s2 0 (- (length s2) cs))))))
3063
3064(defun comint--table-subvert (table s1 s2 string pred action)
3065 "Completion table that replaces the prefix S1 with S2 in STRING.
3066When TABLE, S1 and S2 are provided by `apply-partially', the result
3067is a completion table which completes strings of the form (concat S1 S)
3068in the same way as TABLE completes strings of the form (concat S2 S)."
3069 (let* ((str (if (eq t (compare-strings string 0 (length s1) s1 nil nil
3070 completion-ignore-case))
3071 (concat s2 (comint-unquote-filename
3072 (substring string (length s1))))))
3073 (res (if str (complete-with-action action table str pred))))
3074 (when res
3075 (cond
3076 ((and (eq (car-safe action) 'boundaries))
3077 (let ((beg (or (and (eq (car-safe res) 'boundaries) (cadr res)) 0)))
3078 (list* 'boundaries
3079 (max (length s1)
3080 ;; FIXME: Adjust because of quoting/unquoting.
3081 (+ beg (- (length s1) (length s2))))
3082 (and (eq (car-safe res) 'boundaries) (cddr res)))))
3083 ((stringp res)
3084 (if (eq t (compare-strings res 0 (length s2) s2 nil nil
3085 completion-ignore-case))
3086 (concat s1 (comint-quote-filename
3087 (substring res (length s2))))))
3088 ((eq action t)
3089 (let ((bounds (completion-boundaries str table pred "")))
3090 (if (>= (car bounds) (length s2))
3091 res
3092 (let ((re (concat "\\`"
3093 (regexp-quote (substring s2 (car bounds))))))
3094 (delq nil
3095 (mapcar (lambda (c)
3096 (if (string-match re c)
3097 (substring c (match-end 0))))
3098 res))))))
3099 ;; E.g. action=nil and it's the only completion.
3100 (res)))))
3101
3102(defun comint--complete-file-name-data ()
3103 "Return the completion data for file name at point."
3104 (let* ((filesuffix (cond ((not comint-completion-addsuffix) "")
3105 ((stringp comint-completion-addsuffix)
3106 comint-completion-addsuffix)
3036 ((not (consp comint-completion-addsuffix)) " ") 3107 ((not (consp comint-completion-addsuffix)) " ")
3037 (t (cdr comint-completion-addsuffix)))) 3108 (t (cdr comint-completion-addsuffix))))
3038 (filename (comint-match-partial-filename)) 3109 (filename (comint--match-partial-filename))
3039 (filename-beg (if filename (match-beginning 0) (point))) 3110 (filename-beg (if filename (match-beginning 0) (point)))
3040 (filename-end (if filename (match-end 0) (point))) 3111 (filename-end (if filename (match-end 0) (point)))
3041 (filename (or filename "")) 3112 (unquoted (if filename (comint--unquote&expand-filename filename) ""))
3042 (filedir (file-name-directory filename)) 3113 (table
3043 (filenondir (file-name-nondirectory filename)) 3114 (let ((prefixes (comint--common-quoted-suffix
3044 (directory (if filedir (comint-directory filedir) default-directory)) 3115 unquoted filename)))
3045 (completion (file-name-completion filenondir directory))) 3116 (apply-partially
3046 (cond ((null completion) 3117 #'comint--table-subvert
3047 (if minibuffer-p 3118 #'completion-file-name-table
3048 (minibuffer-message "No completions of %s" filename) 3119 (cdr prefixes) (car prefixes)))))
3049 (message "No completions of %s" filename)) 3120 (list
3050 (setq success nil)) 3121 filename-beg filename-end
3051 ((eq completion t) ; Means already completed "file". 3122 (lambda (string pred action)
3052 (insert filesuffix) 3123 (let ((completion-ignore-case read-file-name-completion-ignore-case)
3053 (unless minibuffer-p 3124 (completion-ignored-extensions comint-completion-fignore))
3054 (message "Sole completion"))) 3125 (if (zerop (length filesuffix))
3055 ((string-equal completion "") ; Means completion on "directory/". 3126 (complete-with-action action table string pred)
3056 (comint-dynamic-list-filename-completions)) 3127 ;; Add a space at the end of completion. Use a terminator-regexp
3057 (t ; Completion string returned. 3128 ;; that never matches since the terminator cannot appear
3058 (let ((file (concat (file-name-as-directory directory) completion))) 3129 ;; within the completion field anyway.
3059 ;; Insert completion. Note that the completion string 3130 (completion-table-with-terminator
3060 ;; may have a different case than what's in the prompt, 3131 (cons filesuffix "\\`a\\`")
3061 ;; if read-file-name-completion-ignore-case is non-nil, 3132 table string pred action)))))))
3062 (delete-region filename-beg filename-end)
3063 (if filedir (insert (comint-quote-filename filedir)))
3064 (insert (comint-quote-filename (directory-file-name completion)))
3065 (cond ((symbolp (file-name-completion completion directory))
3066 ;; We inserted a unique completion.
3067 (insert (if (file-directory-p file) dirsuffix filesuffix))
3068 (unless minibuffer-p
3069 (message "Completed")))
3070 ((and comint-completion-recexact comint-completion-addsuffix
3071 (string-equal filenondir completion)
3072 (file-exists-p file))
3073 ;; It's not unique, but user wants shortest match.
3074 (insert (if (file-directory-p file) dirsuffix filesuffix))
3075 (unless minibuffer-p
3076 (message "Completed shortest")))
3077 ((or comint-completion-autolist
3078 (string-equal filenondir completion))
3079 ;; It's not unique, list possible completions.
3080 (comint-dynamic-list-filename-completions))
3081 (t
3082 (unless minibuffer-p
3083 (message "Partially completed")))))))
3084 success))
3085 3133
3134(defun comint-dynamic-complete-as-filename ()
3135 "Dynamically complete at point as a filename.
3136See `comint-dynamic-complete-filename'. Returns t if successful."
3137 (apply #'completion-in-region (comint--complete-file-name-data)))
3138(make-obsolete 'comint-dynamic-complete-as-filename
3139 'comint-filename-completion "24.1")
3086 3140
3087(defun comint-replace-by-expanded-filename () 3141(defun comint-replace-by-expanded-filename ()
3088 "Dynamically expand and complete the filename at point. 3142 "Dynamically expand and complete the filename at point.
@@ -3155,28 +3209,20 @@ See also `comint-dynamic-complete-filename'."
3155 (unless minibuffer-p 3209 (unless minibuffer-p
3156 (message "Partially completed")) 3210 (message "Partially completed"))
3157 'partial))))))) 3211 'partial)))))))
3212(make-obsolete 'comint-dynamic-simple-complete 'completion-in-region "24.1")
3158 3213
3159 3214
3160(defun comint-dynamic-list-filename-completions () 3215(defun comint-dynamic-list-filename-completions ()
3161 "Display a list of possible completions for the filename at point." 3216 "Display a list of possible completions for the filename at point."
3162 (interactive) 3217 (interactive)
3163 (let* ((completion-ignore-case read-file-name-completion-ignore-case) 3218 (let* ((data (comint--complete-file-name-data))
3164 ;; If we bind this, it breaks remote directory tracking in rlogin.el. 3219 (minibuffer-completion-table (nth 2 data))
3165 ;; I think it was originally bound to solve file completion problems, 3220 (minibuffer-completion-predicate nil)
3166 ;; but subsequent changes may have made this unnecessary. sm. 3221 (ol (make-overlay (nth 0 data) (nth 1 data) nil nil t)))
3167 ;;(file-name-handler-alist nil) 3222 (overlay-put ol 'field 'completion)
3168 (filename (or (comint-match-partial-filename) "")) 3223 (unwind-protect
3169 (filedir (file-name-directory filename)) 3224 (call-interactively 'minibuffer-completion-help)
3170 (filenondir (file-name-nondirectory filename)) 3225 (delete-overlay ol))))
3171 (directory (if filedir (comint-directory filedir) default-directory))
3172 (completions (file-name-all-completions filenondir directory)))
3173 (if (not completions)
3174 (if (window-minibuffer-p (selected-window))
3175 (minibuffer-message "No completions of %s" filename)
3176 (message "No completions of %s" filename))
3177 (comint-dynamic-list-completions
3178 (mapcar 'comint-quote-filename completions)
3179 (comint-quote-filename filenondir)))))
3180 3226
3181 3227
3182;; This is bound locally in a *Completions* buffer to the list of 3228;; This is bound locally in a *Completions* buffer to the list of
@@ -3244,7 +3290,6 @@ Typing SPC flushes the completions buffer."
3244 (if (eq first ?\s) 3290 (if (eq first ?\s)
3245 (set-window-configuration comint-dynamic-list-completions-config) 3291 (set-window-configuration comint-dynamic-list-completions-config)
3246 (setq unread-command-events (listify-key-sequence key))))))) 3292 (setq unread-command-events (listify-key-sequence key)))))))
3247
3248 3293
3249(defun comint-get-next-from-history () 3294(defun comint-get-next-from-history ()
3250 "After fetching a line from input history, this fetches the following line. 3295 "After fetching a line from input history, this fetches the following line.
@@ -3742,9 +3787,8 @@ REGEXP-GROUP is the regular expression group in REGEXP to use."
3742;; 3787;;
3743;; For modes that use comint-mode, comint-dynamic-complete-functions is the 3788;; For modes that use comint-mode, comint-dynamic-complete-functions is the
3744;; hook to add completion functions to. Functions on this list should return 3789;; hook to add completion functions to. Functions on this list should return
3745;; non-nil if completion occurs (i.e., further completion should not occur). 3790;; the completion data according to the documentation of
3746;; You could use comint-dynamic-simple-complete to do the bulk of the 3791;; `completion-at-point-functions'
3747;; completion job.
3748 3792
3749 3793
3750(provide 'comint) 3794(provide 'comint)
diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el
index 0d26d6bdcf6..0adf2a1d8b8 100644
--- a/lisp/minibuffer.el
+++ b/lisp/minibuffer.el
@@ -58,6 +58,8 @@
58 58
59;;; Todo: 59;;; Todo:
60 60
61;; - Make things like icomplete-mode or lightning-completion work with
62;; completion-in-region-mode.
61;; - completion-insert-complete-hook (called after inserting a complete 63;; - completion-insert-complete-hook (called after inserting a complete
62;; completion), typically used for "complete-abbrev" where it would expand 64;; completion), typically used for "complete-abbrev" where it would expand
63;; the abbrev. Tho we'd probably want to provide it from the 65;; the abbrev. Tho we'd probably want to provide it from the
@@ -1314,8 +1316,7 @@ Point needs to be somewhere between START and END."
1314 (save-excursion 1316 (save-excursion
1315 (goto-char (nth 2 completion-in-region--data)) 1317 (goto-char (nth 2 completion-in-region--data))
1316 (line-end-position))) 1318 (line-end-position)))
1317 (when completion-in-region-mode--predicate 1319 (funcall completion-in-region-mode--predicate)))
1318 (funcall completion-in-region-mode--predicate))))
1319 (completion-in-region-mode -1))) 1320 (completion-in-region-mode -1)))
1320 1321
1321;; (defalias 'completion-in-region--prech 'completion-in-region--postch) 1322;; (defalias 'completion-in-region--prech 'completion-in-region--postch)
@@ -1330,12 +1331,12 @@ Point needs to be somewhere between START and END."
1330 (delq (assq 'completion-in-region-mode minor-mode-overriding-map-alist) 1331 (delq (assq 'completion-in-region-mode minor-mode-overriding-map-alist)
1331 minor-mode-overriding-map-alist)) 1332 minor-mode-overriding-map-alist))
1332 (if (null completion-in-region-mode) 1333 (if (null completion-in-region-mode)
1333 (unless (or (equal "*Completions*" (buffer-name (window-buffer))) 1334 (unless (equal "*Completions*" (buffer-name (window-buffer)))
1334 (null completion-in-region-mode--predicate))
1335 (minibuffer-hide-completions)) 1335 (minibuffer-hide-completions))
1336 ;; (add-hook 'pre-command-hook #'completion-in-region--prech) 1336 ;; (add-hook 'pre-command-hook #'completion-in-region--prech)
1337 (set (make-local-variable 'completion-in-region-mode--predicate) 1337 (assert completion-in-region-mode-predicate)
1338 completion-in-region-mode-predicate) 1338 (setq completion-in-region-mode--predicate
1339 completion-in-region-mode-predicate)
1339 (add-hook 'post-command-hook #'completion-in-region--postch) 1340 (add-hook 'post-command-hook #'completion-in-region--postch)
1340 (push `(completion-in-region-mode . ,completion-in-region-mode-map) 1341 (push `(completion-in-region-mode . ,completion-in-region-mode-map)
1341 minor-mode-overriding-map-alist))) 1342 minor-mode-overriding-map-alist)))