aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJimmy Aguilar Mena2020-11-22 23:14:18 +0100
committerJimmy Aguilar Mena2020-11-22 23:58:11 +0100
commitc7c47e78e6c6eaf9518dfc8c7291c5a65b075827 (patch)
treedf9ac2f1a72f90c67469a2667e4daa69fcee223f
parent5dd563f053f2fd57b3115765f920ab5acea1d5a8 (diff)
downloademacs-feature/completions-highlight-modifications.tar.gz
emacs-feature/completions-highlight-modifications.zip
Try another approach even simpler.feature/completions-highlight-modifications
Perform all the operations directly in the completions buffer.
-rw-r--r--lisp/zcomplete.el242
1 files changed, 85 insertions, 157 deletions
diff --git a/lisp/zcomplete.el b/lisp/zcomplete.el
index aa88ad8e47a..b5af6099297 100644
--- a/lisp/zcomplete.el
+++ b/lisp/zcomplete.el
@@ -61,17 +61,6 @@
61 :version "28.1" 61 :version "28.1"
62 :group 'completion) 62 :group 'completion)
63 63
64(defcustom zcomplete-autoselect nil
65 "Select first candidate without extra tab.
66
67When this variable is nil an extra tab is required to select and
68highlight the first candidate in the *Completions* buffer. When
69the value is non-nil the candidate is selected every time the
70buffer is shown and updated."
71 :type 'boolean
72 :group 'zcomplete
73 :version "28.1")
74
75(defcustom zcomplete-set-suffix t 64(defcustom zcomplete-set-suffix t
76 "Insert completion candidate in minibuffer 65 "Insert completion candidate in minibuffer
77 66
@@ -101,56 +90,35 @@ otherwise it goes to the next completion. "
101(defvar zcomplete-overlay (make-overlay 0 0) 90(defvar zcomplete-overlay (make-overlay 0 0)
102 "Overlay to use when `completion-highlight-mode' is enabled.") 91 "Overlay to use when `completion-highlight-mode' is enabled.")
103 92
104(defvar minibuffer-tab-through-completions-function-save nil
105 "Saves the the original value of completion-in-minibuffer-scroll-window.")
106
107;; *Completions* side commands 93;; *Completions* side commands
108(defun zcomplete-select-near () 94(defun zcomplete-select-near ()
109 "Move to and highlight closer item in the completion list." 95 "Move to and highlight closer item in the completion list."
110 (interactive "p") 96 (interactive "p")
111 97 (let ((point (point))
112 (next-completion -1) 98 (pmin (point-min))
113 (next-completion 1) 99 (pmax (point-max))
114 ;; Try to find the closest completion if not in one 100 prev next choice)
115 (cond 101
116 ((eobp) (next-completion -1)) 102 ;; Try to find the closest completion if not in one
117 ((bobp) (next-completion 1))) 103 (if (get-text-property point 'mouse-face)
118 104 (unless isearch-mode ;; assert we are in the beginning
119 (let* ((obeg (point)) 105 (next-completion -1)
120 (oend (next-single-property-change obeg 'mouse-face nil (point-max))) 106 (next-completion 1))
121 (choice (buffer-substring-no-properties obeg oend))) 107
122 108 (setq prev (previous-single-property-change (min pmax (1+ point)) 'mouse-face nil pmin))
123 (move-overlay zcomplete-overlay obeg oend) 109 (setq next (next-single-property-change point 'mouse-face nil pmax))
124 (when zcomplete-set-suffix 110 (if (or (eobp)
125 (zcomplete--set-suffix choice)))) 111 (< (- point prev) (- next point)))
126 112 (next-completion -1)
127(defsubst zcomplete-completions-visible-p () 113 (next-completion 1)))
128 "Return t if *Completions* is visible." 114
129 (and (windowp minibuffer-scroll-window) 115 ;; Select region
130 (window-live-p minibuffer-scroll-window) 116 (setq point (point))
131 (eq t (frame-visible-p (window-frame minibuffer-scroll-window))))) 117 (setq next (next-single-property-change point 'mouse-face nil (point-max)))
132 118 (setq choice (buffer-substring-no-properties point next))
133(defun zcomplete-from-minibuffer (&optional command) 119
134 (interactive) 120 (move-overlay zcomplete-overlay point next)
135 (and (zcomplete-completions-visible-p) 121 (zcomplete--set-suffix choice)))
136 (with-selected-window minibuffer-scroll-window
137 (when-let ((command (or command
138 (lookup-key (current-active-maps)
139 (this-single-command-keys))
140 (lookup-key (current-active-maps)
141 (lookup-key local-function-key-map
142 (this-single-command-keys))))))
143 (call-interactively command)
144 (run-hooks 'post-command-hook)))))
145
146;; Maybe this may be done with an advise?
147(defun minibuffer-choose-completion ()
148 "Execute `choose-completion' in *Completions*."
149 (interactive)
150 (if (and (zcomplete-completions-visible-p)
151 (overlay-buffer zcomplete-overlay))
152 (call-interactively #'zcomplete-from-minibuffer)
153 (minibuffer-complete-and-exit)))
154 122
155;; General commands 123;; General commands
156(defun zcomplete--set-suffix (choice) 124(defun zcomplete--set-suffix (choice)
@@ -158,107 +126,82 @@ otherwise it goes to the next completion. "
158It uses `completion-base-position' to determine the cursor 126It uses `completion-base-position' to determine the cursor
159position. If choice is the empty string the command removes the 127position. If choice is the empty string the command removes the
160suffix." 128suffix."
161 (let* ((obase-position completion-base-position) 129 (when zcomplete-set-suffix
162 (minibuffer-window (active-minibuffer-window)) 130 (let* ((obase-position completion-base-position)
163 (minibuffer-buffer (window-buffer minibuffer-window)) 131 (minibuffer-window (active-minibuffer-window))
164 (completion-no-auto-exit t)) 132 (minibuffer-buffer (window-buffer minibuffer-window))
165 133 (completion-no-auto-exit t))
166 (with-selected-window minibuffer-window 134
167 (let* ((prompt-end (minibuffer-prompt-end)) 135 (with-selected-window minibuffer-window
168 (cursor-pos (if obase-position 136 (let* ((prompt-end (minibuffer-prompt-end))
169 (cadr obase-position) 137 (cursor-pos (if obase-position
170 (choose-completion-guess-base-position choice))) 138 (cadr obase-position)
171 (prefix-len (- cursor-pos prompt-end)) 139 (choose-completion-guess-base-position choice)))
172 (suffix (if (< prefix-len (length choice)) 140 (prefix-len (- cursor-pos prompt-end))
173 (substring choice prefix-len) 141 (suffix (if (< prefix-len (length choice))
174 "")) 142 (substring choice prefix-len)
175 (suffix-len (string-width suffix))) 143 ""))
176 144 (suffix-len (string-width suffix)))
177 (choose-completion-string suffix minibuffer-buffer 145
178 (list cursor-pos (point-max))) 146 (choose-completion-string suffix minibuffer-buffer
179 (add-face-text-property cursor-pos (+ cursor-pos suffix-len) 'shadow) 147 (list cursor-pos (point-max)))
180 (goto-char cursor-pos))))) 148 (add-face-text-property cursor-pos (+ cursor-pos suffix-len) 'shadow)
181 149 (goto-char cursor-pos))))))
182(defun zcomplete--clear-suffix()
183 "Clear completion suffix if set."
184 (zcomplete--set-suffix ""))
185
186(defvar zcomplete-minibuffer-map
187 (let ((map (make-sparse-keymap)))
188 (set-keymap-parent map minibuffer-local-must-match-map)
189 (dolist (key '(up down left right backtab))
190 (define-key map `[(,key)] #'zcomplete-from-minibuffer))
191
192 (define-key map [remap minibuffer-complete-and-exit] #'minibuffer-choose-completion)
193 map)
194 "Keymap used in minibuffer while *Completions* is active.")
195 150
196(defvar zcomplete-completions-map 151(defvar zcomplete-completions-map
197 (let ((map (make-sparse-keymap))) 152 (let ((map (make-sparse-keymap)))
198 (set-keymap-parent map completion-list-mode-map) 153 (define-key map [mouse-2] 'choose-completion)
154 (define-key map [follow-link] 'mouse-face)
155 (define-key map [down-mouse-2] nil)
156 (define-key map "\C-m" 'choose-completion)
157 (define-key map "\e\e\e" 'delete-completion-window)
158 (define-key map [left] 'previous-completion)
159 (define-key map [right] 'next-completion)
160 (define-key map [?\t] 'next-completion)
161 (define-key map [backtab] 'previous-completion)
199 (define-key map "\C-g" #'quit-window) 162 (define-key map "\C-g" #'quit-window)
200 map) 163 map)
201 "Keymap used in *Completions* while highlighting candidates.") 164 "Keymap used in *Completions* while highlighting candidates.")
202 165
203(defun zcomplete--minibuffer-tab-through-completions () 166(defun zcomplete--minibuffer-hook ()
204 "Default action in `minibuffer-scroll-window' WINDOW.
205This is called when *Completions* window is already visible and
206should be assigned to completion-in-minibuffer-scroll-window."
207 (let ((window minibuffer-scroll-window))
208 (with-current-buffer (window-buffer window)
209 (if zcomplete-tab-no-scroll
210 (zcomplete-from-minibuffer #'next-completion)
211 (if (pos-visible-in-window-p (point-max) window) ;; scroll o go to next
212 (if (pos-visible-in-window-p (point-min) window)
213 ;; If all completions are shown point-min and point-max
214 ;; are both visible. Then do the highlight.
215 (zcomplete-from-minibuffer #'next-completion)
216 ;; Else the buffer is too long, so better just scroll it to
217 ;; the beginning as default behavior.
218 (set-window-start window (point-min) nil))
219 ;; Then point-max is not visible the buffer is too long and we
220 ;; can scroll.
221 (with-selected-window window (scroll-up)))))))
222
223(defun zcomplete-maybe-close-completions ()
224 "Close *Completions* buffer when the command is not in the map." 167 "Close *Completions* buffer when the command is not in the map."
225 (zcomplete--clear-suffix) 168 (zcomplete--set-suffix "")
226 (unless (lookup-key zcomplete-minibuffer-map 169 (unless (lookup-key minibuffer-local-must-match-map
227 (this-single-command-keys)) 170 (this-single-command-keys))
228 (minibuffer-hide-completions))) 171 (minibuffer-hide-completions)))
229 172
230(defun zcomplete--hide-completions-advise () 173(defun zcomplete--completions-pre-hook ()
231 "Function to advise minibuffer-hide-completions." 174 "Close *Completions* buffer when the command is not in the map."
232 (remove-hook 'pre-command-hook 175 (zcomplete--set-suffix "")
233 #'zcomplete-maybe-close-completions t)) 176 (when (eq this-command 'self-insert-command)
234 177 (call-interactively #'quit-window)))
235(defun zcomplete-setup () 178
179(defun zcomplete--hack (data context signal)
180 "Alternative to command-error-default-function.
181This will exit the *Completions* if the error is buffer-read-only."
182 (if (eq (car data) 'buffer-read-only)
183 (call-interactively #'quit-window)
184 (command-error-default-function data context signal)))
185
186(defun zcomplete--completions-setup-hook ()
236 "Function to call when enabling the `completion-highlight-mode' mode. 187 "Function to call when enabling the `completion-highlight-mode' mode.
237It is called when showing the *Completions* buffer." 188It is called when showing the *Completions* buffer."
238 (delete-overlay zcomplete-overlay) 189 (delete-overlay zcomplete-overlay)
239 190
240 (with-current-buffer standard-output 191 ;; Add zcomplete-minibuffer-map bindings to minibuffer
241 (when (string= (buffer-name) "*Completions*") 192 (add-hook 'pre-command-hook #'zcomplete--minibuffer-hook nil t)
242
243 (add-hook 'pre-command-hook #'zcomplete--clear-suffix nil t)
244 (add-hook 'post-command-hook #'zcomplete-select-near nil t)
245
246 ;; Add zcomplete-completions-map to *Completions*
247 (use-local-map (make-composed-keymap
248 zcomplete-completions-map (current-local-map)))
249 193
250 ;; Autoselect candidate if enabled 194 ;; After this commands are for Completions
251 (when zcomplete-autoselect 195 (call-interactively #'switch-to-completions)
252 (with-selected-window (get-buffer-window (current-buffer) 0) 196 (add-hook 'pre-command-hook #'zcomplete--completions-pre-hook nil t)
253 (next-completion 1) 197 (add-hook 'post-command-hook #'zcomplete-select-near nil t)
254 (zcomplete-select-near)))))
255 198
256 (add-hook 'pre-command-hook 199 (setq-local command-error-function #'zcomplete--hack)
257 #'zcomplete-maybe-close-completions nil t) 200 (setq-local mode-line-format nil)
201 (use-local-map zcomplete-completions-map)
258 202
259 ;; Add zcomplete-minibuffer-map bindings to minibuffer 203 ;; Autoselect candidate if enabled
260 (use-local-map (make-composed-keymap 204 (zcomplete-select-near))
261 zcomplete-minibuffer-map (current-local-map))))
262 205
263;;;###autoload 206;;;###autoload
264(define-minor-mode zcomplete-mode 207(define-minor-mode zcomplete-mode
@@ -269,24 +212,9 @@ It is called when showing the *Completions* buffer."
269 (if zcomplete-mode 212 (if zcomplete-mode
270 (progn 213 (progn
271 (overlay-put zcomplete-overlay 'face 'zcomplete) 214 (overlay-put zcomplete-overlay 'face 'zcomplete)
215 (add-hook 'completion-setup-hook #'zcomplete--completions-setup-hook t))
272 216
273 (setq minibuffer-tab-through-completions-function-save 217 (remove-hook 'completion-setup-hook #'zcomplete--completions-setup-hook)))
274 minibuffer-tab-through-completions-function)
275
276 (setq minibuffer-tab-through-completions-function
277 #'zcomplete--minibuffer-tab-through-completions)
278
279 (add-hook 'completion-setup-hook #'zcomplete-setup t)
280 (advice-add 'minibuffer-hide-completions
281 :before #'zcomplete--hide-completions-advise))
282
283 ;; Restore the default completion-in-minibuffer-scroll-window
284 (setq minibuffer-tab-through-completions-function
285 minibuffer-tab-through-completions-function-save)
286
287 (remove-hook 'completion-setup-hook #'zcomplete-setup)
288 (advice-remove 'minibuffer-hide-completions
289 #'zcomplete--hide-completions-advise)))
290 218
291(provide 'zcomplete) 219(provide 'zcomplete)
292;;; zcomplete.el ends here 220;;; zcomplete.el ends here