Compare commits

...

28 commits

Author SHA1 Message Date
Jimmy Aguilar Mena
c7c47e78e6 Try another approach even simpler.
Perform all the operations directly in the completions buffer.
2020-11-22 23:58:11 +01:00
Jimmy Aguilar Mena
5dd563f053 Renamed completions-highlight as zcomplete 2020-11-22 12:35:36 +01:00
Jimmy Aguilar Mena
60a1003aee Fix precious commit.
*
lisp/completions-highlight.el (completions-highlight--hide-completions-advise)
: New function to advise minibuffer-hide-completions.
(completions-highlight-select-near) : Unconditional recenter
2020-11-20 22:30:47 +01:00
Jimmy Aguilar Mena
25f23b1910 Add try to close completions more often like zsh.
*
lisp/completions-highlight.el (completions-highlight-maybe-close-completions)
: New function to perform more actions on pre-command-hook.
2020-11-20 19:03:23 +01:00
Jimmy Aguilar Mena
c990a28965 Simplify and add custom
* lisp/completions-highlight.el (completions-highlight-tab-no-scroll) :
New option to control if scroll or select with tab.
(completions-highlight--this-completion) : Removed
(completions-highlight-select-near) : Do search closer if not at point.
(with-minibuffer-scroll-window) : Changed to a function using Juri
Linkov
(minibuffer-choose-completion) : use
completions-highlight-from-minibuffer
(completions-highlight-minibuffer-map) : Use dolist and set only
completions-highlight-from-minibuffer
(completions-highlight--minibuffer-tab-through-completions) : Consider
the new custom to not scroll with tabs.
2020-11-20 19:03:23 +01:00
Jimmy Aguilar Mena
6369e59576 Other changes:
* lisp/completions-highlight.el (completions-highlight-this-completion) :
Rename as completions--highlight-this-completion
(completions-highlight-set-suffix) : New custom to control suffix in insertion
2020-11-20 19:03:23 +01:00
Jimmy Aguilar Mena
3319dcc33f New command minibuffer-choose-completion
This command uses *Completions* candidates only when highlighted.
2020-11-20 19:03:23 +01:00
Jimmy Aguilar Mena
bfb8a712dd Add ignore-errors when executing from minibuffer
This asserts that the hooks are executed in some cases like when EOB.
*
lisp/completions-highlight (completions-highlight-completions-visible-p)
: New function
2020-11-20 19:03:23 +01:00
Jimmy Aguilar Mena
6ea2c5c980 Fixes:
* lisp/completions-highlight.el (minibuffer-completion-set-suffix) :
Renamed as minibuffer-completion--set-suffix.
(completions-highlight--clear-suffix) : New function
(completions-highlight-minibuffer-tab-through-completions) : Renamed as
completions-highlight--minibuffer-tab-through-completions
(completions-highlight-completions-pre-command-hook) :
(completions-highlight-minibuffer-pre-command-hook) : Removed and
references substituted with completions-highlight--clear-suffix.
2020-11-20 19:03:23 +01:00
Jimmy Aguilar Mena
10359ba98a Fix previous commit 2020-11-20 19:03:23 +01:00
Jimmy Aguilar Mena
3f0f13e823 Add backtab commands. 2020-11-20 19:03:23 +01:00
Jimmy Aguilar Mena
ce8b5b2663 Simplify and rely more in the post-command-hook
* lisp/completions-highlight.el (completions-highlight-this-completion)
: Use the new function completions-highlight-select-near.
(completions-highlight-next-completion) : Removed
(completions-highlight-select-near) : New function to select and
highlight next candidate closer to point.
(completions-highlight-previous-completion) :
(completions-highlight-next-line-completion) :
(completions-highlight-previous-line-completion) : Removed as they are
not needed with the hook.
(with-minibuffer-scroll-window) : Add call to
completions-highlight-this-completion at the end.
(minibuffer-next-completion) :
(completions-highlight-previous-completion) :
(completions-highlight-next-line-completion) :
(minibuffer-previous-line-completion) : Remove reference to removed
functions.
(completions-highlight-completions-map) : Clear the bindings for the
removed functions.
(completions-highlight-setup) : Set
completions-highlight-this-completion in post-command-hook instead of
isearch-mode-end-hook.
2020-11-20 19:03:23 +01:00
Jimmy Aguilar Mena
268170e7a9 Define completions-highlight face and group
* lisp/completions-highlight.el (completions-highlight) : New face and
group.
(completions-highlight-mode) : Set new face to completions-highlight-overlay.
2020-11-20 19:03:23 +01:00
Jimmy Aguilar Mena
ab1e2e6b20 Add custom variable completions-highlight-autoselect.
* lisp/completions-highlight.el (completions-highlight-autoselect) : New
custom.
(completions-highlight-setup) : Auto selects the first candidate when
completions-highlight-autoselect is non nil.
2020-11-20 19:03:23 +01:00
Jimmy Aguilar Mena
f19039c2f9 Improve completions-highlight description in file header. 2020-11-20 19:03:23 +01:00
Jimmy Aguilar Mena
11431bc5f6 Add # to function bindings 2020-11-20 19:03:23 +01:00
Jimmy Aguilar Mena
31d6ec4112 Add parent maps
When completions-highlight-mode is enabled use
minibuffer-local-must-match-map as parent keymap.
(completions-highlight-minibuffer-map) : Enforces parent
minibuffer-local-must-match-map unconditionally.
(completions-highlight-completions-map) : Enforces
completion-list-mode-map as parent just in case.
2020-11-20 19:03:23 +01:00
Jimmy Aguilar Mena
5cf9dd62c5 Add autoload decorator.
* lisp/completions-highlight.el (completions-highlight-mode) : Added
autoload decorator.
2020-11-20 19:03:23 +01:00
Jimmy Aguilar Mena
e143246df8 Simplify overlay handling
* lisp/completions-highlight.el (completions-highlight-overlay) :
created on load.
(completions-highlight-completions-pre-command-hook) : Don't move
overlay here.
(completions-highlight-minibuffer-pre-command-hook) : Use delete overlay
instead of conditional
(completions-highlight-mode) : Use overlay-put here instead of the setup.
2020-11-20 19:03:23 +01:00
Jimmy Aguilar Mena
c6943d75eb Simplify setting keymaps.
*
lisp/completions-highlight.el (completions-highlight-minibuffer-map-save)
(completions-highlight-completions-map-save)
(completions-highlight-minibuffer-bindings) :
(completions-highlight-completions-bindings) : Removed functions and
variables.
(completions-highlight-mode) : Remove extra
minibuffer-hide-completions-hook insertion and remove.
2020-11-20 19:03:23 +01:00
Jimmy Aguilar Mena
644d5e5ffc Simplify numeric argument
* lisp/completions-highlight.el (completions-highlight-this-completion)
: Use prefix-numeric-value instead of manually check.
2020-11-20 19:03:23 +01:00
Jimmy Aguilar Mena
6cea8936b1 Fix corner case when going out of bounds
* lisp/completions-highlight.el : Don't go anywhere when in the fist or
last candidate.
* Remove some redundant calls to with-current-buffer
2020-11-20 19:03:23 +01:00
Jimmy Aguilar Mena
42f47e7568 Fix recursive set-keymap-parent in completions-highlight.
*
lisp/completions-highlight.el (completions-highlight-minibuffer-bindings)
:
(completions-highlight-completions-bindings) : Condition
set-keymap-parent to avoid error.
2020-11-20 19:03:23 +01:00
Jimmy Aguilar Mena
3a22b70ef5 Improve keymap handling.
*
lisp/completions-highlight.el (completions-highlight-minibuffer-map-save) :
(completions-highlight-completions-map-save) : New variables to store
the maps before enabling mode.

