Skip to content

Commit

Permalink
counsel.el (counsel-yank-pop): Liken to yank-pop
Browse files Browse the repository at this point in the history
The command yank-pop does too much under the bonnet to ever hope to
emulate, so use it directly.  This respects and updates various
internals, most noticeably kill-ring-yank-pointer, thus allowing
consecutive calls to yank to work.
See https://emacs.stackexchange.com/q/37351/15748.

(counsel--yank-pop-position): New function.
(counsel-yank-pop-action): Use yank-pop.
(counsel-yank-pop): Do The Right Thing w.r.t. point and mark
regardless of whether last-command was a yank.  Adopt
interactive-spec of yank-pop and preselect candidate accordingly.
Abort on empty/blank kill-ring.

Fixes #1190
Fixes #1356
  • Loading branch information
basil-conto authored and abo-abo committed Dec 8, 2017
1 parent 4ea65fc commit 50aa561
Showing 1 changed file with 32 additions and 18 deletions.
50 changes: 32 additions & 18 deletions counsel.el
Expand Up @@ -3148,37 +3148,51 @@ A is the left hand side, B the right hand side."
cand-pairs
counsel-yank-pop-separator))

(defun counsel--yank-pop-position (s)
"Return position of S in `kill-ring' relative to last yank.
S must exist in `kill-ring'."
(or (cl-position s kill-ring-yank-pointer :test #'equal-including-properties)
(+ (cl-position s kill-ring :test #'equal-including-properties)
(- (length kill-ring-yank-pointer)
(length kill-ring)))))

(defun counsel-yank-pop-action (s)
"Insert S into the buffer, overwriting the previous yank."
"Like `yank-pop', but insert the kill corresponding to S."
(with-ivy-window
(delete-region ivy-completion-beg
ivy-completion-end)
(insert (substring-no-properties s))
(setq last-command 'yank)
(yank-pop (counsel--yank-pop-position s))
(setq ivy-completion-end (point))))

(defun counsel-yank-pop-action-remove (s)
"Remove S from the kill ring."
(setq kill-ring (delete s kill-ring)))

;;;###autoload
(defun counsel-yank-pop ()
"Ivy replacement for `yank-pop'."
(interactive)
(setq ivy-completion-beg
(if (eq last-command 'yank)
(save-excursion
(search-backward (car kill-ring)))
(point)))
(setq ivy-completion-end (point))
(let ((cands (delete-dups
(defun counsel-yank-pop (&optional arg)
"Ivy replacement for `yank-pop'.
ARG preselects the corresponding kill during completion."
(interactive "*p")
(let ((ivy-format-function #'counsel--yank-pop-format-function)
(ivy-height 5)
(cands (delete-dups
(cl-mapcan (lambda (s)
(unless (string-match-p "\\`[\n\r[:blank:]]*\\'" s)
(list (ivy-cleanup-string (copy-sequence s)))))
kill-ring)))
(ivy-format-function #'counsel--yank-pop-format-function)
(ivy-height 5))
kill-ring))))
(unless cands
(error "Kill ring is empty or blank"))
(unless (eq last-command 'yank)
(push-mark))
(setq ivy-completion-beg (mark t))
(setq ivy-completion-end (point))
(ivy-read "kill-ring: " cands
:action 'counsel-yank-pop-action
:require-match t
:preselect (let ((kill-ring cands)
(kill-ring-yank-pointer
(member (car kill-ring-yank-pointer) cands))
interprogram-paste-function)
(current-kill (or arg 1) t))
:action #'counsel-yank-pop-action
:caller 'counsel-yank-pop)))

(ivy-set-actions
Expand Down

0 comments on commit 50aa561

Please sign in to comment.