Mercurial > emacs
changeset 94013:bd1b8b62427b
* minibuffer.el (complete-with-action, lazy-completion-table):
Move from subr.el.
(apply-partially, completion-table-dynamic)
(completion-table-with-context, completion-table-with-terminator)
(completion-table-in-turn): New funs.
(completion--make-envvar-table, completion--embedded-envvar-table): New funs.
(read-file-name-internal): Use them.
(completion-setup-hook): Move from simple.el.
* subr.el (complete-with-action, lazy-completion-table):
* simple.el (completion-setup-hook): Move to minibuffer.el.
author | Stefan Monnier <monnier@iro.umontreal.ca> |
---|---|
date | Fri, 11 Apr 2008 22:28:02 +0000 |
parents | cf8425ff53c4 |
children | c4ddffb53395 |
files | lisp/ChangeLog lisp/minibuffer.el lisp/simple.el lisp/subr.el |
diffstat | 4 files changed, 140 insertions(+), 99 deletions(-) [+] |
line wrap: on
line diff
--- a/lisp/ChangeLog Fri Apr 11 22:26:48 2008 +0000 +++ b/lisp/ChangeLog Fri Apr 11 22:28:02 2008 +0000 @@ -1,3 +1,17 @@ +2008-04-11 Stefan Monnier <monnier@iro.umontreal.ca> + + * minibuffer.el (complete-with-action, lazy-completion-table): + Move from subr.el. + (apply-partially, completion-table-dynamic) + (completion-table-with-context, completion-table-with-terminator) + (completion-table-in-turn): New funs. + (completion--make-envvar-table, completion--embedded-envvar-table): + New funs. + (read-file-name-internal): Use them. + (completion-setup-hook): Move from simple.el. + * subr.el (complete-with-action, lazy-completion-table): + * simple.el (completion-setup-hook): Move to minibuffer.el. + 2008-04-11 Glenn Morris <rgm@gnu.org> * Makefile.in (AUTOGENEL): Add calc/calc-loaddefs.el.
--- a/lisp/minibuffer.el Fri Apr 11 22:26:48 2008 +0000 +++ b/lisp/minibuffer.el Fri Apr 11 22:28:02 2008 +0000 @@ -24,14 +24,102 @@ ;; Names starting with "minibuffer--" are for functions and variables that ;; are meant to be for internal use only. -;; TODO: -;; - merge do-completion and complete-word -;; - move all I/O out of do-completion +;; BUGS: +;; - envvar completion for file names breaks completion-base-size. ;;; Code: (eval-when-compile (require 'cl)) +;;; Completion table manipulation + +(defun apply-partially (fun &rest args) + (lexical-let ((fun fun) (args1 args)) + (lambda (&rest args2) (apply fun (append args1 args2))))) + +(defun complete-with-action (action table string pred) + "Perform completion ACTION. +STRING is the string to complete. +TABLE is the completion table, which should not be a function. +PRED is a completion predicate. +ACTION can be one of nil, t or `lambda'." + ;; (assert (not (functionp table))) + (funcall + (cond + ((null action) 'try-completion) + ((eq action t) 'all-completions) + (t 'test-completion)) + string table pred)) + +(defun completion-table-dynamic (fun) + "Use function FUN as a dynamic completion table. +FUN is called with one argument, the string for which completion is required, +and it should return an alist containing all the intended possible +completions. This alist may be a full list of possible completions so that FUN +can ignore the value of its argument. If completion is performed in the +minibuffer, FUN will be called in the buffer from which the minibuffer was +entered. + +The result of the `dynamic-completion-table' form is a function +that can be used as the ALIST argument to `try-completion' and +`all-completion'. See Info node `(elisp)Programmed Completion'." + (lexical-let ((fun fun)) + (lambda (string pred action) + (with-current-buffer (let ((win (minibuffer-selected-window))) + (if (window-live-p win) (window-buffer win) + (current-buffer))) + (complete-with-action action (funcall fun string) string pred))))) + +(defmacro lazy-completion-table (var fun) + "Initialize variable VAR as a lazy completion table. +If the completion table VAR is used for the first time (e.g., by passing VAR +as an argument to `try-completion'), the function FUN is called with no +arguments. FUN must return the completion table that will be stored in VAR. +If completion is requested in the minibuffer, FUN will be called in the buffer +from which the minibuffer was entered. The return value of +`lazy-completion-table' must be used to initialize the value of VAR. + +You should give VAR a non-nil `risky-local-variable' property." + (declare (debug (symbol lambda-expr))) + (let ((str (make-symbol "string"))) + `(completion-table-dynamic + (lambda (,str) + (when (functionp ,var) + (setq ,var (,fun))) + ,var)))) + +(defun completion-table-with-context (prefix table string pred action) + ;; TODO: add `suffix', and think about how we should support `pred'. + ;; Notice that `pred' is not a predicate when called from read-file-name. + ;; (if pred (setq pred (lexical-let ((pred pred)) + ;; ;; FIXME: this doesn't work if `table' is an obarray. + ;; (lambda (s) (funcall pred (concat prefix s)))))) + (let ((comp (complete-with-action action table string nil))) ;; pred + (if (stringp comp) + (concat prefix comp) + comp))) + +(defun completion-table-with-terminator (terminator table string pred action) + (let ((comp (complete-with-action action table string pred))) + (if (eq action nil) + (if (eq comp t) + (concat string terminator) + (if (and (stringp comp) + (eq (complete-with-action action table comp pred) t)) + (concat comp terminator) + comp)) + comp))) + +(defun completion-table-in-turn (a b) + "Create a completion table that first tries completion in A and then in B. +A and B should not be costly (or side-effecting) expressions." + (lexical-let ((a a) (b b)) + (lambda (string pred action) + (or (complete-with-action action a string pred) + (complete-with-action action b string pred))))) + +;;; Minibuffer completion + (defgroup minibuffer nil "Controlling the behavior of the minibuffer." :link '(custom-manual "(emacs)Minibuffer") @@ -363,6 +451,14 @@ (defvar completion-common-substring) +(defvar completion-setup-hook nil + "Normal hook run at the end of setting up a completion list buffer. +When this hook is run, the current buffer is the one in which the +command to display the completion list buffer was run. +The completion list buffer is available as the value of `standard-output'. +The common prefix substring for completion may be available as the +value of `completion-common-substring'. See also `display-completion-list'.") + (defun display-completion-list (completions &optional common-substring) "Display the list of completions, COMPLETIONS, using `standard-output'. Each element may be just a symbol or string @@ -453,12 +549,33 @@ (defun minibuffer--double-dollars (str) (replace-regexp-in-string "\\$" "$$" str)) -(defun read-file-name-internal (string dir action) +(defun completion--make-envvar-table () + (mapcar (lambda (enventry) + (substring enventry 0 (string-match "=" enventry))) + process-environment)) + +(defun completion--embedded-envvar-table (string pred action) + (when (string-match (concat "\\(?:^\\|[^$]\\(?:\\$\\$\\)*\\)" + "$\\([[:alnum:]_]*\\|{\\([^}]*\\)\\)\\'") + string) + (let* ((beg (or (match-beginning 2) (match-beginning 1))) + (table (completion-make-envvar-table)) + (prefix (substring string 0 beg))) + (if (eq (aref string (1- beg)) ?{) + (setq table (apply-partially 'completion-table-with-terminator + "}" table))) + (completion-table-with-context prefix table + (substring string beg) + pred action)))) + +(defun completion--file-name-table (string dir action) "Internal subroutine for read-file-name. Do not call this." (setq dir (expand-file-name dir)) (if (and (zerop (length string)) (eq 'lambda action)) nil ; FIXME: why? - (let* ((str (substitute-in-file-name string)) + (let* ((str (condition-case nil + (substitute-in-file-name string) + (error string))) (name (file-name-nondirectory str)) (specdir (file-name-directory str)) (realdir (if specdir (expand-file-name specdir dir) @@ -503,6 +620,10 @@ (let ((default-directory dir)) (funcall (or read-file-name-predicate 'file-exists-p) str))))))) +(defalias 'read-file-name-internal + (completion-table-in-turn 'completion-embedded-envvar-table + 'completion-file-name-table) + "Internal subroutine for `read-file-name'. Do not call this.") (provide 'minibuffer) ;;; minibuffer.el ends here
--- a/lisp/simple.el Fri Apr 11 22:26:48 2008 +0000 +++ b/lisp/simple.el Fri Apr 11 22:28:02 2008 +0000 @@ -5451,14 +5451,6 @@ (add-hook 'temp-buffer-show-hook 'completion-list-mode-finish) -(defvar completion-setup-hook nil - "Normal hook run at the end of setting up a completion list buffer. -When this hook is run, the current buffer is the one in which the -command to display the completion list buffer was run. -The completion list buffer is available as the value of `standard-output'. -The common prefix substring for completion may be available as the -value of `completion-common-substring'. See also `display-completion-list'.") - ;; Variables and faces used in `completion-setup-function'.
--- a/lisp/subr.el Fri Apr 11 22:26:48 2008 +0000 +++ b/lisp/subr.el Fri Apr 11 22:28:02 2008 +0000 @@ -2688,92 +2688,6 @@ (with-current-buffer ,old-buffer (set-case-table ,old-case-table)))))) -;;;; Constructing completion tables. - -(defun complete-with-action (action table string pred) - "Perform completion ACTION. -STRING is the string to complete. -TABLE is the completion table, which should not be a function. -PRED is a completion predicate. -ACTION can be one of nil, t or `lambda'." - ;; (assert (not (functionp table))) - (funcall - (cond - ((null action) 'try-completion) - ((eq action t) 'all-completions) - (t 'test-completion)) - string table pred)) - -(defmacro dynamic-completion-table (fun) - "Use function FUN as a dynamic completion table. -FUN is called with one argument, the string for which completion is required, -and it should return an alist containing all the intended possible -completions. This alist may be a full list of possible completions so that FUN -can ignore the value of its argument. If completion is performed in the -minibuffer, FUN will be called in the buffer from which the minibuffer was -entered. - -The result of the `dynamic-completion-table' form is a function -that can be used as the ALIST argument to `try-completion' and -`all-completion'. See Info node `(elisp)Programmed Completion'." - (declare (debug (lambda-expr))) - (let ((win (make-symbol "window")) - (string (make-symbol "string")) - (predicate (make-symbol "predicate")) - (mode (make-symbol "mode"))) - `(lambda (,string ,predicate ,mode) - (with-current-buffer (let ((,win (minibuffer-selected-window))) - (if (window-live-p ,win) (window-buffer ,win) - (current-buffer))) - (complete-with-action ,mode (,fun ,string) ,string ,predicate))))) - -(defmacro lazy-completion-table (var fun) - ;; We used to have `&rest args' where `args' were evaluated late (at the - ;; time of the call to `fun'), which was counter intuitive. But to get - ;; them to be evaluated early, we have to either use lexical-let (which is - ;; not available in subr.el) or use `(lambda (,str) ...) which prevents the use - ;; of lexical-let in the callers. - ;; So we just removed the argument. Callers can then simply use either of: - ;; (lazy-completion-table var (lambda () (fun x y))) - ;; or - ;; (lazy-completion-table var `(lambda () (fun ',x ',y))) - ;; or - ;; (lexical-let ((x x)) ((y y)) - ;; (lazy-completion-table var (lambda () (fun x y)))) - ;; depending on the behavior they want. - "Initialize variable VAR as a lazy completion table. -If the completion table VAR is used for the first time (e.g., by passing VAR -as an argument to `try-completion'), the function FUN is called with no -arguments. FUN must return the completion table that will be stored in VAR. -If completion is requested in the minibuffer, FUN will be called in the buffer -from which the minibuffer was entered. The return value of -`lazy-completion-table' must be used to initialize the value of VAR. - -You should give VAR a non-nil `risky-local-variable' property." - (declare (debug (symbol lambda-expr))) - (let ((str (make-symbol "string"))) - `(dynamic-completion-table - (lambda (,str) - (when (functionp ,var) - (setq ,var (,fun))) - ,var)))) - -(defmacro complete-in-turn (a b) - "Create a completion table that first tries completion in A and then in B. -A and B should not be costly (or side-effecting) expressions." - (declare (debug (def-form def-form))) - `(lambda (string predicate mode) - (cond - ((eq mode t) - (or (all-completions string ,a predicate) - (all-completions string ,b predicate))) - ((eq mode nil) - (or (try-completion string ,a predicate) - (try-completion string ,b predicate))) - (t - (or (test-completion string ,a predicate) - (test-completion string ,b predicate)))))) - ;;; Matching and match data. (defvar save-match-data-internal)