X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/a64bfdfa5a90731b804c057f2bcc74a8ba02937c..b895c72059521fec064ff27b4cfcfa4104081c4e:/lisp/emacs-lisp/crm.el diff --git a/lisp/emacs-lisp/crm.el b/lisp/emacs-lisp/crm.el index 3848ab7e6e..035baa0a96 100644 --- a/lisp/emacs-lisp/crm.el +++ b/lisp/emacs-lisp/crm.el @@ -1,6 +1,6 @@ ;;; crm.el --- read multiple strings with completion -;; Copyright (C) 1985-1986, 1993-2011 Free Software Foundation, Inc. +;; Copyright (C) 1985-1986, 1993-2016 Free Software Foundation, Inc. ;; Author: Sen Nagata ;; Keywords: completion, minibuffer, multiple elements @@ -24,27 +24,7 @@ ;; This code defines a function, `completing-read-multiple', which ;; provides the ability to read multiple strings in the minibuffer, -;; with completion. - -;; By using this functionality, a user may specify multiple strings at -;; a single prompt, optionally using completion. - -;; Multiple strings are specified by separating each of the strings -;; with a prespecified separator character. For example, if the -;; separator character is a comma, the strings 'alice', 'bob', and -;; 'eve' would be specified as 'alice,bob,eve'. - -;; The default value for the separator character is the value of -;; `crm-default-separator' (comma). The separator character may be -;; changed by modifying the value of `crm-separator'. - -;; Contiguous strings of non-separator-characters are referred to as -;; 'elements'. In the aforementioned example, the elements are: -;; 'alice', 'bob', and 'eve'. - -;; Completion is available on a per-element basis. For example, if -;; the contents of the minibuffer are 'alice,bob,eve' and point is -;; between 'l' and 'i', pressing TAB operates on the element 'alice'. +;; with completion. See that function's documentation for details. ;; For the moment, I have decided to not bind any special behavior to ;; the separator key. In the future, the separator key might be used @@ -96,14 +76,16 @@ ;; first revamped version ;;; Code: -(defconst crm-default-separator "," - "Default separator for `completing-read-multiple'.") + +;; FIXME I don't see that this needs to exist as a separate variable. +;; crm-separator should suffice. +(defconst crm-default-separator "[ \t]*,[ \t]*" + "Default value of `crm-separator'.") (defvar crm-separator crm-default-separator - "Separator used for separating strings in `completing-read-multiple'. -It should be a single character string that doesn't appear in the list of -completion candidates. Modify this value to make `completing-read-multiple' -use a separator other than `crm-default-separator'.") + "Separator regexp used for separating strings in `completing-read-multiple'. +It should be a regexp that does not match the list of completion candidates. +The default value is `crm-default-separator'.") (defvar crm-local-completion-map (let ((map (make-sparse-keymap))) @@ -143,11 +125,11 @@ nil if none. The value of FLAG is used to specify the type of completion operation. A value of nil specifies `try-completion'. A value of t specifies -`all-completions'. A value of lambda specifes a test for an exact match. +`all-completions'. A value of lambda specifies a test for an exact match. For more information on STRING, PREDICATE, and FLAG, see the Elisp -Reference sections on 'Programmed Completion' and 'Basic Completion -Functions'." +Reference sections on “Programmed Completion” and “Basic Completion +Functions”." (let ((beg 0)) (while (string-match crm-separator string beg) (setq beg (match-end 0))) @@ -157,29 +139,32 @@ Functions'." predicate flag))) -(defun crm--select-current-element () +(defun crm--current-element () "Parse the minibuffer to find the current element. -Place an overlay on the element, with a `field' property, and return it." - (let* ((bob (minibuffer-prompt-end)) - (start (save-excursion +Return the element's boundaries as (START . END)." + (let ((bob (minibuffer-prompt-end))) + (cons (save-excursion (if (re-search-backward crm-separator bob t) (match-end 0) - bob))) - (end (save-excursion + bob)) + (save-excursion (if (re-search-forward crm-separator nil t) (match-beginning 0) - (point-max)))) - (ol (make-overlay start end nil nil t))) - (overlay-put ol 'field (make-symbol "crm")) - ol)) + (point-max)))))) + +(defmacro crm--completion-command (beg end &rest body) + "Run BODY with BEG and END bound to the current element's boundaries." + (declare (indent 2) (debug (sexp sexp &rest body))) + `(let* ((crm--boundaries (crm--current-element)) + (,beg (car crm--boundaries)) + (,end (cdr crm--boundaries))) + ,@body)) (defun crm-completion-help () "Display a list of possible completions of the current minibuffer element." (interactive) - (let ((ol (crm--select-current-element))) - (unwind-protect - (minibuffer-completion-help) - (delete-overlay ol))) + (crm--completion-command beg end + (minibuffer-completion-help beg end)) nil) (defun crm-complete () @@ -188,19 +173,18 @@ If no characters can be completed, display a list of possible completions. Return t if the current element is now a valid match; otherwise return nil." (interactive) - (let ((ol (crm--select-current-element))) - (unwind-protect - (minibuffer-complete) - (delete-overlay ol)))) + (crm--completion-command beg end + (completion-in-region beg end + minibuffer-completion-table + minibuffer-completion-predicate))) (defun crm-complete-word () "Complete the current element at most a single word. Like `minibuffer-complete-word' but for `completing-read-multiple'." (interactive) - (let ((ol (crm--select-current-element))) - (unwind-protect - (minibuffer-complete-word) - (delete-overlay ol)))) + (crm--completion-command beg end + (completion-in-region--single-word + beg end minibuffer-completion-table minibuffer-completion-predicate))) (defun crm-complete-and-exit () "If all of the minibuffer elements are valid completions then exit. @@ -213,18 +197,17 @@ This function is modeled after `minibuffer-complete-and-exit'." (goto-char (minibuffer-prompt-end)) (while (and doexit - (let ((ol (crm--select-current-element))) - (goto-char (overlay-end ol)) - (unwind-protect - (catch 'exit - (minibuffer-complete-and-exit) - ;; This did not throw `exit', so there was a problem. - (setq doexit nil)) - (goto-char (overlay-end ol)) - (delete-overlay ol)) - (not (eobp)))) + (crm--completion-command beg end + (let ((end (copy-marker end t))) + (goto-char end) + (setq doexit nil) + (completion-complete-and-exit beg end + (lambda () (setq doexit t))) + (goto-char end) + (not (eobp)))) + (looking-at crm-separator)) ;; Skip to the next element. - (forward-char 1)) + (goto-char (match-end 0))) (if doexit (exit-minibuffer)))) (defun crm--choose-completion-string (choice buffer base-position @@ -239,36 +222,29 @@ exiting the minibuffer." t)) ;; superemulates behavior of completing_read in src/minibuf.c +;; Use \\ so that help-enable-auto-load can +;; do its thing. Any keymap that is defined will do. ;;;###autoload (defun completing-read-multiple (prompt table &optional predicate require-match initial-input hist def inherit-input-method) "Read multiple strings in the minibuffer, with completion. -By using this functionality, a user may specify multiple strings at a -single prompt, optionally using completion. - -Multiple strings are specified by separating each of the strings with -a prespecified separator character. For example, if the separator -character is a comma, the strings 'alice', 'bob', and 'eve' would be -specified as 'alice,bob,eve'. +The arguments are the same as those of `completing-read'. +\\ +Input multiple strings by separating each one with a string that +matches the regexp `crm-separator'. For example, if the separator +regexp is \",\", entering \"alice,bob,eve\" specifies the strings +\"alice\", \"bob\", and \"eve\". -The default value for the separator character is the value of -`crm-default-separator' (comma). The separator character may be -changed by modifying the value of `crm-separator'. - -Contiguous strings of non-separator-characters are referred to as -'elements'. In the aforementioned example, the elements are: 'alice', -'bob', and 'eve'. +We refer to contiguous strings of non-separator-characters as +\"elements\". In this example there are three elements. Completion is available on a per-element basis. For example, if the -contents of the minibuffer are 'alice,bob,eve' and point is between -'l' and 'i', pressing TAB operates on the element 'alice'. - -The return value of this function is a list of the read strings. +contents of the minibuffer are \"alice,bob,eve\" and point is between +\"l\" and \"i\", pressing \\[minibuffer-complete] operates on the element \"alice\". -See the documentation for `completing-read' for details on the arguments: -PROMPT, TABLE, PREDICATE, REQUIRE-MATCH, INITIAL-INPUT, HIST, DEF, and -INHERIT-INPUT-METHOD." +This function returns a list of the strings that were read, +with empty strings removed." (unwind-protect (progn (add-hook 'choose-completion-string-functions @@ -282,13 +258,14 @@ INHERIT-INPUT-METHOD." (map (if require-match crm-local-must-match-map crm-local-completion-map)) - ;; If the user enters empty input, read-from-minibuffer returns - ;; the empty string, not DEF. + ;; If the user enters empty input, `read-from-minibuffer' + ;; returns the empty string, not DEF. (input (read-from-minibuffer prompt initial-input map nil hist def inherit-input-method))) (and def (string-equal input "") (setq input def)) - (split-string input crm-separator))) + ;; Remove empty strings in the list of read strings. + (split-string input crm-separator t))) (remove-hook 'choose-completion-string-functions 'crm--choose-completion-string)))