multi-mode.el 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. ;;; multi-mode.el --- Allowing multiple major modes in a buffer.
  2. ;;;****************************************************************************
  3. ;;; $Id: multi-mode.el,v 1.2 2002/11/15 09:33:50 marmotte Exp $
  4. ;;;****************************************************************************
  5. ;;
  6. ;;
  7. ;; Description:
  8. ;;
  9. ;; Sometimes it is desirable to have different major modes in one
  10. ;; buffer. One such case occurs when editing comments in a
  11. ;; programming language buffer. Here it might be desirable to use a
  12. ;; totally different mode than the one used for editing the program
  13. ;; code itself.
  14. ;;
  15. ;; I have adoped this practice for editing Prolog. The code itself is
  16. ;; edited in prolog-mode, whereas the comments are edited in
  17. ;; LaTeX-mode.
  18. ;;
  19. ;; It is desirable to use different modes instead of enhancing one
  20. ;; mode because much efford has already been put in various modes
  21. ;; which needs not to be duplicated.
  22. ;;
  23. ;; The multi-mode minor mode provides a means to accomplish such a
  24. ;; feature.
  25. ;;
  26. ;; The modes are described by initializing strings. I assume that
  27. ;; certain tokens (i.e. transition strings) indicate the places where
  28. ;; a new mode should be entered. To determine the mode at a point it
  29. ;; is only neccessary to find the last transition string before point.
  30. ;;
  31. ;; The desired modes are described in a list of pairs or triples
  32. ;; consisting of a transition string and a mode (a symbol).
  33. ;; Optionally a function symbol can be specified which is evaluated to
  34. ;; activate the desired mode. Additionally the mode in absence of
  35. ;; preceding transition strings has to be specified.
  36. ;;
  37. ;;
  38. ;;
  39. ;;
  40. ;; Installation:
  41. ;; 1. Ensure that multi-mode.el is on the load-path.
  42. ;; 2. For efficiency it might be desirable to byte-compile
  43. ;; multi-mode.el.
  44. ;; 3. Put the following in your .emacs file or a similar place
  45. ;; where it is loaded when needed.
  46. ;;
  47. ;; (autoload 'multi-mode
  48. ;; "multi-mode"
  49. ;; "Allowing multiple major modes in a buffer."
  50. ;; t)
  51. ;;
  52. ;; 4. Define your own incarnation of multi mode to serve as major
  53. ;; mode. This can be done in your .emacs file. E.g.
  54. ;;
  55. ;; (defun multi-c-fundamental-mode () (interactive)
  56. ;; (multi-mode 1
  57. ;; 'c-mode
  58. ;; '(\"/*\" fundamental-mode my-fundamental-setup)
  59. ;; '(\"*/\" c-mode)))
  60. ;;
  61. ;; This major mode can now be used to turn on the multi-mode in the
  62. ;; minibuffer, or in the auto-mode-alist, or in the local variables
  63. ;; of a file. E.g.
  64. ;;
  65. ;; (setq auto-mode-alist
  66. ;; (cons '("\\.[ch]$" . multi-c-fundamental-mode)
  67. ;; auto-mode-alist)
  68. ;;
  69. ;;
  70. ;; Bugs and Problems:
  71. ;; - It is rather easy to hang my whole workstation when
  72. ;; multi-mode-transitions has not a proper value.
  73. ;; For sake of efficiency I omit finer type checking to avoid this
  74. ;; problem.
  75. ;; CURE: Never try to change the variable yourself. Use the
  76. ;; function multi-mode instead.
  77. ;;
  78. ;; To do:
  79. ;; - The generalization of transition strings to regular expressions
  80. ;; seems to be straight forward. For efficience reasons I will do it
  81. ;; only upon request.
  82. ;;
  83. ;; - No provisions have been made to make the key bindings accessible
  84. ;; in all modes. This might be desirable.
  85. ;;
  86. ;;
  87. ;; Changes:
  88. ;; $Log: multi-mode.el,v $
  89. ;; Revision 1.2 2002/11/15 09:33:50 marmotte
  90. ;;
  91. ;; * Make most of the config compile
  92. ;;
  93. ;; Revision 1.1 2002/11/14 08:36:38 marmotte
  94. ;; * Changed load of file, to load-path, so that the config files are not
  95. ;; always loaded.
  96. ;; * Added multi-mode to the emacs config
  97. ;; * Added support for php and jsp, throught multi-mode.
  98. ;; - Still need to add a version of c++-mode for php, cause somethings are
  99. ;; not really well handled...
  100. ;;
  101. ; Revision 1.2 1994/06/11 22:08:22 gerd
  102. ; *** empty log message ***
  103. ;
  104. ; Revision 1.1 1994/05/24 12:41:30 gerd
  105. ; A little hack has been enhanced to a minor mode.
  106. ;;
  107. ;;
  108. ;; Author:
  109. ;; Gerd Neugebauer
  110. ;; Vdenburger Str. 16
  111. ;; 64295 Darmstadt (Germany)
  112. ;;
  113. ;; Net: gerd@intellektik.informatik.th-darmstadt.de
  114. ;; gerd@imn.th-leipzig.de
  115. ;;
  116. ;;*****************************************************************************
  117. ;; LCD Archive Entry:
  118. ;; multi-mode|Gerd Neugebauer|gerd@intellektik.informatik.th-darmstadt.de|
  119. ;; Minor mode allowing multiple major modes in a single buffer.|
  120. ;; 11-Jun-1994|1.2|~/misc/multi-mode.el.Z|
  121. ;;*****************************************************************************
  122. ;;
  123. ;; Copyright (C) 1994 Gerd Neugebauer
  124. ;;
  125. ;; multi-mode.el is distributed in the hope that it will be useful,
  126. ;; but WITHOUT ANY WARRANTY. No author or distributor
  127. ;; accepts responsibility to anyone for the consequences of using it
  128. ;; or for whether it serves any particular purpose or works at all,
  129. ;; unless he says so in writing. Refer to the GNU General Public
  130. ;; License for full details.
  131. ;;
  132. ;; Everyone is granted permission to copy, modify and redistribute
  133. ;; multi-mode.el, but only under the conditions described in the
  134. ;; GNU General Public License. A copy of this license is
  135. ;; supposed to have been given to you along with GNU Emacs so you
  136. ;; can know your rights and responsibilities. It should be in a
  137. ;; file named COPYING. Among other things, the copyright notice
  138. ;; and this notice must be preserved on all copies.
  139. ;;
  140. ;;;----------------------------------------------------------------------------
  141. ;;; Variable definitions and initializations
  142. (make-variable-buffer-local 'multi-mode-transitions)
  143. (defvar multi-mode-transitions nil
  144. "Transition definition for the multi-mode minor mode.
  145. ")
  146. (defvar multi-mode-beware '( (not isearch-mode) )
  147. "List of forms to check if multi-mode is desirable. If all forms evaluate to
  148. t then a mode switch is allowed.")
  149. (make-variable-buffer-local 'multi-mode)
  150. (defvar multi-mode nil
  151. "This variable indicates if the multi-mode minor mode is active.")
  152. ;;;----------------------------------------------------------------------------
  153. ;;; Definition of the minor mode
  154. (defun multi-mode (&optional arg &optional initial-mode &rest transitions)
  155. "Allowing multiple major modes in a buffer.
  156. Toggle multi mode. With numeric argument turn on multi mode if the argument
  157. is positive.
  158. Sometimes it is desirable to have different major modes in one buffer. One
  159. such case occurs when editing comments in a programming language buffer.
  160. Here it might be desirable to use a totally different mode than the one
  161. used for editing the program code itself.
  162. It is desirable to use different modes instead of enhancing one mode
  163. because much effort has already been put in various modes which needs not
  164. to be duplicated.
  165. The multi-mode minor mode provides a means to accomplish such a feature.
  166. The modes are described by initializing strings. I assume that certain
  167. tokens (i.e. transition strings) indicate the places where a new mode
  168. should be entered. To determine the mode at a point it is only necessary
  169. to find the last transition string before point.
  170. The desired modes are described in a list of pairs or triples consisting of
  171. a transition string and a mode (a symbol). Optionally a function symbol
  172. can be specified which is evaluated to activate the desired mode.
  173. Additionally the mode in absence of preceding transition strings has to be
  174. specified.
  175. When called not interactively there are additional arguments to specify the
  176. transitions.
  177. INITIAL-MODE is a symbol denoting a major mode to be used before any
  178. transition strings are present before point.
  179. The remaining optional arguments are pairs
  180. (TOKEN MODE)
  181. or triples
  182. (TOKEN MODE FUNCTION)
  183. The first element TOKEN is a string which indicates the token to activate
  184. the mode MODE specified in the second argument. Optionally a third argument
  185. can be given. The symbol FUNCTION is used as a function to be called to
  186. turn on the mode given as second argument. It defaults to MODE.
  187. Consider the following example:
  188. (multi-mode 1
  189. c-mode
  190. (\"/*\" fundamental-mode my-fundamental-setup)
  191. (\"*/\" c-mode))
  192. The first argument forces multi-mode to be turned on. The second argument
  193. declares the default mode to be c-mode. Thus at the beginning of the buffer
  194. c-mode is turned on. If a '/*' is found before point then fundamental-mode
  195. may be turned on. This is done using the function my-fundamental-setup.
  196. If a '*/' is found before point then c-mode may be activated. Which mode is
  197. used depends on the last activating pattern before point. In this example
  198. everything between /* and */ can be edited in fundamental mode. Everything
  199. else is in c-mode.
  200. See also the documentation of multi-mode-beware.";"
  201. (interactive "P")
  202. (setq multi-mode ;
  203. (if (null arg) (not multi-mode) ; Toggle multi-mode if no arg
  204. (> (prefix-numeric-value arg) 0))) ; otherwise turn it on or off
  205. (let ((ok t) ; result of type check
  206. (tt transitions) ; transition table
  207. trans) ; transition
  208. (while tt ; Check the transition table
  209. (setq trans (car tt) ; Get a single transition
  210. tt (cdr tt)) ; Advance the table pointer
  211. (if (or (not (listp trans)) ; Check the transition
  212. (not (stringp (first trans))) ;
  213. (not (symbolp (second trans)))) ;
  214. (setq ok nil ; set error mark
  215. tt nil)) ; stop checking
  216. )
  217. (if (and ok ; if transition table is ok
  218. initial-mode ; check the initial-mode
  219. (symbolp initial-mode)) ;
  220. (setq multi-mode-transitions ; set the local variable
  221. (cons initial-mode transitions))) ;
  222. )
  223. (force-mode-line-update) ; show the new state
  224. )
  225. (or (assq 'multi-mode minor-mode-alist)
  226. (setq minor-mode-alist (cons '(multi-mode " MULTI") minor-mode-alist)))
  227. (defun multi-mode-update-mode ()
  228. "Perform a mode switch if multi-mode is active."
  229. ;; This function only starts to work if multi mode is on
  230. ;; and a transition table is defined. Additionally the forms in
  231. ;; multi-mode-beware are evaluated to see if a mode switch is desirable.
  232. (if (and multi-mode
  233. multi-mode-transitions
  234. (eval (cons 'and multi-mode-beware))
  235. )
  236. (let* ((transition (cdr multi-mode-transitions)) ; get transitions
  237. (mode (car multi-mode-transitions)) ; get initial mode
  238. (mode-function mode) ; set initial mode switching function
  239. (pos -1) ; set the initial position of a transit
  240. hit ; new position of a transition string
  241. tt) ; transition table
  242. (while transition
  243. (setq tt (car transition) ; extract a single transition
  244. transition (cdr transition)) ; advance the transitions
  245. (setq hit (save-excursion ; we don't want to change point
  246. (if (search-backward ; unfailing backward search
  247. (first tt) ; for the transition pattern
  248. nil
  249. t)
  250. (point) ; upon sucess use the position
  251. -2))) ; otherwise try to ignore it
  252. (if (> hit pos) ; pattern is newer than prev.
  253. (setq pos hit ; then save position
  254. mode (second tt) ; the desired mode and an
  255. mode-function (or (third tt) mode)); optional function
  256. )
  257. )
  258. (if (not (equal major-mode mode)) ; if mode needs switching
  259. (let ((transitions multi-mode-transitions)) ; save transition table
  260. (if (fboundp mode-function) ; if mode function is defined
  261. (funcall mode-function)) ; then call it
  262. (setq multi-mode-transitions transitions ; restore transition
  263. multi-mode t))) ; and minor mode
  264. )
  265. )
  266. )
  267. ;;;----------------------------------------------------------------------------
  268. ;;; The function is hooked into the post-command-hook to be called after
  269. ;;; each function.
  270. ;;;
  271. (add-hook 'post-command-hook 'multi-mode-update-mode)
  272. (provide 'multi-mode)