Skip to content

Commit e1e1896

Browse files
committed
Make ghostel-yank-pop fall through to completing-read
When M-y is pressed without a preceding yank, instead of signaling an error, open a completing-read browser over kill-ring and paste the selected entry. This integrates naturally with consult/vertico.
1 parent 27dcec0 commit e1e1896

2 files changed

Lines changed: 57 additions & 14 deletions

File tree

ghostel.el

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1108,21 +1108,26 @@ Use `ghostel-yank-pop' afterwards to cycle through older kills."
11081108

11091109
(defun ghostel-yank-pop ()
11101110
"Replace the just-yanked text with the next kill ring entry.
1111-
Must be called after `ghostel-yank' or `ghostel-yank-pop'.
1112-
Sends backspaces to erase the previous yank, then pastes the next entry."
1111+
After `ghostel-yank' or `ghostel-yank-pop', cycles through the
1112+
kill ring by erasing the previous paste and inserting the next entry.
1113+
Otherwise, opens a `completing-read' browser over `kill-ring' and
1114+
pastes the selected entry into the terminal."
11131115
(interactive)
1114-
(unless (memq last-command '(ghostel-yank ghostel-yank-pop))
1115-
(user-error "Previous command was not a yank"))
1116-
(let* ((prev-text (current-kill ghostel--yank-index t))
1117-
(prev-len (length prev-text)))
1118-
(setq ghostel--yank-index (1+ ghostel--yank-index))
1119-
;; Erase previous paste: send backspaces
1120-
(when (and ghostel--process (process-live-p ghostel--process))
1121-
(process-send-string ghostel--process
1122-
(make-string prev-len ?\x7f)))
1123-
;; Paste the next entry
1124-
(ghostel--paste-text (current-kill ghostel--yank-index t))
1125-
(setq this-command 'ghostel-yank-pop)))
1116+
(if (memq last-command '(ghostel-yank ghostel-yank-pop))
1117+
(let* ((prev-text (current-kill ghostel--yank-index t))
1118+
(prev-len (length prev-text)))
1119+
(setq ghostel--yank-index (1+ ghostel--yank-index))
1120+
;; Erase previous paste: send backspaces
1121+
(when (and ghostel--process (process-live-p ghostel--process))
1122+
(process-send-string ghostel--process
1123+
(make-string prev-len ?\x7f)))
1124+
;; Paste the next entry
1125+
(ghostel--paste-text (current-kill ghostel--yank-index t))
1126+
(setq this-command 'ghostel-yank-pop))
1127+
;; No preceding yank: browse kill ring and paste selection
1128+
(when-let* ((text (completing-read "Paste from kill ring: "
1129+
kill-ring nil t)))
1130+
(ghostel--paste-text text))))
11261131

11271132

11281133
;;; Drag and drop

test/ghostel-test.el

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2608,6 +2608,42 @@ buffer and hand nil to the native module."
26082608
;; M-y should be bound to ghostel-yank-pop, not send-event
26092609
(should (eq (lookup-key ghostel-mode-map (kbd "M-y")) #'ghostel-yank-pop)))
26102610

2611+
;; -----------------------------------------------------------------------
2612+
;; Test: ghostel-yank-pop DWIM
2613+
;; -----------------------------------------------------------------------
2614+
2615+
(ert-deftest ghostel-test-yank-pop-after-yank ()
2616+
"yank-pop after yank should cycle the kill ring."
2617+
(let* ((pasted nil)
2618+
(erased nil)
2619+
(kill-ring '("first" "second" "third"))
2620+
(kill-ring-yank-pointer kill-ring)
2621+
(ghostel--yank-index 0)
2622+
(last-command 'ghostel-yank)
2623+
(ghostel--process (start-process "true" nil "true")))
2624+
(cl-letf (((symbol-function 'ghostel--paste-text)
2625+
(lambda (text) (push text pasted)))
2626+
((symbol-function 'process-live-p) (lambda (_) t))
2627+
((symbol-function 'process-send-string)
2628+
(lambda (_proc str) (setq erased str))))
2629+
(ghostel-yank-pop)
2630+
;; Should have erased the previous paste (5 backspaces for "first")
2631+
(should (= (length erased) 5))
2632+
;; Should have pasted the next kill ring entry
2633+
(should (equal (car pasted) "second")))))
2634+
2635+
(ert-deftest ghostel-test-yank-pop-no-preceding-yank ()
2636+
"yank-pop without preceding yank should use completing-read."
2637+
(let* ((pasted nil)
2638+
(kill-ring '("alpha" "beta"))
2639+
(last-command 'ghostel--self-insert))
2640+
(cl-letf (((symbol-function 'ghostel--paste-text)
2641+
(lambda (text) (push text pasted)))
2642+
((symbol-function 'completing-read)
2643+
(lambda (_prompt coll &rest _) (car coll))))
2644+
(ghostel-yank-pop)
2645+
(should (equal (car pasted) "alpha")))))
2646+
26112647
;; -----------------------------------------------------------------------
26122648
;; Test: ghostel-copy-mode-recenter
26132649
;; -----------------------------------------------------------------------
@@ -3076,6 +3112,8 @@ while :; do sleep 0.1; done'\n")
30763112
ghostel-test-c-g-exits-copy-mode
30773113
ghostel-test-inhibit-quit
30783114
ghostel-test-meta-key-bindings
3115+
ghostel-test-yank-pop-after-yank
3116+
ghostel-test-yank-pop-no-preceding-yank
30793117
ghostel-test-copy-mode-recenter
30803118
ghostel-test-send-next-key-control-x
30813119
ghostel-test-send-next-key-control-h

0 commit comments

Comments
 (0)