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
The list variable @code{completion-styles} specifies the completion
styles to use. Each list element is the name of a completion style (a
Lisp symbol). The available style symbols are stored in the variable
styles to use. Each list element is either the name of a completion
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,
The Emacs Lisp Reference Manual}). The default completion styles are
(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
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
@cindex @code{emacs22}, completion style
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
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

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.
emacs22)
"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
styles for specific categories, such as files, buffers, etc."
@ -1284,11 +1292,18 @@ overrides the default specified in `completion-category-defaults'."
(result-and-style
(seq-some
(lambda (style)
(let (symbols values)
(when (consp style)
(dolist (binding (cadr style))
(push (car binding) symbols)
(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))))
(and probe (cons probe style))))))
(completion--styles md)))
(adjust-fn (get (cdr result-and-style) 'completion--adjust-metadata)))
(when (and adjust-fn metadata)
@ -3868,6 +3883,21 @@ the commands start with a \"-\" or a SPC."
(setq trivial nil)))
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)
"Split STRING into a pattern.
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)
(if pending (push pending 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)
;; Remove empty strings in a separate phase since otherwise a ""