Allow customizing partial-completion to be more like substring

The substring completion style completes "foo-bar" as "*foo-bar*".  The
partial-completion completion style completes "foo-bar" as "foo*bar*".

Previously, it was not possible to get completion of "foo-bar" to act as
"*foo*bar*", e.g. combining the partial-completion and substring styles.
This would be especially useful for things like project-find-file.

Now it is possible by customizing the completion-pcm-leading-wildcard variable
to a non-nil value.

Furthermore, it's convenient to be able to run
regular (completion-pcm-leading-wildcard=t, non-substring)
partial-completion before running completion-pcm-leading-wildcard=nil
partial-completion, since the former provides more narrowly targeted
completions.

It's possible to do this by customizing completion-styles.  Just add
'(partial-completion ((completion-pcm-leading-wildcard t))) and
'(partial-completion ((completion-pcm-leading-wildcard nil))) in that
order.  Then the completion machinery will first run partial-completion
with completion-pcm-leading-wildcard=t, and if that returns no
completions, run partial-completion with
completion-pcm-leading-wildcard=nil.

* lisp/minibuffer.el (completion--nth-completion): Allow an element of
completion-styles to contain a list of bindings.
(completion-styles): Document that.
(completion-pcm-leading-wildcard): Add.
(completion-pcm--string->pattern): Check completion-pcm-leading-wildcard.
(bug#70217)
This commit is contained in:
Spencer Baugh 2024-08-21 11:59:42 -04:00 committed by Eli Zaretskii
parent a7a22e7c22
commit 69ec333eab
3 changed files with 77 additions and 9 deletions

View file

@ -543,8 +543,14 @@ falls back on the next style.
@vindex completion-styles @vindex completion-styles
The list variable @code{completion-styles} specifies the completion The list variable @code{completion-styles} specifies the completion
styles to use. Each list element is the name of a completion style (a styles to use. Each list element is either the name of a completion
Lisp symbol). The available style symbols are stored in the variable style (a Lisp symbol) or a list starting with the name of a completion
style followed by @code{let}-style list of bindings which will be in
effect for that completion style. Multiple elements of
@code{completion-styles} can name the same completion style with
different variable bindings.
The available style symbols are stored in the variable
@code{completion-styles-alist} (@pxref{Completion Variables,,, elisp, @code{completion-styles-alist} (@pxref{Completion Variables,,, elisp,
The Emacs Lisp Reference Manual}). The default completion styles are The Emacs Lisp Reference Manual}). The default completion styles are
(in order): (in order):
@ -569,6 +575,12 @@ Furthermore, a @samp{*} in the minibuffer text is treated as a
@dfn{wildcard}---it matches any string of characters at the @dfn{wildcard}---it matches any string of characters at the
corresponding position in the completion alternative. corresponding position in the completion alternative.
@vindex completion-pcm-leading-wildcard
If @code{completion-pcm-leading-wildcard} is set to @code{t}, this style
always acts as if a @dfn{wildcard} is present at the start of the
minibuffer text, similar to the @code{substring} style. For example,
@samp{l-m} will complete to @samp{emacs-lisp-mode}.
@item emacs22 @item emacs22
@cindex @code{emacs22}, completion style @cindex @code{emacs22}, completion style
This completion style is similar to @code{basic}, except that it This completion style is similar to @code{basic}, except that it

View file

@ -43,6 +43,28 @@ The 'find-function', 'find-library', 'find-face-definition', and
'find-variable' commands now allow retrieving previous input using the 'find-variable' commands now allow retrieving previous input using the
usual minibuffer history commands. Each command has a separate history. usual minibuffer history commands. Each command has a separate history.
** Minibuffer and Completions
+++
*** New user option 'completion-pcm-leading-wildcard'.
This option configures how the partial-completion style does completion.
It defaults to nil, which preserves the existing behavior. When it is set
to t, the partial-completion style behaves more like the substring
style, in that a string being completed can match against a candidate
anywhere in the candidate string.
+++
*** 'completion-styles' now can contain lists of bindings.
In addition to being a symbol naming a completion style, an element of
'completion-styles' can now be a list of the form '(STYLE ((VARIABLE
VALUE) ...))' where STYLE is a symbol naming a completion style.
VARIABLE will be bound to VALUE (without evaluating it) while the style
is executing. This allows multiple references to the same style with
different values for completion-affecting variables like
'completion-pcm-leading-wildcard or 'completion-ignore-case'. This also
applies for the styles configuration in 'completion-category-overrides'
and 'completion-category-defaults'.
** Windows ** Windows

