home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / languages / elisp / misc / min-bind.el < prev    next >
Encoding:
Text File  |  1993-07-07  |  33.0 KB  |  786 lines

  1. ;;; @ min-bind.el  Bind  keymaps, syntax tables and variables in minor modes.
  2. ;;; Version 1.01
  3.  
  4. ;;;   LCD Archive Entry:
  5. ;;;   min-bind|Inge Frick|inge@nada.kth.se|
  6. ;;;   Bind keymaps, syntax tables and varibales in minor modes|
  7. ;;;   09-Jun-1993|1.01|~/misc/min-bind.el.Z|
  8.  
  9. (provide 'min-bind)
  10. (require 'kill-fix)
  11.  
  12. ;;; @@ Copyright
  13. ;;;
  14. ;;; Copyright (C) 1993 Inge Frick (inge@nada.kth.se)
  15. ;;; 
  16. ;;; Almost all the code is by Inge Frick. Some code, much help and
  17. ;;; advise comes from Per Abrahamsen.
  18. ;;;
  19. ;;; This program is free software; you can redistribute it and/or modify
  20. ;;; it under the terms of the GNU General Public License as published by
  21. ;;; the Free Software Foundation; either version 2, or (at your option)
  22. ;;; any later version.
  23. ;;; 
  24. ;;; This program is distributed in the hope that it will be useful,
  25. ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  26. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  27. ;;; GNU General Public License for more details.
  28. ;;; 
  29. ;;; You should have received a copy of the GNU General Public License
  30. ;;; along with this program; if not, write to the Free Software
  31. ;;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  32. ;;;
  33. ;;; This file contains special keymap handling code for emacs 18, emacs
  34. ;;; 19 and lemacs. Selection which code to use is done when compiling.
  35. ;;; As a consequence this file must be byte-compiled on the same type of
  36. ;;; system as where it will be used. The only exceptions are that if it is
  37. ;;; compiled for emacs 18, then it can be used (less optimally) in emacs
  38. ;;; 19 and if you compile for lemacs then you can use it (again less
  39. ;;; optimally) in emacs 19 if you also load the lucid compatibility package.
  40.  
  41. ;;; @@ History:
  42. ;;;
  43. ;;; Version 1.01  Wed Jun  9 17:07:57 1993  inge@nada.kth.se
  44. ;;; In emacs18, full keymaps are converted to sparse keymaps. As a
  45. ;;; consequence full keymaps and sparse keymaps can be handled properly
  46. ;;; in both emacs 18 and 19.
  47. ;;;
  48. ;;; Version 1.00  Thu May 27 09:31:35 1993  inge@nada.kth.se
  49. ;;; First distributed version.
  50.  
  51. ;;; @@ Description:
  52. ;;;
  53. ;;; The main purpose of min-bind is to define functions that can be used
  54. ;;; by e.g. minor modes to bind and unbind variables, keymaps and syntax
  55. ;;; table entries in a consistent way.
  56. ;;; That this is needed, is illustrated by the following simple example:
  57. ;;;  A variable 'varno' has originally value 0.
  58. ;;;  Enter minor mode 'mode1' that changes varno to 1 and remembers the
  59. ;;;  old value.
  60. ;;;  Enter minor mode 'mode2' that changes varno to 2 and remembers the
  61. ;;;  old value.
  62. ;;;  The value of varno is now 2.
  63. ;;;  If you exit the minor modes last in first out, all is well. Exiting
  64. ;;;  mode2, resets varno to 1 and exiting mode1 resets varno to 0.
  65. ;;;  If you exit mode1 first, varno is reset to 0 which mode2 doesn't
  66. ;;;  want. If you then exit mode2, it will reset varno to 1, which is not
  67. ;;;  the original value!
  68. ;;; The problem is that the hierarchy of old values of varno forms a
  69. ;;; stack and have to be restored last in first out.
  70. ;;;
  71. ;;; The functions in min-bind solves this problem by storing this
  72. ;;; hierarchy as an association list with a tag telling which mode each
  73. ;;; value belongs to.  This allows values to be restored in arbitrary
  74. ;;; order.
  75. ;;; The entries in the syntax table can be handled in a similar way, we
  76. ;;; have one alist for each character whose syntax has been modified.
  77. ;;;
  78. ;;; Keymaps are handled somewhat differently: Instead of an hierarchy of
  79. ;;; bindings for each key, we form a hierarchy of keymaps like this:
  80. ;;; If the original local keymap is map0, then mode1 adds keymap map1 and
  81. ;;; mode2 adds map2, we end up with the hierarchy: map2-map1-map0.
  82. ;;; Key lookup in the local keymap will now first look for a key in map2.
  83. ;;; If the key is not found in map2, map1 will be searched and then if
  84. ;;; necessary map0. Both emacs 19 and lemacs have mechanisms for building
  85. ;;; such hierarchies and for emacs 18 we can build such hierarchies for
  86. ;;; sparse keymaps. We also build these hierarchies for all keymaps reached
  87. ;;; through prefix keys.
  88. ;;;
  89. ;;; A minor mode must either be local or non-local. A local minor mode
  90. ;;; affects only buffer local values while a non-local minor mode only
  91. ;;; affects global values (for a buffer-local variable, it affects the
  92. ;;; default value). A minor mode that mixes local and non-local variables
  93. ;;; will have inconsistent effects depending on in which buffer you enter or
  94. ;;; exit it.
  95. ;;; Local minor modes are more common but a non-local minor mode could e.g.
  96. ;;; be used to affect all instances of a major mode.
  97. ;;; Min-bind supports both local and non-local minor modes. If a mode has
  98. ;;; not been declared non-local by the minor-non-local function (see below),
  99. ;;; then it is regarded as a local minor mode and the functions that set a
  100. ;;; variable (minor-set-variable and optionally minor-modify-syntax and
  101. ;;; minor-add-to-keymap) will moke the variable buffer-local.
  102.  
  103. ;;; @@ min-bind defines the following public functions:
  104. ;;;
  105. ;;; minor-set-variable (mode variable value)
  106. ;;;   In MODE set VARIABLE to VALUE.
  107. ;;;   If MODE is local, this will make VARIABLE buffer-local.
  108. ;;;   If MODE is non-local, instead set the default value of VARIABLE.
  109. ;;;   The old value will be restored when `minor-unbind' is called.
  110. ;;;
  111. ;;; minor-modify-syntax-entry (mode char syntax &optional tablename)
  112. ;;;   In MODE set syntax for CHARacter according to string SYNTAX.
  113. ;;;   If the optional argument TABLENAME is present, modify instead the table
  114. ;;;   that is the value of TABLENAME.
  115. ;;;   See 'modify-syntax-entry' for the format of the SYNTAX string.
  116. ;;;   If MODE is local and TABLENAME is present, this will make TABLENAME
  117. ;;;   buffer-local.
  118. ;;;   If MODE is non-local, instead modify the table that is the default value
  119. ;;;   of TABLENAME wich must be present as there is no global syntax table.
  120. ;;;   The old syntax will be restored when `minor-unbind' is called.
  121. ;;;
  122. ;;; minor-add-to-keymap (mode keymap &optional keymapname)
  123. ;;;   In MODE, add copy of KEYMAP to the local (global) keymap.
  124. ;;;   If the optional argument KEYMAPNAME is present, add instead to the
  125. ;;;   keymap that is the value of keymapname.
  126. ;;;   If MODE is local then add to the local keymap or, if KEYMAPNAME is
  127. ;;;   present, to the value of KEYMAPNAME which is made buffer-local.
  128. ;;;   If MODE is non-local, instead add to the global keymap or to the
  129. ;;;   default value of KEYMAPNAME.
  130. ;;;   The old keymap will be restored when `minor-unbind' is called.
  131. ;;;
  132. ;;; minor-unbind (mode)
  133. ;;;   Undo changes made in MODE to variables, keymaps and syntax tables.
  134. ;;;
  135. ;;; The following functions are sometimes useful:
  136. ;;;
  137. ;;; minor-shadowed-variable (mode variable)
  138. ;;;   Get the value shadowed by MODE for VARIABLE.
  139. ;;;
  140. ;;; minor-shadowed-keymap (mode &optional keymapname)
  141. ;;;   Get keymap shadowed by addition in MODE to local (global) keymap or
  142. ;;;   KEYMAPNAME.
  143. ;;;   Mode and optional KEYMAPNAME has the same meaning as in
  144. ;;;   'minor-add-to-keymap'.
  145. ;;;
  146. ;;; minor-call-shadow (mode key &optional keymapname)
  147. ;;;   Call the function shadowed by MODE for KEY interactively.
  148. ;;;   Mode and optional KEYMAPNAME has the same meaning as in
  149. ;;;   'minor-add-to-keymap'.
  150. ;;;
  151. ;;; In most cases, the following macro is useful for defining minor modes:
  152. ;;;
  153. ;;; minor-mode-define (mode name cleanup doc &rest setup)
  154. ;;;   Define local minor MODE with NAME in minor-mode-alist.
  155. ;;;   CLEANUP is code for doing extra cleanup when leaving the mode.
  156. ;;;   DOC is the documentation for the minor mode.
  157. ;;;   The minor mode is setup by the SETUP commands.
  158. ;;;   Modifications done with mode as first argument to minor-set-variable,
  159. ;;;   minor-modify-syntax or minor-add-to-keymap, are undone at exit.
  160. ;;;
  161. ;;; If you want to define a non local minor mode, you need the following:
  162. ;;;
  163. ;;; minor-non-local (mode)
  164. ;;;   Declare minor mode with name MODE to be a non-local minor mode.
  165. ;;;   Undeclared minor modes are local minor modes.
  166. ;;;
  167. ;;; The MODE argument is used just as a tag, you can use any identifier,
  168. ;;; but it is a good idea to use the minor modes mode variable.
  169. ;;;
  170. ;;; The idea of the two minor-shadowed functions, is that you should be
  171. ;;; able to refer to the old variable or keymap binding.
  172. ;;;
  173. ;;; @@ Limitations:
  174. ;;;
  175. ;;; You will get an error: "Duplicated minor binding" if you try to
  176. ;;; modify a variable (or a keymap or a syntax) for the same mode (and
  177. ;;; char) a second time without unbinding it in between.
  178. ;;; If you have a minor mode that needs to change a (public) variable
  179. ;;; more than once, then it is a good idea to use a separate MODE
  180. ;;; identifier in minor-set-variable when setting this variable so that
  181. ;;; you can unbind it without having to unbind all the other minor mode
  182. ;;; variables. Just remember to unbind this variable as well as all the
  183. ;;; others when you exit the minor mode.
  184. ;;; Variables that are internal to a minor mode and not public do of
  185. ;;; course not need to be set by minor-set-variable.
  186. ;;; 
  187. ;;; Do not use define-key to modify a keymap that is also modified by
  188. ;;; minor-add-to-keymap. It will work until you unbind an addition to
  189. ;;; this keymap, then the binding you defined by define-key, will
  190. ;;; dissapear or not in a predictable but possibly unexpected way. If you
  191. ;;; need to define a single key binding, make a (sparse) keymap with your
  192. ;;; keybinding in it and then add this keymap.
  193. ;;;
  194. ;;; Keymaps in lemacs, emacs 19 and emacs 18 are different.
  195. ;;; In lemacs there is really no distinction between full and sparse
  196. ;;; keymaps. There is the concept of keymap parent, which allows building
  197. ;;; a hierarchy of keymaps.
  198. ;;; In emacs 19, sparse or full keymaps can have a parent keymap that can
  199. ;;; be a sparse or full keymap.
  200. ;;; In emacs 18, we can, for a sparse keymap, simulate a parent keymap,
  201. ;;; but this parent must also be a sparse keymap. Because of this, full
  202. ;;; keymaps are converted to sparse keymaps by min-bind when adding
  203. ;;; keymaps. This works, but it is better to avoid full keymaps in minor
  204. ;;; modes.
  205.  
  206. ;;; @@ Binding precedence:
  207. ;;;
  208. ;;; If two minor modes bind the same variable, which binding takes
  209. ;;; precedence? In other words, where in the alist of values do you put a
  210. ;;; new binding?
  211. ;;; The answer for min-bind is that the present version implements dynamic
  212. ;;; binding, so that the latest binding takes precedence, i.e. new bindings
  213. ;;; are always put at the front of the alist of values. It is very easy to
  214. ;;; implement another binding scheme, all that is required is that the
  215. ;;; function minor-posn (see below) returns a pointer into the alist of
  216. ;;; values that points at the position after wich the new binding should be
  217. ;;; positioned.
  218. ;;; There is code that has been commented out in minor-posn that implements
  219. ;;; a static binding scheme based on the opposite order of
  220. ;;; minor-mode-alist. This has the attractive feature that the order of
  221. ;;; modes in the mode line tells the precedence order, with the major mode
  222. ;;; having the lowest precedence and the rightmost minor mode having the
  223. ;;; highest precedence. The problem with this static scheme is that the
  224. ;;; order of minor-mode-alist depends on the somewhat random order in which
  225. ;;; minor mode definitions have been loaded.
  226. ;;; Dynamic binding on the other hand leaves it to the user to determine
  227. ;;; the precedence order by the order in which he enters minor modes. It
  228. ;;; would be nice if the mode line would show the precedence order for
  229. ;;; dynamic binding also. This will probably be done in the next version of
  230. ;;; min-bind by changing the mode line code.
  231.  
  232. ;;; The following variable is defined here to stop the byte compiler from
  233. ;;; complaining. minor-non-local is bound dynamically at entry to all public
  234. ;;; functions. It is used as a free variable by a number of functions.
  235. (defvar minor-non-local nil)
  236.  
  237.  
  238. ;;; @@ public functions
  239.  
  240. (put 'minor-mode-define 'lisp-indent-hook 3)
  241. (defmacro minor-mode-define (mode name cleanup doc &rest setup)
  242.   "Define local minor MODE with NAME in minor-mode-alist.
  243. CLEANUP is code for doing extra cleanup when leaving the mode.
  244. DOC is the documentation for the minor mode.
  245. The minor mode is setup by the SETUP commands.
  246. Modifications done with mode as first argument to minor-set-variable,
  247. minor-modify-syntax or minor-add-to-keymap, are undone at exit."
  248.   (minor-do-define mode name nil cleanup doc setup))
  249.  
  250. (defun minor-non-local (mode)
  251.   "Declare minor mode with name MODE to be a non-local minor mode"
  252.   (put mode 'minor-non-local t))
  253.  
  254.  
  255. (defun minor-set-variable (mode variable value)
  256.   "In MODE set VARIABLE to VALUE.
  257. If mode is local, this will make variable buffer-local.
  258. If mode is non-local, instead set the default value of variable.
  259. The old value will be restored when `minor-unbind' is called."
  260.   (let* ((minor-non-local (minor-non-local-p mode))
  261.          (valist (minor-get-values-alist 'variable variable))
  262.      (premal (minor-posn mode valist)))
  263.     (if valist ()
  264.       (minor-make-local-variable variable)
  265.       (setq valist (list variable (cons nil (minor-get-val variable))))
  266.       (minor-set-values-alist 'variable variable valist))
  267.     (if premal (setq valist premal)
  268.       (minor-set-val variable value))
  269.     (setcdr valist (cons (cons mode value) (cdr valist)))))
  270.       
  271. (defun minor-shadowed-variable (mode variable)
  272.   "Get the value shadowed by MODE for VARIABLE."
  273.   (minor-get-shadow mode 'variable variable))
  274.  
  275.  
  276. (defun minor-modify-syntax-entry (mode char syntax &optional tablename)
  277.   "In MODE set syntax for CHARacter according to string SYNTAX.
  278. If the optional argument TABLENAME is present, modify instead the table
  279. that is the value of tablename.
  280. See 'modify-syntax-entry' for the format of the syntax string.
  281. If mode is local and tablename is present, this will make tablename
  282. buffer-local.
  283. If mode is non-local, instead modify the table that is the default value
  284. of tablename which must be present as there is no global syntax table.
  285. The old syntax will be restored when `minor-unbind' is called."
  286.   (let* ((minor-non-local (minor-non-local-p mode))
  287.          (valist (cdr-safe (minor-get-values-alist 'syntax-table tablename)))
  288.      (table (minor-get-table tablename))
  289.      (premal nil) entry malist)
  290.     (if valist ()
  291.       (minor-make-local-variable tablename)
  292.       (setq valist (list (cons table (copy-syntax-table table))))
  293.       (minor-set-values-alist 'syntax-table tablename (cons tablename valist))
  294.       (minor-set-table tablename (setq table (minor-current valist))))
  295.     (modify-syntax-entry char syntax table)
  296.     (setq entry (cons mode (aref table char)))
  297.     (cond
  298.      ((not (setq malist (assq char (cdr valist)))) ; values alist for char.
  299.       (setcdr valist (cons (setq malist (list char)) (cdr valist)))) ; New char
  300.      ((setq premal (minor-posn mode malist))
  301.       (aset table char (minor-current (cdr malist)))
  302.       (setq malist premal)))
  303.     (setcdr malist (cons entry (cdr malist)))))
  304.  
  305.  
  306. (defun minor-add-to-keymap (mode keymap &optional keymapname)
  307.   "For MODE, add copy of KEYMAP to the local (global) keymap or to KEYMAPNAME.
  308. If the optional third argument KEYMAPNAME is not nil, it will be used
  309. intstead of the current map.
  310. For a non-local MODE add to global keymap or to default value of KEYMAPNAME."
  311.   (let* ((minor-non-local (minor-non-local-p mode))
  312.      (valist (minor-get-values-alist 'keymap keymapname))
  313.      (premal (minor-posn mode valist))
  314.      (acs-list (minor-accessible-copied-keymaps keymap))
  315.      (maps acs-list)
  316.      pair nmap pred)
  317.     (if valist ()
  318.       (minor-make-local-variable keymapname)      
  319.       (setq valist
  320.         (list keymapname
  321.           (cons nil (minor-try-accessible-keymaps keymapname))))
  322.       (minor-set-values-alist 'keymap keymapname valist))
  323.     (while maps            ; For keymap and all sub-keymaps
  324.       (setq pair (car maps))
  325.       (setq nmap (minor-next-map pair (cdr (or premal valist))))
  326.       (minor-replace-parent pair nil nmap)
  327.       (if (and premal (setq pred (minor-pred-map-pair pair (cdr valist))))
  328.       (minor-replace-parent pred nmap (cdr pair)))
  329.       (setq maps (cdr maps)))
  330.     (if premal (setq valist premal)
  331.       (minor-set-map keymapname (cdr (car acs-list))))
  332.     (setcdr valist (cons (cons mode acs-list) (cdr valist)))))
  333.  
  334. (defun minor-shadowed-keymap (mode &optional keymapname)
  335.   "Get keymap shadowed by addition in MODE to local (global) keymap.
  336. Mode and optional KEYMAPNAME has the same meaning as in 'minor-add-to-keymap'."
  337.   (minor-get-shadow mode 'keymap keymapname))
  338.  
  339. (defun minor-call-shadow (mode key &optional keymapname)
  340.   "Call the function shadowed by MODE for KEY interactively.
  341. Mode and optional KEYMAPNAME has the same meaning as in 'minor-add-to-keymap'."
  342.   (let ((old-map (current-local-map)))
  343.     (unwind-protect
  344.     (progn
  345.       (use-local-map (minor-shadowed-keymap mode keymapname))
  346.       (while (keymapp (key-binding key))
  347.         (message key)
  348.         (setq key (concat key (char-to-string (read-char)))))
  349.       (command-execute key))
  350.       (use-local-map old-map))))
  351.  
  352.  
  353. (defun minor-unbind (mode)
  354.   "Undo changes made in MODE to variables, keymaps and syntax tables."
  355.   (let* ((minor-non-local (minor-non-local-p mode))
  356.      (types (cons nil (minor-get-data)))
  357.      (mld types) mal)
  358.     (while (cdr types)            ; For each type:
  359.       (let* ((vars (car (cdr types)))
  360.          (fn (get (car vars) 'minor-remove-function)))
  361.     (while (cdr vars)        ; For each var
  362.       (setq mal (car (cdr vars)))
  363.       (setcdr mal (funcall fn mode (car mal) (cdr mal)))
  364.       (if (cdr-safe (cdr mal)) (setq vars (cdr vars)) ; Next var
  365.         (setcdr vars (cdr (cdr vars))))) ; Remove empty var
  366.     (if (cdr (car (cdr types))) (setq types (cdr types)) ; Next type
  367.       (setcdr types (cdr (cdr types)))))) ; Remove empty type
  368.     (minor-set-data (cdr mld))))
  369.  
  370.  
  371. ;;; @@ Simple list manipulation functions
  372.  
  373. (defun minor-list-find (element list &optional stop)
  374.   ;; Return the sublist starting with ELEMENT in the alist LIST.
  375.   (while (not (or (eq list stop) (eq element (car (car list)))))
  376.     (setq list (cdr list)))
  377.   (if (not (eq list stop)) list))
  378.  
  379. (defun minor-remassq (entry alist)
  380.   ;; Remove first association (if any) for entry ENTRY in alist ALIST.
  381.   (cond
  382.    ((null alist) ())
  383.    ((eq entry (car (car alist))) (cdr alist))
  384.    (t (setcdr alist (minor-remassq entry (cdr alist))) alist)))
  385.  
  386. (defun minor-last (list)
  387.   ;; Return last link in list list.
  388.   (while (cdr list) (setq list (cdr list)))
  389.   list)
  390.  
  391. ;;; @@ Command support
  392.  
  393. (defun minor-do-define (mode name non-local cleanup doc setup)
  394.   ;; Do the job for macro minor-mode-define.
  395.   (` (progn
  396.        (,@ (if (and cleanup (not non-local))
  397.            (list (` (put '(, mode) 'killing-local-variable-function
  398.                  (function (lambda (&rest ignore)
  399.                      (, cleanup))))))))
  400.        (if (not (assoc '(, mode) minor-mode-alist))
  401.        (setq minor-mode-alist (cons (list '(, mode) (, (concat " " name)))
  402.                     minor-mode-alist)))
  403.        (defvar (, mode) nil
  404.      (, (concat "Flag indicating whether " name " minor mode is active.")))
  405.        ((, (if non-local 'minor-non-local 'make-variable-buffer-local))
  406.     '(, mode))
  407.        (defun (, mode) (&optional arg)
  408.      (, doc)
  409.      (interactive "P")
  410.      (cond
  411.       ((and arg
  412.         (if (<= (prefix-numeric-value arg) 0) (not (, mode))
  413.           (, mode)))
  414.        ())                ; Do nothing if already in wanted mode.
  415.       ((setq (, mode) (not (, mode))) (,@ setup))
  416.       (t (,@ (if cleanup (list cleanup)))
  417.          (minor-unbind '(, mode))))
  418.      ;; No-op, but updates mode line.
  419.      (set-buffer-modified-p (buffer-modified-p))))))
  420.  
  421. (defun minor-get-shadow (mode type variable)
  422.   ;; Get the value shadowed by MODE for a type TYPE VARIABLE.
  423.   ;; Returns nil if MODE not there.
  424.   (let* ((minor-non-local (minor-non-local-p mode))
  425.      (mal (cdr-safe            ;Skip this mode
  426.            (minor-list-find        ;Find this mode for this type
  427.         mode (minor-get-values-alist type variable)))))
  428.     (if mal (funcall (get type 'minor-current-function) mal))))
  429.  
  430. (defun minor-non-local-p (mode)
  431.   (get mode 'minor-non-local))
  432.  
  433. (defun minor-make-local-variable (var)
  434.   (if (and var (not minor-non-local)) (make-local-variable var)))
  435.  
  436. ;;; @@ Private variable
  437.  
  438. ;;; All the hierarchies of values are stored in the global resp. buffer local
  439. ;;; variables minor-non-local-data and minor-local-data, both of which are an
  440. ;;; alist of alists of alists with the format:
  441. ;;; (.. (TYPE .. (VAR . VALIST) ..) ..)
  442. ;;; Here TYPE is 'variable, 'keymap, or 'syntax-table,
  443. ;;;      VAR is name of a variable, a keymap or a syntax-table,
  444. ;;;      VALIST varies according to TYPE.
  445. ;;; For variables the format for VALIST is:
  446. ;;;   (.. (MODE . VALUE) ..)
  447. ;;; for keymaps the format is:
  448. ;;;   (.. (MODE .. (KEY . MAP) ..) ..)
  449. ;;; and for syntax tables the format is:
  450. ;;;   ((OTABLE . TABLE) .. (CHAR .. (MODE . SYNTAX) ..) ..)
  451. ;;; Here MODE is the name of a minor mode,
  452. ;;;      VALUE is the value of VAR in mode MODE,
  453. ;;;      KEY is a prefix key sequence,
  454. ;;;      MAP is the (sub-) keymap of keymap VAR with prefix KEY in mode MODE,
  455. ;;;      OTABLE is the original syntax table value for VAR and TABLE is the
  456. ;;;       copy of OTABLE that is used,
  457. ;;;      CHAR is a character in the syntax table,
  458. ;;;      SYNTAX is the the syntax table entry for CHAR in MODE for the
  459. ;;;       syntaxtable VAR.
  460. ;;; For variables and keymaps, MODE nil represents the original value for VAR.
  461. ;;; For syntax-tables and keymaps, VAR nil is used to represent the current
  462. ;;; syntax-table or the local or global keymap.
  463.  
  464. (defvar minor-non-local-data nil)
  465. (defvar minor-local-data nil)
  466. (make-variable-buffer-local 'minor-local-data)
  467.  
  468. ;;; @@ Functions for handling minor-data
  469.  
  470. (put 'minor-local-data 'killing-local-variable-function 'minor-unbind-all)
  471. (defun minor-unbind-all (old-vars)
  472.   ;; This function is called by a modified kill-all-local-variables when
  473.   ;; minor-local-data is killed. Its purpose is to reset to base value
  474.   ;; the minor variables that have not been killed.
  475.   (let ((types (assq 'minor-local-data old-vars)) ; minor-local-data
  476.     (locals (buffer-local-variables)) var valist)
  477.     (while (setq types (cdr types))        ; For each type:
  478.       (let* ((vars (car types))
  479.          (cfn (get (car vars) 'minor-current-function))
  480.          (bfn (get (car vars) 'minor-base-function)))
  481.     (while (setq vars (cdr vars))    ; For each var (variable):
  482.       (and (setq var (car (car vars))) ; if it is not nil and
  483.            (assq var locals)    ; not killed and
  484.            (eq (symbol-value var)    ; still has its minor current
  485.            (funcall cfn (setq valist (cdr (car vars))))) ; value then
  486.            (set var (funcall bfn valist)))))))) ; reset it to base value
  487.  
  488. (defun minor-get-values-alist (type var)
  489.   (assq var (cdr-safe (assq type (minor-get-data)))))
  490.  
  491. (defun minor-set-values-alist (type var valist)
  492.   (let* ((types minor-local-data)
  493.      (vars (assq type types))
  494.      (mal (if vars (assq var (cdr vars)))))
  495.     (if mal (setcdr mal (cdr valist))
  496.       (if vars (setcdr vars (cons valist (cdr vars)))
  497.     (minor-set-data (cons (list type valist) types))))))
  498.  
  499. (defun minor-get-data ()
  500.   (if minor-non-local minor-non-local-data
  501.     minor-local-data))
  502.  
  503. (defun minor-set-data (types)
  504.   (if minor-non-local (setq minor-non-local-data types)
  505.     (setq minor-local-data types)))
  506.  
  507. (defun minor-posn (mode valist)
  508.   ;; Check for duplicate minor binding and return position after wich MODE
  509.   ;; should be inserted into VALIST. Return nil for insertion at beginning
  510.   ;; of valist.
  511.   (let (mal)
  512.     (cond
  513.      ((null (setq valist (cdr-safe valist))) nil)
  514.      ((assq mode valist) (error "Duplicated minor binding"))
  515.      ;; The following code gives a static ordering of minor-mode variables,
  516.      ;; based on the opposite order of that in minor-mode-alist. Tags not in
  517.      ;; minor-mode-alist are ordered dynamically and before all tags in
  518.      ;; minor-mode-alist.  If this code is commented out, you get a dynamic
  519.      ;; ordering of all tags.
  520. ;;;  ((and (setq mal (minor-list-find mode minor-mode-alist)) ; a minor mode
  521. ;;;       (progn (setq mal (cdr mal))    ; with
  522. ;;;          (not (minor-list-find (car (car valist)) ; lower priority
  523. ;;;                 minor-mode-alist mal)))) ; than current
  524. ;;;   (while (and (cdr valist)
  525. ;;;          (not (minor-list-find (car (car (cdr valist)))
  526. ;;;                    minor-mode-alist mal)))
  527. ;;;    (setq valist (cdr valist)))
  528. ;;;   valist)
  529.      (t nil))))            ; This line should not be commented out.
  530.     
  531.  
  532. ;;; @@ Support functions for variables
  533.  
  534. (put 'variable 'minor-current-function 'minor-current)
  535. (defun minor-current (valist)
  536.   (cdr (car valist)))
  537.  
  538. (put 'variable 'minor-base-function 'minor-base)
  539. (defun minor-base (valist)
  540.   (minor-current (minor-last valist)))
  541.  
  542. (put 'variable 'minor-remove-function 'minor-remove-variable-function)
  543. (defun minor-remove-variable-function (mode variable valist)
  544.   ;; Remove MODE variable from variable VARIABLE and values alist VALIST.
  545.   (let ((entry (assq mode valist)))
  546.     (cond
  547.      ((null entry) valist)        ; Do nothing if not there
  548.      ((eq entry (car valist))        ; Current added variable
  549.       (minor-set-val variable (minor-current (cdr valist)))
  550.       (cdr valist))
  551.      (t (delq entry valist)))))        ; Not current, remove from values alist
  552.  
  553. (defun minor-get-val (variable)
  554.   (if minor-non-local (default-value variable)
  555.     (symbol-value variable)))
  556.  
  557. (defun minor-set-val (variable value)
  558.   (if minor-non-local (set-default variable value)
  559.     (set variable value)))
  560.  
  561. ;;; @@ Support functions for syntax table
  562.  
  563. (put 'syntax-table 'minor-current-function 'minor-current)
  564.  
  565. (put 'syntax-table 'minor-base-function 'minor-base-table)
  566. (defun minor-base-table (valist)
  567.   (car (car valist)))
  568.  
  569. (put 'syntax-table 'minor-remove-function 'minor-remove-syntax-table-function)
  570. (defun minor-remove-syntax-table-function (mode tablename valist)
  571.   ;; Remove MODE syntax table entries from syntax table TABLENAME and
  572.   ;; values alist VALIST.
  573.   (let ((table (minor-current valist)) (otable (minor-base-table valist))
  574.     (mal valist))
  575.     (while (cdr mal)
  576.       (let* ((calist (car (cdr mal)))
  577.          (char (car calist)))
  578.     (cond
  579.      ((not (eq mode (car (car (cdr calist))))) ; Not latest entry
  580.       (minor-remassq mode (cdr calist)) ; If there, remove it.
  581.       (setq mal (cdr mal)))
  582.      ((setcdr calist (cdr (cdr calist))) ; Not last entry.
  583.       (aset table char (minor-current (cdr calist)))
  584.       (setq mal (cdr mal)))
  585.      (t (aset table char (aref otable char)) ; No minor entries for this,
  586.         (setcdr mal (cdr (cdr mal))))))) ; remove it, restore base syntax.
  587.     (if (not (cdr valist))
  588.     (minor-set-table tablename otable)) ; Base syntax for all.
  589.     valist))
  590.  
  591. (defun minor-get-table (tablename)
  592.   (cond
  593.    (tablename (minor-get-val tablename))
  594.    (minor-non-local (error "No global syntax table"))
  595.    (t (syntax-table))))
  596.  
  597. (defun minor-set-table (tablename table)
  598.   (cond
  599.    (tablename (minor-set-val tablename table))
  600.    (t (set-syntax-table table))))
  601.  
  602.  
  603. ;;; @@ Support functions for keymaps
  604.  
  605. (put 'keymap 'minor-current-function 'minor-current-map)
  606. (defun minor-current-map (valist)
  607.   (cdr (car (cdr (car valist)))))
  608.  
  609. (put 'keymap 'minor-base-function 'minor-base-map)
  610. (defun minor-base-map (valist)
  611.   (minor-current-map (minor-last valist)))
  612.  
  613. (put 'keymap 'minor-remove-function 'minor-remove-keymap-function)
  614. (defun minor-remove-keymap-function (mode keymapname valist)
  615.   ;; Remove MODE keymap from keymap KEYMAPNAME and values alist VALIST.
  616.   (let ((mapl (minor-list-find mode valist)) acs-list)
  617.     (cond
  618.      ((null mapl) valist)        ; Do nothing if not there
  619.      ((eq mapl valist)            ; Latest added keymap
  620.       (minor-set-map keymapname (minor-current-map (cdr valist)))
  621.       (cdr valist))
  622.      (t (setq acs-list (car mapl))    ; Not latest, cut it out.
  623.     (while (setq acs-list (cdr acs-list)) ; For each map and submap,
  624.       (let ((pred (minor-pred-map-pair (car acs-list) valist))) ; if fund
  625.         (if pred            ; predesseor,
  626.         (minor-replace-parent    ; cut map out from keymap chain.
  627.          pred (cdr (car acs-list))
  628.          (minor-next-map pred (cdr mapl))))))
  629.     (delq (car mapl) valist)))))    ; remove from values alist
  630.  
  631. (defun minor-set-map (keymapname map)
  632.   (cond
  633.    (keymapname (minor-set-val keymapname map))
  634.    (minor-non-local (use-global-map map))
  635.    (t (use-local-map map))))
  636.  
  637. ;;; The values alist for keymaps has the following format:
  638. ;;; (.. (MODE . ACS-LIST) ..)
  639. ;;; where ACS-LIST is the output of minor-accessible-copied-keymaps and has
  640. ;;; the format:
  641. ;;; (.. (KEY . MAP) ..)
  642. ;;; where KEY is the prefix key sequence for the keymap MAP and MAP is an
  643. ;;; entry in the parent chain that has the prefix KEY.
  644. ;;; The following two functions, move up resp. down the parent chain by
  645. ;;; searching up resp. down the values alist for maps with the same prefix.
  646.  
  647. (defun minor-pred-map-pair (pair valist)
  648.   (let ((key (car pair)) (pred nil) tmp)
  649.     ;; Search for the last (key . map) pair with prefix (car PAIR) that
  650.     ;; comes before PAIR in VALIST.
  651.     (while (and valist
  652.         (or (not (setq tmp (assoc key (car valist)))) ; no map or
  653.             (and (not (eq tmp pair)) (setq pred tmp))))    ; not eq pair
  654.       (setq valist (cdr valist)))
  655.     pred))
  656.  
  657. (defun minor-next-map (pair valist)
  658.   (let ((key (car pair)) (map nil))
  659.     ;; Find first keymap that has prefix key (car PAIR) in VALIST.
  660.     (while (and valist (not (setq map (assoc key (cdr (car valist))))))
  661.       (setq valist (cdr valist)))
  662.     (cdr-safe map)))
  663.  
  664. ;;; The following keymap handling code is partly system dependent. We use
  665. ;;; two macros to select the right code for emacs 18, emacs 19 or lemacs.
  666.  
  667. (put 'minor-iflemacs 'lisp-indent-hook 1)
  668. (defmacro minor-iflemacs (yy &rest nn)
  669.   (cond
  670.    ((fboundp 'keymap-parent) yy)    ; lemacs
  671.    ((null nn) ())
  672.    ((cdr nn) (cons 'progn nn))
  673.    (t (car nn))))
  674.  
  675. (put 'minor-if19 'lisp-indent-hook 1)
  676. (defmacro minor-if19 (yy &rest nn)
  677.   (cond
  678.    ((> (string-to-int emacs-version) 18) yy) ; lemacs or emacs 19
  679.    ((null nn) ())
  680.    ((cdr nn) (cons 'progn nn))
  681.    (t (car nn))))
  682.  
  683. (defun minor-replace-parent (pred omap nmap)
  684.   ;; In keymap chain (cdr PRED) replace map OMAP with map NMAP;
  685.   (let (tmp)            ; Look for element before omap in pred.
  686.     (setq pred (cdr pred))
  687.     (minor-if19 ()
  688.       ;; In emacs 18 skip keymap header.
  689.       (setq omap (cdr-safe omap))
  690.       (setq nmap (cdr-safe nmap)))
  691.     (while (and (not (eq omap
  692.              (setq tmp (minor-iflemacs (keymap-parent pred)
  693.                      (cdr pred)))))
  694.         (setq pred tmp)))
  695.     (if pred (minor-iflemacs (set-keymap-parent pred nmap)
  696.            (setcdr pred nmap)))))
  697.  
  698. (defun minor-try-accessible-keymaps (keymapname)
  699.   ;; Return the accessible-keymaps list for the keymap corresponding to
  700.   ;; KEYMAPNAME.
  701.   ;; For emacs 18 replace full keymaps by sparse.
  702.   (let ((keymap (cond
  703.          (keymapname (minor-get-val keymapname))
  704.          (minor-non-local (current-global-map))
  705.          (t (current-local-map)))))
  706.     (if (null keymap) (list (cons nil nil)) ; No keymap.
  707.       (minor-if19 (accessible-keymaps keymap)
  708.     (let* ((acs (accessible-keymaps keymap))
  709.            (tmp acs))
  710.       (while (and tmp (not (vectorp (cdr (car tmp))))) ; Look for full
  711.         (setq tmp (cdr tmp)))               ; keymaps.
  712.       (if tmp            ; If some full keymaps.
  713.           (cons (cons nil keymap)    ; Original here to restore at end.
  714.             (minor-accessible-copied-keymaps keymap)) ; Use sparse.
  715.         acs))))))        ; Only sparse keymaps.
  716.  
  717. (defun minor-accessible-copied-keymaps (keymap)
  718.   ;; This function does two things:
  719.   ;; 1. It copies KEYMAP. The only differrence from copy-keymap, is that it
  720.   ;; for lemacs also copies the whole parent chain. It would be better if
  721.   ;; only accessible keymaps where copied, but to do that one would need a
  722.   ;; version of copy-keymap that didn't copy sub-keymaps.
  723.   ;; 2. It returns an alist looking like that returned by accessible-keymaps
  724.   ;; but it doesn't include keymaps that have not been copied, i.e. keymaps
  725.   ;; accessible by indirection. It does include though, not shadowed keymaps
  726.   ;; in the parent chain.
  727.   ;; It would be much better if copy-keymap and accessible-keymaps had an
  728.   ;; optional flag that made them do this.
  729.   ;; In emacs 18 this function also converts all full keymaps to sparse
  730.   ;; keymaps.
  731.   (let* ((acs-list (list (cons (minor-if19 [] "")
  732.                    (setq keymap (copy-keymap keymap)))))
  733.      (tail acs-list)
  734.      (this acs-list)
  735.      tmap keys thismap
  736.      (acs-help        ; This function is called for each element of
  737.       (function            ; a keymap with MAPQ as the binding of
  738.        (lambda  (key mapq)        ; KEY in the keymap looked upon.
  739.          (and            ; If it is
  740.           (keymapp mapq)        ;  a keymap,
  741.           (not (symbolp mapq))    ;  not an indirection trough a symbol
  742.           (progn (setq key (minor-if19 (vconcat keys (list key))
  743.                  (concat keys (char-to-string key))))
  744.              (eq mapq (lookup-key keymap key))) ;  and not shadowed,
  745.           (setq tail (setcdr tail    ;  then add at end of acs-list.
  746.                  (list (cons key mapq)))))))))
  747.     (while this
  748.       (setq keys (car (car this)))
  749.       (setq thismap (cdr (car this)))
  750.       (minor-iflemacs
  751.       (while thismap
  752.         (map-keymap acs-help thismap)
  753.         (setq tmap thismap)
  754.         (if (setq thismap (keymap-parent thismap))
  755.         (set-keymap-parent tmap
  756.                    (setq thismap (copy-keymap thismap)))))
  757.     (minor-if19 ()
  758.       (if (vectorp thismap)    ; In emacs 18, convert full keymap to sparse.
  759.           (let ((nmap (list 'keymap)) (key (length thismap)) val)
  760.         (while (>= (setq key (1- key)) 0)
  761.           (if (setq val (aref thismap key))
  762.               (setcdr nmap (cons (cons key val) (cdr nmap)))))
  763.         (setcdr (car this) (setq thismap nmap))
  764.         (if (not (equal keys "")) (define-key keymap keys thismap)))))
  765.         (while (setq thismap (cdr thismap))
  766.       (let ((elem (car thismap)))
  767.         (minor-if19
  768.         (cond
  769.          ((consp elem) (funcall acs-help (car elem) (cdr elem)))
  770.          ((vectorp elem)
  771.           (let ((key (length elem)))
  772.             (while (>= (setq key (1- key)) 0)
  773.               (funcall acs-help key (aref elem key))))))
  774.           (funcall acs-help (car elem) (cdr elem))))))
  775.       (setq this (cdr this)))
  776.     acs-list))
  777.  
  778. ;;; @@ Emacs
  779.  
  780. ;;; Local Variables:
  781. ;;; mode: emacs-lisp
  782. ;;; eval: (put 'minor-iflemacs 'lisp-indent-hook 1)
  783. ;;; eval: (put 'minor-if19 'lisp-indent-hook 1)
  784. ;;; outline-regexp: ";;; @+\\|(......"
  785. ;;; End:
  786.