Merge branch 'feature/completions-customs'

This commit is contained in:
Juri Linkov 2022-03-22 10:22:46 +02:00
commit 15ac51e0fd
5 changed files with 212 additions and 42 deletions

View file

@ -624,11 +624,18 @@ completion alternatives in the completion list.
@vindex completion-auto-help
If @code{completion-auto-help} is set to @code{nil}, the completion
commands never display the completion list buffer; you must type
@kbd{?} to display the list. If the value is @code{lazy}, Emacs only
@kbd{?} to display the list. If the value is @code{lazy}, Emacs only
shows the completion list buffer on the second attempt to complete.
In other words, if there is nothing to complete, the first @key{TAB}
echoes @samp{Next char not unique}; the second @key{TAB} shows the
completion list buffer.
completion list buffer. With the previous values and the default
@code{t} the completions are hidden when some unique completion is
executed. If @code{completion-auto-help} is set to @code{always}, the
completion commands are always shown after a completion attempt, or
updated if they are already visible. If the value is @code{visible},
then completions are not hidden, but updated if they are already
visible while the current behavior stays the same as default if they
are not.
@vindex completion-cycle-threshold
If @code{completion-cycle-threshold} is non-@code{nil}, completion
@ -651,6 +658,32 @@ changed by changing the @code{completions-format} user option. If
@code{vertical}, sort the completions vertically in columns instead,
and if @code{one-column}, just use a single column.
@vindex completions-max-height
When @code{completions-max-height} is non-@code{nil}, it limits the
size of the completions window. It is specified in lines and include
mode, header line and a bottom divider, if any. For a more complex
control of the Completion window display properties, you can use
@code{display-buffer-alist} (@pxref{Buffer Display Action
Alists,,Action Alists for Buffer Display, elisp, The Emacs Lisp
Reference Manual}).
@vindex completions-header-format
The variable @code{completions-header-format} is a formatted string to
control the informative line shown before the completions list of
candidates. It may contain a @code{%s} to show the total number of
completions. When it is @code{nil}, the message is totally suppressed.
Text properties may be added to change the appearance, some useful
ones are @code{face} or @code{cursor-intangible} (@pxref{Special
Properties,,Properties with Special Meanings, elisp, The Emacs Lisp
Reference Manual}).
@vindex completions-highlight-face
When @code{completions-highlight-face} is a face name, then the
current completion candidate will be highlighted with that face. The
default value is @code{completions-highlight}. When the value is
@code{nil}, no highlighting is performed. This feature sets the text
property @code{cursor-face}.
@node Minibuffer History
@section Minibuffer History
@cindex minibuffer history

View file

@ -3551,6 +3551,17 @@ that alter the text size (e.g., @code{:height}, @code{:weight}, and
@code{:slant}). Those attributes are always the same as for the
unhighlighted text.
@item cursor-face
@kindex cursor-face @r{(text property)}
This property is similar to @code{mouse-face}, but the face is used if
the cursor (instead of mouse) is on or near the character. Near has
the same meaning that in @code{mouse-face} and the highlighting only
takes effect if the mode @code{cursor-face-highlight-mode} is enabled;
otherwise no highlighting is performed. When the variable
@code{cursor-face-highlight-nonselected-window} is non-@code{nil}, the
text is highlighted even if the window is not selected that is similar
to @code{highlight-nonselected-windows} for the region.
@item fontified
@kindex fontified @r{(text property)}
This property says whether the text is ready for display. If

View file