(completions-highlight-minibuffer-map) :
(completions-highlight-completions-map) : Maps for the mode in
minibuffer and Completions.
(completions-highlight-minibuffer-bindings) :
(completions-highlight-completions-bindings) : Modified to do maps
handling using maps parent.
(completions-highlight-minibuffer-tab-through-completions) : Add call to
completions-highlight-completions-bindings.
(completions-highlight-minibuffer-bindings) : Fix name.
2020-11-20 19:03:23 +01:00
Jimmy Aguilar Mena
d4d9f6a0ad Fix initial comment in completions-highlight file.
* lisp/completions-highlight.el : Remove and fix some comments.
2020-11-20 19:03:23 +01:00
Jimmy Aguilar Mena
d015144058 Add completions-highlight-mode initial implementation.
New mode to highlight candidates in *Completions* buffer and improve
navigation.
* lisp/completions-highlight.el : New file with the initial working
implementation. This is an initial version but functional for the moment.
2020-11-20 19:03:23 +01:00
Jimmy Aguilar Mena
5509afa6e9 Document the changes in the API for Completions.
* doc/lispref/hooks.texi : Document completion-setup-hook and
minibuffer-hide-completions-hook.
* doc/lispref/minibuf.texi : Add entries for the hooks.
* etc/NEWS : Briefly comment the modifications and the API.
2020-11-20 19:03:23 +01:00
Jimmy Aguilar Mena
b1a027de35 Insert some modifications to implement completions highlighting.
This are changes needed in the minibuffer API to do highlighting from a
different package.