View file

@ -1141,7 +1141,15 @@ and DOC describes the way this style of completion works.")
;; and simply add "bar" to the end of the result. ;; and simply add "bar" to the end of the result.
emacs22) emacs22)
"List of completion styles to use. "List of completion styles to use.
The available styles are listed in `completion-styles-alist'. An element should be a symbol which is listed in
`completion-styles-alist'.
An element can also be a list of the form
(STYLE ((VARIABLE VALUE) ...))
STYLE must be a symbol listed in `completion-styles-alist', followed by
a `let'-style list of variable/value pairs. VARIABLE will be bound to
VALUE (without evaluating it) while the style is handling completion.
This allows repeating the same style with different configurations.
Note that `completion-category-overrides' may override these Note that `completion-category-overrides' may override these
styles for specific categories, such as files, buffers, etc." styles for specific categories, such as files, buffers, etc."
@ -1284,11 +1292,18 @@ overrides the default specified in `completion-category-defaults'."
(result-and-style (result-and-style
(seq-some (seq-some
(lambda (style) (lambda (style)
(let ((probe (funcall (let (symbols values)
(or (nth n (assq style completion-styles-alist)) (when (consp style)
(error "Invalid completion style %s" style)) (dolist (binding (cadr style))
string table pred point))) (push (car binding) symbols)
(and probe (cons probe style)))) (push (cadr binding) values))
(setq style (car style)))
(cl-progv symbols values
(let ((probe (funcall
(or (nth n (assq style completion-styles-alist))
(error "Invalid completion style %s" style))
string table pred point)))
(and probe (cons probe style))))))
(completion--styles md))) (completion--styles md)))
(adjust-fn (get (cdr result-and-style) 'completion--adjust-metadata))) (adjust-fn (get (cdr result-and-style) 'completion--adjust-metadata)))
(when (and adjust-fn metadata) (when (and adjust-fn metadata)
@ -3868,6 +3883,21 @@ the commands start with a \"-\" or a SPC."
(setq trivial nil))) (setq trivial nil)))
trivial))) trivial)))
(defcustom completion-pcm-leading-wildcard nil
"If non-nil, partial-completion completes as if there's a leading wildcard.
If nil (the default), partial-completion requires a matching completion
alternative to have the same beginning as the first \"word\" in the
minibuffer text, where \"word\" is determined by
`completion-pcm-word-delimiters'.
If non-nil, partial-completion allows any string of characters to occur
at the beginning of a completion alternative, as if a wildcard such as
\"*\" was present at the beginning of the minibuffer text. This makes
partial-completion behave more like the substring completion style."
:version "30.1"
:type 'boolean)
(defun completion-pcm--string->pattern (string &optional point) (defun completion-pcm--string->pattern (string &optional point)
"Split STRING into a pattern. "Split STRING into a pattern.
A pattern is a list where each element is either a string A pattern is a list where each element is either a string
@ -3918,7 +3948,11 @@ or a symbol, see `completion-pcm--merge-completions'."
(when (> (length string) p0) (when (> (length string) p0)
(if pending (push pending pattern)) (if pending (push pending pattern))
(push (substring string p0) pattern)) (push (substring string p0) pattern))
(nreverse pattern)))) (setq pattern (nreverse pattern))
(when completion-pcm-leading-wildcard
(when (stringp (car pattern))
(push 'prefix pattern)))
pattern)))
(defun completion-pcm--optimize-pattern (p) (defun completion-pcm--optimize-pattern (p)
;; Remove empty strings in a separate phase since otherwise a "" ;; Remove empty strings in a separate phase since otherwise a ""