-
Notifications
You must be signed in to change notification settings - Fork 1
/
mwe-log-commands.el
executable file
·162 lines (139 loc) · 6.15 KB
/
mwe-log-commands.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
;;; mwe-log-commands.el --- log keyboard commands to buffer
;; Copyright (C) 2004 Free Software Foundation, Inc.
;; Author: Michael Weber <michaelw@foldr.org>
;; Keywords: help
;; Initial-version: <2004-10-07 11:41:28 michaelw>
;; Time-stamp: <2004-11-06 17:08:11 michaelw>
;; This file is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.
;; This file is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to
;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
;;; Commentary:
;; This add-on can be used to demo Emacs to an audience. When
;; activated, keystrokes get logged into a designated buffer, along
;; with the command bound to them.
;; To enable, use e.g.:
;;
;; (add-hook 'LaTeX-mode-hook (function mwe:log-keyboard-commands))
;;
;; To see the log buffer, call M-x mwe:open-command-log-buffer.
;;; Code:
(require 'cl)
(defvar mwe:*log-keyboard-commands* nil
"Non-nil means enabling keyboard command logging.
This variable by default is made buffer-local.")
(make-variable-buffer-local 'mwe:*log-keyboard-commands*)
(defvar mwe:*log-command-exceptions*
'(nil self-insert-command backward-char forward-char
delete-char delete-backward-char backward-delete-char
backward-delete-char-untabify
universal-argument universal-argument-other-key
universal-argument-minus universal-argument-more
beginning-of-line end-of-line recenter
move-end-of-line move-beginning-of-line
handle-switch-frame
newline previous-line next-line)
"A list commands which should not be logged, despite logging being enabled.
Frequently used non-interesting commands (like cursor movements) should be put here.")
(defvar mwe:*command-log-buffer* nil
"Reference of the currenly used buffer to display logged commands.")
(defvar mwe:*command-repetitions* 0
"Count of how often the last keyboard commands has been repeated.")
(defvar mwe:*last-keyboard-command* nil
"Last logged keyboard command.")
(defvar mwe:*log-command-indentation* 11
"*Indentation of commands in command log buffer.")
;;;###autoload
(defun mwe:log-keyboard-commands (&optional arg)
"Enables keyboard command logging for the current buffer.
If optional ARG is nil, logging is turned off."
(interactive "P")
(setq mwe:*log-keyboard-commands* (or arg t)))
(defun mwe:buffer-log-command-p (cmd &optional buffer)
"Determines whether keyboard command CMD should be logged.
If non-nil, BUFFER specifies the buffer used to determine whether CMD should be logged.
If BUFFER is nil, the current buffer is assumed."
(let ((val (if buffer
(buffer-local-value mwe:*log-keyboard-commands* buffer)
mwe:*log-keyboard-commands*)))
(and (not (null val))
(null (member cmd mwe:*log-command-exceptions*)))))
(defmacro mwe:with-saved-command-environment (&rest body)
(declare (indent 0))
`(let ((deactivate-mark nil) ; do not deactivate mark in transient
; mark mode
;; do not let random commands scribble over
;; {THIS,LAST}-COMMAND
(this-command this-command)
(last-command last-command))
,@body))
;;;###autoload
(defun mwe:open-command-log-buffer (&optional arg)
"Opens (and creates, if non-existant) a buffer used for logging keyboard commands.
If ARG is Non-nil, the existing command log buffer is cleared."
(interactive "P")
(prog1 (setq mwe:*command-log-buffer* (get-buffer-create " *command-log*"))
(when arg (with-current-buffer mwe:*command-log-buffer*
(erase-buffer)))
(pop-to-buffer mwe:*command-log-buffer* nil t)))
(defun mwe:scroll-buffer-window (buffer &optional move-fn)
"Updates `point' of windows containing BUFFER according to MOVE-FN.
If non-nil, MOVE-FN is called on every window which displays BUFFER.
If nil, MOVE-FN defaults to scrolling to the bottom, making the last line visible.
Scrolling up can be accomplished with:
\(mwe:scroll-buffer-window buf (lambda () (goto-char (point-min))))
"
(let ((selected (selected-window))
(point-mover (or move-fn
(function (lambda () (goto-char (point-max)))))))
(walk-windows (function (lambda (window)
(when (eq (window-buffer window) buffer)
(select-window window)
(funcall point-mover)
(select-window selected))))
nil t)))
(defmacro mwe:with-command-log-buffer (&rest body)
(declare (indent 0))
`(when (and (not (null mwe:*command-log-buffer*))
(buffer-name mwe:*command-log-buffer*))
(with-current-buffer mwe:*command-log-buffer*
,@body)))
(add-hook 'pre-command-hook
(defun mwe:log-command (&optional cmd)
"Hook into `pre-command-hook' to intercept command activation."
(mwe:with-saved-command-environment
(setq cmd (or cmd this-command))
(when (mwe:buffer-log-command-p cmd)
(mwe:with-command-log-buffer
(let ((current (current-buffer)))
(goto-char (point-max))
(cond ((eq cmd mwe:*last-keyboard-command*)
(incf mwe:*command-repetitions*)
(save-match-data
(when (and (> mwe:*command-repetitions* 1)
(search-backward "[" (line-beginning-position -1) t))
(delete-region (point) (line-end-position))))
(backward-char) ; skip over either ?\newline or ?\space before ?\[
(insert " [")
(princ (1+ mwe:*command-repetitions*) current)
(insert " times]"))
(t ;; (message "last cmd: %s cur: %s" last-command cmd)
(setq mwe:*command-repetitions* 0)
(insert (key-description (this-command-keys)))
(when (>= (current-column) mwe:*log-command-indentation*)
(newline))
(move-to-column mwe:*log-command-indentation* t)
(princ cmd current)
(newline)
(setq mwe:*last-keyboard-command* cmd)))
(mwe:scroll-buffer-window current)))))))
(provide 'mwe-log-commands)
;;; mwe-log-commands.el ends here