(icomplete-prospects-height): Add :group.
[bpt/emacs.git] / lisp / minibuffer.el
index 53f3689..f24d1b0 100644 (file)
@@ -6,28 +6,49 @@
 
 ;; This file is part of GNU Emacs.
 
-;; GNU Emacs is free software; you can redistribute it and/or modify
+;; GNU Emacs is free software: you can redistribute it and/or modify
 ;; it under the terms of the GNU General Public License as published by
 ;; the Free Software Foundation, either version 3 of the License, or
 ;; (at your option) any later version.
 
-;; This program is distributed in the hope that it will be useful,
+;; GNU Emacs is distributed in the hope that it will be useful,
 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 ;; GNU General Public License for more details.
 
 ;; You should have received a copy of the GNU General Public License
-;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
 
 ;;; 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 . SUFFIX) in which case it should return
+;;   (boundaries START . END).  See `completion-boundaries'.
+;;   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.
 ;; - A feature like completing-help.el.
 ;; - Make the `hide-spaces' arg of all-completions obsolete?
@@ -43,14 +64,37 @@ element in the returned list of completions.  See `completion-base-size'.")
 
 ;;; Completion table manipulation
 
+;; New completion-table operation.
+(defun completion-boundaries (string table pred suffix)
+  "Return the boundaries of the completions returned by TABLE for STRING.
+STRING is the string on which completion will be performed.
+SUFFIX is the string after point.
+The result is of the form (START . END) where START is the position
+in STRING of the beginning of the completion field and END is the position
+in SUFFIX of the end of the completion field.
+I.e. START is the same as the `completion-base-size'.
+E.g. for simple completion tables, the result is always (0 . (length SUFFIX))
+and for file names the result is the positions delimited by
+the closest directory separators."
+  (let ((boundaries (if (functionp table)
+                        (funcall table string pred (cons 'boundaries suffix)))))
+    (if (not (eq (car-safe boundaries) 'boundaries))
+        (setq boundaries nil))
+    (cons (or (cadr boundaries) 0)
+          (or (cddr boundaries) (length suffix)))))
+
 (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 @@ 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))
+  (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,24 +160,38 @@ You should give VAR a non-nil `risky-local-variable' property."
 
 (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.
-  (if (functionp 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 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))))
+  ;; Notice that `pred' may not be a function in some abusive cases.
+  (when (functionp pred)
+    (setq pred
+          (lexical-let ((pred pred))
+            ;; Predicates are called differently depending on the nature of
+            ;; the completion table :-(
+            (cond
+             ((vectorp table)           ;Obarray.
+              (lambda (sym) (funcall pred (concat prefix (symbol-name sym)))))
+             ((hash-table-p table)
+              (lambda (s v) (funcall pred (concat prefix s))))
+             ((functionp table)
+              (lambda (s) (funcall pred (concat prefix s))))
+             (t                         ;Lists and alists.
+              (lambda (s)
+                (funcall pred (concat prefix (if (consp s) (car s) s)))))))))
+  (if (eq (car-safe action) 'boundaries)
+      (let* ((len (length prefix))
+             (bound (completion-boundaries string table pred (cdr action))))
+        (list* 'boundaries (+ (car bound) len) (cdr bound)))
+    (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
@@ -141,7 +203,18 @@ You should give VAR a non-nil `risky-local-variable' property."
                  (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.
@@ -149,7 +222,7 @@ You should give VAR a non-nil `risky-local-variable' property."
 
 (defun completion-table-with-predicate (table pred1 strict string pred2 action)
   "Make a completion table equivalent to TABLE but filtered through PRED1.
-PRED1 is a function of one argument which returns non-nil iff the
+PRED1 is a function of one argument which returns non-nil if and only if the
 argument is an element of TABLE which should be considered for completion.
 STRING, PRED2, and ACTION are the usual arguments to completion tables,
 as described in `try-completion', `all-completions', and `test-completion'.
@@ -243,16 +316,15 @@ the second failed attempt to complete."
   '((basic completion-basic-try-completion completion-basic-all-completions)
     (emacs22 completion-emacs22-try-completion completion-emacs22-all-completions)
     (emacs21 completion-emacs21-try-completion completion-emacs21-all-completions)
-    ;; (partial-completion
-    ;;  completion-pcm--try-completion completion-pcm--all-completions)
-    )
+    (partial-completion
+     completion-pcm-try-completion completion-pcm-all-completions))
   "List of available completion styles.
 Each element has the form (NAME TRY-COMPLETION ALL-COMPLETIONS)
-where NAME is the name that should be used in `completion-styles'
+where NAME is the name that should be used in `completion-styles',
 TRY-COMPLETION is the function that does the completion, and
 ALL-COMPLETIONS is the function that lists the completions.")
 
-(defcustom completion-styles '(basic)
+(defcustom completion-styles '(basic partial-completion)
   "List of completion styles to use."
   :type `(repeat (choice ,@(mapcar (lambda (x) (list 'const (car x)))
                                    completion-styles-alist)))
@@ -285,12 +357,12 @@ a new position for point."
   "List the possible completions of STRING in completion table TABLE.
 Only the elements of table that satisfy predicate PRED are considered.
 POINT is the position of point within STRING.
-The return value is a list of completions and may contain the BASE-SIZE
+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
@@ -350,8 +422,9 @@ E = after completion we now have an Exact match.
           ;; Insert in minibuffer the chars we got.
           (goto-char end)
           (insert completion)
-          (delete-region beg end)
-          (goto-char (+ beg comp-pos)))
+          (delete-region beg end))
+       ;; Move point.
+       (goto-char (+ beg comp-pos))
 
         (if (not (or unchanged completed))
           ;; The case of the string changed, but that's all.  We're not sure
@@ -406,19 +479,75 @@ scroll the window of possible completions."
          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)))))
+
+(defvar completion-all-sorted-completions nil)
+(make-variable-buffer-local 'completion-all-sorted-completions)
+
+(defun completion--flush-all-sorted-completions (&rest ignore)
+  (setq completion-all-sorted-completions nil))
+
+(defun completion-all-sorted-completions ()
+  (or completion-all-sorted-completions
+      (let* ((start (field-beginning))
+             (end (field-end))
+             (all (completion-all-completions (buffer-substring start end)
+                                              minibuffer-completion-table
+                                              minibuffer-completion-predicate
+                                              (- (point) start)))
+             (last (last all))
+             (base-size (or (cdr last) 0)))
+        (when last
+          (setcdr last nil)
+          ;; Prefer shorter completions.
+          (setq all (sort all (lambda (c1 c2) (< (length c1) (length c2)))))
+          ;; Prefer recently used completions.
+          (let ((hist (symbol-value minibuffer-history-variable)))
+            (setq all (sort all (lambda (c1 c2)
+                                  (> (length (member c1 hist))
+                                     (length (member c2 hist)))))))
+          ;; Cache the result.  This is not just for speed, but also so that
+          ;; repeated calls to minibuffer-force-complete can cycle through
+          ;; all possibilities.
+          (add-hook 'after-change-functions
+                    'completion--flush-all-sorted-completions nil t)
+          (setq completion-all-sorted-completions
+                (nconc all base-size))))))
+
+(defun minibuffer-force-complete ()
+  "Complete the minibuffer to an exact match.
+Repeated uses step through the possible completions."
+  (interactive)
+  ;; FIXME: Need to deal with the extra-size issue here as well.
+  (let* ((start (field-beginning))
+         (end (field-end))
+         (all (completion-all-sorted-completions)))
+    (if (not (consp all))
+        (minibuffer-message (if all "No more completions" "No completions"))
+      (goto-char end)
+      (insert (car all))
+      (delete-region (+ start (cdr (last all))) end)
+      ;; If completing file names, (car all) may be a directory, so we'd now
+      ;; have a new set of possible completions and might want to reset
+      ;; completion-all-sorted-completions to nil, but we prefer not to,
+      ;; so that repeated calls minibuffer-force-complete still cycle
+      ;; through the previous possible completions.
+      (setq completion-all-sorted-completions (cdr all)))))
 
 (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)))
@@ -457,11 +586,11 @@ a repetition of this command will exit."
       (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)
@@ -475,6 +604,14 @@ a repetition of this command will exit."
         (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
@@ -550,14 +687,14 @@ is added, provided that matches some possible completion.
 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.
@@ -567,8 +704,9 @@ It also eliminates runs of equal strings."
     (let* ((length (apply 'max
                          (mapcar (lambda (s)
                                    (if (consp s)
-                                       (+ (length (car s)) (length (cadr s)))
-                                     (length s)))
+                                       (+ (string-width (car s))
+                                           (string-width (cadr s)))
+                                     (string-width s)))
                                  strings)))
           (window (get-buffer-window (current-buffer) 0))
           (wwidth (if window (1- (window-width window)) 79))
@@ -596,13 +734,14 @@ It also eliminates runs of equal strings."
                                  ;; We can't just set tab-width, because
                                  ;; completion-setup-function will kill all
                                  ;; local variables :-(
-                                 `(display (space :align-to ,column))))
-         (when (< wwidth (+ (max colwidth
-                                 (if (consp str)
-                                     (+ (length (car str)) (length (cadr str)))
-                                   (length str)))
-                            column))
-           (delete-char -2) (insert "\n") (setq column 0))
+                                 `(display (space :align-to ,column)))
+           (when (< wwidth (+ (max colwidth
+                                   (if (consp str)
+                                       (+ (string-width (car str))
+                                          (string-width (cadr str)))
+                                     (string-width str)))
+                              column))
+             (delete-char -2) (insert "\n") (setq column 0)))
          (if (not (consp str))
              (put-text-property (point) (progn (insert str) (point))
                                 'mouse-face 'highlight)
@@ -611,15 +750,58 @@ It also eliminates runs of equal strings."
            (put-text-property (point) (progn (insert (cadr str)) (point))
                                'mouse-face nil)))))))
 
-(defvar completion-common-substring)
+(defvar completion-common-substring nil)
+(make-obsolete-variable 'completion-common-substring nil "23.1")
 
 (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'.")
+See also `display-completion-list'.")
+
+(defface completions-first-difference
+  '((t (:inherit bold)))
+  "Face put on the first uncommon character in completions in *Completions* buffer."
+  :group 'completion)
+
+(defface completions-common-part
+  '((t (:inherit default)))
+  "Face put on the common prefix substring in completions in *Completions* buffer.
+The idea of `completions-common-part' is that you can use it to
+make the common parts less visible than normal, so that the rest
+of the differing parts is, by contrast, slightly highlighted."
+  :group 'completion)
+
+(defun completion-hilit-commonality (completions prefix-len)
+  (when completions
+    (let* ((last (last completions))
+           (base-size (cdr last))
+           (com-str-len (- prefix-len (or base-size 0))))
+      ;; Remove base-size during mapcar, and add it back later.
+      (setcdr last nil)
+      (nconc
+       (mapcar
+        (lambda (elem)
+          (let ((str
+                 ;; Don't modify the string itself, but a copy, since the
+                 ;; the string may be read-only or used for other purposes.
+                 ;; Furthermore, since `completions' may come from
+                 ;; display-completion-list, `elem' may be a list.
+                 (if (consp elem)
+                     (car (setq elem (cons (copy-sequence (car elem))
+                                           (cdr elem))))
+                   (setq elem (copy-sequence elem)))))
+            (put-text-property 0 com-str-len
+                               'font-lock-face 'completions-common-part
+                               str)
+            (if (> (length str) com-str-len)
+                (put-text-property com-str-len (1+ com-str-len)
+                                   'font-lock-face 'completions-first-difference
+                                   str)))
+          elem)
+        completions)
+       base-size))))
 
 (defun display-completion-list (completions &optional common-substring)
   "Display the list of completions, COMPLETIONS, using `standard-output'.
@@ -632,14 +814,14 @@ The actual completion alternatives, as inserted, are given `mouse-face'
 properties of `highlight'.
 At the end, this runs the normal hook `completion-setup-hook'.
 It can find the completion buffer in `standard-output'.
-The optional second arg COMMON-SUBSTRING is a string.
+The obsolete optional second arg COMMON-SUBSTRING is a string.
 It is used to put faces, `completions-first-difference' and
 `completions-common-part' on the completion buffer.  The
 `completions-common-part' face is put on the common substring
-specified by COMMON-SUBSTRING.  If COMMON-SUBSTRING is nil
-and the current buffer is not the minibuffer, the faces are not put.
-Internally, COMMON-SUBSTRING is bound to `completion-common-substring'
-during running `completion-setup-hook'."
+specified by COMMON-SUBSTRING."
+  (if common-substring
+      (setq completions (completion-hilit-commonality
+                         completions (length common-substring))))
   (if (not (bufferp standard-output))
       ;; This *never* (ever) happens, so there's no point trying to be clever.
       (with-temp-buffer
@@ -660,6 +842,8 @@ during running `completion-setup-hook'."
           (setcdr last nil)) ;Make completions a properly nil-terminated list.
        (completion--insert-strings completions))))
 
+  ;; The hilit used to be applied via completion-setup-hook, so there
+  ;; may still be some code that uses completion-common-substring.
   (let ((completion-common-substring common-substring))
     (run-hooks 'completion-setup-hook))
   nil)
@@ -720,6 +904,37 @@ during running `completion-setup-hook'."
     (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)
+  ;; M-TAB is already abused for many other purposes, so we should find
+  ;; another binding for it.
+  ;; (define-key map "\e\t" 'minibuffer-force-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))
 
@@ -728,24 +943,43 @@ during running `completion-setup-hook'."
             (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 ((suffix (cdr action)))
+        (if (string-match completion--embedded-envvar-re string)
+            (list* 'boundaries
+                   (or (match-beginning 2) (match-beginning 1))
+                   (when (string-match "[^[:alnum:]_]" suffix)
+                     (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 string)))
+          (end (string-match "/" (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.
@@ -776,8 +1010,8 @@ during running `completion-setup-hook'."
 
        ((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.
@@ -799,14 +1033,13 @@ during running `completion-setup-hook'."
 
           (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
@@ -851,6 +1084,10 @@ such as making the current buffer visit no file in the case of
   :group 'minibuffer
   :type 'boolean)
 
+;; Not always defined, but only called if next-read-file-uses-dialog-p says so.
+(declare-function x-file-dialog "xfns.c"
+                  (prompt dir &optional default-filename mustmatch only-dir-p))
+
 (defun read-file-name (prompt &optional dir default-filename mustmatch initial predicate)
   "Read file name, prompting with PROMPT and completing in directory DIR.
 Value is not expanded---you must call `expand-file-name' yourself.
@@ -986,7 +1223,9 @@ Like `internal-complete-buffer', but removes BUFFER from the completion list."
       completion)))
 
 (defun completion-emacs21-all-completions (string table pred point)
-  (all-completions string table pred t))
+  (completion-hilit-commonality
+   (all-completions string table pred t)
+   (length string)))
 
 ;;; Basic completion, used in Emacs-22.
 
@@ -998,20 +1237,346 @@ Like `internal-complete-buffer', but removes BUFFER from the completion list."
       ;; Merge a trailing / in completion with a / after point.
       ;; We used to only do it for word completion, but it seems to make
       ;; sense for all completions.
-      (if (and (eq ?/ (aref completion (1- (length completion))))
+      ;; Actually, claiming this feature was part of Emacs-22 completion
+      ;; is pushing it a bit: it was only done in minibuffer-completion-word,
+      ;; which was (by default) not bound during file completion, where such
+      ;; slashes are most likely to occur.
+      (if (and (not (zerop (length completion)))
+               (eq ?/ (aref completion (1- (length completion))))
                (not (zerop (length suffix)))
                (eq ?/ (aref suffix 0)))
-          ;; This leaves point before the / .
-          ;; Should we maybe put it after the / ?  --Stef
-          (setq completion (substring completion 0 -1)))
+          ;; This leaves point after the / .
+          (setq suffix (substring suffix 1)))
       (cons (concat completion suffix) (length completion)))))
 
 (defun completion-emacs22-all-completions (string table pred point)
-  (all-completions (substring string 0 point) table pred t))
+  (completion-hilit-commonality
+   (all-completions (substring string 0 point) table pred t)
+   point))
+
+(defun completion-basic-try-completion (string table pred point)
+  (let ((suffix (substring string point))
+        (completion (try-completion (substring string 0 point) table pred)))
+    (if (not (stringp completion))
+        completion
+      ;; Merge end of completion with beginning of suffix.
+      ;; Simple generalization of the "merge trailing /" done in Emacs-22.
+      (when (and (not (zerop (length suffix)))
+                 (string-match "\\(.+\\)\n\\1" (concat completion "\n" suffix)
+                               ;; Make sure we don't compress things to less
+                               ;; than we started with.
+                               point)
+                 ;; Just make sure we didn't match some other \n.
+                 (eq (match-end 1) (length completion)))
+        (setq suffix (substring suffix (- (match-end 1) (match-beginning 1)))))
+
+      (cons (concat completion suffix) (length completion)))))
 
-(defalias 'completion-basic-try-completion 'completion-emacs22-try-completion)
 (defalias 'completion-basic-all-completions 'completion-emacs22-all-completions)
 
+;;; Partial-completion-mode style completion.
+
+;; BUGS:
+
+;; - "minibuffer-s- TAB" with minibuffer-selected-window ends up with
+;;   "minibuffer--s-" which matches other options.
+
+(defvar completion-pcm--delim-wild-regex nil)
+
+(defun completion-pcm--prepare-delim-re (delims)
+  (setq completion-pcm--delim-wild-regex (concat "[" delims "*]")))
+
+(defcustom completion-pcm-word-delimiters "-_. "
+  "A string of characters treated as word delimiters for completion.
+Some arcane rules:
+If `]' is in this string, it must come first.
+If `^' is in this string, it must not come first.
+If `-' is in this string, it must come first or right after `]'.
+In other words, if S is this string, then `[S]' must be a valid Emacs regular
+expression (not containing character ranges like `a-z')."
+  :set (lambda (symbol value)
+         (set-default symbol value)
+         ;; Refresh other vars.
+         (completion-pcm--prepare-delim-re value))
+  :initialize 'custom-initialize-reset
+  :group 'minibuffer
+  :type 'string)
+
+(defun completion-pcm--pattern-trivial-p (pattern)
+  (and (stringp (car pattern)) (null (cdr 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 string)))
+      (let ((prefix (substring string 0 point))
+            (suffix (substring string point)))
+        (append (completion-pcm--string->pattern prefix)
+                '(point)
+                (completion-pcm--string->pattern suffix)))
+    (let ((pattern nil)
+          (p 0)
+          (p0 0))
+
+      (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)))
+          (push 'any pattern)
+          (setq p0 p))
+        (incf p))
+
+      ;; 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 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)
+                                     "\\(.*?\\)" ".*?"))
+               (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 (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!
+      (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!
+    (let* (;; Convert search pattern to a standard regular expression.
+          (regex (completion-pcm--pattern->regex pattern))
+          (completion-regexp-list (cons regex completion-regexp-list))
+          (compl (all-completions
+                   (concat prefix (if (stringp (car pattern)) (car pattern) ""))
+                  table pred))
+           (last (last compl)))
+      (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
+       (let ((case-fold-search completion-ignore-case)
+              (poss ()))
+         (dolist (c compl)
+           (when (string-match regex c) (push c poss)))
+         poss)))))
+
+(defun completion-pcm--hilit-commonality (pattern completions)
+  (when completions
+    (let* ((re (completion-pcm--pattern->regex pattern '(point)))
+           (last (last completions))
+           (base-size (cdr last)))
+      ;; Remove base-size during mapcar, and add it back later.
+      (setcdr last nil)
+      (nconc
+       (mapcar
+        (lambda (str)
+          ;; Don't modify the string itself.
+          (setq str (copy-sequence str))
+          (unless (string-match re str)
+            (error "Internal error: %s does not match %s" re str))
+          (let ((pos (or (match-beginning 1) (match-end 0))))
+            (put-text-property 0 pos
+                               'font-lock-face 'completions-common-part
+                               str)
+            (if (> (length str) pos)
+                (put-text-property pos (1+ pos)
+                                   'font-lock-face 'completions-first-difference
+                                   str)))
+          str)
+        completions)
+       base-size))))
+
+(defun completion-pcm--find-all-completions (string table pred point)
+  (let* ((beforepoint (substring string 0 point))
+         (afterpoint (substring string point))
+         (bounds (completion-boundaries beforepoint table pred afterpoint))
+         (prefix (substring beforepoint 0 (car bounds)))
+         (suffix (substring afterpoint (cdr bounds)))
+         firsterror)
+    (setq string (substring string (car bounds) (+ point (cdr bounds))))
+    (let* ((relpoint (- point (car bounds)))
+           (pattern (completion-pcm--string->pattern string relpoint))
+           (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.
+                ;; FIXME: COMPLETE REWRITE!!!
+                (let* ((newbeforepoint
+                        (concat subprefix (car suball)
+                                (substring string 0 relpoint)))
+                       (leftbound (+ (length subprefix) (length (car suball))))
+                       (newbounds (completion-boundaries
+                                   newbeforepoint table pred afterpoint)))
+                  (unless (or (and (eq (cdr bounds) (cdr newbounds))
+                                   (eq (car newbounds) leftbound))
+                              ;; Refuse new boundaries if they step over
+                              ;; the submatch.
+                              (< (car newbounds) leftbound))
+                    ;; The new completed prefix does change the boundaries
+                    ;; of the completed substring.
+                    (setq suffix (substring afterpoint (cdr newbounds)))
+                    (setq string
+                          (concat (substring newbeforepoint (car newbounds))
+                                  (substring afterpoint 0 (cdr newbounds))))
+                    (setq between (substring newbeforepoint leftbound
+                                             (car newbounds)))
+                    (setq pattern (completion-pcm--string->pattern
+                                   string
+                                   (- (length newbeforepoint)
+                                      (car newbounds)))))
+                  (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)))
+                  ;; FIXME: This can come in handy for try-completion,
+                  ;; but isn't right for all-completions, since it lists
+                  ;; invalid completions.
+                  ;; (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)
+  (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."
+  (cond
+   ((null (cdr strs)) (list (car strs)))
+   (t
+    (let ((re (completion-pcm--pattern->regex pattern 'group))
+          (ccs ()))                     ;Chopped completions.
+
+      ;; First chop each string into the parts corresponding to each
+      ;; non-constant element of `pattern', using regexp-matching.
+      (let ((case-fold-search completion-ignore-case))
+        (dolist (str strs)
+          (unless (string-match re str)
+            (error "Internal error: %s doesn't match %s" str re))
+          (let ((chopped ())
+                (i 1))
+            (while (match-beginning i)
+              (push (match-string i str) chopped)
+              (setq i (1+ i)))
+            ;; Add the text corresponding to the implicit trailing `any'.
+            (push (substring str (match-end 0)) chopped)
+            (push (nreverse chopped) ccs))))
+
+      ;; Then for each of those non-constant elements, extract the
+      ;; commonality between them.
+      (let ((res ()))
+        ;; Make the implicit `any' explicit.  We could make it explicit
+        ;; everywhere, but it would slow down regexp-matching a little bit.
+        (dolist (elem (append pattern '(any)))
+          (if (stringp elem)
+              (push elem res)
+            (let ((comps ()))
+              (dolist (cc (prog1 ccs (setq ccs nil)))
+                (push (car cc) comps)
+                (push (cdr cc) ccs))
+              (let* ((prefix (try-completion "" comps))
+                     (unique (or (and (eq prefix t) (setq prefix ""))
+                                 (eq t (try-completion prefix comps)))))
+                (unless (equal prefix "") (push prefix res))
+                ;; If there's only one completion, `elem' is not useful
+                ;; any more: it can only match the empty string.
+                ;; FIXME: in some cases, it may be necessary to turn an
+                ;; `any' into a `star' because the surrounding context has
+                ;; changed such that string->pattern wouldn't add an `any'
+                ;; here any more.
+                (unless unique (push elem res))))))
+        ;; We return it in reverse order.
+        res)))))
+
+(defun completion-pcm--pattern->string (pattern)
+  (mapconcat (lambda (x) (cond
+                     ((stringp x) x)
+                     ((eq x 'star) "*")
+                     ((eq x 'any) "")
+                     ((eq x 'point) "")))
+             pattern
+             ""))
+
+(defun completion-pcm-try-completion (string table pred point)
+  (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
+            ;; order of preference) either at the old point, or at
+            ;; the last place where there's something to choose, or
+            ;; at the very end.
+             (pointpat (or (memq 'point mergedpat) (memq 'any mergedpat)
+                          mergedpat))
+             ;; New pos from the start.
+             (newpos (length (completion-pcm--pattern->string pointpat)))
+            ;; Do it afterwards because it changes `pointpat' by sideeffect.
+             (merged (completion-pcm--pattern->string (nreverse mergedpat))))
+        (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)
 
 ;; arch-tag: ef8a0a15-1080-4790-a754-04017c02f08f