@ -577,6 +577,31 @@ This option controls the sorting of the completion candidates in
the "*Completions*" buffer. Available styles are no sorting,
alphabetical (the default), or a custom sort function.
+++
*** New values for the 'completion-auto-help' option.
There are two new values to control the way "*Completions*" behave after
a <tab> if completion is not unique. 'always' updates or shows
the "*Completions*" buffer after any attempt to complete. 'visual' is
like 'always', but only update the completions if they are already
visible. The default value 't' always hides the completion buffer after
some completion is made.
+++
*** New user option 'completions-max-height'.
This option limits the height of the "*Completions*" buffer.
+++
*** New option 'completions-header-format'
This is a string to control the message to show before completions.
It may contain a "%s" to show the total number of completions. If nil no
completions are shown.
+++
*** New option 'completions-highlight-face'.
When this variable is a face name, it highlights the current candidate
in the "*Completions*" buffer with that face. When the value is nil,
no highlighting is performed at all.
** Isearch and Replace
+++
@ -1301,6 +1326,13 @@ property.
** New 'min-width' 'display' property.
This allows setting a minimum display width for a region of text.
+++
** New 'cursor-face' text property.
This uses 'cursor-face' instead of the default face when cursor is on or
near the character and 'cursor-face-highlight-mode' is enabled. The
variable 'cursor-face-highlight-nonselected-window' is similar to
'highlight-nonselected-windows', but for this property.
+++
** New event type 'touch-end'.
This event is sent whenever the user's finger moves off the mouse

View file

