(pcomplete-comint-setup): If there's a choice, replace
[bpt/emacs.git] / lisp / cedet / mode-local.el
CommitLineData
7b232be9
CY
1;;; mode-local.el --- Support for mode local facilities
2;;
3;; Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation, Inc.
4;;
5;; Author: David Ponce <david@dponce.com>
6;; Maintainer: David Ponce <david@dponce.com>
7;; Created: 27 Apr 2004
8;; Keywords: syntax
9
10;; This file is part of GNU Emacs.
11
12;; GNU Emacs is free software: you can redistribute it and/or modify
13;; it under the terms of the GNU General Public License as published by
14;; the Free Software Foundation, either version 3 of the License, or
15;; (at your option) any later version.
16
17;; GNU Emacs is distributed in the hope that it will be useful,
18;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20;; GNU General Public License for more details.
21
22;; You should have received a copy of the GNU General Public License
23;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
24
25;;; Commentary:
26;;
27;; Each major mode will want to support a specific set of behaviors.
28;; Usually generic behaviors that need just a little bit of local
29;; specifics.
30;;
31;; This library permits the setting of override functions for tasks of
32;; that nature, and also provides reasonable defaults.
33;;
34;; There are buffer local variables, and frame local variables.
35;; This library gives the illusion of mode specific variables.
36;;
37;; You should use a mode-local variable or override to allow extension
38;; only if you expect a mode author to provide that extension. If a
39;; user might wish to customize a give variable or function then
40;; the existing customization mechanism should be used.
41
42;; To Do:
43;; Allow customization of a variable for a specific mode?
44;;
45;; Add macro for defining the '-default' functionality.
46
47;;; Code:
48
49(eval-when-compile (require 'cl))
50
51;;; Misc utilities
52;;
53(defun mode-local-map-file-buffers (function &optional predicate buffers)
54 "Run FUNCTION on every file buffer found.
55FUNCTION does not have arguments; when it is entered `current-buffer'
56is the currently selected file buffer.
57If optional argument PREDICATE is non nil, only select file buffers
58for which the function PREDICATE return non-nil.
59If optional argument BUFFERS is non-nil, it is a list of buffers to
60walk through. It defaults to `buffer-list'."
61 (dolist (b (or buffers (buffer-list)))
62 (and (buffer-live-p b) (buffer-file-name b)
63 (with-current-buffer b
64 (when (or (not predicate) (funcall predicate))
65 (funcall function))))))
66
67(defsubst get-mode-local-parent (mode)
68 "Return the mode parent of the major mode MODE.
69Return nil if MODE has no parent."
70 (or (get mode 'mode-local-parent)
71 (get mode 'derived-mode-parent)))
72
73(defun mode-local-equivalent-mode-p (mode)
74 "Is the major-mode in the current buffer equivalent to a mode in MODES."
75 (let ((modes nil))
76 (while mode
77 (setq modes (cons mode modes)
78 mode (get-mode-local-parent mode)))
79 modes))
80
81(defun mode-local-map-mode-buffers (function modes)
82 "Run FUNCTION on every file buffer with major mode in MODES.
83MODES can be a symbol or a list of symbols.
84FUNCTION does not have arguments."
85 (or (listp modes) (setq modes (list modes)))
86 (mode-local-map-file-buffers
87 function #'(lambda ()
88 (let ((mm (mode-local-equivalent-mode-p major-mode))
89 (ans nil))
90 (while (and (not ans) mm)
91 (setq ans (memq (car mm) modes)
92 mm (cdr mm)) )
93 ans))))
94\f
95;;; Hook machinery
96;;
97(defvar mode-local-init-hook nil
98 "Hook run after a new file buffer is created.
99The current buffer is the newly created file buffer.")
100
101(defvar mode-local-changed-mode-buffers nil
102 "List of buffers whose `major-mode' has changed recently.")
103
104(defvar mode-local--init-mode nil)
105
106(defsubst mode-local-initialized-p ()
107 "Return non-nil if mode local is initialized in current buffer.
108That is, if the current `major-mode' is equal to the major mode for
109which mode local bindings have been activated."
110 (eq mode-local--init-mode major-mode))
111
112(defun mode-local-post-major-mode-change ()
113 "Initialize mode-local facilities.
114This is run from `find-file-hook', and from `post-command-hook'
115after changing the major mode."
116 (remove-hook 'post-command-hook 'mode-local-post-major-mode-change nil)
117 (let ((buffers mode-local-changed-mode-buffers))
118 (setq mode-local-changed-mode-buffers nil)
119 (mode-local-map-file-buffers
120 (lambda ()
121 ;; Make sure variables are set up for this mode.
122 (activate-mode-local-bindings)
123 (run-hooks 'mode-local-init-hook))
124 (lambda ()
125 (not (mode-local-initialized-p)))
126 buffers)))
127
128(defun mode-local-on-major-mode-change ()
129 "Function called in `change-major-mode-hook'."
130 (add-to-list 'mode-local-changed-mode-buffers (current-buffer))
131 (add-hook 'post-command-hook 'mode-local-post-major-mode-change t nil))
132\f
133;;; Mode lineage
134;;
135(defsubst set-mode-local-parent (mode parent)
136 "Set parent of major mode MODE to PARENT mode.
137To work properly, this function should be called after PARENT mode
138local variables have been defined."
139 (put mode 'mode-local-parent parent)
140 ;; Refresh mode bindings to get mode local variables inherited from
141 ;; PARENT. To work properly, the following should be called after
142 ;; PARENT mode local variables have been defined.
143 (mode-local-map-mode-buffers #'activate-mode-local-bindings mode))
144
145(defmacro define-child-mode (mode parent &optional docstring)
146 "Make major mode MODE inherits behavior from PARENT mode.
147DOCSTRING is optional and not used.
148To work properly, this should be put after PARENT mode local variables
149definition."
150 `(set-mode-local-parent ',mode ',parent))
151
152(defun mode-local-use-bindings-p (this-mode desired-mode)
153 "Return non-nil if THIS-MODE can use bindings of DESIRED-MODE."
154 (let ((ans nil))
155 (while (and (not ans) this-mode)
156 (setq ans (eq this-mode desired-mode))
157 (setq this-mode (get-mode-local-parent this-mode)))
158 ans))
159
160\f
161;;; Core bindings API
162;;
163(defvar mode-local-symbol-table nil
164 "Buffer local mode bindings.
165These symbols provide a hook for a `major-mode' to specify specific
166behaviors. Use the function `mode-local-bind' to define new bindings.")
167(make-variable-buffer-local 'mode-local-symbol-table)
168
169(defvar mode-local-active-mode nil
170 "Major mode in which bindings are active.")
171
172(defsubst new-mode-local-bindings ()
173 "Return a new empty mode bindings symbol table."
174 (make-vector 13 0))
175
176(defun mode-local-bind (bindings &optional plist mode)
177 "Define BINDINGS in the specified environment.
178BINDINGS is a list of (VARIABLE . VALUE).
179Optional argument PLIST is a property list each VARIABLE symbol will
180be set to. The following properties have special meaning:
181
182- `constant-flag' if non-nil, prevent to rebind variables.
183- `mode-variable-flag' if non-nil, define mode variables.
184- `override-flag' if non-nil, define override functions.
185
186The `override-flag' and `mode-variable-flag' properties are mutually
187exclusive.
188
189If optional argument MODE is non-nil, it must be a major mode symbol.
190BINDINGS will be defined globally for this major mode. If MODE is
191nil, BINDINGS will be defined locally in the current buffer, in
192variable `mode-local-symbol-table'. The later should be done in MODE
193hook."
194 ;; Check plist consistency
195 (and (plist-get plist 'mode-variable-flag)
196 (plist-get plist 'override-flag)
197 (error "Bindings can't be both overrides and mode variables"))
198 (let (table variable varname value binding)
199 (if mode
200 (progn
201 ;; Install in given MODE symbol table. Create a new one if
202 ;; needed.
203 (setq table (or (get mode 'mode-local-symbol-table)
204 (new-mode-local-bindings)))
205 (put mode 'mode-local-symbol-table table))
206 ;; Fail if trying to bind mode variables in local context!
207 (if (plist-get plist 'mode-variable-flag)
208 (error "Mode required to bind mode variables"))
209 ;; Install in buffer local symbol table. Create a new one if
210 ;; needed.
211 (setq table (or mode-local-symbol-table
212 (setq mode-local-symbol-table
213 (new-mode-local-bindings)))))
214 (while bindings
215 (setq binding (car bindings)
216 bindings (cdr bindings)
217 varname (symbol-name (car binding))
218 value (cdr binding))
219 (if (setq variable (intern-soft varname table))
220 ;; Binding already exists
221 ;; Check rebind consistency
222 (cond
223 ((equal (symbol-value variable) value)
224 ;; Just ignore rebind with the same value.
225 )
226 ((get variable 'constant-flag)
227 (error "Can't change the value of constant `%s'"
228 variable))
229 ((and (get variable 'mode-variable-flag)
230 (plist-get plist 'override-flag))
231 (error "Can't rebind override `%s' as a mode variable"
232 variable))
233 ((and (get variable 'override-flag)
234 (plist-get plist 'mode-variable-flag))
235 (error "Can't rebind mode variable `%s' as an override"
236 variable))
237 (t
238 ;; Merge plist and assign new value
239 (setplist variable (append plist (symbol-plist variable)))
240 (set variable value)))
241 ;; New binding
242 (setq variable (intern varname table))
243 ;; Set new plist and assign initial value
244 (setplist variable plist)
245 (set variable value)))
246 ;; Return the symbol table used
247 table))
248
249(defsubst mode-local-symbol (symbol &optional mode)
250 "Return the mode local symbol bound with SYMBOL's name.
251Return nil if the mode local symbol doesn't exist.
252If optional argument MODE is nil, lookup first into locally bound
253symbols, then in those bound in current `major-mode' and its parents.
254If MODE is non-nil, lookup into symbols bound in that major mode and
255its parents."
256 (let ((name (symbol-name symbol)) bind)
257 (or mode
258 (setq mode mode-local-active-mode)
259 (setq mode major-mode
260 bind (and mode-local-symbol-table
261 (intern-soft name mode-local-symbol-table))))
262 (while (and mode (not bind))
263 (or (and (get mode 'mode-local-symbol-table)
264 (setq bind (intern-soft
265 name (get mode 'mode-local-symbol-table))))
266 (setq mode (get-mode-local-parent mode))))
267 bind))
268
269(defsubst mode-local-symbol-value (symbol &optional mode property)
270 "Return the value of the mode local symbol bound with SYMBOL's name.
271If optional argument MODE is non-nil, restrict lookup to that mode and
272its parents (see the function `mode-local-symbol' for more details).
273If optional argument PROPERTY is non-nil the mode local symbol must
274have that property set. Return nil if the symbol doesn't exist, or
275doesn't have PROPERTY set."
276 (and (setq symbol (mode-local-symbol symbol mode))
277 (or (not property) (get symbol property))
278 (symbol-value symbol)))
279\f
280;;; Mode local variables
281;;
282(defun activate-mode-local-bindings (&optional mode)
283 "Activate variables defined locally in MODE and its parents.
284That is, copy mode local bindings into corresponding buffer local
285variables.
286If MODE is not specified it defaults to current `major-mode'.
287Return the alist of buffer-local variables that have been changed.
288Elements are (SYMBOL . PREVIOUS-VALUE), describing one variable."
289 ;; Hack -
290 ;; do not do this if we are inside set-auto-mode as we may be in
291 ;; an initialization race condition.
292 (if (or (and (featurep 'emacs) (boundp 'keep-mode-if-same))
293 (and (featurep 'xemacs) (boundp 'just-from-file-name)))
294 ;; We are inside set-auto-mode, as this is an argument that is
295 ;; vaguely unique.
296
297 ;; This will make sure that when everything is over, this will get
298 ;; called and we won't be under set-auto-mode anymore.
299 (mode-local-on-major-mode-change)
300
301 ;; Do the normal thing.
302 (let (modes table old-locals)
303 (unless mode
304 (set (make-local-variable 'mode-local--init-mode) major-mode)
305 (setq mode major-mode))
306 ;; Get MODE's parents & MODE in the right order.
307 (while mode
308 (setq modes (cons mode modes)
309 mode (get-mode-local-parent mode)))
310 ;; Activate mode bindings following parent modes order.
311 (dolist (mode modes)
312 (when (setq table (get mode 'mode-local-symbol-table))
313 (mapatoms
314 #'(lambda (var)
315 (when (get var 'mode-variable-flag)
316 (let ((v (intern (symbol-name var))))
317 ;; Save the current buffer-local value of the
318 ;; mode-local variable.
319 (and (local-variable-p v (current-buffer))
320 (push (cons v (symbol-value v)) old-locals))
321 (set (make-local-variable v) (symbol-value var)))))
322 table)))
323 old-locals)))
324
325(defun deactivate-mode-local-bindings (&optional mode)
326 "Deactivate variables defined locally in MODE and its parents.
327That is, kill buffer local variables set from the corresponding mode
328local bindings.
329If MODE is not specified it defaults to current `major-mode'."
330 (unless mode
331 (kill-local-variable 'mode-local--init-mode)
332 (setq mode major-mode))
333 (let (table)
334 (while mode
335 (when (setq table (get mode 'mode-local-symbol-table))
336 (mapatoms
337 #'(lambda (var)
338 (when (get var 'mode-variable-flag)
339 (kill-local-variable (intern (symbol-name var)))))
340 table))
341 (setq mode (get-mode-local-parent mode)))))
342
343(defmacro with-mode-local-symbol (mode &rest body)
344 "With the local bindings of MODE symbol, evaluate BODY.
345The current mode bindings are saved, BODY is evaluated, and the saved
346bindings are restored, even in case of an abnormal exit.
347Value is what BODY returns.
348This is like `with-mode-local', except that MODE's value is used.
349To use the symbol MODE (quoted), use `with-mode-local'."
350 (let ((old-mode (make-symbol "mode"))
351 (old-locals (make-symbol "old-locals"))
352 (new-mode (make-symbol "new-mode"))
353 (local (make-symbol "local")))
354 `(let ((,old-mode mode-local-active-mode)
355 (,old-locals nil)
356 (,new-mode ,mode)
357 )
358 (unwind-protect
359 (progn
360 (deactivate-mode-local-bindings ,old-mode)
361 (setq mode-local-active-mode ,new-mode)
362 ;; Save the previous value of buffer-local variables
363 ;; changed by `activate-mode-local-bindings'.
364 (setq ,old-locals (activate-mode-local-bindings ,new-mode))
365 ,@body)
366 (deactivate-mode-local-bindings ,new-mode)
367 ;; Restore the previous value of buffer-local variables.
368 (dolist (,local ,old-locals)
369 (set (car ,local) (cdr ,local)))
370 ;; Restore the mode local variables.
371 (setq mode-local-active-mode ,old-mode)
372 (activate-mode-local-bindings ,old-mode)))))
373(put 'with-mode-local-symbol 'lisp-indent-function 1)
374
375(defmacro with-mode-local (mode &rest body)
376 "With the local bindings of MODE, evaluate BODY.
377The current mode bindings are saved, BODY is evaluated, and the saved
378bindings are restored, even in case of an abnormal exit.
379Value is what BODY returns.
380This lis like `with-mode-local-symbol', except that MODE is quoted
381and is note evaluated."
382 `(with-mode-local-symbol ',mode ,@body))
383(put 'with-mode-local 'lisp-indent-function 1)
384
385
386(defsubst mode-local-value (mode sym)
387 "Return the value of the MODE local variable SYM."
388 (or mode (error "Missing major mode symbol"))
389 (mode-local-symbol-value sym mode 'mode-variable-flag))
390
391(defmacro setq-mode-local (mode &rest args)
392 "Assign new values to variables local in MODE.
393MODE must be a major mode symbol.
394ARGS is a list (SYM VAL SYM VAL ...).
395The symbols SYM are variables; they are literal (not evaluated).
396The values VAL are expressions; they are evaluated.
397Set each SYM to the value of its VAL, locally in buffers already in
398MODE, or in buffers switched to that mode.
399Return the value of the last VAL."
400 (when args
401 (let (i ll bl sl tmp sym val)
402 (setq i 0)
403 (while args
404 (setq tmp (make-symbol (format "tmp%d" i))
405 i (1+ i)
406 sym (car args)
407 val (cadr args)
408 ll (cons (list tmp val) ll)
409 bl (cons `(cons ',sym ,tmp) bl)
410 sl (cons `(set (make-local-variable ',sym) ,tmp) sl)
411 args (cddr args)))
412 `(let* ,(nreverse ll)
413 ;; Save mode bindings
414 (mode-local-bind (list ,@bl) '(mode-variable-flag t) ',mode)
415 ;; Assign to local variables in all existing buffers in MODE
416 (mode-local-map-mode-buffers #'(lambda () ,@sl) ',mode)
417 ;; Return the last value
418 ,tmp)
419 )))
420
421(defmacro defvar-mode-local (mode sym val &optional docstring)
422 "Define MODE local variable SYM with value VAL.
423DOCSTRING is optional."
424 `(progn
425 (setq-mode-local ,mode ,sym ,val)
426 (put (mode-local-symbol ',sym ',mode)
427 'variable-documentation ,docstring)
428 ',sym))
429(put 'defvar-mode-local 'lisp-indent-function 'defun)
430
431(defmacro defconst-mode-local (mode sym val &optional docstring)
432 "Define MODE local constant SYM with value VAL.
433DOCSTRING is optional."
434 (let ((tmp (make-symbol "tmp")))
435 `(let (,tmp)
436 (setq-mode-local ,mode ,sym ,val)
437 (setq ,tmp (mode-local-symbol ',sym ',mode))
438 (put ,tmp 'constant-flag t)
439 (put ,tmp 'variable-documentation ,docstring)
440 ',sym)))
441(put 'defconst-mode-local 'lisp-indent-function 'defun)
442\f
443;;; Function overloading
444;;
445(defun make-obsolete-overload (old new)
446 "Mark OLD overload as obsoleted by NEW overload."
447 (put old 'overload-obsoleted-by new)
448 (put old 'mode-local-overload t)
449 (put new 'overload-obsolete old))
450
451(defsubst overload-obsoleted-by (overload)
452 "Get the overload symbol obsoleted by OVERLOAD.
453Return the obsolete symbol or nil if not found."
454 (get overload 'overload-obsolete))
455
456(defsubst overload-that-obsolete (overload)
457 "Return the overload symbol that obsoletes OVERLOAD.
458Return the symbol found or nil if OVERLOAD is not obsolete."
459 (get overload 'overload-obsoleted-by))
460
461(defsubst fetch-overload (overload)
462 "Return the current OVERLOAD function, or nil if not found.
463First, lookup for OVERLOAD into locally bound mode local symbols, then
464in those bound in current `major-mode' and its parents."
465 (or (mode-local-symbol-value overload nil 'override-flag)
466 ;; If an obsolete overload symbol exists, try it.
467 (and (overload-obsoleted-by overload)
468 (mode-local-symbol-value
469 (overload-obsoleted-by overload) nil 'override-flag))))
470
471(defun mode-local--override (name args body)
472 "Return the form that handles overloading of function NAME.
473ARGS are the arguments to the function.
474BODY is code that would be run when there is no override defined. The
475default is to call the function `NAME-default' with the appropriate
476arguments.
477See also the function `define-overload'."
478 (let* ((default (intern (format "%s-default" name)))
479 (overargs (delq '&rest (delq '&optional (copy-sequence args))))
480 (override (make-symbol "override")))
481 `(let ((,override (fetch-overload ',name)))
482 (if ,override
483 (funcall ,override ,@overargs)
484 ,@(or body `((,default ,@overargs)))))
485 ))
486
487(defun mode-local--expand-overrides (name args body)
488 "Expand override forms that overload function NAME.
489ARGS are the arguments to the function NAME.
490BODY is code where override forms are searched for expansion.
491Return result of expansion, or BODY if no expansion occurred.
492See also the function `define-overload'."
493 (let ((forms body)
494 (ditto t)
495 form xbody)
496 (while forms
497 (setq form (car forms))
498 (cond
499 ((atom form))
500 ((eq (car form) :override)
501 (setq form (mode-local--override name args (cdr form))))
502 ((eq (car form) :override-with-args)
503 (setq form (mode-local--override name (cadr form) (cddr form))))
504 ((setq form (mode-local--expand-overrides name args form))))
505 (setq ditto (and ditto (eq (car forms) form))
506 xbody (cons form xbody)
507 forms (cdr forms)))
508 (if ditto body (nreverse xbody))))
509
510(defun mode-local--overload-body (name args body)
511 "Return the code that implements overloading of function NAME.
512ARGS are the arguments to the function NAME.
513BODY specifies the overload code.
514See also the function `define-overload'."
515 (let ((result (mode-local--expand-overrides name args body)))
516 (if (eq body result)
517 (list (mode-local--override name args body))
518 result)))
519
520(defmacro define-overloadable-function (name args docstring &rest body)
521 "Define a new function, as with `defun' which can be overloaded.
522NAME is the name of the function to create.
523ARGS are the arguments to the function.
524DOCSTRING is a documentation string to describe the function. The
525docstring will automatically had details about its overload symbol
526appended to the end.
527BODY is code that would be run when there is no override defined. The
528default is to call the function `NAME-default' with the appropriate
529arguments.
530
531BODY can also include an override form that specifies which part of
532BODY is specifically overridden. This permits to specify common code
533run for both default and overridden implementations.
534An override form is one of:
535
536 1. (:override [OVERBODY])
537 2. (:override-with-args OVERARGS [OVERBODY])
538
539OVERBODY is the code that would be run when there is no override
540defined. The default is to call the function `NAME-default' with the
541appropriate arguments deduced from ARGS.
542OVERARGS is a list of arguments passed to the override and
543`NAME-default' function, in place of those deduced from ARGS."
544 `(eval-and-compile
545 (defun ,name ,args
546 ,docstring
547 ,@(mode-local--overload-body name args body))
548 (put ',name 'mode-local-overload t)))
549(put :override-with-args 'lisp-indent-function 1)
550
551(defalias 'define-overload 'define-overloadable-function)
552
553(defsubst function-overload-p (symbol)
554 "Return non-nil if SYMBOL is a function which can be overloaded."
555 (and symbol (symbolp symbol) (get symbol 'mode-local-overload)))
556
557(defmacro define-mode-local-override
558 (name mode args docstring &rest body)
559 "Define a mode specific override of the function overload NAME.
560Has meaning only if NAME has been created with `define-overload'.
561MODE is the major mode this override is being defined for.
562ARGS are the function arguments, which should match those of the same
563named function created with `define-overload'.
564DOCSTRING is the documentation string.
565BODY is the implementation of this function."
566 (let ((newname (intern (format "%s-%s" name mode))))
567 `(progn
568 (eval-and-compile
569 (defun ,newname ,args
570 ,(format "%s\n\nOverride %s in `%s' buffers."
571 docstring name mode)
572 ;; The body for this implementation
573 ,@body)
574 ;; For find-func to locate the definition of NEWNAME.
575 (put ',newname 'definition-name ',name))
576 (mode-local-bind '((,name . ,newname))
577 '(override-flag t)
578 ',mode))
579 ))
580\f
581;;; Read/Query Support
582(defun mode-local-read-function (prompt &optional initial hist default)
583 "Interactively read in the name of a mode-local function.
584PROMPT, INITIAL, HIST, and DEFAULT are the same as for `completing-read'."
585 (completing-read prompt obarray 'function-overload-p t initial hist default))
586\f
587;;; Help support
588;;
589(defun overload-docstring-extension (overload)
590 "Return the doc string that augments the description of OVERLOAD."
591 (let ((doc "\n\This function can be overloaded\
592 with `define-mode-local-override'.")
593 (sym (overload-obsoleted-by overload)))
594 (when sym
595 (setq doc (format "%s\nIt makes the overload `%s' obsolete."
596 doc sym)))
597 (setq sym (overload-that-obsolete overload))
598 (when sym
599 (setq doc (format "%s\nThis overload is obsoletes;\nUse `%s' instead."
600 doc sym)))
601 doc))
602
603(defun mode-local-augment-function-help (symbol)
604 "Augment the *Help* buffer for SYMBOL.
605SYMBOL is a function that can be overridden."
606 (with-current-buffer "*Help*"
607 (pop-to-buffer (current-buffer))
608 (unwind-protect
609 (progn
610 (toggle-read-only -1)
611 (goto-char (point-min))
612 (unless (re-search-forward "^$" nil t)
613 (goto-char (point-max))
614 (beginning-of-line)
615 (forward-line -1))
616 (insert (overload-docstring-extension symbol) "\n")
617 ;; NOTE TO SELF:
618 ;; LIST ALL LOADED OVERRIDES FOR SYMBOL HERE
619 )
620 (toggle-read-only 1))))
621
622;; Help for mode-local bindings.
623(defun mode-local-print-binding (symbol)
624 "Print the SYMBOL binding."
625 (let ((value (symbol-value symbol)))
626 (princ (format "\n `%s' value is\n " symbol))
627 (if (and value (symbolp value))
628 (princ (format "`%s'" value))
629 (let ((pt (point)))
630 (pp value)
631 (save-excursion
632 (goto-char pt)
633 (indent-sexp))))
634 (or (bolp) (princ "\n"))))
635
636(defun mode-local-print-bindings (table)
637 "Print bindings in TABLE."
638 (let (us ;; List of unpecified symbols
639 mc ;; List of mode local constants
640 mv ;; List of mode local variables
641 ov ;; List of overloaded functions
642 fo ;; List of final overloaded functions
643 )
644 ;; Order symbols by type
645 (mapatoms
646 #'(lambda (s)
647 (add-to-list (cond
648 ((get s 'mode-variable-flag)
649 (if (get s 'constant-flag) 'mc 'mv))
650 ((get s 'override-flag)
651 (if (get s 'constant-flag) 'fo 'ov))
652 ('us))
653 s))
654 table)
655 ;; Print symbols by type
656 (when us
657 (princ "\n !! Unpecified symbols\n")
658 (mapc 'mode-local-print-binding us))
659 (when mc
660 (princ "\n ** Mode local constants\n")
661 (mapc 'mode-local-print-binding mc))
662 (when mv
663 (princ "\n ** Mode local variables\n")
664 (mapc 'mode-local-print-binding mv))
665 (when fo
666 (princ "\n ** Final overloaded functions\n")
667 (mapc 'mode-local-print-binding fo))
668 (when ov
669 (princ "\n ** Overloaded functions\n")
670 (mapc 'mode-local-print-binding ov))
671 ))
672
673(defun mode-local-describe-bindings-2 (buffer-or-mode)
674 "Display mode local bindings active in BUFFER-OR-MODE."
675 (let (table mode)
676 (princ "Mode local bindings active in ")
677 (cond
678 ((bufferp buffer-or-mode)
679 (with-current-buffer buffer-or-mode
680 (setq table mode-local-symbol-table
681 mode major-mode))
682 (princ (format "%S\n" buffer-or-mode))
683 )
684 ((symbolp buffer-or-mode)
685 (setq mode buffer-or-mode)
686 (princ (format "`%s'\n" buffer-or-mode))
687 )
688 ((signal 'wrong-type-argument
689 (list 'buffer-or-mode buffer-or-mode))))
690 (when table
691 (princ "\n- Buffer local\n")
692 (mode-local-print-bindings table))
693 (while mode
694 (setq table (get mode 'mode-local-symbol-table))
695 (when table
696 (princ (format "\n- From `%s'\n" mode))
697 (mode-local-print-bindings table))
698 (setq mode (get-mode-local-parent mode)))))
699
700(defun mode-local-describe-bindings-1 (buffer-or-mode &optional interactive-p)
701 "Display mode local bindings active in BUFFER-OR-MODE.
702Optional argument INTERACTIVE-P is non-nil if the calling command was
703invoked interactively."
704 (if (fboundp 'with-displaying-help-buffer)
705 ;; XEmacs
706 (with-displaying-help-buffer
707 #'(lambda ()
708 (with-current-buffer standard-output
709 (mode-local-describe-bindings-2 buffer-or-mode)
710 (when (fboundp 'frob-help-extents)
711 (goto-char (point-min))
712 (frob-help-extents standard-output)))))
713 ;; GNU Emacs
714 (when (fboundp 'help-setup-xref)
715 (help-setup-xref
716 (list 'mode-local-describe-bindings-1 buffer-or-mode)
717 interactive-p))
718 (with-output-to-temp-buffer (help-buffer) ; "*Help*"
719 (with-current-buffer standard-output
720 (mode-local-describe-bindings-2 buffer-or-mode)))))
721
722(defun describe-mode-local-bindings (buffer)
723 "Display mode local bindings active in BUFFER."
724 (interactive "b")
725 (when (setq buffer (get-buffer buffer))
726 (mode-local-describe-bindings-1 buffer (interactive-p))))
727
728(defun describe-mode-local-bindings-in-mode (mode)
729 "Display mode local bindings active in MODE hierarchy."
730 (interactive
731 (list (completing-read
732 "Mode: " obarray
733 #'(lambda (s) (get s 'mode-local-symbol-table))
734 t (symbol-name major-mode))))
735 (when (setq mode (intern-soft mode))
736 (mode-local-describe-bindings-1 mode (interactive-p))))
737\f
738;; ;;; find-func support (Emacs 21.4, or perhaps 22.1)
739;; ;;
740;; (condition-case nil
741;; ;; Try to get find-func so we can modify it.
742;; (require 'find-func)
743;; (error nil))
744
745;; (when (boundp 'find-function-regexp)
746;; (unless (string-match "ine-overload" find-function-regexp)
747;; (if (string-match "(def\\\\(" find-function-regexp)
748;; (let ((end (match-end 0))
749;; )
750;; (setq find-function-regexp
751;; (concat (substring find-function-regexp 0 end)
752;; "ine-overload\\|ine-mode-local-override\\|"
753;; "ine-child-mode\\|"
754;; (substring find-function-regexp end)))))))
755\f
756;;; edebug support
757;;
758(defun mode-local-setup-edebug-specs ()
759 "Define edebug specification for mode local macros."
760 (def-edebug-spec setq-mode-local
761 (symbolp &rest symbolp form))
762 (def-edebug-spec defvar-mode-local
763 (&define symbolp name def-form [ &optional stringp ] ))
764 (def-edebug-spec defconst-mode-local
765 defvar-mode-local)
766 (def-edebug-spec define-overload
767 (&define name lambda-list stringp def-body))
768 (def-edebug-spec define-overloadable-function
769 (&define name lambda-list stringp def-body))
770 (def-edebug-spec define-mode-local-override
771 (&define name symbolp lambda-list stringp def-body)))
772
773(add-hook 'edebug-setup-hook 'mode-local-setup-edebug-specs)
774
775(add-hook 'find-file-hook 'mode-local-post-major-mode-change)
776(add-hook 'change-major-mode-hook 'mode-local-on-major-mode-change)
777
778(provide 'mode-local)
779
3999968a 780;; arch-tag: 14b77823-f93c-4b3d-9116-495f69a6ec07
7b232be9 781;;; mode-local.el ends here