From: Eshel Yaron Date: Mon, 29 Apr 2024 19:45:25 +0000 (+0200) Subject: Make completion preview cleanup more robust X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=5f847dd724bdcb41f31e4284f290c830ff19ffbb;p=emacs.git Make completion preview cleanup more robust --- diff --git a/lisp/completion-preview.el b/lisp/completion-preview.el index 4e2f013b57a..d2926b00c5a 100644 --- a/lisp/completion-preview.el +++ b/lisp/completion-preview.el @@ -230,20 +230,13 @@ Completion Preview mode avoids updating the preview after these commands.") "Return property PROP of the completion preview overlay." (overlay-get completion-preview--overlay prop)) +(defvar completion-preview--buffer nil + "Buffer showing the completion preview, or nil when there is none.") + (defvar completion-preview--window nil "Window showing the completion preview, or nil when there is none.") -(defun completion-preview--window-selection-change (window) - "Hide completion preview in WINDOW after switching to another window. -Completion Preview mode adds this function to -`window-selection-change-functions', which see." - (unless (or (eq window (selected-window)) - (eq window (minibuffer-selected-window))) - (with-current-buffer (window-buffer window) - (let ((completion-preview--window window)) - (completion-preview-active-mode -1))))) - -(defvar-local completion-preview--original-cursor-type 'unset +(defvar completion-preview--original-cursor-type 'unset "Value of `cursor-type' to restore after dismissing the completion preview. A value of `unset' means there's nothing to restore.") @@ -262,9 +255,11 @@ set to the value of this option while the completion preview is visible." (not (eq completion-preview--original-cursor-type 'unset))) (defsubst completion-preview--restore-cursor () - (set-window-parameter completion-preview--window 'cursor-type - completion-preview--original-cursor-type) - (setq completion-preview--original-cursor-type 'unset)) + (when (completion-preview--cursor-modified-p) + (when (window-live-p completion-preview--window) + (set-window-parameter completion-preview--window 'cursor-type + completion-preview--original-cursor-type)) + (setq completion-preview--original-cursor-type 'unset))) (defsubst completion-preview--modify-cursor () (setq completion-preview--original-cursor-type @@ -277,20 +272,31 @@ set to the value of this option while the completion preview is visible." :interactive nil (if completion-preview-active-mode (progn - (add-hook 'window-selection-change-functions - #'completion-preview--window-selection-change nil t) + (add-hook 'post-command-hook #'completion-preview--cleanup -10) (when (and completion-preview-cursor-type (not (completion-preview--cursor-modified-p)) (= (point) (completion-preview--get 'completion-preview-end))) (completion-preview--modify-cursor)) - (setq completion-preview--window (selected-window))) - (remove-hook 'window-selection-change-functions - #'completion-preview--window-selection-change t) - (when (completion-preview--cursor-modified-p) - (completion-preview--restore-cursor)) - (setq completion-preview--window nil) + (setq completion-preview--window (selected-window) + completion-preview--buffer (current-buffer))) + (remove-hook 'post-command-hook #'completion-preview--cleanup) + (completion-preview--restore-cursor) + (setq completion-preview--window nil + completion-preview--buffer nil) (completion-preview-hide))) +(defun completion-preview--cleanup () + "Dismiss completion preview and restore cursor shape if window changed." + (unless (or (and (eq completion-preview--window (selected-window)) + (eq completion-preview--buffer (current-buffer))) + (and (eq completion-preview--window (minibuffer-selected-window)) + (eq completion-preview--buffer (window-buffer (minibuffer-selected-window))))) + (when (buffer-live-p completion-preview--buffer) + (with-current-buffer completion-preview--buffer + (completion-preview-active-mode -1))) + (completion-preview--restore-cursor) + (remove-hook 'post-command-hook 'completion-preview--cleanup))) + (defvar completion-preview-completion-styles '(basic) "List of completion styles that Completion Preview mode uses. @@ -452,17 +458,6 @@ point, otherwise hide it." (defun completion-preview--post-command () "Create, update or delete completion preview post last command." - ;; If the last command switched from one window showing this buffer to - ;; another, the buffer-local `post-command-hook' might run before - ;; `window-selection-change-functions'. Prompty restore the cursor in - ;; the previously selected window, since we may remove our function - ;; from `window-selection-change-functions' before it gets a chance to - ;; do so. - (unless (or (eq completion-preview--window (selected-window)) - (eq completion-preview--window (minibuffer-selected-window))) - (when (completion-preview--cursor-modified-p) - (completion-preview--restore-cursor)) - (setq completion-preview--window nil)) (let ((internal-p (or completion-preview--inhibit-update-p (memq this-command completion-preview--internal-commands)))) @@ -635,7 +630,7 @@ completion suggestion, and \\[completion-preview-prev-candidate] cycles backward." :lighter " CP" (if completion-preview-mode - (add-hook 'post-command-hook #'completion-preview--post-command nil t) + (add-hook 'post-command-hook #'completion-preview--post-command 10 t) (remove-hook 'post-command-hook #'completion-preview--post-command t) (completion-preview-active-mode -1))) diff --git a/test/lisp/completion-preview-tests.el b/test/lisp/completion-preview-tests.el index 7d358d07519..1b0ef28f54d 100644 --- a/test/lisp/completion-preview-tests.el +++ b/test/lisp/completion-preview-tests.el @@ -307,4 +307,21 @@ instead." (should exit-fn-called) (should (equal exit-fn-args '("foobar" finished)))))) +(ert-deftest completion-preview-cursor-type () + "Test modification of `cursor-type' when completion preview is visible." + (with-temp-buffer + (setq-local completion-at-point-functions + (list + (completion-preview-tests--capf + '("foobar" "foobaz")))) + (insert "foo") + (let ((this-command 'self-insert-command)) + (completion-preview--post-command)) + (should (eq completion-preview-cursor-type + (window-parameter nil 'cursor-type))) + (should (completion-preview--cursor-modified-p)) + (let ((this-command 'keyboard-quit)) + (completion-preview--post-command)) + (should (not (completion-preview--cursor-modified-p))))) + ;;; completion-preview-tests.el ends here