@ -897,8 +897,17 @@ If the current buffer is not a minibuffer, erase its entire contents."
If the value is t the *Completions* buffer is displayed whenever completion
is requested but cannot be done.
If the value is `lazy', the *Completions* buffer is only displayed after
the second failed attempt to complete."
:type '(choice (const nil) (const t) (const lazy)))
the second failed attempt to complete.
If the value is 'always', the completion commands are always shown
after a completion attempt, or updated if they are already visible.
If the value is 'visible', then completions are not hidden, but updated
if they are already visible while the current behavior stays the same
as default if they are not."
:type '(choice (const :tag "Disabled" nil)
(const :tag "Enabled legacy" t)
(const :tag "After a second attempt" lazy)
(const :tag "Visible update" visible)
(const :tag "Always update" always)))
(defvar completion-styles-alist
'((emacs21
@ -1343,16 +1352,18 @@ when the buffer's text is already an exact match."
(completion--cache-all-sorted-completions beg end comps)
(minibuffer-force-complete beg end))
(completed
;; We could also decide to refresh the completions,
;; if they're displayed (and assuming there are
;; completions left).
(minibuffer-hide-completions)
(if exact
;; If completion did not put point at end of field,
;; it's a sign that completion is not finished.
(completion--done completion
(if (< comp-pos (length completion))
'exact 'unknown))))
(cond
((pcase completion-auto-help
('visible (get-buffer-window "*Completions*" 0))
('always t))
(minibuffer-completion-help beg end))
(t (minibuffer-hide-completions)
(when exact
;; If completion did not put point at end of field,
;; it's a sign that completion is not finished.
(completion--done completion
(if (< comp-pos (length completion))
'exact 'unknown))))))
;; Show the completion table, if requested.
((not exact)
(if (pcase completion-auto-help
@ -1842,6 +1853,17 @@ Return nil if there is no valid completion, else t."
This face is only used if the strings used for completions
doesn't already specify a face.")
(defface completions-highlight
'((t :inherit highlight))
"Default face for highlighting the current completion candidate."
:version "29.1")
(defcustom completions-highlight-face 'completions-highlight
"A face name to highlight the current completion candidate.
If the value is nil, no highlighting is performed."
:type '(choice (const nil) face)
:version "29.1")
(defcustom completions-format 'horizontal
"Define the appearance and sorting of completions.
If the value is `vertical', display completions sorted vertically
@ -1861,6 +1883,17 @@ completions."
:type 'boolean
:version "28.1")
(defcustom completions-header-format
(propertize "%s possible completions:\n"
'face 'shadow
:help "Please select a completion")
"Format of completions header.
It may contain one %s to show the total count of completions.
When nil, no header is shown."
:type '(choice (const :tag "No header" nil)
(string :tag "Header format string"))
:version "29.1")
(defun completion--insert-strings (strings &optional group-fun)
"Insert a list of STRINGS into the current buffer.
The candidate strings are inserted into the buffer depending on the
@ -2012,7 +2045,7 @@ Runs of equal candidate strings are eliminated. GROUP-FUN is a
(funcall group-fun str 'transform)
str))
(point))
`(mouse-face highlight completion--string ,str))
`(mouse-face highlight cursor-face ,completions-highlight-face completion--string ,str))
;; If `str' is a list that has 2 elements,
;; then the second element is a suffix annotation.
;; If `str' has 3 elements, then the second element
@ -2123,10 +2156,9 @@ candidates."
(with-current-buffer standard-output
(goto-char (point-max))
(if (null completions)
(insert "There are no possible completions of what you have typed.")
(insert "Possible completions are:\n")
(completion--insert-strings completions group-fun))))
(when completions-header-format
(insert (format completions-header-format (length completions))))
(completion--insert-strings completions group-fun)))
(run-hooks 'completion-setup-hook)
nil)
@ -2198,6 +2230,19 @@ variables.")
(equal pre-msg (and exit-fun (current-message))))
(completion--message message))))
(defcustom completions-max-height nil
"Maximum height for *Completions* buffer window."
:type '(choice (const nil) natnum)
:version "29.1")
(defun completions--fit-window-to-buffer (&optional win &rest _)
"Resize *Completions* buffer window."
(if temp-buffer-resize-mode
(let ((temp-buffer-max-height (or completions-max-height
temp-buffer-max-height)))
(resize-temp-buffer-window win))
(fit-window-to-buffer win completions-max-height)))
(defun minibuffer-completion-help (&optional start end)
"Display a list of possible completions of the current minibuffer contents."
(interactive)
@ -2261,9 +2306,7 @@ variables.")
,(if (eq (selected-window) (minibuffer-window))
'display-buffer-at-bottom
'display-buffer-below-selected))
,(if temp-buffer-resize-mode
'(window-height . resize-temp-buffer-window)
'(window-height . fit-window-to-buffer))
(window-height . completions--fit-window-to-buffer)
,(when temp-buffer-resize-mode
'(preserve-size . (nil . t)))
(body-function
@ -2354,6 +2397,7 @@ variables.")
"Get rid of an out-of-date *Completions* buffer."
;; FIXME: We could/should use minibuffer-scroll-window here, but it
;; can also point to the minibuffer-parent-window, so it's a bit tricky.
(interactive)
(let ((win (get-buffer-window "*Completions*" 0)))
(if win (with-selected-window win (bury-buffer)))))

View file

@ -6483,27 +6483,38 @@ An example is a rectangular region handled as a list of
separate contiguous regions for each line."
(cdr (region-bounds)))
(defun redisplay--unhighlight-overlay-function (rol)
"If ROL is an overlay, call `delete-overlay'."
(when (overlayp rol) (delete-overlay rol)))
(defvar redisplay-unhighlight-region-function
(lambda (rol) (when (overlayp rol) (delete-overlay rol))))
#'redisplay--unhighlight-overlay-function
"Function to remove the region-highlight overlay.")
(defun redisplay--highlight-overlay-function (start end window rol &optional face)
"Update the overlay ROL in WINDOW with FACE in range START-END."
(unless face (setq face 'region))
(if (not (overlayp rol))
(let ((nrol (make-overlay start end)))
(funcall redisplay-unhighlight-region-function rol)
(overlay-put nrol 'window window)
(overlay-put nrol 'face face)
;; Normal priority so that a large region doesn't hide all the
;; overlays within it, but high secondary priority so that if it
;; ends/starts in the middle of a small overlay, that small overlay
;; won't hide the region's boundaries.
(overlay-put nrol 'priority '(nil . 100))
nrol)
(unless (eq (overlay-get rol 'face) face)
(overlay-put rol 'face face))
(unless (and (eq (overlay-buffer rol) (current-buffer))
(eq (overlay-start rol) start)
(eq (overlay-end rol) end))
(move-overlay rol start end (current-buffer)))
rol))
(defvar redisplay-highlight-region-function
(lambda (start end window rol)
(if (not (overlayp rol))
(let ((nrol (make-overlay start end)))
(funcall redisplay-unhighlight-region-function rol)
(overlay-put nrol 'window window)
(overlay-put nrol 'face 'region)
;; Normal priority so that a large region doesn't hide all the
;; overlays within it, but high secondary priority so that if it
;; ends/starts in the middle of a small overlay, that small overlay
;; won't hide the region's boundaries.
(overlay-put nrol 'priority '(nil . 100))
nrol)
(unless (and (eq (overlay-buffer rol) (current-buffer))
(eq (overlay-start rol) start)
(eq (overlay-end rol) end))
(move-overlay rol start end (current-buffer)))
rol))
#'redisplay--highlight-overlay-function
"Function to move the region-highlight overlay.
This function is called with four parameters, START, END, WINDOW
and OVERLAY. If OVERLAY is nil, a new overlay is created. In
@ -6528,8 +6539,33 @@ The overlay is returned by the function.")
(funcall redisplay-highlight-region-function
start end window rol)))
(unless (equal new rol)
(set-window-parameter window 'internal-region-overlay
new))))))
(set-window-parameter window 'internal-region-overlay new))))))
(defcustom cursor-face-highlight-nonselected-window nil
"Non-nil means highlight text with `cursor-face' even in nonselected windows.
This variable is similar to `highlight-nonselected-windows'."
:local t
:type 'boolean
:version "29.1")
(defun redisplay--update-cursor-face-highlight (window)
"Highlights the overlay used to highlight text with cursor-face."
(let ((rol (window-parameter window 'internal-cursor-face-overlay)))
(if-let* (((or cursor-face-highlight-nonselected-window
(eq window (selected-window))
(and (window-minibuffer-p)
(eq window (minibuffer-selected-window)))))
(pt (window-point window))
(cursor-face (get-text-property pt 'cursor-face)))
(let* ((start (previous-single-property-change
(1+ pt) 'cursor-face nil (point-min)))
(end (next-single-property-change
pt 'cursor-face nil (point-max)))
(new (redisplay--highlight-overlay-function
start end window rol cursor-face)))
(unless (equal new rol)
(set-window-parameter window 'internal-cursor-face-overlay new)))
(redisplay--unhighlight-overlay-function rol))))
(defvar pre-redisplay-functions (list #'redisplay--update-region-highlight)
"Hook run just before redisplay.
@ -6537,6 +6573,15 @@ It is called in each window that is to be redisplayed. It takes one argument,
which is the window that will be redisplayed. When run, the `current-buffer'
is set to the buffer displayed in that window.")
(define-minor-mode cursor-face-highlight-mode
"When enabled, respect the cursor-face property."
:global nil
(if cursor-face-highlight-mode
(add-hook 'pre-redisplay-functions
#'redisplay--update-cursor-face-highlight nil t)
(remove-hook 'pre-redisplay-functions
#'redisplay--update-cursor-face-highlight t)))
(defun redisplay--pre-redisplay-functions (windows)
(with-demoted-errors "redisplay--pre-redisplay-functions: %S"
(if (null windows)
@ -9355,6 +9400,11 @@ Called from `temp-buffer-show-hook'."
(if base-dir (setq default-directory base-dir))
(when completion-tab-width
(setq tab-width completion-tab-width))
;; Maybe enable cursor completions-highlight.
(when completions-highlight-face
;; Keep highlighting even if not selected.
(setq-local cursor-face-highlight-nonselected-window t)
(cursor-face-highlight-mode 1))
;; Maybe insert help string.
(when completion-show-help
(goto-char (point-min))