* lisp/minibuffer.el (minibuffer-tab-through-completions-function) : New
variable containing the action to do when pressing tab in minibuffer
and *Completions* are shown.
(minibuffer-tab-through-completions-default) : Default function value
for minibuffer-tab-through-completions-function.
(completion--in-region-1) : Modification to funcall
minibuffer-tab-through-completions-function.
(minibuffer-hide-completions-hook) : New hook to call after
closing *Completions* buffer.
(minibuffer-hide-completions) : Modify to run hook
minibuffer-hide-completions-hook.
2020-11-20 19:03:23 +01:00
5 changed files with 261 additions and 10 deletions

View file

@ -182,6 +182,9 @@ The command loop runs this soon after @code{post-command-hook} (q.v.).
@itemx minibuffer-exit-hook
@xref{Minibuffer Misc}.
@item completion-setup-hook
@xref{Minibuffer Misc}.
@item mouse-leave-buffer-hook
@vindex mouse-leave-buffer-hook
Hook run when about to switch windows with a mouse command.

View file

@ -2617,6 +2617,12 @@ This is a normal hook that is run whenever the minibuffer is exited.
@xref{Hooks}.
@end defvar
@defvar completion-setup-hook
This is a normal hook that is run every time the Completions buffer is
shown or created.
@xref{Hooks}.
@end defvar
@defvar minibuffer-help-form
@anchor{Definition of minibuffer-help-form}
The current value of this variable is used to rebind @code{help-form}

View file

@ -1317,6 +1317,14 @@ This face is used for error messages from 'diff'.
*** New command 'diff-refresh-hunk'.
This new command (bound to 'C-c C-l') regenerates the current hunk.
** Completions
---
*** New option 'minibuffer-tab-through-completions-function'
This contains the function to call when completions are shown and
the *Completions* is already visible already. The variable contains
the default value 'minibuffer-tab-through-completions-default'.
** Miscellaneous
---

View file

