| 1 | ;;; chistory.el --- list command history |
| 2 | |
| 3 | ;; Copyright (C) 1985, 2001-2014 Free Software Foundation, Inc. |
| 4 | |
| 5 | ;; Author: K. Shane Hartman |
| 6 | ;; Maintainer: emacs-devel@gnu.org |
| 7 | ;; Keywords: convenience |
| 8 | |
| 9 | ;; This file is part of GNU Emacs. |
| 10 | |
| 11 | ;; GNU Emacs is free software: you can redistribute it and/or modify |
| 12 | ;; it under the terms of the GNU General Public License as published by |
| 13 | ;; the Free Software Foundation, either version 3 of the License, or |
| 14 | ;; (at your option) any later version. |
| 15 | |
| 16 | ;; GNU Emacs is distributed in the hope that it will be useful, |
| 17 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 18 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 19 | ;; GNU General Public License for more details. |
| 20 | |
| 21 | ;; You should have received a copy of the GNU General Public License |
| 22 | ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. |
| 23 | |
| 24 | ;;; Commentary: |
| 25 | |
| 26 | ;; This really has nothing to do with list-command-history per se, but |
| 27 | ;; its a nice alternative to C-x ESC ESC (repeat-complex-command) and |
| 28 | ;; functions as a lister if given no pattern. It's not important |
| 29 | ;; enough to warrant a file of its own. |
| 30 | |
| 31 | ;;; Code: |
| 32 | |
| 33 | (defgroup chistory nil |
| 34 | "List command history." |
| 35 | :group 'keyboard) |
| 36 | |
| 37 | ;;;###autoload |
| 38 | (defun repeat-matching-complex-command (&optional pattern) |
| 39 | "Edit and re-evaluate complex command with name matching PATTERN. |
| 40 | Matching occurrences are displayed, most recent first, until you select |
| 41 | a form for evaluation. If PATTERN is empty (or nil), every form in the |
| 42 | command history is offered. The form is placed in the minibuffer for |
| 43 | editing and the result is evaluated." |
| 44 | (interactive "sRedo Command (regexp): ") |
| 45 | (if pattern |
| 46 | (if (string-match "[^ \t]" pattern) |
| 47 | (setq pattern (substring pattern (match-beginning 0))) |
| 48 | (setq pattern nil))) |
| 49 | (let ((history command-history) |
| 50 | (temp) |
| 51 | (what)) |
| 52 | (while (and history (not what)) |
| 53 | (setq temp (car history)) |
| 54 | (if (and (or (not pattern) (string-match pattern (symbol-name (car temp)))) |
| 55 | (y-or-n-p (format "Redo %S? " temp))) |
| 56 | (setq what (car history)) |
| 57 | (setq history (cdr history)))) |
| 58 | (if (not what) |
| 59 | (error "Command history exhausted") |
| 60 | ;; Try to remove any useless command history element for this command. |
| 61 | (if (eq (car (car command-history)) 'repeat-matching-complex-command) |
| 62 | (setq command-history (cdr command-history))) |
| 63 | (edit-and-eval-command "Redo: " what)))) |
| 64 | |
| 65 | (defcustom default-command-history-filter-garbage |
| 66 | '(command-history-mode |
| 67 | list-command-history |
| 68 | electric-command-history) |
| 69 | "A list of symbols to be ignored by `default-command-history-filter'. |
| 70 | If that function is given a list whose car is an element of this list, |
| 71 | then it will return non-nil (indicating the list should be discarded from |
| 72 | the history). |
| 73 | Initially, all commands related to the command history are discarded." |
| 74 | :type '(repeat symbol) |
| 75 | :group 'chistory) |
| 76 | |
| 77 | (defvar list-command-history-filter 'default-command-history-filter |
| 78 | "Predicate to test which commands should be excluded from the history listing. |
| 79 | If non-nil, should be the name of a function of one argument. |
| 80 | It is passed each element of the command history when |
| 81 | \\[list-command-history] is called. If the filter returns non-nil for |
| 82 | some element, that element is excluded from the history listing. The |
| 83 | default filter removes commands associated with the command-history.") |
| 84 | |
| 85 | (defun default-command-history-filter (frob) |
| 86 | "Filter commands matching `default-command-history-filter-garbage' list |
| 87 | from the command history." |
| 88 | (or (not (consp frob)) |
| 89 | (memq (car frob) default-command-history-filter-garbage))) |
| 90 | |
| 91 | (defcustom list-command-history-max 32 |
| 92 | "If non-nil, maximum length of the listing produced by `list-command-history'." |
| 93 | :type '(choice integer (const nil)) |
| 94 | :group 'chistory) |
| 95 | |
| 96 | ;;;###autoload |
| 97 | (defun list-command-history () |
| 98 | "List history of commands typed to minibuffer. |
| 99 | The number of commands listed is controlled by `list-command-history-max'. |
| 100 | Calls value of `list-command-history-filter' (if non-nil) on each history |
| 101 | element to judge if that element should be excluded from the list. |
| 102 | |
| 103 | The buffer is left in Command History mode." |
| 104 | (interactive) |
| 105 | (with-output-to-temp-buffer |
| 106 | "*Command History*" |
| 107 | (let ((history command-history) |
| 108 | (buffer-read-only nil) |
| 109 | (count (or list-command-history-max -1))) |
| 110 | (while (and (/= count 0) history) |
| 111 | (if (and (bound-and-true-p list-command-history-filter) |
| 112 | (funcall list-command-history-filter (car history))) |
| 113 | nil |
| 114 | (setq count (1- count)) |
| 115 | (prin1 (car history)) |
| 116 | (terpri)) |
| 117 | (setq history (cdr history)))) |
| 118 | (with-current-buffer "*Command History*" |
| 119 | (goto-char (point-min)) |
| 120 | (if (eobp) |
| 121 | (error "No command history") |
| 122 | (command-history-mode))))) |
| 123 | |
| 124 | (define-obsolete-variable-alias 'command-history-map |
| 125 | 'command-history-mode-map "24.1") |
| 126 | (defvar command-history-mode-map |
| 127 | (let ((map (make-sparse-keymap))) |
| 128 | (set-keymap-parent map lisp-mode-shared-map) |
| 129 | (suppress-keymap map) |
| 130 | (define-key map "x" 'command-history-repeat) |
| 131 | (define-key map "\n" 'next-line) |
| 132 | (define-key map "\r" 'next-line) |
| 133 | (define-key map "\177" 'previous-line) |
| 134 | map) |
| 135 | "Keymap for `command-history-mode'.") |
| 136 | |
| 137 | (define-derived-mode command-history-mode fundamental-mode "Command History" |
| 138 | "Major mode for listing and repeating recent commands. |
| 139 | |
| 140 | Keybindings: |
| 141 | \\{command-history-mode-map}" |
| 142 | (lisp-mode-variables nil) |
| 143 | (set-syntax-table emacs-lisp-mode-syntax-table) |
| 144 | (setq buffer-read-only t)) |
| 145 | |
| 146 | (defcustom command-history-hook nil |
| 147 | "If non-nil, its value is called on entry to `command-history-mode'." |
| 148 | :type 'hook |
| 149 | :group 'chistory) |
| 150 | |
| 151 | (defun command-history-repeat () |
| 152 | "Repeat the command shown on the current line. |
| 153 | The buffer for that command is the previous current buffer." |
| 154 | (interactive) |
| 155 | (save-excursion |
| 156 | (eval (prog1 |
| 157 | (save-excursion |
| 158 | (beginning-of-line) |
| 159 | (read (current-buffer))) |
| 160 | (set-buffer |
| 161 | (car (cdr (buffer-list)))))))) |
| 162 | |
| 163 | ;;;###autoload |
| 164 | (defun command-history () |
| 165 | "Examine commands from `command-history' in a buffer. |
| 166 | The number of commands listed is controlled by `list-command-history-max'. |
| 167 | The command history is filtered by `list-command-history-filter' if non-nil. |
| 168 | Use \\<command-history-map>\\[command-history-repeat] to repeat the command on the current line. |
| 169 | |
| 170 | Otherwise much like Emacs-Lisp Mode except that there is no self-insertion |
| 171 | and digits provide prefix arguments. Tab does not indent. |
| 172 | \\{command-history-map} |
| 173 | |
| 174 | This command always recompiles the Command History listing |
| 175 | and runs the normal hook `command-history-hook'." |
| 176 | (interactive) |
| 177 | (list-command-history) |
| 178 | (pop-to-buffer "*Command History*") |
| 179 | (run-hooks 'command-history-hook)) |
| 180 | |
| 181 | (provide 'chistory) |
| 182 | |
| 183 | ;;; chistory.el ends here |