emacs-31 6b31360a319: Fix c-pcm-try-completion with boundaries completion

Sean Whitton <[email protected]> Thu, 2 Jul 2026 05:37:54 -0400 (EDT)
Newsgroups gmane.emacs.diffs
Message-ID <[email protected]>
branch: emacs-31
commit 6b31360a3195ba9786df9767097961fcfa49b909
Author: Spencer Baugh <[email protected]>
Commit: Sean Whitton <[email protected]>

    Fix c-pcm-try-completion with boundaries completion
    
    PCM try-completion could behavior incorrectly with completion
    tables using boundaries, such as file name completion.  It would
    "grow" earlier path components as if point was at the end of
    each path component (rather than at its true location), which
    meant all path components would "grow" not only from the left
    \(which is correct) but also from the right (which can only work
    when point is there).
    
    * lisp/minibuffer.el (completion-pcm--find-all-completions):
    Drop the sub-pattern's trailing `point' (bug#80914).
    * test/lisp/minibuffer-tests.el (completion-pcm-test-9): New
    test.
---
 lisp/minibuffer.el                               |  5 +++++
 test/lisp/minibuffer-resources/pcm/sources/clang |  0
 test/lisp/minibuffer-resources/pcm/sys/class     |  0
 test/lisp/minibuffer-tests.el                    | 15 +++++++++++++++
 4 files changed, 20 insertions(+)

diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el
index a24b92cdae8..4db3d0d0bea 100644
--- a/lisp/minibuffer.el
+++ b/lisp/minibuffer.el
@@ -4608,6 +4608,11 @@ filter out additional entries (because TABLE might not obey PRED)."
                      ;; Text that goes between the new submatches and the
                      ;; completion substring.
                      (between nil))
+          ;; SUBPAT was computed with point=(length substring); remove
+          ;; the trailing `point' since that's not the real location of
+          ;; point (bug#80914).
+          (cl-assert (eq (car (last subpat)) 'point))
+          (setq subpat (butlast subpat))
           ;; Eliminate submatches that don't end with the separator.
           (dolist (submatch (prog1 suball (setq suball ())))
             (when (eq sep (aref submatch (1- (length submatch))))
diff --git a/test/lisp/minibuffer-resources/pcm/sources/clang b/test/lisp/minibuffer-resources/pcm/sources/clang
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/test/lisp/minibuffer-resources/pcm/sys/class b/test/lisp/minibuffer-resources/pcm/sys/class
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/test/lisp/minibuffer-tests.el b/test/lisp/minibuffer-tests.el
index 16ee1753645..1db0c07f510 100644
--- a/test/lisp/minibuffer-tests.el
+++ b/test/lisp/minibuffer-tests.el
@@ -340,6 +340,21 @@
                   "" '("fooxbar" "fooybar") nil 0)
                  '("foobar" . 3))))
 
+(ert-deftest completion-pcm-bug80914 ()
+  ;; Completing a partial match in an earlier component (here "s"
+  ;; matches both "sys" and "sources", which contain "class" and
+  ;; "clang") should not leave a stray `point' in the middle of the
+  ;; merged pattern (bug#80914).
+  (let ((default-directory (ert-resource-directory))
+        (input "pcm/s/cl"))
+    ;; The pattern has a single `point' at the end rather than an extra
+    ;; `point' after the "s".
+    (should (equal (completion-pcm--find-all-completions
+                    input #'completion--file-name-table nil (length input))
+                   '(("s" any "/" "cl" point)
+                     ("sources/clang" "sys/class")
+                     "pcm/" "")))))
+
 (ert-deftest completion-pcm-test-anydelim ()
   ;; After each delimiter is a special wildcard which matches any
   ;; sequence of delimiters.