summaryrefslogtreecommitdiff
path: root/modules/show-kill-ring.el
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2025-10-12 11:47:26 -0500
committerCraig Jennings <c@cjennings.net>2025-10-12 11:47:26 -0500
commit092304d9e0ccc37cc0ddaa9b136457e56a1cac20 (patch)
treeea81999b8442246c978b364dd90e8c752af50db5 /modules/show-kill-ring.el
changing repositories
Diffstat (limited to 'modules/show-kill-ring.el')
-rw-r--r--modules/show-kill-ring.el125
1 files changed, 125 insertions, 0 deletions
diff --git a/modules/show-kill-ring.el b/modules/show-kill-ring.el
new file mode 100644
index 00000000..c50e5dbb
--- /dev/null
+++ b/modules/show-kill-ring.el
@@ -0,0 +1,125 @@
+;;; show-kill-ring --- Displays Previous Kill Ring Entries -*- lexical-binding: t; coding: utf-8; -*-
+;; Show Kill Ring
+;; Stolen from Steve Yegge when he wasn't looking
+;; enhancements and bugs added by Craig Jennings <c@cjennings.net>
+;;
+;;; Commentary:
+;; Browse items you've previously killed.
+;; Yank text using C-u, the index, then C-y.
+;;
+;; I've lovingly kept the nice 1970s aesthetic, complete with wood paneling.
+;; Maybe I'll give it a makeover at some point.
+;;
+;;; Code:
+
+(require 'cl-lib)
+
+(defvar show-kill-max-item-size 1000
+ "This represents the size of a \='kill ring\=' entry.
+
+A positive number means to limit the display of \='kill-ring\=' items to
+that number of characters.")
+
+(defun show-kill-ring-exit ()
+ "Exit the show-kill-ring buffer."
+ (interactive)
+ (quit-window t))
+
+(defun show-kill-ring ()
+ "Show the current contents of the kill ring in a separate buffer.
+
+This makes it easy to figure out which prefix to pass to yank."
+ (interactive)
+ ;; kill existing one, since erasing it doesn't work
+ (let ((buf (get-buffer "*Kill Ring*")))
+ (and buf (kill-buffer buf)))
+
+ (let* ((buf (get-buffer-create "*Kill Ring*"))
+ (temp kill-ring)
+ (count 1)
+ (bar (make-string 32 ?=))
+ (bar2 (concat " " bar))
+ (item " Item ")
+ (yptr nil) (ynum 1))
+ (set-buffer buf)
+ (erase-buffer)
+
+ (show-kill-insert-header)
+
+ ;; show each of the items in the kill ring, in order
+ (while temp
+ ;; insert our little divider
+ (insert (concat "\n" bar item (prin1-to-string count) " "
+ (if (< count 10) bar2 bar) "\n"))
+
+ ;; if this is the yank pointer target, grab it
+ (when (equal temp kill-ring-yank-pointer)
+ (setq yptr (car temp) ynum count))
+
+ ;; insert the item and loop
+ (show-kill-insert-item (car temp))
+ (cl-incf count)
+ (setq temp (cdr temp)))
+
+ ;; show info about yank item
+ (show-kill-insert-footer yptr ynum)
+
+ ;; use define-key instead of local-set-key
+ (use-local-map (make-sparse-keymap))
+ (define-key (current-local-map) "q" 'show-kill-ring-exit)
+
+ ;; show it
+ (goto-char (point-min))
+ (setq buffer-read-only t)
+ (set-buffer-modified-p nil)
+ ;; display-buffer rather than pop-to-buffer
+ ;; easier for user to C-u (item#) C-y
+ ;; while the point is where they want to yank
+ (display-buffer buf)))
+
+(defun show-kill-insert-item (item)
+ "Insert an ITEM from the kill ring into the current buffer.
+
+If it's too long, truncate it first."
+ (let ((max show-kill-max-item-size))
+ (cond
+ ((or (not (numberp max))
+ (< max 0)
+ (< (length item) max))
+ (insert item))
+ (t
+ ;; put ellipsis on its own line if item is longer than 1 line
+ (let ((preview (substring item 0 max)))
+ (if (< (length item) (- (frame-width) 5))
+ (insert (concat preview "..." ))
+ (insert (concat preview "\n..."))))))))
+
+(defun show-kill-insert-header ()
+ "Insert the show-kill-ring header or a notice if the kill ring is empty."
+ (if kill-ring
+ (insert "Contents of the kill ring:\n")
+ (insert "The kill ring is empty")))
+
+(defun show-kill-insert-footer (yptr ynum)
+ "Insert final divider and the yank-pointer (YPTR YNUM) info."
+ (when kill-ring
+ (save-excursion
+ (re-search-backward "^\\(=+ Item [0-9]+\\ +=+\\)$"))
+ (insert "\n")
+ (insert (make-string (length (match-string 1)) ?=))
+ ;; Use number-to-string instead of int-to-string
+ (insert (concat "\n\nItem " (number-to-string ynum)
+ " is the next to be yanked:\n\n"))
+ (show-kill-insert-item yptr)
+ (insert "\n\nThe prefix arg will yank relative to this item.")))
+
+(defun empty-kill-ring ()
+ "Force garbage collection of huge kill ring entries that I don't care about."
+ (interactive)
+ (setq kill-ring nil)
+ (garbage-collect))
+
+(global-set-key (kbd "M-K") 'show-kill-ring)
+
+(provide 'show-kill-ring)
+;;; show-kill-ring.el ends here