source: branches/acode-rewrite/source/cocoa-ide/hemlock/src/interp.lisp

Last change on this file was 16082, checked in by Gary Byers, 11 years ago

Merge trunk changes into this branch. Expect some things to explode.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.2 KB
RevLine 
[6]1;;; -*- Log: hemlock.log; Package: Hemlock-Internals -*-
2;;;
3;;; **********************************************************************
4;;; This code was written as part of the CMU Common Lisp project at
5;;; Carnegie Mellon University, and has been placed in the public domain.
6;;;
7#+CMU (ext:file-comment
8 "$Header$")
9;;;
10;;; **********************************************************************
11;;;
12;;; Written by Rob MacLachlan and Blaine Burks.
13;;;
14;;; This file contains the routines which define hemlock commands and
15;;; the command interpreter.
16;;;
17
18(in-package :hemlock-internals)
19
[553]20
21
[670]22
[6]23(defun %print-hcommand (obj stream depth)
24 (declare (ignore depth))
25 (write-string "#<Hemlock Command \"" stream)
26 (write-string (command-name obj) stream)
27 (write-string "\">" stream))
28
29
30
31
32;;;; Key Tables:
33;;;
34;;; A key table provides a way to translate a sequence of characters to some
35;;; lisp object. It is currently represented by a tree of hash-tables, where
36;;; each level is a hashing from a key to either another hash-table or a value.
37
38
39;;; GET-TABLE-ENTRY returns the value at the end of a series of hashings. For
40;;; our purposes it is presently used to look up commands and key-translations.
[8428]41;;;
[6]42(defun get-table-entry (table key &key (end (length key)))
[8428]43 (let ((foo nil))
[6]44 (dotimes (i end foo)
45 (let ((key-event (aref key i)))
46 (setf foo (gethash key-event table))
47 (unless (hash-table-p foo) (return foo))
48 (setf table foo)))))
49
50;;; SET-TABLE-ENTRY sets the entry for key in table to val, creating new
51;;; tables as needed. If val is nil, then use REMHASH to remove this element
52;;; from the hash-table.
53;;;
54(defun set-table-entry (table key val)
55 (dotimes (i (1- (length key)))
56 (let* ((key-event (aref key i))
57 (foo (gethash key-event table)))
58 (if (hash-table-p foo)
59 (setf table foo)
60 (let ((new-table (make-hash-table)))
61 (setf (gethash key-event table) new-table)
62 (setf table new-table)))))
63 (if (null val)
64 (remhash (aref key (1- (length key))) table)
65 (setf (gethash (aref key (1- (length key))) table) val)))
66
67
68
69;;;; Key Translation:
70;;;
71;;; Key translations are maintained using a key table. If a value is an
72;;; integer, then it is prefix bits to be OR'ed with the next character. If it
73;;; is a key, then we translate to that key.
74
75(defvar *key-translations* (make-hash-table))
76
77;;; TRANSLATE-KEY -- Internal
78;;;
79;;; This is used internally to do key translations when we want the
80;;; canonical representation for Key. Result, if supplied, is an adjustable
81;;; vector with a fill pointer. We compute the output in this vector. If the
82;;; key ends in the prefix of a translation, we just return that part
83;;; untranslated and return the second value true.
84;;;
[8428]85(defun translate-key (key &optional (result (make-array (length key)
86 :fill-pointer 0
[6]87 :adjustable t))
88 (temp (make-array 10 :fill-pointer 0 :adjustable t)))
89 (let ((key-len (length key))
90 (start 0)
91 (try-pos 0)
92 (prefix 0))
93 (setf (fill-pointer temp) 0)
94 (setf (fill-pointer result) 0)
95 (loop
96 (when (= try-pos key-len) (return))
[8428]97 (let ((key-event (aref key try-pos)))
[6]98 (vector-push-extend
99 (make-key-event key-event (logior (key-event-bits key-event) prefix))
100 temp)
101 (setf prefix 0))
102 (let ((entry (get-table-entry *key-translations* temp)))
103 (cond ((hash-table-p entry)
104 (incf try-pos))
105 (t
106 (etypecase entry
107 (null
108 (vector-push-extend (aref temp 0) result)
109 (incf start))
110 (simple-vector
111 (dotimes (i (length entry))
112 (vector-push-extend (aref entry i) result))
113 (setf start (1+ try-pos)))
114 (integer
115 (setf start (1+ try-pos))
116 (when (= start key-len) (return))
117 (setf prefix (logior entry prefix))))
118 (setq try-pos start)
119 (setf (fill-pointer temp) 0)))))
120 (dotimes (i (length temp))
121 (vector-push-extend (aref temp i) result))
122 (values result (not (zerop (length temp))))))
123
124
125;;; KEY-TRANSLATION -- Public.
126;;;
127(defun key-translation (key)
128 "Return the key translation for Key, or NIL if there is none. If Key is a
129 prefix of a translation, then :Prefix is returned. Whenever Key appears as a
130 subsequence of a key argument to the binding manipulation functions, that
131 portion will be replaced with the translation. A key translation may also be
132 a list (:Bits {Bit-Name}*). In this case, the named bits will be set in the
133 next character in the key being translated."
134 (let ((entry (get-table-entry *key-translations* (crunch-key key))))
135 (etypecase entry
136 (hash-table :prefix)
[8428]137 ((or simple-vector null) entry)
[6]138 (integer
139 (cons :bits (key-event-bits-modifiers entry))))))
140
141;;; %SET-KEY-TRANSLATION -- Internal
142;;;
[8428]143(defun %set-key-translation (key new-value)
[6]144 (let ((entry (cond ((and (consp new-value) (eq (car new-value) :bits))
145 (apply #'make-key-event-bits (cdr new-value)))
146 (new-value (crunch-key new-value))
147 (t new-value))))
148 (set-table-entry *key-translations* (crunch-key key) entry)
149 new-value))
150;;;
151(defsetf key-translation %set-key-translation
152 "Set the key translation for a key. If set to null, deletes any
153 translation.")
154
155
156
157
158;;;; Interface Utility Functions:
159
160(defvar *global-command-table* (make-hash-table)
161 "The command table for global key bindings.")
162
163;;; GET-RIGHT-TABLE -- Internal
164;;;
165;;; Return a hash-table depending on "kind" and checking for errors.
166;;;
167(defun get-right-table (kind where)
168 (case kind
169 (:global
170 (when where
171 (error "Where argument ~S is meaningless for :global bindings."
172 where))
173 *global-command-table*)
174 (:mode (let ((mode (getstring where *mode-names*)))
175 (unless mode
176 (error "~S is not a defined mode." where))
177 (mode-object-bindings mode)))
178 (:buffer (unless (bufferp where)
179 (error "~S is not a buffer." where))
180 (buffer-bindings where))
181 (t (error "~S is not a valid binding type." kind))))
182
183
184;;; CRUNCH-KEY -- Internal.
185;;;
186;;; Take a key in one of the various specifications and turn it into the
187;;; standard one: a simple-vector of characters.
[8428]188;;;
[6]189(defun crunch-key (key)
190 (typecase key
191 (key-event (vector key))
[8428]192 ((or list vector) ;List thrown in gratuitously.
[6]193 (when (zerop (length key))
194 (error "A zero length key is illegal."))
195 (unless (every #'key-event-p key)
196 (error "A Key ~S must contain only key-events." key))
197 (coerce key 'simple-vector))
198 (t
199 (error "Key ~S is not a key-event or sequence of key-events." key))))
200
201
202
203
204;;;; Exported Primitives:
205
206(declaim (special *command-names*))
207
208;;; BIND-KEY -- Public.
209;;;
210(defun bind-key (name key &optional (kind :global) where)
211 "Bind a Hemlock command to some key somewhere. Name is the string name
212 of a Hemlock command, Key is either a key-event or a vector of key-events.
213 Kind is one of :Global, :Mode or :Buffer, and where is the mode name or
214 buffer concerned. Kind defaults to :Global."
215 ;;(with-simple-restart (continue "Go on, ignoring binding attempt."))
216 (handler-bind ((error
[8428]217 #'(lambda (condition)
218 (format *error-output*
219 "~&Error while trying to bind key ~A: ~A~%"
[6]220 key condition)
221 (message (format nil "~a" condition))
222 #-GZ (return-from bind-key nil)
223 )))
224 (let ((cmd (getstring name *command-names*))
225 (table (get-right-table kind where))
226 (key (copy-seq (translate-key (crunch-key key)))))
227 (cond (cmd
228 (set-table-entry table key cmd)
229 (push (list key kind where) (command-%bindings cmd))
230 cmd)
231 (t
232 (error "~S is not a defined command." name))))))
233
234
235;;; DELETE-KEY-BINDING -- Public
236;;;
237;;; Stick NIL in the key table specified.
238;;;
239(defun delete-key-binding (key &optional (kind :global) where)
240 "Remove a Hemlock key binding somewhere. Key is either a key-event or a
241 vector of key-events. Kind is one of :Global, :Mode or :Buffer, andl where
242 is the mode name or buffer concerned. Kind defaults to :Global."
243 (set-table-entry (get-right-table kind where)
244 (translate-key (crunch-key key))
245 nil))
246
247
248;;; GET-CURRENT-BINDING -- Internal
[16082]249;;;
[8428]250;;; Look up a key in the current environment.
251;;;
252(defun get-current-binding (key)
253 (let ((buffer (current-buffer))
254 (t-bindings nil) res t-res)
255 (multiple-value-setq (res t-res) (get-binding-in-buffer key buffer))
256 (when t-res (push t-res t-bindings))
257 (loop while (null res)
258 for mode in (buffer-minor-mode-objects buffer)
259 do (multiple-value-setq (res t-res) (get-binding-in-mode key mode))
260 do (when t-res (push t-res t-bindings)))
261 (when (null res)
262 (multiple-value-setq (res t-res)
[6]263 (get-binding-in-mode key (buffer-major-mode-object buffer)))
[8428]264 (when t-res (push t-res t-bindings)))
265 (values (or res (get-table-entry *global-command-table* key))
266 (nreverse t-bindings))))
267
268(defun get-binding-in-buffer (key buffer)
269 (let ((res (get-table-entry (buffer-bindings buffer) key)))
[6]270 (when res
[8428]271 (if (and (commandp res) (command-transparent-p res))
272 (values nil res)
273 (values res nil)))))
274
275(defun get-binding-in-mode (key mode)
276 (let* ((res (or (get-table-entry (mode-object-bindings mode) key)
277 (let ((default (mode-object-default-command mode)))
278 (and default (getstring default *command-names*))))))
279 (when res
280 (if (or (mode-object-transparent-p mode)
281 (and (commandp res) (command-transparent-p res)))
[6]282 (values nil res)
283 (values res nil)))))
284
285
286;;; GET-COMMAND -- Public.
287;;;
288(defun get-command (key &optional (kind :global) where)
289 "Return the command object for the command bound to key somewhere.
290 If key is not bound, return nil. Key is either a key-event or a vector of
291 key-events. If key is a prefix of a key-binding, then return :prefix.
292 Kind is one of :global, :mode or :buffer, and where is the mode name or
293 buffer concerned. Kind defaults to :Global."
294 (multiple-value-bind (key prefix-p)
295 (translate-key (crunch-key key))
296 (let ((entry (if (eq kind :current)
297 (get-current-binding key)
298 (get-table-entry (get-right-table kind where) key))))
299 (etypecase entry
300 (null (if prefix-p :prefix nil))
301 (command entry)
302 (hash-table :prefix)))))
303
304(defvar *map-bindings-key* (make-array 5 :adjustable t :fill-pointer 0))
305
306;;; MAP-BINDINGS -- Public.
307;;;
308(defun map-bindings (function kind &optional where)
309 "Map function over the bindings in some place. The function is passed the
310 key and the command to which it is bound."
311 (labels ((mapping-fun (hash-key hash-value)
312 (vector-push-extend hash-key *map-bindings-key*)
313 (etypecase hash-value
314 (command (funcall function *map-bindings-key* hash-value))
315 (hash-table (maphash #'mapping-fun hash-value)))
316 (decf (fill-pointer *map-bindings-key*))))
317 (setf (fill-pointer *map-bindings-key*) 0)
318 (maphash #'mapping-fun (get-right-table kind where))))
319
320;;; MAKE-COMMAND -- Public.
[8428]321;;;
[6]322;;; If the command is already defined, then alter the command object;
323;;; otherwise, make a new command object and enter it into the *command-names*.
324;;;
325(defun make-command (name documentation function &key transparent-p)
326 "Create a new Hemlock command with Name and Documentation which is
327 implemented by calling the function-value of the symbol Function"
328 (let ((entry (getstring name *command-names*)))
[8428]329 (cond
330 (entry
[6]331 (setf (command-name entry) name)
332 (setf (command-documentation entry) documentation)
[8428]333 (setf (command-function entry) function)
[6]334 (setf (command-transparent-p entry) transparent-p))
335 (t
336 (setf (getstring name *command-names*)
337 (internal-make-command name documentation function transparent-p))))))
338
339
340;;; COMMAND-NAME, %SET-COMMAND-NAME -- Public.
341;;;
342(defun command-name (command)
343 "Returns the string which is the name of Command."
344 (command-%name command))
345;;;
346(defun %set-command-name (command new-name)
347 (check-type command command)
348 (check-type new-name string)
349 (setq new-name (coerce new-name 'simple-string))
350 (delete-string (command-%name command) *command-names*)
351 (setf (getstring new-name *command-names*) command)
352 (setf (command-%name command) new-name))
353
354
355;;; COMMAND-BINDINGS -- Public.
356;;;
357;;; Check that all the supposed bindings really exists. Bindings which
358;;; were once made may have been overwritten. It is easier to filter
359;;; out bogus bindings here than to catch all the cases that can make a
360;;; binding go away.
361;;;
362(defun command-bindings (command)
363 "Return a list of lists of the form (key kind where) describing
364 all the places where Command is bound."
365 (check-type command command)
366 (let (result)
367 (declare (list result))
368 (dolist (place (command-%bindings command))
369 (let ((table (case (cadr place)
370 (:global *global-command-table*)
371 (:mode
372 (let ((m (getstring (caddr place) *mode-names*)))
373 (when m (mode-object-bindings m))))
374 (t
375 (when (member (caddr place) *buffer-list*)
376 (buffer-bindings (caddr place)))))))
377 (when (and table
378 (eq (get-table-entry table (car place)) command)
[16082]379 (not (member place result :test #'equalp)))
380 (push place result))))
381 result))
382
383;;; COMMANDS-AND-BINDINGS -- Public
384;;;
385;;; Return a list of (command . key-bindings), for use in help. Looks only at bindings
386;;; in modes in "Default Modes" variable, doesn't require current buffer.
387;;;
388(defun commands-and-bindings (&optional (modes (value hemlock::default-modes)))
389 (when (some #'stringp modes)
390 (setq modes (mapcar (lambda (m) (if (stringp m) (get-mode-object m) m)) modes)))
391 (loop for cmd in (string-table-values *command-names*)
392 as bindings = (command-bindings cmd)
393 ;; collect unshadowed bindings
394 as keys = (loop for (key-seq) in bindings
395 when (eq cmd (get-binding-with-modes key-seq modes))
396 collect key-seq)
397 unless (or (and bindings (not keys)) ;; ignore pseudo-commands like "I-Search whatever"
398 (command-transparent-p cmd) ;; ignore addons like exit search mode.
399 (eq cmd (get-default-command)) ;; ignore illegal
400 (eq cmd (get-self-insert-command));; and self insert
401 (> (length keys) 5)) ;; ignore commmands like "Digit"
402 collect (cons cmd keys)))
403
404(defun get-binding-with-modes (key modes)
405 (or (loop for mode in modes ;; first find minor mode binding
406 do (when (stringp mode) (setq mode (get-mode-object mode)))
407 thereis (and (not (mode-object-major-p mode)) (get-binding-in-mode key mode)))
408 (loop for mode in modes ;; next try major mode
409 do (when (stringp mode) (setq mode (get-mode-object mode)))
410 thereis (and (mode-object-major-p mode) (get-binding-in-mode key mode)))
[8428]411 (get-table-entry *global-command-table* key)))
[6]412
413
414
415(defvar *key-event-history* (make-ring 60))
416
417;;; LAST-COMMAND-TYPE -- Public
418;;;
419;;;
[8428]420(defun last-command-type ()
[6]421 "Return the command-type of the last command invoked.
422 If no command-type has been set then return NIL. Setting this with
423 Setf sets the value for the next command."
424 *last-last-command-type*)
[8428]425
[6]426;;; %SET-LAST-COMMAND-TYPE -- Internal
427;;;
428(defun %set-last-command-type (type)
429 (setf (hemlock-last-command-type *current-view*) type))
430
431
[8428]432;;; PREFIX-ARGUMENT -- Public
433;;;
[6]434;;;
[8428]435(defun prefix-argument ()
436 "Return the current value of prefix argument."
437 *last-prefix-argument*)
[6]438
[8428]439(defun get-self-insert-command ()
440 ;; Get the command used to implement normal character insertion in current buffer.
441 (getstring (value hemlock::self-insert-command-name) *command-names*))
[12422]442
443(defun get-default-command ()
444 ;; Get the command used when no binding is present in current buffer.
445 (getstring (value hemlock::default-command-name) *command-names*))
[12430]446
447(defun get-system-default-behavior-command ()
448 ;; Get the command used to invoke "System Default Behavior"
449 (getstring (value hemlock::system-default-behavior-command-name) *command-names*))
450
451(defvar *native-key-events* (make-hash-table :test #'eq))
452
453
454
455(defun native-key-event-p (key)
456 (check-type key key-event)
457 (gethash key *native-key-events*))
458
459
[16082]460(defun (setf native-key-event-p) (flag key)
461 (check-type key key-event)
462 (if flag
463 (setf (gethash key *native-key-events*) flag)
464 (remhash key *native-key-events*)))
Note: See TracBrowser for help on using the repository browser.