mende@porthos.rutgers.edu (Bob Mende) (02/24/88)
This is browse-yank mode. It is a major mode that will allow
browsing, editing, and inserting the contents of the kill-ring. While
it may not be the worlds cleanest elisp code, it does work. If you
have and bug fixes, changes, or comments please mail them to me
Bob Mende
2/23/88
---------------clip here and save valuable coupons---------------
;; 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)))))))
--
mende@rutgers.edu {...}!rutgers!mende mende@zodiac.bitnet
What I want to find out is -- do parrots know much about Astro-Turf?