mende@athos.rutgers.edu (Bob Mende Pie) (09/28/88)
I have received a lot of requests for my kill-ring-browser, so I will post it here... Please mail me all comments and suggestions. Also, rms pointed out that there is the yank-pop command (which is M-y by default... I bind browse-yank to M-y). yank-pop acts can act as a kill-ring-browser, but it can be confusing as well. ;; browse-yank.el ;; ;; A major mode for the browsing, editing, and selectively inserting ;; elements of the kill-ring. ;; ;; Written by Robert Mende mende@rutgers.edu ;; send all bugs/suggestions to author ;; suggested binding: M-y ;; Copyright (C) 1985, 1986 Free Software Foundation, Inc. ;; This file is not officialy part of GNU Emacs. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY. No author or distributor ;; accepts responsibility to anyone for the consequences of using it ;; or for whether it serves any particular purpose or works at all, ;; unless he says so in writing. Refer to the GNU Emacs General Public ;; License for full details. ;; Everyone is granted permission to copy, modify and redistribute ;; GNU Emacs, but only under the conditions described in the ;; GNU Emacs General Public License. A copy of this license is ;; supposed to have been given to you along with GNU Emacs so you ;; can know your rights and responsibilities. It should be in a ;; file named COPYING. Among other things, the copyright notice ;; and this notice must be preserved on all copies. (defmacro for (i lb ub &rest body) "Iterative \"for\" loop, in the form (for I LB UB BODY). I is locally set to each number between LB and UB inclusive. Boundary points LB and UB evaluated once. BODY not evaluated if boundary test fails. Returns nil." (list 'let (list (list i lb) (list '__%__UB__%__ ub)) (append (list 'while (list '<= i '__%__UB__%__)) body (list (list 'setq i (list '1+ i)))))) (defvar browse-yank-buffer "*Browse Yank*" "name of the buffer in which the kill-ring is browsed.") (defvar browse-yank-barf-message "Can't browse-yank an empty kill-ring." "Error message displayed when an attempt is made to browse an empty kill-ring. Raison d'etre stems from the ludicrous jests poked at the command's name by people much less mature than you and I.") (defvar browse-yank-height 5 "number of lines in the browse-yank window") (defvar browse-yank-inserted-p nil) (defvar browse-yank-orig-window-config nil "Window configuration prior to splitting off the browse-yank window.") (defvar browse-yank-cur 0 "The ordinal position in the kill-ring, starting from the most recent kill (position 1).") (defvar browse-yank-cur-txt "0" "As browse-yank-cur, but a string suitable for display in the mode-line.") (defvar browse-yank-max 0 "The ordinal position of the last element of the kill-ring.") (defvar browse-yank-max-txt "0" "As browse-yank-max, but a string suitable for display in the mode-line.") (defvar browse-yank-mode-map (make-sparse-keymap) "the keymap in used in browse-yank-mode.") (define-key browse-yank-mode-map "\C-g" 'browse-yank-abort) (define-key browse-yank-mode-map "\C-x\C-m" 'browse-yank-insert) (define-key browse-yank-mode-map "?" 'describe-mode) (define-key browse-yank-mode-map ">" 'browse-yank-goto-last) (define-key browse-yank-mode-map "<" 'browse-yank-goto-first) (define-key browse-yank-mode-map "s" 'browse-yank-search-forward) (define-key browse-yank-mode-map "r" 'browse-yank-search-backward) (define-key browse-yank-mode-map "q" 'browse-yank-quit) (define-key browse-yank-mode-map "p" 'browse-yank-previous-yank) (define-key browse-yank-mode-map "n" 'browse-yank-next-yank) (define-key browse-yank-mode-map "m" 'browse-yank-yanks-saved) (define-key browse-yank-mode-map "l" 'browse-yank-locate-regexp) (define-key browse-yank-mode-map "j" 'browse-yank-goto-yank) (define-key browse-yank-mode-map "i" 'browse-yank-insert) (define-key browse-yank-mode-map "h" 'browse-yank-help) (define-key browse-yank-mode-map "g" 'browse-yank-to-register) (define-key browse-yank-mode-map "e" 'browse-yank-edit) (defvar browse-yank-edit-mode-map (copy-keymap text-mode-map) "Keymap in use in browse-yank-edit-mode.") (define-key browse-yank-edit-mode-map "\C-c\C-c" 'browse-yank-cease-edit) (define-key browse-yank-edit-mode-map "\C-c\C-]" 'browse-yank-abort-edit) ;; define a mode that is only used when executing a browse-yank (defun browse-yank-mode () "Major mode for browsing, editing, and inserting elements of the kill-ring. This is a browse-yank specific facility, and should be only used by the function browse-yank (see browse-yank). Commands are: \\{browse-yank-mode-map}" (kill-all-local-variables) (make-local-variable 'mode-line-process) (make-local-variable 'minor-mode-alist) (mapcar '(lambda (minmode) (set (car minmode) nil)) minor-mode-alist) (use-local-map browse-yank-mode-map) (setq mode-name "Browse Yank") (setq mode-line-process (concat ": " browse-yank-cur-txt "/" browse-yank-max-txt)) (setq buffer-read-only t) (setq major-mode 'browse-yank-mode) (goto-char (point-min)) (run-hooks 'browse-yank-hook)) ;; browse-yank ... The command that this whole thing is about (defun browse-yank (arg) "An interactive kill-ring browsing, editing, and yanking utility. See function browse-yank-mode for more details. Author's gripe: When evaluated, the window split is messy, and I don't like the lossage in the window configuration during the actual browse-yank. I'm not sure who's to blame for the appearance. Pop-to-buffer? Split-window? Myself? I cant not have a window 'pop' to the top (or bottom) of the screen and not mess up the order of the buffers. If you dont like it, please re-write it, and if you dont want to do that .... see figure 1." (interactive "P") (if (= 0 (length kill-ring)) (progn (ding) (message browse-yank-barf-message)) (progn (setq browse-yank-orig-window-config (current-window-configuration)) (pop-to-buffer (get-buffer-create browse-yank-buffer)) (browse-yank-mode) (enlarge-window (- browse-yank-height (window-height))) (setq browse-yank-cur 0) (browse-yank-make-txt) (browse-yank-display 0)))) (defun browse-yank-abort () "Abort a browse-yank." (interactive) (ding) (browse-yank-quit)) (defun browse-yank-quit () "Quit gracefully from a browse-yank" (interactive) (set-window-configuration browse-yank-orig-window-config) (kill-buffer browse-yank-buffer) (if browse-yank-inserted-p (pop-to-buffer browse-yank-inserted-p))) (defun browse-yank-insert () "`Yank' the contents of the browse-yank-buffer (an element of the kill-ring) at the point's last location outside of the buffer, completing the browse-yank." (interactive) (save-window-excursion (delete-window) (setq browse-yank-inserted-p (buffer-name)) (insert-buffer browse-yank-buffer)) (browse-yank-quit)) (defun browse-yank-display (browse-yank-yank-to-display) "Display the kill-ring ELEMENT in the browse-yank buffer, updating the mode-line." (setq buffer-read-only nil) (erase-buffer) (goto-char (point-min)) (insert (nth browse-yank-yank-to-display kill-ring)) (goto-char (point-min)) (setq mode-line-process (concat ": " browse-yank-cur-txt "/" browse-yank-max-txt)) (setq buffer-read-only t)) (defun browse-yank-make-txt () "Update the textual versions of the counters used by browse-yank (see browse-yank-cur and browse-yank-max)." (setq browse-yank-cur-txt (int-to-string (1+ browse-yank-cur))) (setq browse-yank-max (1- (length kill-ring))) (setq browse-yank-max-txt (int-to-string (1+ browse-yank-max)))) (defun browse-yank-goto-first () "Goto first element of kill-ring in browse-yank-mode." (interactive) (browse-yank-goto-yank 1)) (defun browse-yank-goto-last () "Goto last element of kill-ring in browse-yank-mode." (interactive) (browse-yank-goto-yank (length kill-ring))) (defun browse-yank-locate-regexp (string) "Display all elements of kill-ring that contain REGEXP, in browse-yank-mode." (interactive (list (read-from-minibuffer (concat "Regexp to locate [" search-last-regexp "]: ")))) (if (zerop (length string)) (setq string search-last-regexp) (setq search-last-regexp string)) (if (zerop (length string)) (error "Cant search for NULL string") (let ((wherebe (mapcar '(lambda (el) (if (string-match string el) t)) kill-ring)) (loc "")) (for i 0 (length wherebe) (if (car (nthcdr i wherebe)) (setq loc (concat loc (prin1-to-string (1+ i)) ",")))) (if (zerop (length loc)) (progn (ding) (message "String not found in any yanks.")) (setq loc (substring loc 0 (1- (length loc)))) (message (concat "Found in yanks: " loc ".")))))) (defun browse-yank-search-backward (string) "Search backward in kill ring for REGEXP, in browse-yank-mode." (interactive (list (read-from-minibuffer (concat "Search backwards for regexp [" search-last-regexp "]: ")))) (cond ((zerop (length string)) (setq string search-last-regexp) (setq search-last-regexp string)) ((zerop (length string)) (nil)) (t (let ((loc (1+ (regexp-search-list string (nthcdr (- (length kill-ring) browse-yank-cur) (reverse kill-ring)))))) (if (<= loc browse-yank-cur) (progn (browse-yank-next-yank loc) (goto-char (1+ (string-match string (buffer-substring (point-min) (point-max)))))) (error "Search failed: \"%s\"" string)))))) (defun browse-yank-search-forward (string) "Search forward for a occurance of REGEXP in kill-ring, for browse-yank." (interactive (list (read-from-minibuffer (concat "Search forward for regexp [" search-last-regexp "]: ")))) (if (zerop (length string)) (setq string search-last-regexp) (setq search-last-regexp string)) (if (zerop (length string)) (nil) (let ((loc (regexp-search-list string kill-ring (1+ browse-yank-cur)))) (if (= loc (length kill-ring)) (error "Search failed: \"%s\"" string) (browse-yank-goto-yank (1+ loc))) (goto-char (1+ (string-match string (buffer-substring (point-min) (point-max)))))))) (defun browse-yank-goto-yank (arg) "Display the supplied kill-ring position in the browse-yank-buffer." (interactive "nGoto yank: ") (cond ((< arg 1) (error "Argument must be positive.")) ((> arg (length kill-ring)) (error "Argument exceeds the length of kill-ring.")) (t (setq browse-yank-cur (1- arg)) (browse-yank-make-txt) (browse-yank-display browse-yank-cur)))) (defun browse-yank-next-yank (arg) "Goto the next element of the kill-ring in browse-yank buffer." (interactive "p") (let ((temp-pos (- browse-yank-cur arg))) (cond ((< temp-pos 0) (error "No following item in kill-ring.")) ((> temp-pos (- (length kill-ring) 1)) (error "No preceding item in kill-ring.")) (t (setq browse-yank-cur (- browse-yank-cur arg)) (browse-yank-make-txt) (browse-yank-display browse-yank-cur))))) (defun browse-yank-previous-yank (arg) "Goto the previous element of the kill-ring in browse-yank buffer." (interactive "p") (browse-yank-next-yank (- arg))) (defun buffer-to-register (char) "Set the contents of the current buffer into register CHAR." (interactive "cCopy to register: ") (set-register char (buffer-substring (point-min) (point-defun)))) (fset 'browse-yank-to-register (symbol-function 'buffer-to-register)) (defun browse-yank-help () "Spit out a simple help message for browse-yank-mode." (interactive) (message "(e)dit (i)nsert (j)ump (l)ocate (n)ext (p)revious (q)uit (?)describe-mode")) (defun browse-yank-yanks-saved (string) "Set kill-ring-max to a user defined value and make sure that displayed information is valid and sane." (interactive (list (read-from-minibuffer (concat "Number of elements in kill-ring [" kill-ring-max "]: ")))) (if (not (zerop (length string))) (let ((size (string-to-int string))) (if (or (not (numberp size)) (<= size 0)) (error "Please give a positive number.")) (setq kill-ring-max size) (if (> (length kill-ring) kill-ring-max) (setcdr (nthcdr (1- kill-ring-max) kill-ring) nil)) (setq kill-ring-yank-pointer kill-ring) (if (< size (1+ browse-yank-max)) (progn (setq browse-yank-max size) (if (< size (1+ browse-yank-cur)) (progn (setq browse-yank-cur browse-yank-max) (browse-yank-goto-yank browse-yank-cur)) (browse-yank-goto-yank (1+ browse-yank-cur)))))))) (defun browse-yank-edit-mode () "Major mode for editing the contents of a Yank Buffer The editing commands are the same as in Text mode, together with two commands to return to regular Browse Yank Mode: \\{browse-yank-edit-mode-map}? This mode runs the contents of browse-yank-edit-mode-hook if it exists." (use-local-map browse-yank-edit-mode-map) (setq major-mode 'browse-yank-edit-mode) (setq mode-name "Browse Yank Edit") (run-hooks 'browse-yank-edit-mode-hook)) (defun browse-yank-edit () "Edit the browse-yank buffer; switch to browse-yank-edit-mode." (interactive) (browse-yank-edit-mode) (setq buffer-read-only nil) (set-buffer-modified-p (buffer-modified-p)) (setq mode-line-process (concat "ing: " browse-yank-cur-txt)) (message "Editing: Type C-c C-c to return to Browse Yank, C-c C-] to abort.")) (defun browse-yank-cease-edit () "Finish editing message; switch back to Browse Yank proper." (interactive) (rplaca (nthcdr browse-yank-cur kill-ring) (buffer-substring (point-min) (point-max))) (setq buffer-read-only t) (browse-yank-mode) (browse-yank-display browse-yank-cur)) (defun browse-yank-abort-edit () "Abort edit of browse-yank buffer; restore original contents." (interactive) (setq buffer-read-only t) (browse-yank-mode) (browse-yank-display browse-yank-cur)) (defun regexp-search-list (re l &optional start) "Return position of first occurence of REGEXP in LIST starting at position START (optional)." (if (null start) (setq start 0)) (+ start (- (length (nthcdr start l)) (length (memq t (mapcar '(lambda (el) (if (string-match re el) t)) (nthcdr start l))))))) /Bob... -- {...}!rutgers!mende mende@aramis.rutgers.edu mende@zodiac.bitnet STEVEN SPEILBERG has a hangnail on his left foot, I am so envious!