@ -1283,6 +1283,27 @@ scroll the window of possible completions."
minibuffer-completion-table
minibuffer-completion-predicate)))
(defun minibuffer-tab-through-completions-default ()
"Default action in `minibuffer-scroll-window' WINDOW.
This is called when *Completions* window is already visible."
(let ((window minibuffer-scroll-window))
(with-current-buffer (window-buffer window)
(if (pos-visible-in-window-p (point-max) window)
;; If end is in view, scroll up to the beginning.
(set-window-start window (point-min) nil)
;; Else scroll down one screen.
(with-selected-window window
(scroll-up)))
nil)))
(defvar minibuffer-tab-through-completions-function
#'minibuffer-tab-through-completions-default
"Function to execute when requested completion.
This is used when *Completions* frame is already visible and the
completions command is called again. This function receives the
window to execute commands as a paramenter.")
(defun completion--in-region-1 (beg end)
;; If the previous command was not this,
;; mark the completion buffer obsolete.
@ -1290,21 +1311,14 @@ scroll the window of possible completions."
(unless (eq 'completion-at-point last-command)
(completion--flush-all-sorted-completions)
(setq minibuffer-scroll-window nil))
(cond
;; If there's a fresh completion window with a live buffer,
;; and this command is repeated, scroll that window.
((and (window-live-p minibuffer-scroll-window)
(eq t (frame-visible-p (window-frame minibuffer-scroll-window))))
(let ((window minibuffer-scroll-window))
(with-current-buffer (window-buffer window)
(if (pos-visible-in-window-p (point-max) window)
;; If end is in view, scroll up to the beginning.
(set-window-start window (point-min) nil)
;; Else scroll down one screen.
(with-selected-window window
(scroll-up)))
nil)))
;; Action to perform when pressing tab and completions are shown.
(funcall minibuffer-tab-through-completions-function)
nil)
;; If we're cycling, keep on cycling.
((and completion-cycling completion-all-sorted-completions)
(minibuffer-force-complete beg end)

220
lisp/zcomplete.el Normal file
View file

@ -0,0 +1,220 @@
;;; zcomplete.el --- highlight and natural move throw *Completions* buffer -*- lexical-binding: t -*-
;; Copyright (C) 2020 Free Software Foundation, Inc.
;; Author: Jimmy Aguilar Mena <spacibba at aol dot com>
;; Created: Aug 2020 Jimmy Aguilar Mena spacibba@aol.com
;; Keywords: help, abbrev
;; This file is part of GNU Emacs.
;; 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.
;; 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
;; Enabling this package implements more dynamic interaction with the
;; *Completions* buffer to give the user a similar experience than
;; interacting with Zle from zsh shell. This basically means:
;; 0. When tab is pressed in the minibuffer the *Completions* buffer
;; is shown as usual.
;; 1.1 If the completion list is too large then a second tab just
;; scrolls the list.
;; 1.2 If all the completion candidates are visible then a second tab
;; highlights the first candidate and completed in the minibuffer.
;; (selected)
;; 2. Every time tab is pressed the next horizontal completion (on the
;; right) is selected.
;; 3. When a candidate is highlighted arrow keys also selects the next
;; candidate in the arrow direction. The arrow produces the same
;; result either in the minibuffer or in *Completions* window.
;; The package intents to implement such functionalities without using
;; hacks or complex functions, using the default Emacs *Completions*
;; infrastructure. The main advantage is that it is not needed to
;; switch to/from *Completions* buffer to select a candidate from the
;; list with arrow keys.
;;; Code:
(require 'simple)
(require 'minibuffer)
(defgroup zcomplete nil
"Highlight candidates in completions buffer."
:version "28.1"
:group 'completion)
(defcustom zcomplete-set-suffix t
"Insert completion candidate in minibuffer
When this variable is nil the completions will be highlighted but
not inserted in the minibuffer."
:type 'boolean
:group 'zcomplete
:version "28.1")
(defcustom zcomplete-tab-no-scroll nil
"When press tab with too many candidates go to next or scroll.
When non-nil tab always go to next completions independently of
the *Completions* buffer size. When this variable is nil tab
scrolls the *Completions* buffer if there are too many candidates
otherwise it goes to the next completion. "
:type 'boolean
:group 'zcomplete
:version "28.1")
(defface zcomplete
'((t :inherit highlight :extend t))
"Default face for highlighting the current line in Hl-Line mode."
:version "28.1"
:group 'zcomplete)
(defvar zcomplete-overlay (make-overlay 0 0)
"Overlay to use when `completion-highlight-mode' is enabled.")
;; *Completions* side commands
(defun zcomplete-select-near ()
"Move to and highlight closer item in the completion list."
(interactive "p")
(let ((point (point))
(pmin (point-min))
(pmax (point-max))
prev next choice)
;; Try to find the closest completion if not in one
(if (get-text-property point 'mouse-face)
(unless isearch-mode ;; assert we are in the beginning
(next-completion -1)
(next-completion 1))
(setq prev (previous-single-property-change (min pmax (1+ point)) 'mouse-face nil pmin))
(setq next (next-single-property-change point 'mouse-face nil pmax))
(if (or (eobp)
(< (- point prev) (- next point)))
(next-completion -1)
(next-completion 1)))
;; Select region
(setq point (point))
(setq next (next-single-property-change point 'mouse-face nil (point-max)))
(setq choice (buffer-substring-no-properties point next))
(move-overlay zcomplete-overlay point next)
(zcomplete--set-suffix choice)))
;; General commands
(defun zcomplete--set-suffix (choice)
"Set CHOICE suffix to current completion.
It uses `completion-base-position' to determine the cursor
position. If choice is the empty string the command removes the
suffix."
(when zcomplete-set-suffix
(let* ((obase-position completion-base-position)
(minibuffer-window (active-minibuffer-window))
(minibuffer-buffer (window-buffer minibuffer-window))
(completion-no-auto-exit t))
(with-selected-window minibuffer-window
(let* ((prompt-end (minibuffer-prompt-end))
(cursor-pos (if obase-position
(cadr obase-position)
(choose-completion-guess-base-position choice)))
(prefix-len (- cursor-pos prompt-end))
(suffix (if (< prefix-len (length choice))
(substring choice prefix-len)
""))
(suffix-len (string-width suffix)))
(choose-completion-string suffix minibuffer-buffer
(list cursor-pos (point-max)))
(add-face-text-property cursor-pos (+ cursor-pos suffix-len) 'shadow)
(goto-char cursor-pos))))))
(defvar zcomplete-completions-map
(let ((map (make-sparse-keymap)))
(define-key map [mouse-2] 'choose-completion)
(define-key map [follow-link] 'mouse-face)
(define-key map [down-mouse-2] nil)
(define-key map "\C-m" 'choose-completion)
(define-key map "\e\e\e" 'delete-completion-window)
(define-key map [left] 'previous-completion)
(define-key map [right] 'next-completion)
(define-key map [?\t] 'next-completion)
(define-key map [backtab] 'previous-completion)
(define-key map "\C-g" #'quit-window)
map)
"Keymap used in *Completions* while highlighting candidates.")
(defun zcomplete--minibuffer-hook ()
"Close *Completions* buffer when the command is not in the map."
(zcomplete--set-suffix "")
(unless (lookup-key minibuffer-local-must-match-map
(this-single-command-keys))
(minibuffer-hide-completions)))
(defun zcomplete--completions-pre-hook ()
"Close *Completions* buffer when the command is not in the map."
(zcomplete--set-suffix "")
(when (eq this-command 'self-insert-command)
(call-interactively #'quit-window)))
(defun zcomplete--hack (data context signal)
"Alternative to command-error-default-function.
This will exit the *Completions* if the error is buffer-read-only."
(if (eq (car data) 'buffer-read-only)
(call-interactively #'quit-window)
(command-error-default-function data context signal)))
(defun zcomplete--completions-setup-hook ()
"Function to call when enabling the `completion-highlight-mode' mode.
It is called when showing the *Completions* buffer."
(delete-overlay zcomplete-overlay)
;; Add zcomplete-minibuffer-map bindings to minibuffer
(add-hook 'pre-command-hook #'zcomplete--minibuffer-hook nil t)
;; After this commands are for Completions
(call-interactively #'switch-to-completions)
(add-hook 'pre-command-hook #'zcomplete--completions-pre-hook nil t)
(add-hook 'post-command-hook #'zcomplete-select-near nil t)
(setq-local command-error-function #'zcomplete--hack)
(setq-local mode-line-format nil)
(use-local-map zcomplete-completions-map)
;; Autoselect candidate if enabled
(zcomplete-select-near))
;;;###autoload
(define-minor-mode zcomplete-mode
"Completion highlight mode to enable candidates highlight in the minibuffer."
:global t
:group 'minibuffer
(if zcomplete-mode
(progn
(overlay-put zcomplete-overlay 'face 'zcomplete)
(add-hook 'completion-setup-hook #'zcomplete--completions-setup-hook t))
(remove-hook 'completion-setup-hook #'zcomplete--completions-setup-hook)))
(provide 'zcomplete)
;;; zcomplete.el ends here