Mercurial > emacs
changeset 95145:096cfec41046
(completion-boundaries): New function.
(completion--some): Delay errors.
(complete-with-action, completion-table-with-context): Handle `boundaries'.
(completion--try-word-completion): Avoid partial-completion
when the user hasn't entered anything yet.
(minibuffer-local-map, minibuffer-local-filename-completion-map)
(minibuffer-local-must-match-map, minibuffer-local-completion-map)
(minibuffer-local-must-match-filename-map, minibuffer-local-ns-map):
Setup default keybindings.
(completion--embedded-envvar-re): New var.
(completion--embedded-envvar-table): Use it. Handle `boundaries' case.
(completion--file-name-table): Handle `boundaries' case.
(completion-pcm--pattern->regex): Avoid pathological backtracking.
(completion-pcm--all-completions): Add a `prefix' arg.
(completion-pcm--find-all-completions): New function.
(completion-pcm-all-completions, completion-pcm-try-completion): Use it.
author | Stefan Monnier <monnier@iro.umontreal.ca> |
---|---|
date | Tue, 20 May 2008 17:03:30 +0000 |
parents | c9d1dab54646 |
children | a8bf1f66a719 |
files | lisp/ChangeLog lisp/minibuffer.el |
diffstat | 2 files changed, 332 insertions(+), 104 deletions(-) [+] |
line wrap: on
line diff
--- a/lisp/ChangeLog Tue May 20 16:33:58 2008 +0000 +++ b/lisp/ChangeLog Tue May 20 17:03:30 2008 +0000 @@ -1,16 +1,33 @@ 2008-05-20 Stefan Monnier <monnier@iro.umontreal.ca> + * minibuffer.el (completion-boundaries): New function. + (completion--some): Delay errors. + (complete-with-action, completion-table-with-context): + Handle `boundaries' case. + (completion--try-word-completion): Avoid partial-completion + when the user hasn't entered anything yet. + (minibuffer-local-map, minibuffer-local-filename-completion-map) + (minibuffer-local-must-match-map, minibuffer-local-completion-map) + (minibuffer-local-must-match-filename-map, minibuffer-local-ns-map): + Setup default keybindings. + (completion--embedded-envvar-re): New var. + (completion--embedded-envvar-table): Use it. Handle `boundaries' case. + (completion--file-name-table): Handle `boundaries' case. + (completion-pcm--pattern->regex): Avoid pathological backtracking. + (completion-pcm--all-completions): Add a `prefix' arg. + (completion-pcm--find-all-completions): New function. + (completion-pcm-all-completions, completion-pcm-try-completion): + Use it. + * icomplete.el (icomplete-completions): Don't use `predicate' with a table of a different type than `candidates'. 2008-05-20 Roland Winkler <Roland.Winkler@physik.uni-erlangen.de> - * proced.el (proced-goal-header-re): Renamed from - proced-procname-column-regexp. - (proced-goal-column): Renamed from proced-procname-column. - (proced-move-to-goal-column): Renamed from - proced-move-to-procname. - (proced-header-face, proced-header-regexp): Removed. + * proced.el (proced-goal-column): Rename from proced-procname-column. + (proced-goal-header-re): Rename from proced-procname-column-regexp. + (proced-move-to-goal-column): Rename from proced-move-to-procname. + (proced-header-face, proced-header-regexp): Remove. (proced-font-lock-keywords): Remove proced-header-face. (proced-header-alist, proced-sorting-schemes-re): New variables. (proced): Rename Proced buffer to *Proced*. @@ -18,9 +35,9 @@ (proced-do-mark, proced-do-mark-all, proced-toggle-marks) (proced-hide-processes): Do not treat first line as special. (proced-header-space): New function. - (proced-update): Use header-line-format. Initialize - proced-header-alist and proced-sorting-schemes-re. Set - proced-goal-column. Include proced-command in mode-name. + (proced-update): Use header-line-format. + Initialize proced-header-alist and proced-sorting-schemes-re. + Set proced-goal-column. Include proced-command in mode-name. (proced-send-signal): Use header-line-format for *Marked Processes* buffer. (proced-sort): Restrict minibuffer completion to applicable
--- a/lisp/minibuffer.el Tue May 20 16:33:58 2008 +0000 +++ b/lisp/minibuffer.el Tue May 20 17:03:30 2008 +0000 @@ -21,11 +21,32 @@ ;;; Commentary: -;; Names starting with "minibuffer--" are for functions and variables that -;; are meant to be for internal use only. +;; Names with "--" are for functions and variables that are meant to be for +;; internal use only. + +;; Functional completion tables have an extended calling conventions: +;; - If completion-all-completions-with-base-size is set, then all-completions +;; should return the base-size in the last cdr. +;; - The `action' can be (additionally to nil, t, and lambda) of the form +;; (boundaries . POS) in which case it should return (boundaries START . END). +;; Any other return value should be ignored (so we ignore values returned +;; from completion tables that don't know about this new `action' form). +;; See `completion-boundaries'. + +;;; Bugs: + +;; - completion-ignored-extensions is ignored by partial-completion because +;; pcm merges the `all' output to synthesize a `try' output and +;; read-file-name-internal's `all' output doesn't obey +;; completion-ignored-extensions. +;; - choose-completion can't automatically figure out the boundaries +;; corresponding to the displayed completions. `base-size' gives the left +;; boundary, but not the righthand one. So we need to add +;; completion-extra-size (and also completion-no-auto-exit). ;;; Todo: +;; - add support for ** to pcm. ;; - Make read-file-name-predicate obsolete. ;; - New command minibuffer-force-complete that chooses one of all-completions. ;; - Add vc-file-name-completion-table to read-file-name-internal. @@ -43,14 +64,37 @@ ;;; Completion table manipulation +;; New completion-table operation. +(defun completion-boundaries (string table pred pos) + "Return the boundaries of the completions returned by TABLE at POS. +STRING is the string on which completion will be performed. +The result is of the form (START . END) and gives the start and end position +corresponding to the substring of STRING that can be completed by one +of the elements returned by +\(all-completions (substring STRING 0 POS) TABLE PRED). +I.e. START is the same as the `completion-base-size'. +E.g. for simple completion tables, the result is always (0 . (length STRING)) +and for file names the result is the substring around POS delimited by +the closest directory separators." + (let ((boundaries (if (functionp table) + (funcall table string pred (cons 'boundaries pos))))) + (if (not (eq (car-safe boundaries) 'boundaries)) + (setq boundaries nil)) + (cons (or (cadr boundaries) 0) + (or (cddr boundaries) (length string))))) + (defun completion--some (fun xs) "Apply FUN to each element of XS in turn. Return the first non-nil returned value. Like CL's `some'." - (let (res) + (let ((firsterror nil) + res) (while (and (not res) xs) - (setq res (funcall fun (pop xs)))) - res)) + (condition-case err + (setq res (funcall fun (pop xs))) + (error (unless firsterror (setq firsterror err)) nil))) + (or res + (if firsterror (signal (car firsterror) (cdr firsterror)))))) (defun apply-partially (fun &rest args) "Do a \"curried\" partial application of FUN to ARGS. @@ -66,13 +110,17 @@ 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)) + (cond + ((functionp table) (funcall table string pred action)) + ((eq (car-safe action) 'boundaries) + (cons 'boundaries (completion-boundaries string table pred (cdr action)))) + (t + (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. @@ -112,8 +160,7 @@ (defun completion-table-with-context (prefix table string pred action) ;; TODO: add `suffix' maybe? - ;; Notice that `pred' is not a predicate when called from read-file-name - ;; or Info-read-node-name-2. + ;; Notice that `pred' may not be a function in some abusive cases. (when (functionp pred) (setq pred (lexical-let ((pred pred)) @@ -129,18 +176,23 @@ (t ;Lists and alists. (lambda (s) (funcall pred (concat prefix (if (consp s) (car s) s))))))))) - (let ((comp (complete-with-action action table string pred))) - (cond - ;; In case of try-completion, add the prefix. - ((stringp comp) (concat prefix comp)) - ;; In case of non-empty all-completions, - ;; add the prefix size to the base-size. - ((consp comp) - (let ((last (last comp))) - (when completion-all-completions-with-base-size - (setcdr last (+ (or (cdr last) 0) (length prefix)))) - comp)) - (t comp)))) + (if (eq (car-safe action) 'boundaries) + (let* ((len (length prefix)) + (bound (completion-boundaries string table pred + (- (cdr action) len)))) + (list* 'boundaries (+ (car bound) len) (+ (cdr bound) len))) + (let ((comp (complete-with-action action table string pred))) + (cond + ;; In case of try-completion, add the prefix. + ((stringp comp) (concat prefix comp)) + ;; In case of non-empty all-completions, + ;; add the prefix size to the base-size. + ((consp comp) + (let ((last (last comp))) + (when completion-all-completions-with-base-size + (setcdr last (+ (or (cdr last) 0) (length prefix)))) + comp)) + (t comp))))) (defun completion-table-with-terminator (terminator table string pred action) (cond @@ -152,7 +204,18 @@ (eq (try-completion comp table pred) t)) (concat comp terminator) comp)))) - ((eq action t) (all-completions string table pred)) + ((eq action t) + ;; FIXME: We generally want the `try' and `all' behaviors to be + ;; consistent so pcm can merge the `all' output to get the `try' output, + ;; but that sometimes clashes with the need for `all' output to look + ;; good in *Completions*. + ;; (let* ((all (all-completions string table pred)) + ;; (last (last all)) + ;; (base-size (cdr last))) + ;; (when all + ;; (setcdr all nil) + ;; (nconc (mapcar (lambda (s) (concat s terminator)) all) base-size))) + (all-completions string table pred)) ;; completion-table-with-terminator is always used for ;; "sub-completions" so it's only called if the terminator is missing, ;; in which case `test-completion' should return nil. @@ -297,10 +360,10 @@ POINT is the position of point within STRING. The return value is a list of completions and may contain the base-size in the last `cdr'." - ;; The property `completion-styles' indicates that this functional - ;; completion-table claims to take care of completion styles itself. - ;; [I.e. It will most likely call us back at some point. ] (let ((completion-all-completions-with-base-size t)) + ;; The property `completion-styles' indicates that this functional + ;; completion-table claims to take care of completion styles itself. + ;; [I.e. It will most likely call us back at some point. ] (if (and (symbolp table) (get table 'completion-styles)) ;; Extended semantics for functional completion-tables: ;; They accept a 4th argument `point' and when called with action=t @@ -417,19 +480,22 @@ nil) (case (completion--do-completion) - (0 nil) - (1 (goto-char (field-end)) - (minibuffer-message "Sole completion") - t) - (3 (goto-char (field-end)) - (minibuffer-message "Complete, but not unique") - t) - (t t))))) + (#b000 nil) + (#b001 (goto-char (field-end)) + (minibuffer-message "Sole completion") + t) + (#b011 (goto-char (field-end)) + (minibuffer-message "Complete, but not unique") + t) + (t t))))) (defun minibuffer-complete-and-exit () "If the minibuffer contents is a valid completion then exit. Otherwise try to complete it. If completion leads to a valid completion, -a repetition of this command will exit." +a repetition of this command will exit. +If `minibuffer-completion-confirm' is equal to `confirm', then do not +try to complete, but simply ask for confirmation and accept any +input if confirmed." (interactive) (let ((beg (field-beginning)) (end (field-end))) @@ -468,11 +534,11 @@ (case (condition-case nil (completion--do-completion) (error 1)) - ((1 3) (exit-minibuffer)) - (7 (if (not minibuffer-completion-confirm) - (exit-minibuffer) - (minibuffer-message "Confirm") - nil)) + ((#b001 #b011) (exit-minibuffer)) + (#b111 (if (not minibuffer-completion-confirm) + (exit-minibuffer) + (minibuffer-message "Confirm") + nil)) (t nil)))))) (defun completion--try-word-completion (string table predicate point) @@ -486,6 +552,14 @@ (let ((exts '(" " "-")) (before (substring string 0 point)) (after (substring string point)) + ;; If the user hasn't entered any text yet, then she + ;; presumably hits SPC to see the *completions*, but + ;; partial-completion will often find a " " or a "-" to match. + ;; So disable partial-completion in that situation. + (completion-styles + (or (and (equal string "") + (remove 'partial-completion completion-styles)) + completion-styles)) tem) (while (and exts (not (consp tem))) (setq tem (completion-try-completion @@ -561,14 +635,14 @@ Return nil if there is no valid completion, else t." (interactive) (case (completion--do-completion 'completion--try-word-completion) - (0 nil) - (1 (goto-char (field-end)) - (minibuffer-message "Sole completion") - t) - (3 (goto-char (field-end)) - (minibuffer-message "Complete, but not unique") - t) - (t t))) + (#b000 nil) + (#b001 (goto-char (field-end)) + (minibuffer-message "Sole completion") + t) + (#b011 (goto-char (field-end)) + (minibuffer-message "Complete, but not unique") + t) + (t t))) (defun completion--insert-strings (strings) "Insert a list of STRINGS into the current buffer. @@ -778,6 +852,34 @@ (ding)) (exit-minibuffer)) +;;; Key bindings. + +(let ((map minibuffer-local-map)) + (define-key map "\C-g" 'abort-recursive-edit) + (define-key map "\r" 'exit-minibuffer) + (define-key map "\n" 'exit-minibuffer)) + +(let ((map minibuffer-local-completion-map)) + (define-key map "\t" 'minibuffer-complete) + (define-key map " " 'minibuffer-complete-word) + (define-key map "?" 'minibuffer-completion-help)) + +(let ((map minibuffer-local-must-match-map)) + (define-key map "\r" 'minibuffer-complete-and-exit) + (define-key map "\n" 'minibuffer-complete-and-exit)) + +(let ((map minibuffer-local-filename-completion-map)) + (define-key map " " nil)) +(let ((map minibuffer-local-must-match-filename-map)) + (define-key map " " nil)) + +(let ((map minibuffer-local-ns-map)) + (define-key map " " 'exit-minibuffer) + (define-key map "\t" 'exit-minibuffer) + (define-key map "?" 'self-insert-and-exit)) + +;;; Completion tables. + (defun minibuffer--double-dollars (str) (replace-regexp-in-string "\\$" "$$" str)) @@ -786,24 +888,45 @@ (substring enventry 0 (string-match "=" enventry))) process-environment)) +(defconst completion--embedded-envvar-re + (concat "\\(?:^\\|[^$]\\(?:\\$\\$\\)*\\)" + "$\\([[:alnum:]_]*\\|{\\([^}]*\\)\\)\\'")) + (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)))) + (if (eq (car-safe action) 'boundaries) + ;; Compute the boundaries of the subfield to which this + ;; completion applies. + (let* ((pos (cdr action)) + (suffix (substring string pos))) + (if (string-match completion--embedded-envvar-re + (substring string 0 pos)) + (list* 'boundaries (or (match-beginning 2) (match-beginning 1)) + (when (string-match "[^[:alnum:]_]" suffix) + (+ pos (match-beginning 0)))))) + (when (string-match completion--embedded-envvar-re 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 pred action) "Internal subroutine for `read-file-name'. Do not call this." - (if (and (zerop (length string)) (eq 'lambda action)) - nil ; FIXME: why? + (cond + ((and (zerop (length string)) (eq 'lambda action)) + nil) ; FIXME: why? + ((eq (car-safe action) 'boundaries) + ;; FIXME: Actually, this is not always right in the presence of + ;; envvars, but there's not much we can do, I think. + (let ((start (length (file-name-directory + (substring string 0 (cdr action))))) + (end (string-match "/" string (cdr action)))) + (list* 'boundaries start end))) + + (t (let* ((dir (if (stringp pred) ;; It used to be that `pred' was abused to pass `dir' ;; as an argument. @@ -834,8 +957,8 @@ ((eq action t) (let ((all (file-name-all-completions name realdir)) - ;; Actually, this is not always right in the presence of - ;; envvars, but there's not much we can do, I think. + ;; FIXME: Actually, this is not always right in the presence + ;; of envvars, but there's not much we can do, I think. (base-size (length (file-name-directory string)))) ;; Check the predicate, if necessary. @@ -857,14 +980,13 @@ (if (and completion-all-completions-with-base-size (consp all)) ;; Add base-size, but only if the list is non-empty. - (nconc all base-size)) - - all)) + (nconc all base-size) + all))) (t ;; Only other case actually used is ACTION = lambda. (let ((default-directory dir)) - (funcall (or read-file-name-predicate 'file-exists-p) str))))))) + (funcall (or read-file-name-predicate 'file-exists-p) str)))))))) (defalias 'read-file-name-internal (completion-table-in-turn 'completion--embedded-envvar-table @@ -1130,13 +1252,13 @@ (defun completion-pcm--pattern-trivial-p (pattern) (and (stringp (car pattern)) (null (cdr pattern)))) -(defun completion-pcm--string->pattern (basestr &optional point) - "Split BASESTR into a pattern. +(defun completion-pcm--string->pattern (string &optional point) + "Split STRING into a pattern. A pattern is a list where each element is either a string or a symbol chosen among `any', `star', `point'." - (if (and point (< point (length basestr))) - (let ((prefix (substring basestr 0 point)) - (suffix (substring basestr point))) + (if (and point (< point (length string))) + (let ((prefix (substring string 0 point)) + (suffix (substring string point))) (append (completion-pcm--string->pattern prefix) '(point) (completion-pcm--string->pattern suffix))) @@ -1144,9 +1266,9 @@ (p 0) (p0 0)) - (while (setq p (string-match completion-pcm--delim-wild-regex basestr p)) - (push (substring basestr p0 p) pattern) - (if (eq (aref basestr p) ?*) + (while (setq p (string-match completion-pcm--delim-wild-regex string p)) + (push (substring string p0 p) pattern) + (if (eq (aref string p) ?*) (progn (push 'star pattern) (setq p0 (1+ p))) @@ -1156,27 +1278,36 @@ ;; An empty string might be erroneously added at the beginning. ;; It should be avoided properly, but it's so easy to remove it here. - (delete "" (nreverse (cons (substring basestr p0) pattern)))))) + (delete "" (nreverse (cons (substring string p0) pattern)))))) (defun completion-pcm--pattern->regex (pattern &optional group) + (let ((re (concat "\\`" (mapconcat (lambda (x) (case x - ((star any point) (if (if (consp group) (memq x group) group) + ((star any point) + (if (if (consp group) (memq x group) group) "\\(.*?\\)" ".*?")) (t (regexp-quote x)))) pattern - ""))) + "")))) + ;; Avoid pathological backtracking. + (while (string-match "\\.\\*\\?\\(?:\\\\[()]\\)*\\(\\.\\*\\?\\)" re) + (setq re (replace-match "" t t re 1))) + re)) -(defun completion-pcm--all-completions (pattern table pred) +(defun completion-pcm--all-completions (prefix pattern table pred) "Find all completions for PATTERN in TABLE obeying PRED. PATTERN is as returned by `completion-pcm--string->pattern'." ;; Find an initial list of possible completions. (if (completion-pcm--pattern-trivial-p pattern) ;; Minibuffer contains no delimiters -- simple case! - (all-completions (car pattern) table pred) + (let* ((all (all-completions (concat prefix (car pattern)) table pred)) + (last (last all))) + (if last (setcdr last nil)) + all) ;; Use all-completions to do an initial cull. This is a big win, ;; since all-completions is written in C! @@ -1184,11 +1315,14 @@ (regex (completion-pcm--pattern->regex pattern)) (completion-regexp-list (cons regex completion-regexp-list)) (compl (all-completions - (if (stringp (car pattern)) (car pattern) "") + (concat prefix (if (stringp (car pattern)) (car pattern) "")) table pred)) (last (last compl))) - ;; FIXME: If `base-size' is not 0, we have a problem :-( - (if last (setcdr last nil)) + (when last + (if (and (numberp (cdr last)) (/= (cdr last) (length prefix))) + (message "Inconsistent base-size returned by completion table %s" + table)) + (setcdr last nil)) (if (not (functionp table)) ;; The internal functions already obeyed completion-regexp-list. compl @@ -1224,11 +1358,85 @@ completions) base-size)))) +(defun completion-pcm--find-all-completions (string table pred point) + (let* ((bounds (completion-boundaries string table pred point)) + (prefix (substring string 0 (car bounds))) + (suffix (substring string (cdr bounds))) + (origstring string) + firsterror) + (setq string (substring string (car bounds) (cdr bounds))) + (let* ((pattern (completion-pcm--string->pattern + string (- point (car bounds)))) + (all (condition-case err + (completion-pcm--all-completions prefix pattern table pred) + (error (unless firsterror (setq firsterror err)) nil)))) + (when (and (null all) + (> (car bounds) 0) + (null (ignore-errors (try-completion prefix table pred)))) + ;; The prefix has no completions at all, so we should try and fix + ;; that first. + (let ((substring (substring prefix 0 -1))) + (destructuring-bind (subpat suball subprefix subsuffix) + (completion-pcm--find-all-completions + substring table pred (length substring)) + (let ((sep (aref prefix (1- (length prefix)))) + ;; Text that goes between the new submatches and the + ;; completion substring. + (between nil)) + ;; Eliminate submatches that don't end with the separator. + (dolist (submatch (prog1 suball (setq suball ()))) + (when (eq sep (aref submatch (1- (length submatch)))) + (push submatch suball))) + (when suball + ;; Update the boundaries and corresponding pattern. + ;; We assume that all submatches result in the same boundaries + ;; since we wouldn't know how to merge them otherwise anyway. + (let* ((newstring (concat subprefix (car suball) string suffix)) + (newpoint (+ point (- (length newstring) + (length origstring)))) + (newbounds (completion-boundaries + newstring table pred newpoint)) + (newsubstring + (substring newstring (car newbounds) (cdr newbounds)))) + (unless (or (equal newsubstring string) + ;; Refuse new boundaries if they step over + ;; the submatch. + (< (car newbounds) + (+ (length subprefix) (length (car suball))))) + ;; The new completed prefix does change the boundaries + ;; of the completed substring. + (setq suffix (substring newstring (cdr newbounds))) + (setq string newsubstring) + (setq between (substring newstring + (+ (length subprefix) + (length (car suball))) + (car newbounds))) + (setq pattern (completion-pcm--string->pattern + string (- newpoint (car bounds))))) + (dolist (submatch suball) + (setq all (nconc (mapcar + (lambda (s) (concat submatch between s)) + (completion-pcm--all-completions + (concat subprefix submatch between) + pattern table pred)) + all))) + (unless all + ;; Even though we found expansions in the prefix, none + ;; leads to a valid completion. + ;; Let's keep the expansions, tho. + (dolist (submatch suball) + (push (concat submatch between newsubstring) all))))) + (setq pattern (append subpat (list 'any (string sep)) + (if between (list between)) pattern)) + (setq prefix subprefix))))) + (if (and (null all) firsterror) + (signal (car firsterror) (cdr firsterror)) + (list pattern all prefix suffix))))) + (defun completion-pcm-all-completions (string table pred point) - (let ((pattern (completion-pcm--string->pattern string point))) - (completion-pcm--hilit-commonality - pattern - (completion-pcm--all-completions pattern table pred)))) + (destructuring-bind (pattern all &optional prefix suffix) + (completion-pcm--find-all-completions string table pred point) + (completion-pcm--hilit-commonality pattern all))) (defun completion-pcm--merge-completions (strs pattern) "Extract the commonality in STRS, with the help of PATTERN." @@ -1289,8 +1497,8 @@ "")) (defun completion-pcm-try-completion (string table pred point) - (let* ((pattern (completion-pcm--string->pattern string point)) - (all (completion-pcm--all-completions pattern table pred))) + (destructuring-bind (pattern all prefix suffix) + (completion-pcm--find-all-completions string table pred point) (when all (let* ((mergedpat (completion-pcm--merge-completions all pattern)) ;; `mergedpat' is in reverse order. Place new point (by @@ -1303,7 +1511,10 @@ (newpos (length (completion-pcm--pattern->string pointpat))) ;; Do it afterwards because it changes `pointpat' by sideeffect. (merged (completion-pcm--pattern->string (nreverse mergedpat)))) - (cons merged newpos))))) + (if (and (> (length merged) 0) (> (length suffix) 0) + (eq (aref merged (1- (length merged))) (aref suffix 0))) + (setq suffix (substring suffix 1))) + (cons (concat prefix merged suffix) (+ newpos (length prefix))))))) (provide 'minibuffer)