blob: 48c9746178f8b6508a76e5a83d1589f6403e0670 (
plain)
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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
|
;;; multi-mode.el --- Allowing multiple major modes in a buffer.
;;;****************************************************************************
;;; $Id: multi-mode.el,v 1.2 1994/06/11 22:08:22 gerd Exp gerd $
;;;****************************************************************************
;;
;;
;; Description:
;;
;; Sometimes it is desirable to have different major modes in one
;; buffer. One such case occurs when editing comments in a
;; programming language buffer. Here it might be desirable to use a
;; totally different mode than the one used for editing the program
;; code itself.
;;
;; I have adoped this practice for editing Prolog. The code itself is
;; edited in prolog-mode, whereas the comments are edited in
;; LaTeX-mode.
;;
;; It is desirable to use different modes instead of enhancing one
;; mode because much efford has already been put in various modes
;; which needs not to be duplicated.
;;
;; The multi-mode minor mode provides a means to accomplish such a
;; feature.
;;
;; The modes are described by initializing strings. I assume that
;; certain tokens (i.e. transition strings) indicate the places where
;; a new mode should be entered. To determine the mode at a point it
;; is only neccessary to find the last transition string before point.
;;
;; The desired modes are described in a list of pairs or triples
;; consisting of a transition string and a mode (a symbol).
;; Optionally a function symbol can be specified which is evaluated to
;; activate the desired mode. Additionally the mode in absence of
;; preceding transition strings has to be specified.
;;
;;
;;
;;
;; Installation:
;; 1. Ensure that multi-mode.el is on the load-path.
;; 2. For efficiency it might be desirable to byte-compile
;; multi-mode.el.
;; 3. Put the following in your .emacs file or a similar place
;; where it is loaded when needed.
;;
;; (autoload 'multi-mode
;; "multi-mode"
;; "Allowing multiple major modes in a buffer."
;; t)
;;
;; 4. Define your own incarnation of multi mode to serve as major
;; mode. This can be done in your .emacs file. E.g.
;;
;; (defun multi-c-fundamental-mode () (interactive)
;; (multi-mode 1
;; 'c-mode
;; '(\"/*\" fundamental-mode my-fundamental-setup)
;; '(\"*/\" c-mode)))
;;
;; This major mode can now be used to turn on the multi-mode in the
;; minibuffer, or in the auto-mode-alist, or in the local variables
;; of a file. E.g.
;;
;; (setq auto-mode-alist
;; (cons '("\\.[ch]$" . multi-c-fundamental-mode)
;; auto-mode-alist)
;;
;;
;; Bugs and Problems:
;; - It is rather easy to hang my whole workstation when
;; multi-mode-transitions has not a proper value.
;; For sake of efficiency I omit finer type checking to avoid this
;; problem.
;; CURE: Never try to change the variable yourself. Use the
;; function multi-mode instead.
;;
;; To do:
;; - The generalization of transition strings to regular expressions
;; seems to be straight forward. For efficience reasons I will do it
;; only upon request.
;;
;; - No provisions have been made to make the key bindings accessible
;; in all modes. This might be desirable.
;;
;;
;; Changes:
;; $Log: multi-mode.el,v $
; Revision 1.2 1994/06/11 22:08:22 gerd
; *** empty log message ***
;
; Revision 1.1 1994/05/24 12:41:30 gerd
; A little hack has been enhanced to a minor mode.
;;
;;
;; Author:
;; Gerd Neugebauer
;; Ödenburger Str. 16
;; 64295 Darmstadt (Germany)
;;
;; Net: gerd@intellektik.informatik.th-darmstadt.de
;; gerd@imn.th-leipzig.de
;;
;;*****************************************************************************
;; LCD Archive Entry:
;; multi-mode|Gerd Neugebauer|gerd@intellektik.informatik.th-darmstadt.de|
;; Minor mode allowing multiple major modes in a single buffer.|
;; $Date: 1994/06/11 22:08:22 $|$Revision: 1.2 $||
;;*****************************************************************************
;;
;; Copyright (C) 1994 Gerd Neugebauer
;;
;; multi-mode.el is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY. No author or distributor
;; accepts responsibility to anyone for the consequences of using it
;; or for whether it serves any particular purpose or works at all,
;; unless he says so in writing. Refer to the GNU General Public
;; License for full details.
;;
;; Everyone is granted permission to copy, modify and redistribute
;; multi-mode.el, but only under the conditions described in the
;; GNU General Public License. A copy of this license is
;; supposed to have been given to you along with GNU Emacs so you
;; can know your rights and responsibilities. It should be in a
;; file named COPYING. Among other things, the copyright notice
;; and this notice must be preserved on all copies.
;;
;;;----------------------------------------------------------------------------
;;; Variable definitions and initializations
(make-variable-buffer-local 'multi-mode-transitions)
(defvar multi-mode-transitions nil
"Transition definition for the multi-mode minor mode.
")
(defvar multi-mode-beware '( (not isearch-mode) )
"List of forms to check if multi-mode is desirable. If all forms evaluate to
t then a mode switch is allowed.")
(make-variable-buffer-local 'multi-mode)
(defvar multi-mode nil
"This variable indicates if the multi-mode minor mode is active.")
;;;----------------------------------------------------------------------------
;;; Definition of the minor mode
(defun multi-mode (&optional arg &optional initial-mode &rest transitions)
"Allowing multiple major modes in a buffer.
Toggle multi mode. With numeric argument turn on multi mode if the argument
is positive.
Sometimes it is desirable to have different major modes in one buffer. One
such case occurs when editing comments in a programming language buffer.
Here it might be desirable to use a totally different mode than the one
used for editing the program code itself.
It is desirable to use different modes instead of enhancing one mode
because much effort has already been put in various modes which needs not
to be duplicated.
The multi-mode minor mode provides a means to accomplish such a feature.
The modes are described by initializing strings. I assume that certain
tokens (i.e. transition strings) indicate the places where a new mode
should be entered. To determine the mode at a point it is only necessary
to find the last transition string before point.
The desired modes are described in a list of pairs or triples consisting of
a transition string and a mode (a symbol). Optionally a function symbol
can be specified which is evaluated to activate the desired mode.
Additionally the mode in absence of preceding transition strings has to be
specified.
When called not interactively there are additional arguments to specify the
transitions.
INITIAL-MODE is a symbol denoting a major mode to be used before any
transition strings are present before point.
The remaining optional arguments are pairs
(TOKEN MODE)
or triples
(TOKEN MODE FUNCTION)
The first element TOKEN is a string which indicates the token to activate
the mode MODE specified in the second argument. Optionally a third argument
can be given. The symbol FUNCTION is used as a function to be called to
turn on the mode given as second argument. It defaults to MODE.
Consider the following example:
(multi-mode 1
c-mode
(\"/*\" fundamental-mode my-fundamental-setup)
(\"*/\" c-mode))
The first argument forces multi-mode to be turned on. The second argument
declares the default mode to be c-mode. Thus at the beginning of the buffer
c-mode is turned on. If a '/*' is found before point then fundamental-mode
may be turned on. This is done using the function my-fundamental-setup.
If a '*/' is found before point then c-mode may be activated. Which mode is
used depends on the last activating pattern before point. In this example
everything between /* and */ can be edited in fundamental mode. Everything
else is in c-mode.
See also the documentation of multi-mode-beware."
(interactive "P")
(setq multi-mode ;
(if (null arg) (not multi-mode) ; Toggle multi-mode if no arg
(> (prefix-numeric-value arg) 0))) ; otherwise turn it on or off
(let ((ok t) ; result of type check
(tt transitions) ; transition table
trans) ; transition
(while tt ; Check the transition table
(setq trans (car tt) ; Get a single transition
tt (cdr tt)) ; Advance the table pointer
(if (or (not (listp trans)) ; Check the transition
(not (stringp (first trans))) ;
(not (symbolp (second trans)))) ;
(setq ok nil ; set error mark
tt nil)) ; stop checking
)
(if (and ok ; if transition table is ok
initial-mode ; check the initial-mode
(symbolp initial-mode)) ;
(setq multi-mode-transitions ; set the local variable
(cons initial-mode transitions))) ;
)
(force-mode-line-update) ; show the new state
)
(or (assq 'multi-mode minor-mode-alist)
(setq minor-mode-alist (cons '(multi-mode " MULTI") minor-mode-alist)))
(defun multi-mode-update-mode ()
"Perform a mode switch if multi-mode is active."
;; This function only starts to work if multi mode is on
;; and a transition table is defined. Additionally the forms in
;; multi-mode-beware are evaluated to see if a mode switch is desirable.
(if (and multi-mode
multi-mode-transitions
(eval (cons 'and multi-mode-beware))
)
(let* ((transition (cdr multi-mode-transitions)) ; get transitions
(mode (car multi-mode-transitions)) ; get initial mode
(mode-function mode) ; set initial mode switching function
(pos -1) ; set the initial position of a transit
hit ; new position of a transition string
tt) ; transition table
(while transition
(setq tt (car transition) ; extract a single transition
transition (cdr transition)) ; advance the transitions
(setq hit (save-excursion ; we don't want to change point
(if (search-backward ; unfailing backward search
(first tt) ; for the transition pattern
nil
t)
(point) ; upon sucess use the position
-2))) ; otherwise try to ignore it
(if (> hit pos) ; pattern is newer than prev.
(setq pos hit ; then save position
mode (second tt) ; the desired mode and an
mode-function (or (third tt) mode)); optional function
)
)
(if (not (equal major-mode mode)) ; if mode needs switching
(let ((transitions multi-mode-transitions)) ; save transition table
(if (fboundp mode-function) ; if mode function is defined
(funcall mode-function)) ; then call it
(setq multi-mode-transitions transitions ; restore transition
multi-mode t))) ; and minor mode
)
)
)
;;;----------------------------------------------------------------------------
;;; The function is hooked into the post-command-hook to be called after
;;; each function.
;;;
(add-hook 'post-command-hook 'multi-mode-update-mode)
(provide 'multi-mode)
|