;; prefix (so nothing is underlined in the preview), it displays a list
;; of all matching completion candidates.
;;
+;; Completion Preview mode can change the cursor shape while displaying
+;; the preview right after point. By default, it uses a vertical bar
+;; that clearly separates the completion preview from the preceding
+;; buffer text. This is especially useful if otherwise your cursor is
+;; otherwise box shaped, since a box cursor on top of the first
+;; character of the completion preview might make it harder to tell
+;; whether that character is part of the preview or not. To select
+;; another cursor shape, or to disable this feature entirely, customize
+;; the user option `completion-preview-cursor-type'.
+;;
;; If you set the user option `completion-preview-exact-match-only' to
;; non-nil, Completion Preview mode only suggests a completion
;; candidate when its the only possible completion for the (partial)
"Return property PROP of the completion preview overlay."
(overlay-get completion-preview--overlay prop))
+(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
(unless (or (eq window (selected-window))
(eq window (minibuffer-selected-window)))
(with-current-buffer (window-buffer window)
- (completion-preview-active-mode -1))))
+ (let ((completion-preview--window window))
+ (completion-preview-active-mode -1)))))
+
+(defvar-local 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.")
+
+(defcustom completion-preview-cursor-type 'bar
+ "Type of cursor to use when completion preview is visible.
+If nil, Completion Preview mode does not alter the cursor. Otherwise,
+the `cursor-type' window parameter of the selected window is temporarily
+set to the value of this option while the completion preview is visible."
+ :type `(choice (const :tag "Leave cursor unchanged" nil)
+ ,@(remove '(const :tag "None " nil)
+ (cdr (get 'cursor-type 'custom-type)))
+ (const :tag "None" none)))
+
+(defsubst completion-preview--cursor-modified-p ()
+ "Return non-nil if the cursor shape is currently modified."
+ (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))
+
+(defsubst completion-preview--modify-cursor ()
+ (setq completion-preview--original-cursor-type
+ (window-parameter completion-preview--window 'cursor-type))
+ (set-window-parameter completion-preview--window
+ 'cursor-type completion-preview-cursor-type))
(define-minor-mode completion-preview-active-mode
"Mode for when the completion preview is shown."
:interactive nil
(if completion-preview-active-mode
- (add-hook 'window-selection-change-functions
- #'completion-preview--window-selection-change nil t)
+ (progn
+ (add-hook 'window-selection-change-functions
+ #'completion-preview--window-selection-change nil t)
+ (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)
(completion-preview-hide)))
(defvar completion-preview-completion-styles '(basic)
(common (completion-preview--get 'completion-preview-common))
(suffix (nth index sufs))
(cand nil))
+ (if (completion-preview--cursor-modified-p)
+ ;; If we have changed the cursor type, check if point is still
+ ;; at the beginning of the preview overlay, and restore the
+ ;; original cursor type if not.
+ (unless (= (point) end) (completion-preview--restore-cursor))
+ ;; Otherwise, if we haven't changed the cursor type, that means
+ ;; point was not at the beginning of the preview overlay. Maybe
+ ;; now it is, in which case we need to set the cursor type now.
+ (when (and completion-preview-cursor-type (= (point) end))
+ (completion-preview--modify-cursor)))
(set-text-properties 0 (length suffix)
(list 'face (if (cdr sufs)
'completion-preview
(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))))