dispch.sl 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519
  1. %
  2. % DISPCH.SL - Dispatch table utilities
  3. %
  4. % Author: William F. Galway
  5. % Symbolic Computation Group
  6. % Computer Science Dept.
  7. % University of Utah
  8. % Date: 25 July 1982
  9. % Copyright (c) 1982 University of Utah
  10. %
  11. % The dispatch table (determining "keyboard bindings") is the 256 element
  12. % vector "MainDispatch", AUGMENTED by association lists for C-X
  13. % (and possibly other prefix) characters. We actually use an association
  14. % list of association lists: the top level is a list of
  15. % (prefixchar . association-list), the second level is a list of
  16. % (character_to_follow_prefix_char . procedure). Associated with every
  17. % buffer is a list of forms to evaluate which will establish that buffer's
  18. % mode(s)--namely, the keyboard bindings that are in effect for that
  19. % buffer.
  20. % csp 7/7/82
  21. % - Put all dispatch list and mode functions together, and collected
  22. % some into this file from EMODE1.
  23. % - Modified EstablishCurrentMode to invoke DefinePrefixChars directly.
  24. % Generalized the idea of adding to a dispatch list with the function
  25. % AddToKeyList.
  26. % - Modified mode lists to EVAL entries rather than APPLYing functions
  27. % to NIL.
  28. % AS 7/12/82
  29. % - Added C-X D (Dired), C-X K (Kill Buffer), M-C-L (Previous BUffer)
  30. % commands to Basic Dispatch list.
  31. % - Separated out read-only text commands into ReadOnlyTextDispatchList.
  32. % AS 7/21/82
  33. % - Attached C-V and M-V to new scroll-window functions.
  34. % WFG 25 July 1982
  35. % - Dired stuff commented back out for now. ModeEstablishProcedures
  36. % renamed to be ModeEstablishExpressions.
  37. % AS 7/15/82
  38. % - Changed AddToKeyList to add the new definition at the end of the
  39. % list, so that it will override existing definitions.
  40. % - Added C-Q.
  41. % AS 8/2/82
  42. % - Revised $Iterate to use delayed prompting feature.
  43. % WFG 23 August 1982
  44. % - Changed AddToKeyList to call EstablishCurrentMode iff *EMODE is T.
  45. (FLUID
  46. '(
  47. MainDispatch % Dispatch table (vector), an entry for each key
  48. PrefixAssociationLists % Additional dispatch information for
  49. % prefixed characters.
  50. % List of declared prefix characters.
  51. PrefixCharacterList
  52. SelfInsertCharacter % Character being dispatched upon.
  53. last_operation % The "last" routine dispatched to (before the
  54. % "current operation").
  55. % List of expressions to be evaluated. Each expression is expected to
  56. % modify (add to?) the dispatch table.
  57. ModeEstablishExpressions
  58. FundamentalTextMode % See below
  59. ))
  60. % Create MainDispatch vector, 256 entries in all.
  61. (setf MainDispatch (MkVect 255))
  62. % List of valid prefix characters.
  63. (setf PrefixCharacterList NIL)
  64. % Add a new prefix character and associated prompt.
  65. (DE define_prefix_character (chr prompt-string)
  66. (setf PrefixCharacterList
  67. (cons (cons chr prompt-string) PrefixCharacterList)))
  68. % Set up initial list of valid prefix characters. Note that ESC (etc?)
  69. % aren't implemented as "prefix characters", (although, perhaps they should
  70. % be?) NOTE: there seems to be something wrong in that we're using this
  71. % general tool for only one prefix character. (Note that M-X is not a
  72. % prefix character.)
  73. (define_prefix_character (char (cntrl X)) "C-X ")
  74. % Generate a list of character codes, or a single character, from a list of
  75. % "character descriptors". Syntax is similar to that for the "Char"
  76. % macro.
  77. (DM CharSequence (chlist)
  78. (prog (processed-list)
  79. (setf processed-list
  80. (for (in chr-descriptor (cdr chlist))
  81. (collect (DoChar chr-descriptor))))
  82. % If there was a single character in the list, just return the
  83. % character code.
  84. (return
  85. (cond
  86. % Just return the character code if a single character.
  87. ((equal (length processed-list) 1)
  88. (car processed-list))
  89. % Otherwise, return the (quoted) list of character codes.
  90. (T
  91. `(quote ,processed-list))))))
  92. % Return T if character has meta bit set.
  93. (DS MetaP (chr)
  94. (GreaterP chr 127))
  95. % Convert character to meta-character.
  96. (DS MakeMeta (chr)
  97. (LOR chr 8#200))
  98. % Return character with meta bit "stripped off"--converts meta to normal char.
  99. (DS UnMeta (chr)
  100. (LAND chr 8#177))
  101. % This version of "UpperCaseP" also handles meta-characters.
  102. (DE X-UpperCaseP (chr)
  103. (cond
  104. ((MetaP chr)
  105. (UpperCaseP (UnMeta chr)))
  106. (T
  107. (UpperCaseP chr))))
  108. (DE X-Char-DownCase (chr)
  109. (cond
  110. ((MetaP chr)
  111. (MakeMeta (Char-DownCase (UnMeta chr))))
  112. (T
  113. (Char-DownCase chr))))
  114. % Set up a "clear" dispatch table.
  115. (DE ClearDispatch ()
  116. (progn
  117. (for (from i 0 255 1)
  118. (do (Undefine i)))
  119. (setf PrefixAssociationLists NIL)))
  120. % Set up the keyboard dispatch table for a character or "extended character".
  121. % If the character is uppercase, define the equivalent lower case character
  122. % also.
  123. (DE SetKey (xchar op)
  124. (cond
  125. ((NumberP xchar) % Add table entry for a simple character code.
  126. (progn
  127. (setf (indx MainDispatch xchar) op)
  128. (cond
  129. ((X-UpperCaseP xchar)
  130. (setf (indx MainDispatch (X-Char-DownCase xchar)) op)))))
  131. % If a valid prefixed character.
  132. ((and (PairP xchar) (Atsoc (car xchar) PrefixCharacterList))
  133. (prog (prefix-char assoc-entry)
  134. (setf prefix-char (car xchar))
  135. % Look up the prefix character in the a-list of a-lists.
  136. (setf assoc-entry (Atsoc prefix-char PrefixAssociationLists))
  137. % Add the prefix character if no entry present yet.
  138. (cond
  139. ((null assoc-entry)
  140. (setf PrefixAssociationLists
  141. (cons
  142. (setf assoc-entry (cons prefix-char NIL))
  143. PrefixAssociationLists))))
  144. % Now, add the prefixed character to the association list. Note
  145. % that in case of duplicate entries the last one added is the one
  146. % that counts. (Perhaps we should go to a little more work and
  147. % DelQIP any old entry?)
  148. (RPLACD assoc-entry
  149. % (cadr xchar) is the prefixed character.
  150. (cons (cons (cadr xchar) op) (cdr assoc-entry)))
  151. % Define the lower case version of the character, if relevent.
  152. (cond
  153. ((X-UpperCaseP (cadr xchar))
  154. (RPLACD assoc-entry
  155. (cons (cons
  156. (X-Char-DownCase (cadr xchar))
  157. op)
  158. (cdr assoc-entry)))))))
  159. % If we get here, SetKey was given a bad argument
  160. (T
  161. % (Use EMODEerror instead?)
  162. (Error 666 "Bad argument for SetKey"))))
  163. % Procedure to define a character as "self inserting".
  164. (DE MakeSelfInserting (chr)
  165. (SetKey chr 'InsertSelfCharacter))
  166. % Define a character so that it just "dings" bell.
  167. (DE Undefine (chr)
  168. (SetKey chr 'Ding))
  169. (FLUID '(new-oper))
  170. % Dispatch on next command character, "remember" the associated operation.
  171. (DE Dispatcher ()
  172. (progn
  173. (Dispatch (GetNextCommandCharacter))
  174. (setf last_operation new-oper)))
  175. % Dispatch on a character, "remember" the associated dispatch routine.
  176. (DE Dispatch (chr)
  177. (prog (oper)
  178. (setf oper (indx MainDispatch chr))
  179. (setf new-oper oper)
  180. (apply oper NIL)))
  181. % Read another character, and then perform appropriate operation from
  182. % appropriate prefix "table" (association list).
  183. (DE do-prefix ()
  184. (prog (prefix-entry char-entry chr)
  185. (setf prefix-entry (atsoc SelfInsertCharacter PrefixAssociationLists))
  186. (cond
  187. % "Complain" if no entry.
  188. ((null prefix-entry)
  189. (ding))
  190. % Otherwise, read a character and look up its entry.
  191. (T
  192. (setf chr
  193. (prompt_for_character
  194. % Prompt string for prefix
  195. (cdr (Atsoc SelfInsertCharacter PrefixCharacterList))))
  196. (setf char-entry (Atsoc chr prefix-entry))
  197. (cond
  198. ((null char-entry)
  199. (progn
  200. % Make note of the fact that we ding!
  201. (setf new-oper 'ding)
  202. (ding)))
  203. (T
  204. (apply (setf new-oper (cdr char-entry)) NIL)))))))
  205. % Treat next command character" as "Meta-character". (This routine is
  206. % normally invoked by the "escape" character.)
  207. (DE EscapeAsMeta ()
  208. (dispatch (LOR 8#200 (prompt_for_character "M-"))))
  209. % Treat the next character as a "control-meta-character". (This routine is
  210. % normally invoked by cntrl-Z.)
  211. (DE DoControlMeta ()
  212. (dispatch (LOR 8#200 (LAND 8#37 (prompt_for_character "M-C-")))))
  213. (FLUID '(pushed_back_characters))
  214. % Get command character, processing keyboard macros (someday! ), etc.
  215. % Parity mask is used to clear "parity bit" for those terminals that don't
  216. % have a meta key. It should be 8#177 in that case. Should be 8#377 for
  217. % terminals with a meta key. (Probably the wrong place to do this--if we
  218. % also expect to handle keyboard macros! )
  219. (DE GetNextCommandCharacter ()
  220. (cond
  221. % re-read any pushed back stuff.
  222. (pushed_back_characters
  223. (progn
  224. (setf SelfInsertCharacter (car pushed_back_characters))
  225. (setf pushed_back_characters (cdr pushed_back_characters))))
  226. (T
  227. (setf SelfInsertCharacter (Land parity_mask (PBIN))))))
  228. % "Push back" a character.
  229. (DE push_back (chr)
  230. (setf pushed_back_characters (cons chr pushed_back_characters)))
  231. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  232. % Manipulating mode tables
  233. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  234. % Set up dispatch table for current buffer, by evaluating the expressions
  235. % in ModeEstablishExpressions.
  236. (De EstablishCurrentMode ()
  237. (progn
  238. (ClearDispatch)
  239. % Use reverse so things on front of list are evaluated last. (So that
  240. % later incremental changes are added later.)
  241. (for (in x (reverse ModeEstablishExpressions))
  242. (do
  243. (cond
  244. ((pairp x) (eval x))
  245. (t
  246. (error 667
  247. (bldmsg
  248. "%r is not a valid ""mode establish expression"" (non-list)"))))))
  249. % csp 7/782
  250. % Prefix chars are totally global anyway, so let them be
  251. % established here, and let them override regular key defns.
  252. (DefinePrefixChars)))
  253. % This list of (character-sequence . operation) defines a partial set
  254. % of bindings for text mode (and other derived modes). This list
  255. % contains only commands that don't modify the buffer.
  256. (setf ReadOnlyTextDispatchList (list
  257. % These commands are read-only commands for text mode.
  258. (cons (char (cntrl @)) 'SetMark)
  259. (cons (char (cntrl A)) '$BeginningOfLine)
  260. (cons (char (cntrl B)) '$BackwardCharacter)
  261. (cons (char (cntrl E)) '$EndOfLine)
  262. (cons (char (cntrl F)) '$ForwardCharacter)
  263. (cons (char (cntrl N)) '$ForwardLine)
  264. (cons (char (cntrl P)) '$BackwardLine)
  265. (cons (char (cntrl R)) 'reverse_string_search)
  266. (cons (char (cntrl S)) 'forward_string_search)
  267. (cons (char (cntrl V)) 'scroll-window-up-page-command)
  268. (cons (char (meta (cntrl B))) 'backward_sexpr)
  269. (cons (char (meta (cntrl F))) 'forward_sexpr)
  270. (cons (char (meta B)) 'backward_word)
  271. (cons (char (meta F)) 'forward_word)
  272. (cons (char (meta V)) 'scroll-window-down-page-command)
  273. (cons (char (meta W)) 'copy_region)
  274. (cons (char (meta <)) '$BeginningOfBuffer)
  275. (cons (char (meta >)) '$EndOfBuffer)
  276. (cons (CharSequence (cntrl X) (cntrl X)) 'ExchangePointAndMark)
  277. % Note that these two would be nice to have for other "data modes" than
  278. % text. But current versions aren't generic enough.
  279. (cons (CharSequence (cntrl X) 1) 'OneWindow)
  280. (cons (CharSequence (cntrl X) 2) 'TwoRfaceWindows)
  281. ))
  282. % This list of (character-sequence . operation) defines bindings for text mode
  283. % (and other derived modes). TextDispatchList includes the initial contents of
  284. % ReadOnlyTextDispatchList (above). Be sure to put read-only commands on that
  285. % list!
  286. (setf TextDispatchList
  287. (append
  288. (list
  289. (cons (char !)) 'insert_matching_paren)
  290. (cons (char (cntrl D)) '$DeleteForwardCharacter)
  291. (cons (char (cntrl K)) 'kill_line)
  292. (cons (char (cntrl O)) 'OpenLine)
  293. (cons (char (cntrl Q)) 'InsertNextCharacter)
  294. (cons (char (cntrl T)) 'transpose_characters)
  295. (cons (char (cntrl W)) 'kill_region)
  296. (cons (char (cntrl Y)) 'insert_kill_buffer)
  297. (cons (char (meta (cntrl K))) 'kill_forward_sexpr)
  298. (cons (char (meta (cntrl RUBOUT))) 'kill_backward_sexpr)
  299. (cons (char (meta D)) 'kill_forward_word)
  300. (cons (char (meta Y)) 'unkill_previous)
  301. (cons (char (meta RUBOUT)) 'kill_backward_word)
  302. (cons (char DELETE) '$DeleteBackwardCharacter)
  303. (cons (char LF) '$CRLF)
  304. (cons (char CR) '$CRLF)
  305. (cons (char (meta !%)) 'Query-Replace-Command)
  306. (cons (CharSequence (cntrl X) (cntrl R)) 'CntrlXread)
  307. (cons (CharSequence (cntrl X) (cntrl S)) 'save_file)
  308. (cons (CharSequence (cntrl X) (cntrl W)) 'CntrlXwrite)
  309. )
  310. ReadOnlyTextDispatchList
  311. ))
  312. % Add the (chr opr) binding to a list with name listname.
  313. (de AddToKeyList (listname chr opr)
  314. (let*
  315. ((old-list (eval listname))
  316. (old-binding (atsoc chr old-list))
  317. (binding (cons chr opr)))
  318. (cond
  319. % If the binding isn't already in the a-list.
  320. ((null old-binding)
  321. % Add the new binding (Destructively to the end, so it's sure to
  322. % override any old stuff).
  323. (set listname (aconc old-list binding)))
  324. % Otherwise, replace the old operation in the binding.
  325. (T
  326. (setf (cdr old-binding) opr)))
  327. % Update the current mode if EMODE is running, in case it's affected by
  328. % the list we just modified.
  329. (cond
  330. (*EMODE
  331. (EstablishCurrentMode)))))
  332. % Add a new key binding to "text mode".
  333. (de SetTextKey (chr opr)
  334. (AddToKeyList 'TextDispatchList chr opr))
  335. % Add a new key binding to "Lisp mode".
  336. (de SetLispKey (chr opr)
  337. (AddToKeyList 'LispDispatchList chr opr))
  338. % Execute the expressions in this list to establish "Fundamental Text Mode".
  339. (setf FundamentalTextMode
  340. '((SetKeys TextDispatchList)
  341. (SetKeys BasicDispatchList)
  342. (NormalSelfInserts)))
  343. (de SetKeys (lis)
  344. (for (in x lis) (do (SetKey (car x) (cdr x)))))
  345. (de NormalSelfInserts ()
  346. (for (from i 32 126) (do (MakeSelfInserting i))))
  347. (setf BasicDispatchList
  348. (list
  349. (cons (char ESC) 'EscapeAsMeta)
  350. (cons (char (cntrl U)) '$Iterate)
  351. (cons (char (cntrl Z)) 'DoControlMeta)
  352. % NOT basic?
  353. (cons (CharSequence (cntrl X) (cntrl B)) 'PrintBufferNames)
  354. (cons (CharSequence (cntrl X) B) 'ChooseBuffer)
  355. %Dired stuff commented out for now.
  356. %? (cons (CharSequence (cntrl X) D) 'dired-command)
  357. % window-kill-buffer not implemented yet?
  358. %? (cons (CharSequence (cntrl X) K) 'window-kill-buffer)
  359. % "C-X N" switches to "next window" (or "other window" if in "two
  360. % window mode").
  361. (cons (CharSequence (cntrl X) N) 'next_window)
  362. % "C-X O" does the same as "C-X N"
  363. (cons (CharSequence (cntrl X) O) 'next_window)
  364. % "C-X P" moves to "previous window".
  365. (cons (CharSequence (cntrl X) P) 'previous_window_command)
  366. % C-X C-Z causes us to exit to monitor.
  367. (cons (CharSequence (cntrl X) (cntrl Z)) 'QUIT)
  368. % M-C-Z causes us to rebind the channels for "normal" I/O, and
  369. % leave EMODE.
  370. (cons (char (meta (cntrl Z))) 'OldFace)
  371. %Dired stuff commented out for now.
  372. %? (cons (char (meta (cntrl L))) 'SelectPreviousBuffer)
  373. (cons (char (cntrl L)) 'FullRefresh)
  374. % Two ways to invoke the help function.
  375. (cons (char (meta !/ )) '$HelpDispatch)
  376. (cons (char (meta !?)) '$HelpDispatch)
  377. (cons (CharSequence (cntrl X) (cntrl F)) 'find_file)
  378. (cons (CharSequence (cntrl X) (cntrl P)) 'WriteScreenPhoto)
  379. (cons (char (meta X)) 'execute_command)))
  380. % Define the prefix characters given in PrefixCharacterList.
  381. (de DefinePrefixChars ()
  382. (for (in prefix-entry PrefixCharacterList)
  383. (do
  384. % car gives character code for prefix.
  385. (SetKey (car prefix-entry) 'do-prefix))))
  386. % IS THE FOLLOWING REALLY APPROPRIATE TO DISPATCH?
  387. % Simulate EMACS's C-U, C-U meaning 4, C-U C-U meaning 16, etc., and C-U
  388. % <integer> meaning <integer>. This command suffers from the flaw of
  389. % simply iterating the following command, instead of giving it a
  390. % parameter. Thus, for example, C-U C-A won't do what you expect.
  391. % Written by Alan Snyder, HP labs.
  392. (fluid '(prompt-immediately prompt-was-output))
  393. % C-U handler.
  394. (de $iterate ()
  395. (let ((arg 1)
  396. (ch (char (control U)))
  397. (previous-ch nil)
  398. (prompt "")
  399. (prompt-immediately nil)
  400. )
  401. (while T
  402. (cond ((eqn ch (char (control U)))
  403. (if previous-ch (setq prompt (concat prompt " ")))
  404. (setq prompt (concat prompt "C-U"))
  405. (setq arg (times arg 4))
  406. )
  407. % Note check for non-meta character. (Since DigitP blows up
  408. % otherwise? Test may be obsolete??)
  409. ((and (LessP ch 128) (digitp ch))
  410. (if (and previous-ch (digitp previous-ch))
  411. (setq arg (plus (times arg 10) (char-digit ch)))
  412. % ELSE
  413. (setq arg (char-digit ch))
  414. (setq prompt (concat prompt " "))
  415. )
  416. (setq prompt (concat prompt (string ch)))
  417. )
  418. (t (exit)))
  419. (setq previous-ch ch)
  420. (setq ch (prompt_for_character prompt))
  421. (setq prompt-immediately prompt-was-output)
  422. )
  423. (for (from i 1 arg 1)
  424. (do (dispatch ch)
  425. % NOTE KLUDGE! Need to work this out better!
  426. (setf last_operation new-oper)))
  427. ))
  428. % Convert from character code to digit.
  429. (de char-digit (c)
  430. (cond ((digitp c) (difference (char-int c) (char-int (char 0))))))