home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / gnu / lucid / lemacs-19.6 / lisp / comint / history.el < prev    next >
Encoding:
Text File  |  1992-06-29  |  6.6 KB  |  165 lines

  1. ;; Copyright (C) 1989 Free Software Foundation, Inc.
  2. ;; This file is part of GNU Emacs.
  3.  
  4. ;; GNU Emacs is free software; you can redistribute it and/or modify
  5. ;; it under the terms of the GNU General Public License as published by
  6. ;; the Free Software Foundation; either version 1, or (at your option)
  7. ;; any later version.
  8.  
  9. ;; GNU Emacs is distributed in the hope that it will be useful,
  10. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. ;; GNU General Public License for more details.
  13.  
  14. ;; You should have received a copy of the GNU General Public License
  15. ;; along with GNU Emacs; see the file COPYING.  If not, write to
  16. ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18. ;; suggested generic history stuff  -- tale
  19.  
  20. ;; This is intended to provided easy access to a list of elements
  21. ;; being kept as a history ring.
  22.  
  23. ;; To use, variables for a list and the index to it need to be kept, and
  24. ;; a limit to how large the list can grow.  Short wrappers can than be provided
  25. ;; to interact with these functions.
  26.  
  27. ;; For example, a typical application of this is in interactive processes,
  28. ;; like shell or gdb.  A history can be kept of commands that are sent
  29. ;; to the process so that they are easily retrieved for re-inspection or
  30. ;; re-use.  Using process "foo" to illustrate:
  31.  
  32. ;; Variable foo-history will be the list.  foo-history-index would be the
  33. ;; pointer to the current item within the list; it is based with 0 being
  34. ;; the most recent element added to the list.  foo-history-size can be a
  35. ;; user-variable which controls how many items are allowed to exist.
  36.  
  37. ;; The following functions could interactive with the list; foo-mark
  38. ;; in these examples trackes the end of output from foo-process.
  39.  
  40. ;; (defun foo-history-previous (arg) ;; Suggested binding: C-c C-p
  41. ;;   "Retrieve the previous command sent to the foo process.
  42. ;; ARG means to select that message out of the list (0 is the first)."
  43. ;;   (interactive "P")
  44. ;;   (history-fetch 'foo-history 'foo-history-index (or arg 'previous)
  45. ;;                  foo-mark (point-max)))
  46.  
  47. ;; foo-history-next would look practically the same, but substituting "next"
  48. ;; for "previous".  Suggested binding: C-c C-n
  49.  
  50. ;; (defun foo-history-clear () ;; Suggested binding: C-c C-u
  51. ;;   "Clear the input region for the foo-process and reset history location."
  52. ;;   (interactive)
  53. ;;   (delete-region foo-mark (goto-char (point-max))))
  54.  
  55. ;; To get the history on the stack, an extremely minimal function would look
  56. ;; something like this, probably bound to RET:
  57.  
  58. ;; (defun foo-send ()
  59. ;;   "Send a command to foo-process."
  60. ;;   (interactive)
  61. ;;   (let ((str (buffer-substring foo-mark (goto-char (point-max)))))
  62. ;;     (insert ?\C-j)
  63. ;;     (setq foo-history-index -1) ; reset the index
  64. ;;     (set-marker foo-mark (point))
  65. ;;     (send-string foo-process str)
  66. ;;     (history-add 'foo-history str foo-history-size)))
  67.  
  68. ;; ToDo: history-isearch
  69.  
  70. (provide 'history)
  71.  
  72. (defvar history-last-search ""
  73.   "The last regexp used by history-search which resulted in a match.")
  74.  
  75. (defun history-add (list item size)
  76.   "At the head of LIST append ITEM.  Limit the length of LIST to SIZE elements.
  77. LIST should be the name of the list."
  78.   (set list (append (list item) (eval list)))
  79.   (let ((elist (eval list)))
  80.     (if (> (length elist) size)
  81.     (setcdr (nthcdr (1- size) elist) nil))))
  82.  
  83. (defun history-fetch (list index dir &optional beg end)
  84.   "Retrieve an entry from LIST, working from INDEX in direction DIR.
  85. LIST should be the name of the list, for message purposes.  INDEX should be
  86. the name of the variable used to index the list, so it can be maintained.
  87. DIR non-nil means to use previous entry, unless it is the symbol ``next''
  88. to get the next entry or a number to get an absolute reference.  DIR
  89. nil is equivalent to ``next''.
  90.  
  91. If optional numeric argument BEG is preset, it is taken as the point to insert
  92. the entry in the current buffer, leaving point at the start of the entry.
  93. If followed by a numeric END, the region between BEG and END will be deleted
  94. before the entry is inserted."
  95.   (let (str (eind (eval index)) (elist (eval list)))
  96.     (cond
  97.      ((numberp dir)
  98.       (setq str (nth dir elist))
  99.       (if str (set index dir) (message "No entry %d in %s." dir list)))
  100.      ((or (not dir) (eq dir 'next))
  101.       (if (= eind -1)
  102.           (message "No next entry in %s." list)
  103.         (set index (1- eind))
  104.         (setq str (if (zerop eind) "" (nth (1- eind) elist)))))
  105.      (t
  106.       (if (>= (1+ eind) (length elist))
  107.           (message "No previous entry in %s." list)
  108.         (set index (1+ eind))
  109.         (setq str (nth (1+ eind) elist)))))
  110.     (if (not (and (integer-or-marker-p beg) str)) ()
  111.       (if (integer-or-marker-p end) (delete-region beg end))
  112.       (insert str)
  113.       (goto-char beg))
  114.     str))
  115.  
  116. (defun history-search (list index dir regexp &optional beg end)
  117.   "In history LIST, starting at INDEX and working in direction DIR, find REGEXP.
  118. LIST and INDEX should be their respective symbol names.  DIR nil or 'forward
  119. means to search from the current index toward the most recent history entry.
  120. DIR non-nil means to search toward the oldest entry.  The current entry is
  121. not checked in either case.
  122.  
  123. If an entry is found and optional numeric argument BEG exists then the entry
  124. will be inserted there and point left at BEG.  If numeric END also exists
  125. then the region will be deleted between BEG and END."
  126.   (let* ((forw (or (not dir) (eq dir 'forward))) str found
  127.      (eind (eval index))
  128.      (elist (eval list))
  129.      (slist (if forw
  130.             (nthcdr (- (length elist) eind) (reverse elist))
  131.           (nthcdr (1+ eind) elist))))
  132.     (while (and (not found) slist)
  133.       (if (string-match regexp (car slist))
  134.       (setq found (car slist)
  135.         history-last-search regexp))
  136.       (setq eind (+ (if forw -1 1) eind)
  137.         slist (cdr slist)))
  138.     (if (not found)
  139.     (error "\"%s\" not found %s in %s"
  140.            regexp (if forw "forward" "backward") list)           
  141.       (set index eind)
  142.       (if (not (integer-or-marker-p beg)) ()
  143.     (if (integer-or-marker-p end) (delete-region beg end))
  144.     (insert found)
  145.     (goto-char beg)))
  146.     found))
  147.  
  148. (defun history-menu (list buffer &optional notemp)
  149.   "Show the history kept by LIST in BUFFER.
  150. This function will use ``with-output-to-temp-buffer'' unless optional third
  151. argument NOTEMP is non-nil."
  152.   (let ((pop-up-windows t) (line 0) 
  153.     (menu
  154.      (mapconcat (function (lambda (item)
  155.                 (setq line (1+ line))
  156.                 (format (format "%%%dd: %%s"
  157.                         (int-to-string (length list)))
  158.                     line item)))
  159.             list "\n")))
  160.     (if notemp
  161.     (save-excursion
  162.       (insert menu)
  163.       (display-buffer buffer))
  164.       (with-output-to-temp-buffer buffer (princ menu)))))
  165.