weiner@novavax.UUCP (Bob Weiner) (06/17/89)
Here is a feature laden rolodex system I cooked up so that I could rapidly find phone numbers and all sorts of random bits of information that were previously scattered in many different files. A simpler version of the rolodex for simpler folks is also included. This shar archive also includes an update of my smart-menu package (used in conjunction with smart-key) which includes a number of improvements and supports the rolodex system. Please let me know any innovative uses that you find for the rolodex system. =================================Cut Here=================================== #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: rolo.el rolo-logic.el rolo-simple.el smart-menu.el # Wrapped by root@ar_weiner on Fri Jun 16 18:09:17 1989 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'rolo.el' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'rolo.el'\" else echo shar: Extracting \"'rolo.el'\" \(16075 characters\) sed "s/^X//" >'rolo.el' <<'END_OF_FILE' X;;!emacs X;; X;; FILE: rolo.el X;; SUMMARY: Retrieves and sorts entries from a list of rolodex files X;; USAGE: GNU Emacs Lisp Library X;; X;; AUTHOR: Bob Weiner X;; ORG: Motorola, Inc., Communications Sector, Applied Research X;; E-MAIL: USENET: weiner@novavax.UUCP X;; X;; ORIG-DATE: 7-Jun-89 at 22:08:29 X;; LAST-MOD: 16-Jun-89 at 14:56:11 by Bob Weiner X;; X;; Copyright (C) 1989 Bob Weiner and Free Software Foundation, Inc. X;; Available for use and distribution under the same terms as GNU Emacs. X;; X;; This file is not yet part of GNU Emacs. X;; This could use a key or field limited searching capability. X;; X;; DESCRIPTION: X;; X;; All I wanted to do was look up a phone number quickly . . . X;; X;; FEATURES: X;; X;; 1. Multiple rolodex files. X;; X;; 2. Hierarchical rolodex entries as in: X;; * Company X;; ** Manager X;; *** Underlings X;; X;; Searching for Manager turns up all Underlings. Searching for X;; Company retrieves all listed employees. X;; X;; This hierarchical system has proved very effective for retrieving X;; computer system administration problem reports by vendor name, X;; problem number or by subject area without having to resort to a X;; database system. X;; X;; 4. String and regular expression searching capabilities. Ability to X;; restrict number of matches or to report number of matches without X;; displaying entries. X;; X;; 5. Smart sorting of entries by hierarchy level. X;; X;; See "rolo-logic.el" for logical search functions (and, or, not, xor). X;; X;; X;; FOR NON-PROGRAMMERS: X;; X;; Modify the second file entry in the definition of 'rolo-file-list' X;; before using this package. X;; X;; To add personal files to rolo-file-list--when you find these functions are X;; useful for any sort of list lookup--add the following to your ~/.emacs X;; file (substituting where you see <fileN>): X;; X;; (require 'rolo) X;; (setq rolo-file-list (append rolo-file-list '("<file1>" "<file2>"))) X;; X;; The only command you absolutely need that is defined here is X;; 'rolo-fgrep'; it locates any matching entries in a set of rolodex files. X;; I recommend that you add the following key binding to one of your site X;; specific Emacs initialization files: X;; X;; (global-set-key "\C-x4r" 'rolo-fgrep) X;; X;; Calling 'rolo-fgrep' with a prefix argument limits the number of matches X;; to the specified number of entries. X;; X;; The following commands are also provided: X;; 'rolo-grep' finds all entries matching a regular expression in a set X;; of rolodex files; X;; 'rolo-edit' edits one's personal rolodex file; X;; 'rolo-sort' sorts all levels of entries in a rolodex file. X;; X;; To make the 'rolo' library load whenever you initially call any of these X;; functions, add the following to any of your Emacs init files: X;; X;; (autoload 'rolo-fgrep "rolo" X;; "Find entries in rolodex." X;; t) X;; (autoload 'rolo-grep "rolo" X;; "Find entries in rolodex." X;; t) X;; (autoload 'rolo-edit "rolo" X;; "Edit personal rolodex file." X;; t) X;; (autoload 'rolo-sort "rolo" X;; "Sort rolodex file." X;; t) X;; X;; X;; Entries in rolodex files are separated by patterns matching X;; 'rolo-entry-regexp'. Each entry may have any number of sub-entries X;; which represent the next level down in the entry hierarchy. X;; Sub-entries' separator patterns are always longer than their parents'. X;; For example, if an entry began with '*' then its sub-entries would begin X;; with '**' and so on. Blank lines in rolodex files will not end up where X;; you want them if you use the rolo-sort commands; therefore, blank lines X;; are not recommended. X;; X;; The reasons that the entries in 'rolo-file-list' have ".otl" suffixes X;; are so that they do not conflict with file names that other rolodex X;; programs might use and so that they are edited in 'outline-mode' by X;; default. If you want the latter behavior, uncomment and add something X;; like the following to one of your GNU Emacs initialization files: X;; X;; ;; Add to the list of suffixes that causes automatic mode invocation X;; (setq auto-mode-alist X;; (append '(("\\.otl$" . outline-mode)) auto-mode-alist)) X;; X;; Here is a snippet from our group rolodex file (the ';'s should be X;; removed of course and the '*'s should begin at the start of the line): X;; X;;============================================================================= X;; GROUP ROLODEX X;; <Last Name>, <First Name> <Co/Categ> W<Work #> H<Home #> P<Pager #> X;; F<Fax #> M<Modem #> C<Cellular #> X;; R<Other-radio #> X;; <Address> <Miscellaneous Info, Key Words> X;;============================================================================= X;;* EX594, Digital-Systems-Research X;;** Weiner, Bob Motorola W2087 P7-7489 X;; FL19, L-1035 X;; X;; X;; FOR PROGRAMMERS: X;; X;; If you change the value of 'rolo-entry-regexp', you will have to modify X;; 'rolo-sort'. X;; X;; The following additional functions are provided: X;; 'rolo-sort-level' sorts a specific level of entries in a rolodex file; X;; 'rolo-map-level' runs a user specified function on a specific level of X;; entries in a rolodex file. X;; 'rolo-fgrep-file', same as 'rolo-fgrep' but operates on a single file X;; 'rolo-grep-file, same as 'rolo-grep' but operates on a single file X;; X;; The buffers containing the rolodex files are not killed after a search X;; on the assumption that another search is likely to follow within this X;; Emacs session. You may wish to change this behavior. X;; X;; This code works fine on properly formatted rolodex files but probably X;; will fail on certain improperly formatted ones. X;; X;; DESCRIP-END. X X(defconst rolo-file-list '("~/.rolodex.otl" "~ex594/.rolodex.otl") X "List of files containing rolodex entries. XThe first file should be a user-specific rolodex file, typically in the home Xdirectory. The second file is often a shared, group-specific rolodex file. X XA rolo-file consists of: X (1) an optional header beginning with and ending with a line which matches X rolo-hdr-regexp; X (2) one or more rolodex entries beginning with rolo-entry-regexp, which X may be nested.") X X(defconst rolo-entry-regexp "^\*+" X "Regular expression to match the beginning of a rolodex entry. XThis pattern must match the beginning of the line. Entries may be nested Xthrough the use of increasingly longer beginning patterns.") X X(defconst rolo-hdr-regexp "^===" X "Regular expression to match the first and last lines of rolodex file headers. XThis header is inserted into rolo-display-buffer before any entries from the Xfile are added.") X X(defconst rolo-display-buffer "*Rolodex*" X "Buffer used to display set of last matching rolodex entries.") X X(defun rolo-fgrep (string &optional max-matches rolo-file count-only) X "Display rolodex entries matching STRING, to a maximum of prefix arg MAX-MATCHES, Xin file(s) from optional ROLO-FILE or rolo-file-list. Default is to find all Xmatching entries. Each entry is displayed with all of its sub-entries. XOptional COUNT-ONLY non-nil means don't display matching entries. XReturns number of entries matched. See also documentation for the variable Xrolo-file-list." X (interactive "sRolodex string to match: \nP") X (let ((total-matches X (rolo-grep (regexp-quote string) max-matches rolo-file count-only))) X (if (interactive-p) X (message (concat (if (= total-matches 0) "No" total-matches) X " matching entr" X (if (= total-matches 1) "y" "ies") X " found in rolodex."))) X total-matches)) X X(defun rolo-grep (regexp &optional max-matches rolo-bufs count-only) X "Display rolodex entries matching REGEXP, to a maximum of prefix arg MAX-MATCHES, Xin buffer(s) from optional ROLO-BUFS or rolo-file-list. Default is to find all Xmatching entries. Each entry is displayed with all of its sub-entries. XOptional COUNT-ONLY non-nil means don't display matching entries. XReturns number of entries matched. See also documentation for the variable Xrolo-file-list." X (interactive "sRolodex regular expression to match: \nP") X (let ((rolo-file-list X (cond ((null rolo-bufs) rolo-file-list) X ((listp rolo-bufs) rolo-bufs) X ((list rolo-bufs)))) X (obuf (current-buffer)) X (display-buf (if count-only X nil X (set-buffer (get-buffer-create rolo-display-buffer)))) X (total-matches 0)) X (if count-only nil (setq buffer-read-only nil) (erase-buffer)) X (mapcar '(lambda (file) X (if (or (null max-matches) (> max-matches 0)) X (let ((num-matched X (rolo-grep-file file regexp max-matches count-only))) X (setq total-matches (+ total-matches num-matched)) X (or (null max-matches) X (setq max-matches (- max-matches num-matched)))))) X rolo-file-list) X (if (or count-only (= total-matches 0)) X nil X (pop-to-buffer display-buf) X (goto-char (point-min)) X (set-buffer-modified-p nil) X (setq buffer-read-only t) X (let ((buf (get-buffer-window obuf))) X (if buf (select-window buf) (switch-to-buffer buf)))) X (if (interactive-p) X (message (concat (if (= total-matches 0) "No" total-matches) X " matching entr" X (if (= total-matches 1) "y" "ies") X " found in rolodex."))) X total-matches)) X X(defun rolo-edit () X "Display personal rolodex file for editing." X (interactive) X (find-file (car rolo-file-list))) X X(defun rolo-sort (&optional rolo-file) X "Sort up to 14 levels of entries in ROLO-FILE (default is personal rolodex file). XUses default rolo-entry-regexp for sort. Returns list of number of groupings Xat each entry level." X (interactive "fRolodex file to sort: ") X (if (not rolo-file) (setq rolo-file (car rolo-file-list))) X (let ((level-regexp (regexp-quote "**************")) X (entries-per-level-list) X (n)) X (while (not (equal level-regexp "")) X (setq n (rolo-sort-level rolo-file level-regexp)) X (if (or (/= n 0) entries-per-level-list) X (setq entries-per-level-list X (append (list n) entries-per-level-list))) X (setq level-regexp (substring level-regexp 0 (- (length level-regexp) 2)))) X entries-per-level-list)) X X(defun rolo-sort-level (rolo-file level-regexp &optional max-groupings) X "Sort groupings of entries in ROLO-FILE at hierarchy level given by LEVEL-REGEXP Xto a maximum of optional MAX-GROUPINGS. Nil value of MAX-GROUPINGS means all Xgroupings at the given level. LEVEL-REGEXP should simply match the text of Xany rolodex entry of the given level, not the beginning of a line (^); an Xexample, might be (regexp-quote \"**\") to match level two. Returns number Xof groupings sorted." X (interactive "sRolodex file to sort: \nRegexp to match text of level's entries: \nP") X (rolo-map-level X '(lambda (start end) (sort-lines nil start end)) X rolo-file X level-regexp X max-groupings)) X X(defun rolo-map-level (func rolo-buf level-regexp &optional max-groupings) X "Perform FUNC on each grouping of ROLO-BUF entries at hierarchy level LEVEL-REGEXP Xto a maximum of optional argument MAX-GROUPINGS. Nil value of MAX-GROUPINGS Xmeans all groupings at the given level. FUNC should take two arguments, the Xstart and the end of the region that it should manipulate. LEVEL-REGEXP Xshould simply match the text of any rolodex entry of the given level, not the Xbeginning of a line (^); an example, might be (regexp-quote \"**\") to match Xlevel two. Returns number of groupings matched." X (if (and (or (null max-groupings) (< 0 max-groupings)) X (or (bufferp rolo-buf) X (if (file-exists-p rolo-buf) X (setq rolo-buf (find-file-noselect rolo-buf t))))) X (let ((num-found 0) X (exact-level-regexp (concat "^\\(" level-regexp "\\)[ \t\n]")) X (outline-regexp rolo-entry-regexp) X (level-len)) X ;; Load 'outline' library since its functions are used here. X (if (not (boundp 'outline-mode-map)) X (load-library "outline")) X (set-buffer rolo-buf) X (goto-char (point-min)) X ;; Pass buffer header if it exists X (if (re-search-forward rolo-hdr-regexp nil t 2) X (forward-line)) X (while (and (or (null max-groupings) (< num-found max-groupings)) X (re-search-forward exact-level-regexp nil t)) X (setq num-found (1+ num-found)) X (let* ((opoint (prog1 (point) (beginning-of-line))) X (grouping-start (point)) X (start grouping-start) X (level-len (or level-len (- (1- opoint) start))) X (next-level-len) X (next-entry-exists) X (grouping-end) X (no-subtree)) X (while (and (progn X (if (setq next-entry-exists X (re-search-forward rolo-entry-regexp nil t 2)) X (setq next-level-len (- (point) X (progn (beginning-of-line) X (point))) X grouping-end (< next-level-len level-len) X no-subtree (<= next-level-len level-len)) X (setq grouping-end t no-subtree t) X (goto-char (point-max))) X (let ((end (point))) X (goto-char start) X (hide-subtree) ; And hide multiple lines of entry X ;; Move to start of next entry at equal or higher level X (setq start X (if no-subtree X end X (if (re-search-forward rolo-entry-regexp X nil t) X (progn (beginning-of-line) (point)) X (point-max)))) X ;; Remember last expression in 'progn' must always X ;; return non-nil X (goto-char start))) X (not grouping-end))) X (let ((end (point))) X (goto-char grouping-start) X (funcall func grouping-start end) X (goto-char end)))) X (show-all) X num-found) X 0)) X X(defun rolo-fgrep-file (rolo-buf string &optional max-matches count-only) X "Retrieve entries in ROLO-BUF matching STRING to a maximum of optional MAX-MATCHES. XNil value of MAX-MATCHES means find all matches. Optional COUNT-ONLY non-nil Xmeans don't retrieve matching entries. Returns number of matching entries Xfound." X (rolo-grep-file rolo-buf (regexp-quote string) max-matches count-only)) X X(defun rolo-grep-file (rolo-buf regexp &optional max-matches count-only) X "Retrieve entries in ROLO-BUF matching REGEXP to a maximum of optional MAX-MATCHES. XNil value of MAX-MATCHES means find all matches. Optional COUNT-ONLY non-nil Xmeans don't retrieve matching entries. Returns number of matching entries Xfound." X (if (and (or (null max-matches) (< 0 max-matches)) X (or (bufferp rolo-buf) X (if (file-exists-p rolo-buf) X (setq rolo-buf (find-file-noselect rolo-buf t))))) X (let ((hdr-pos) (num-found 0) (curr-entry-level)) X (set-buffer rolo-buf) X (goto-char (point-min)) X (if (re-search-forward rolo-hdr-regexp nil t 2) X (progn (forward-line) X (setq hdr-pos (cons (point-min) (point))))) X (re-search-forward rolo-entry-regexp nil t) X (while (and (or (null max-matches) (< num-found max-matches)) X (re-search-forward regexp nil t)) X (re-search-backward rolo-entry-regexp nil t) X (let ((start (point)) X (next-entry-exists)) X (re-search-forward rolo-entry-regexp nil t) X (rolo-to-entry-end X t (setq curr-entry-level (buffer-substring start (point)))) X (or count-only X (and (= num-found 0) hdr-pos X (progn (append-to-buffer rolo-display-buffer X (car hdr-pos) (cdr hdr-pos))))) X (setq num-found (1+ num-found)) X (or count-only X (append-to-buffer rolo-display-buffer start (point))))) X num-found) X 0)) X X;; X;; INTERNAL FUNCTIONS. X;; X X(defun rolo-to-entry-end (&optional include-sub-entries curr-entry-level) X"Go to end of whole entry if optional INCLUDE-SUB-ENTRIES is non-nil. XCURR-ENTRY-LEVEL is a string whose length is the same as the last found entry Xheader. If INCLUDE-SUB-ENTRIES is nil, CURR-ENTRY-LEVEL is not needed." X (while (and (setq next-entry-exists X (re-search-forward rolo-entry-regexp nil t)) X include-sub-entries X (> (- (point) (save-excursion X (beginning-of-line) X (point))) X (length curr-entry-level)))) X (if next-entry-exists X (progn (beginning-of-line) (point)) X (goto-char (point-max)))) X X X(provide 'rolo) END_OF_FILE if test 16075 -ne `wc -c <'rolo.el'`; then echo shar: \"'rolo.el'\" unpacked with wrong size! fi # end of 'rolo.el' fi if test -f 'rolo-logic.el' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'rolo-logic.el'\" else echo shar: Extracting \"'rolo-logic.el'\" \(7746 characters\) sed "s/^X//" >'rolo-logic.el' <<'END_OF_FILE' X;;!emacs X;; X;; FILE: rolo-logic.el X;; SUMMARY: Performs logical retrievals on rolodex files X;; USAGE: GNU Emacs Lisp Library X;; X;; AUTHOR: Bob Weiner X;; ORG: Motorola, Inc., Communications Sector, Applied Research X;; E-MAIL: USENET: weiner@novavax.UUCP X;; X;; ORIG-DATE: 13-Jun-89 at 22:57:33 X;; LAST-MOD: 16-Jun-89 at 18:05:05 by Bob Weiner X;; X;; Copyright (C) 1989 Bob Weiner and Free Software Foundation, Inc. X;; Available for use and distribution under the same terms as GNU Emacs. X;; X;; This file is not yet part of GNU Emacs. X;; X;; DESCRIPTION: X;; X;; INSTALLATION: X;; X;; See also rolo.el. These functions are separated from rolo.el since many X;; users may never want or need them. They can be automatically loaded when X;; desired by adding the following to one of your Emacs init files: X;; X;; (autoload 'rolo-logic "rolo-logic" X;; "Logical rolodex search filters." X;; t) X;; X;; FEATURES: X;; X;; 1. One command, 'rolo-logic' which takes a logical search expression as X;; an argument and displays any matching entries. X;; X;; 2. Logical 'and', 'or', 'not', and 'xor' rolodex entry retrieval filter X;; functions. They take any number of string or boolean arguments and X;; may be nested. NOTE THAT THESE FUNCTIONS SHOULD NEVER BE CALLED X;; DIRECTLY UNLESS THE FREE VARIABLES 'start' and 'end' ARE BOUND X;; BEFOREHAND. X;; X;; EXAMPLE: X;; X;; (rolo-logic '(lambda () X;; (rolo-and X;; (rolo-xor "secretary" "Tool-And-Die") X;; "secretary"))) X;; X;; would find all non-Tool-And-Die Corp. secretaries in your rolodex. X;; X;; X;; X;; The logical matching routines are not really optimal, but then most X;; rolodex files are not terribly lengthy either. X;; X;; DESCRIP-END. X X(require 'rolo) X X(defun rolo-logic (func &optional in-bufs count-only include-sub-entries X no-sub-entries-out) X "Apply FUNC to all entries in optional IN-BUFS, display entries where FUNC is non-nil. XIf IN-BUFS is nil, 'rolo-file-list' is used. If optional COUNT-ONLY is Xnon-nil, don't display entries, return count of matching entries only. If Xoptional INCLUDE-SUB-ENTRIES flag is non-nil, FUNC will be applied across all Xsub-entries at once. Default is to apply FUNC to each entry and sub-entry Xseparately. Entries are displayed with all of their sub-entries unless XINCLUDE-SUB-ENTRIES is nil and optional NO-SUB-ENTRIES-OUT flag is non-nil. XFUNC should use the free variables 'start' and 'end' which contain the limits Xof the region on which it should operate. Returns number of applications of XFUNC that return non-nil." X (interactive "xLogic function of no arguments, (lambda () (<function calls>): ") X (let ((obuf (current-buffer)) X (display-buf (if count-only X nil X (prog1 (set-buffer (get-buffer-create rolo-display-buffer)) X (setq buffer-read-only nil) X (erase-buffer))))) X (let ((result X (mapcar X '(lambda (in-bufs) X (rolo-map-logic func in-bufs count-only include-sub-entries X no-sub-entries-out)) X (cond ((null in-bufs) rolo-file-list) X ((listp in-bufs) in-bufs) X ((list in-bufs)))))) X (let ((total-matches (apply '+ result))) X (if (or count-only (= total-matches 0)) X nil X (pop-to-buffer display-buf) X (goto-char (point-min)) X (set-buffer-modified-p nil) X (setq buffer-read-only t) X (let ((buf (get-buffer-window obuf))) X (if buf (select-window buf) (switch-to-buffer buf)))) X (if (interactive-p) X (message (concat (if (= total-matches 0) "No" total-matches) X " matching entr" X (if (= total-matches 1) "y" "ies") X " found in rolodex."))) X total-matches)))) X X(defun rolo-map-logic (func rolo-buf &optional count-only X include-sub-entries no-sub-entries-out) X "Apply FUNC to all entries in ROLO-BUF, write to buffer entries where FUNC is non-nil. XIf optional COUNT-ONLY is non-nil, don't display entries, return count of Xmatching entries only. If optional INCLUDE-SUB-ENTRIES flag is non-nil, FUNC Xwill be applied across all sub-entries at once. Default is to apply FUNC to Xeach entry and sub-entry separately. Entries are displayed with all of their Xsub-entries unless INCLUDE-SUB-ENTRIES is nil and optional NO-SUB-ENTRIES-OUT Xflag is non-nil. FUNC should use the free variables 'start' and 'end' which Xcontain the limits of the region on which it should operate. Returns number Xof applications of FUNC that return non-nil." X (if (or (bufferp rolo-buf) X (if (file-exists-p rolo-buf) X (setq rolo-buf (find-file-noselect rolo-buf t)))) X (let* ((display-buf (set-buffer (get-buffer-create rolo-display-buffer))) X (buffer-read-only)) X (let ((hdr-pos) (num-found 0)) X (set-buffer rolo-buf) X (goto-char (point-min)) X (if (re-search-forward rolo-hdr-regexp nil t 2) X (progn (forward-line) X (setq hdr-pos (cons (point-min) (point))))) X (let* ((start) X (end) X (end-entry-hdr) X (curr-entry-level)) X (while (re-search-forward rolo-entry-regexp nil t) X (setq start (save-excursion (beginning-of-line) (point)) X next-entry-exists nil X end-entry-hdr (point) X curr-entry-level (buffer-substring start end-entry-hdr) X end (rolo-to-entry-end include-sub-entries curr-entry-level)) X (let ((fun (funcall func))) X (or count-only X (and fun (= num-found 0) hdr-pos X (append-to-buffer display-buf X (car hdr-pos) (cdr hdr-pos)))) X (if fun X (progn (goto-char end) X (setq num-found (1+ num-found) X end (if (or include-sub-entries X no-sub-entries-out) X end X (goto-char (rolo-to-entry-end X t curr-entry-level)))) X (or count-only X (append-to-buffer display-buf start end))) X (goto-char end-entry-hdr))))) X num-found)) X 0)) X X X;; X;; INTERNAL FUNCTIONS. X;; X X;; Do NOT call the following functions directly. X;; Send them as parts of a lambda expression to 'rolo-logic'. X X(defun rolo-not (&rest list-of-pats) X "Logical <not> rolodex entry filter. LIST-OF-PATS is a list of pattern elements. XEach element may be t, nil, or a string." X (let ((pat-list list-of-pats) X (pat)) X (while (and pat-list X (or (not (setq pat (car pat-list))) X (and (not (eq pat t)) X (goto-char start) X (not (search-forward pat end t))))) X (setq pat-list (cdr pat-list))) X (if pat-list nil t))) X X(defun rolo-or (&rest list-of-pats) X "Logical <or> rolodex entry filter. LIST-OF-PATS is a list of pattern elements. XEach element may be t, nil, or a string." X (let ((pat-list list-of-pats) X (pat)) X (while (and pat-list X (or (not (setq pat (car pat-list))) X (and (not (eq pat t)) X (goto-char start) X (not (search-forward pat end t))))) X (setq pat-list (cdr pat-list))) X (if pat-list t nil))) X X(defun rolo-xor (&rest list-of-pats) X "Logical <xor> rolodex entry filter. LIST-OF-PATS is a list of pattern elements. XEach element may be t, nil, or a string." X (let ((pat-list list-of-pats) X (pat) X (matches 0)) X (while (and pat-list X (or (not (setq pat (car pat-list))) X (and (or (eq pat t) X (not (goto-char start)) X (search-forward pat end t)) X (setq matches (1+ matches))) X t) X (< matches 2)) X (setq pat-list (cdr pat-list))) X (= matches 1))) X X(defun rolo-and (&rest list-of-pats) X "Logical <and> rolodex entry filter. LIST-OF-PATS is a list of pattern elements. XEach element may be t, nil, or a string." X (let ((pat-list list-of-pats) X (pat)) X (while (and pat-list X (setq pat (car pat-list)) X (or (eq pat t) X (not (goto-char start)) X (search-forward pat end t))) X (setq pat-list (cdr pat-list))) X (if pat-list nil t))) X X(provide 'rolo-logic) END_OF_FILE if test 7746 -ne `wc -c <'rolo-logic.el'`; then echo shar: \"'rolo-logic.el'\" unpacked with wrong size! fi # end of 'rolo-logic.el' fi if test -f 'rolo-simple.el' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'rolo-simple.el'\" else echo shar: Extracting \"'rolo-simple.el'\" \(2466 characters\) sed "s/^X//" >'rolo-simple.el' <<'END_OF_FILE' X;;!emacs X;; X;; FILE: rolo-simple.el X;; SUMMARY: Very simple routines to display entries matching a string X;; from a rolodex file. For those who find "rolo.el" too X;; intimidating. X;; USAGE: GNU Emacs Lisp Library X;; X;; AUTHOR: Bob Weiner X;; ORG: Motorola, Inc., Communications Sector, Applied Research X;; E-MAIL: USENET: weiner@novavax.UUCP X;; X;; ORIG-DATE: 7-Jun-89 at 22:08:29 X;; LAST-MOD: 16-Jun-89 at 00:27:20 by Bob Weiner X;; X;; Copyright (C) 1989 Bob Weiner and Free Software Foundation, Inc. X;; Available for use and distribution under the same terms as GNU Emacs. X;; X;; This file is not part of GNU Emacs. X;; X;; DESCRIPTION: X;; DESCRIP-END. X X(defconst rolo-file "~/.rolodex.otl" X "User-specific file in which rolodex entries are stored.") X X(defconst rolo-entry-regexp "^\*+" X "Regular expression to match the beginning of a rolodex entry.") X X(defconst rolo-hdr-regexp "^===" X "Regular expression to match the last line of the rolodex file header. XThis header is inserted into rolo-display-buffer before any entries are Xadded.") X X(defconst rolo-display-buffer "*Rolodex*" X "Buffer used to display set of last matching rolodex entries.") X X(defun rolo-fgrep (string) X "Find entries in rolo-file matching STRING. XThe rolo-file consists of a header terminated by a line which matches Xrolo-hdr-regexp. And rolodex entries beginning with rolo-entry-regexp." X (interactive "sRolodex string to match: ") X (let ((obuf (current-buffer))) X (save-excursion X (set-buffer (get-buffer-create rolo-display-buffer)) X (erase-buffer) X (find-file rolo-file) X (goto-char (point-min)) X (save-excursion X (if (re-search-forward rolo-hdr-regexp nil t) X (progn (forward-line) X (append-to-buffer rolo-display-buffer X (point-min) (point))))) X (re-search-forward rolo-entry-regexp nil t) X (beginning-of-line) X (while (search-forward string nil t) X (re-search-backward rolo-entry-regexp nil t) X (let ((start (point))) X (if (re-search-forward rolo-entry-regexp nil t 2) X (beginning-of-line) X (goto-char (point-max))) X (append-to-buffer rolo-display-buffer start (point))))) X (pop-to-buffer rolo-display-buffer) X (set-buffer-modified-p nil) X (select-window (get-buffer-window obuf)))) X X(defun rolo-edit () X "Display user-specific rolodex file for editing." X (interactive) X (find-file rolo-file)) X X(provide 'rolo) END_OF_FILE if test 2466 -ne `wc -c <'rolo-simple.el'`; then echo shar: \"'rolo-simple.el'\" unpacked with wrong size! fi # end of 'rolo-simple.el' fi if test -f 'smart-menu.el' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'smart-menu.el'\" else echo shar: Extracting \"'smart-menu.el'\" \(6580 characters\) sed "s/^X//" >'smart-menu.el' <<'END_OF_FILE' X;;!emacs X;; X;; FILE: smart-menu.el X;; SUMMARY: Display subsystem menu for use with 'smart-key.el' package. X;; USAGE: GNU Emacs Lisp Library X;; X;; AUTHOR: Bob Weiner, Applied Research, Motorola, Inc. X;; E-MAIL: USENET: weiner@novavax.UUCP X;; ORIG-DATE: 20-Apr-89 X;; LAST-MOD: 15-Jun-89 at 23:11:21 by Bob Weiner X;; X;; Copyright (C) 1989 Bob Weiner and Free Software Foundation, Inc. X;; Available for use and distribution under the same terms as GNU Emacs. X;; X;; This file is not part of GNU Emacs. X;; X;; DESCRIPTION: X;;; X;;; This code is machine independent. X;;; X;;; To install: X;;; X;;; See smart-key.el X;;; X;;; You need this function if you don't already have it. X;;; (defun alist-value (compar-op tag alist) X;;; "Use COMPAR-OP (comparison operator) and TAG to extract matching value from ALIST." X;;; (let ((val)) X;;; (while (and (null val) alist) X;;; (if (funcall compar-op (car (car alist)) tag) X;;; (setq val (cdr (car alist)))) X;;; (setq alist (cdr alist))) X;;; val)) X;;; X;; DESCRIP-END. X X(require 'rolo) X X(defconst smart-menu-at-bottom t X "Non-nil means display menu below current window, nil means above.") X X(defconst smart-menu-alist X (list X (cons "Buffer-Menu" '(buffer-menu nil)) X (cons "Calendar" '(calendar)) X (cons "Dired-Home-Dir" '(dired "~")) X (cons "<Help>" '(smart-menu-help)) X (cons "Info" '(info)) X (cons "Rmail" '(rmail)) X (cons "Mail" '(mail)) X (cons "Shell" '(shell)) X (cons "Tutorial" '(help-with-tutorial)) X (cons "Search-Rolodex-for-String" '(call-interactively 'rolo-fgrep)) X (cons "Search-Rolodex-for-Regexp" '(call-interactively 'rolo-grep)) X (cons "Search-Rolodex-Using-Logical-Expression" '(call-interactively X 'rolo-logic)) X (cons "Edit-Personal-Rolodex" '(rolo-edit)) X (cons "Sort-Personal-Rolodex" '(rolo-sort)) X (cons "<Quit>" t)) X "Alist of smart menu items vs corresponding expressions to execute. XEach element looks like (STRING . EXPRESSION). XSelecting an item that matches STRING causes evaluation of EXPRESSION.") X X(defconst smart-menu-buffer "*Smart Menu*" X "Name of the buffer used for the smart subsystem menu.") X X(defvar *smart-menu-window-config* nil X "Window configuration prior to entry of smart menu mode.") X X(defvar *smart-menu-prev-mode* nil X "Records major-mode prior to entry of smart-menu.") X X(defvar *smart-menu-height* 0 X "Records window height to use for smart menu display.") X X(defvar smart-menu-mode-map nil X "Keymap containing smart-menu commands.") X(if smart-menu-mode-map X nil X (setq smart-menu-mode-map (copy-keymap text-mode-map)) X (define-key smart-menu-mode-map "h" 'smart-menu-help) X (define-key smart-menu-mode-map "q" 'smart-menu-quit) X (define-key smart-menu-mode-map " " 'smart-menu-select) X (define-key smart-menu-mode-map "\C-m" 'smart-menu-select)) X X;; Smart menu mode is suitable only for specially formatted data. X(put 'smart-menu-mode 'mode-class 'special) X X(defun smart-menu-mode () X "Smart-menu mode provides a menu of commands for entering subsystems. XSee also the documentation for 'smart-menu'. X X\\[smart-menu-select] or \\[smart-key] selects entries in the menu. X\\[smart-menu-quit] or \\[smart-key-meta] quits from the menu." X (kill-all-local-variables) X (use-local-map smart-menu-mode-map) X (setq major-mode 'smart-menu-mode) X (setq mode-name "smart-menu") X (set-syntax-table text-mode-syntax-table) X (setq local-abbrev-table text-mode-abbrev-table) X (setq case-fold-search t) X (setq buffer-read-only t) X (run-hooks 'smart-menu-mode-hook)) X X(defun smart-menu () X "Smart-menu pops up a window with a menu of commands for entering subsystems. X\\[smart-menu-select] or \\[smart-key] selects entries in the menu. X\\[smart-menu-quit] or \\[smart-key-meta] quits from the menu." X (interactive) X (setq *smart-menu-window-config* (current-window-configuration)) X (let ((buf (get-buffer-create smart-menu-buffer)) X (pop-up-windows t)) X (setq *smart-menu-prev-mode* major-mode) X (split-window-vertically) X (if smart-menu-at-bottom X (pop-to-buffer buf) X (switch-to-buffer buf)) X (or (eq major-mode 'smart-menu-mode) X (smart-menu-mode)) X ;; If empty buffer X (if (= (save-excursion (end-of-buffer) (point)) 1) X (let ((buffer-read-only nil) X (item-str) X (len 0)) X (mapcar X '(lambda (s) X (setq item-str X (concat item-str X (if (>= (+ len (length s) 2) X (window-width)) X (progn X (setq len 0 X *smart-menu-height* X (1+ *smart-menu-height*)) X "\n")) X s " ")) X (setq len (+ len (length s) 2))) X (mapcar 'car smart-menu-alist)) X (setq *smart-menu-height* (+ *smart-menu-height* 3)) X (insert "\n" item-str) X (goto-char (point-min)) X (set-buffer-modified-p nil))) X ;; Smallest size you can shrink a window X (let ((height (window-height))) X (shrink-window (min (- height *smart-menu-height*) (- height 4)))))) X X(defun smart-menu-select (&optional arg) X "Select smart menu item that point is within and execute associated command. XAlso quits from smart menu mode. With prefix ARG, quits only." X (interactive "P") X (if arg X (smart-menu-quit t) X (let ((item (extract-item-around-point))) X (if (string= item "") X (error "No command selected.") X (let ((exec-cmd (alist-value 'string-match item smart-menu-alist))) X (if exec-cmd X (progn (smart-menu-quit) X (eval exec-cmd)) X (beep) X (message (format "Unimplemented command selected, '%s'." item)))))))) X X(defun smart-menu-help () X "Displays description of major mode prior to smart-menu invocation." X (interactive) X (describe-function *smart-menu-prev-mode*)) X X(defun smart-menu-quit (&optional arg) X "Quit from smart menu. Restore previous window configuration. XOptional ARG kills the smart menu buffer rather than just burying it." X (interactive "P") X (let ((buf (get-buffer smart-menu-buffer))) X (if (not buf) X nil X (if (not arg) X (bury-buffer buf) X (kill-buffer buf) X (setq *smart-menu-height* 0)) X ;; Restore window configuration prior to smart menu entry. X (if *smart-menu-window-config* X (progn X (set-window-configuration *smart-menu-window-config*) X (setq *smart-menu-window-config* nil)))))) X X(defun extract-item-around-point () X "Return whitespace separated menu item that point is within or before." X (interactive) X (save-excursion X (skip-chars-backward "^ \t\n") X (let ((start (point))) X (skip-chars-forward "^ \t\n") X (buffer-substring start (point))))) X X(provide 'smart-menu) END_OF_FILE if test 6580 -ne `wc -c <'smart-menu.el'`; then echo shar: \"'smart-menu.el'\" unpacked with wrong size! fi # end of 'smart-menu.el' fi echo shar: End of shell archive. exit 0 -- -- Bob Weiner, Motorola, Inc., USENET: ...!gatech!uflorida!novavax!weiner (407) 738-2087