]> code.delx.au - gnu-emacs/blob - lisp/cedet/semantic/util-modes.el
Merge changes from emacs-23 branch.
[gnu-emacs] / lisp / cedet / semantic / util-modes.el
1 ;;; semantic/util-modes.el --- Semantic minor modes
2
3 ;; Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010
4 ;; Free Software Foundation, Inc.
5
6 ;; Authors: Eric M. Ludlam <zappo@gnu.org>
7 ;; David Ponce <david@dponce.com>
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 ;; Semantic utility minor modes.
28 ;;
29
30 ;;; Code:
31
32 ;; FIXME: compiling util-modes.el seems to require loading util-modes.el,
33 ;; so if the previous compilation generated a file that fails to load,
34 ;; recompiling fails to fix the problem.
35 (require 'semantic)
36
37 ;;; Group for all semantic enhancing modes
38 (defgroup semantic-modes nil
39 "Minor modes associated with the Semantic architecture."
40 :group 'semantic)
41
42 ;;;;
43 ;;;; Semantic minor modes stuff
44 ;;;;
45 (defcustom semantic-update-mode-line t
46 "If non-nil, show enabled minor modes in the mode line.
47 Only minor modes that are not turned on globally are shown in the mode
48 line."
49 :group 'semantic
50 :type 'boolean
51 :require 'semantic/util-modes
52 :initialize 'custom-initialize-default
53 :set (lambda (sym val)
54 (set-default sym val)
55 ;; Update status of all Semantic enabled buffers
56 (semantic-mode-line-update)))
57
58 (defcustom semantic-mode-line-prefix
59 (propertize "S" 'face 'bold)
60 "Prefix added to minor mode indicators in the mode line."
61 :group 'semantic
62 :type 'string
63 :require 'semantic/util-modes
64 :initialize 'custom-initialize-default)
65
66 (defvar semantic-minor-modes-format nil
67 "Mode line format showing Semantic minor modes which are locally enabled.
68 It is displayed in the mode line.")
69 (put 'semantic-minor-modes-format 'risky-local-variable t)
70
71 (defvar semantic-minor-mode-alist nil
72 "Alist saying how to show Semantic minor modes in the mode line.
73 Like variable `minor-mode-alist'.")
74
75 (defun semantic-mode-line-update ()
76 "Update mode line format of Semantic minor modes.
77 Only minor modes that are locally enabled are shown in the mode line."
78 (setq semantic-minor-modes-format nil)
79 (dolist (x semantic-minor-mode-alist)
80 (setq minor-mode-alist (delq (assq (car x) minor-mode-alist)
81 minor-mode-alist)))
82 (when semantic-update-mode-line
83 (let ((locals '()))
84 ;; Select the minor modes that aren't enabled globally and who
85 ;; have a non-empty "name".
86 (dolist (x semantic-minor-mode-alist)
87 (unless (or (memq (car x) semantic-init-hook)
88 (not (string-match "^[ ]*\\(.+\\)" (cadr x))))
89 (push (list (car x) (concat "/" (match-string 1 (cadr x)))) locals)))
90 ;; Then build the format spec.
91 (when locals
92 (let ((prefix (if (string-match "^[ ]*\\(.+\\)"
93 semantic-mode-line-prefix)
94 (match-string 1 semantic-mode-line-prefix)
95 "S")))
96 (setq semantic-minor-modes-format
97 `((:eval (if (or ,@(mapcar 'car locals))
98 ,(concat " " prefix)))))
99 ;; It would be easier to just put `locals' inside
100 ;; semantic-minor-modes-format, but then things like
101 ;; mode-line-minor-mode-help can't find the right major mode
102 ;; any more. So instead, we carefully put the minor modes
103 ;; in minor-mode-alist.
104 (let* ((elem (or (assq 'semantic-minor-modes-format
105 minor-mode-alist)
106 ;; FIXME: This entry is meaningless for
107 ;; mode-line-minor-mode-help.
108 '(semantic-minor-modes-format
109 semantic-minor-modes-format)))
110 (tail (or (memq elem minor-mode-alist)
111 (setq minor-mode-alist
112 (cons elem minor-mode-alist)))))
113 (setcdr tail (nconc locals (cdr tail)))))))))
114
115 (defun semantic-desktop-ignore-this-minor-mode (buffer)
116 "Installed as a minor-mode initializer for Desktop mode.
117 BUFFER is the buffer to not initialize a Semantic minor mode in."
118 nil)
119
120 (defun semantic-add-minor-mode (toggle name)
121 "Register a new Semantic minor mode.
122 TOGGLE is a symbol which is the name of a buffer-local variable that
123 is toggled on or off to say whether the minor mode is active or not.
124 It is also an interactive function to toggle the mode.
125
126 NAME specifies what will appear in the mode line when the minor mode
127 is active. NAME should be either a string starting with a space, or a
128 symbol whose value is such a string."
129 ;; Record how to display this minor mode in the mode line
130 (let ((mm (assq toggle semantic-minor-mode-alist)))
131 (if mm
132 (setcdr mm (list name))
133 (setq semantic-minor-mode-alist (cons (list toggle name)
134 semantic-minor-mode-alist))))
135 (semantic-mode-line-update)
136
137 ;; Semantic minor modes don't work w/ Desktop restore.
138 ;; This line will disable this minor mode from being restored
139 ;; by Desktop.
140 (when (boundp 'desktop-minor-mode-handlers)
141 (add-to-list 'desktop-minor-mode-handlers
142 (cons toggle 'semantic-desktop-ignore-this-minor-mode))))
143
144 (defun semantic-toggle-minor-mode-globally (mode &optional arg)
145 "Toggle minor mode MODE in every Semantic enabled buffer.
146 Return non-nil if MODE is turned on in every Semantic enabled buffer.
147 If ARG is positive, enable, if it is negative, disable.
148 MODE must be a valid minor mode defined in `minor-mode-alist' and must be
149 too an interactive function used to toggle the mode."
150 ;; FIXME: All callers should pass a -1 or +1 argument.
151 (or (and (fboundp mode) (or (assq mode minor-mode-alist) ;Needed?
152 (assq mode semantic-minor-mode-alist)))
153 (error "Semantic minor mode %s not found" mode))
154 ;; Add or remove the MODE toggle function from `semantic-init-hook'.
155 (cond
156 ;; Turn off if ARG < 0
157 ((< arg 0) (remove-hook 'semantic-init-hook mode))
158 ;; Turn on if ARG > 0
159 ((> arg 0) (add-hook 'semantic-init-hook mode))
160 ;; Otherwise just check MODE state
161 (t
162 (error "semantic-toggle-minor-mode-globally: arg should be -1 or 1")))
163 ;; Update the minor mode format.
164 (semantic-mode-line-update)
165 ;; Then turn MODE on or off in every Semantic enabled buffer.
166 (semantic-map-buffers #'(lambda () (funcall mode arg))))
167 \f
168 ;;;;
169 ;;;; Minor mode to highlight areas that a user edits.
170 ;;;;
171
172 ;;;###autoload
173 (define-minor-mode global-semantic-highlight-edits-mode
174 "Toggle global use of option `semantic-highlight-edits-mode'.
175 If ARG is positive or nil, enable, if it is negative, disable."
176 :global t :group 'semantic :group 'semantic-modes
177 (semantic-toggle-minor-mode-globally
178 'semantic-highlight-edits-mode
179 (if global-semantic-highlight-edits-mode 1 -1)))
180
181 (defcustom semantic-highlight-edits-mode-hook nil
182 "Hook run at the end of function `semantic-highlight-edits-mode'."
183 :group 'semantic
184 :type 'hook)
185
186 (defface semantic-highlight-edits-face
187 '((((class color) (background dark))
188 ;; Put this back to something closer to black later.
189 (:background "gray20"))
190 (((class color) (background light))
191 (:background "gray90")))
192 "Face used to show dirty tokens in `semantic-highlight-edits-mode'."
193 :group 'semantic-faces)
194
195 (defun semantic-highlight-edits-new-change-hook-fcn (overlay)
196 "Function set into `semantic-edits-new-change-hook'.
197 Argument OVERLAY is the overlay created to mark the change.
198 This function will set the face property on this overlay."
199 (semantic-overlay-put overlay 'face 'semantic-highlight-edits-face))
200
201 (defvar semantic-highlight-edits-mode-map
202 (let ((km (make-sparse-keymap)))
203 km)
204 "Keymap for highlight-edits minor mode.")
205
206 ;;;###autoload
207 (define-minor-mode semantic-highlight-edits-mode
208 "Minor mode for highlighting changes made in a buffer.
209 Changes are tracked by semantic so that the incremental parser can work
210 properly.
211 This mode will highlight those changes as they are made, and clear them
212 when the incremental parser accounts for those edits.
213 With prefix argument ARG, turn on if positive, otherwise off. The
214 minor mode can be turned on only if semantic feature is available and
215 the current buffer was set up for parsing. Return non-nil if the
216 minor mode is enabled."
217 :keymap semantic-highlight-edits-mode-map
218 (if semantic-highlight-edits-mode
219 (if (not (and (featurep 'semantic) (semantic-active-p)))
220 (progn
221 ;; Disable minor mode if semantic stuff not available
222 (setq semantic-highlight-edits-mode nil)
223 (error "Buffer %s was not set up for parsing"
224 (buffer-name)))
225 (semantic-make-local-hook 'semantic-edits-new-change-hooks)
226 (add-hook 'semantic-edits-new-change-hooks
227 'semantic-highlight-edits-new-change-hook-fcn nil t))
228 ;; Remove hooks
229 (remove-hook 'semantic-edits-new-change-hooks
230 'semantic-highlight-edits-new-change-hook-fcn t)))
231
232 (semantic-add-minor-mode 'semantic-highlight-edits-mode
233 "e")
234 \f
235 ;;;;
236 ;;;; Minor mode to show unmatched-syntax elements
237 ;;;;
238
239 ;;;###autoload
240 (define-minor-mode global-semantic-show-unmatched-syntax-mode
241 "Toggle global use of option `semantic-show-unmatched-syntax-mode'.
242 If ARG is positive or nil, enable, if it is negative, disable."
243 :global t :group 'semantic :group 'semantic-modes
244 ;; Not needed because it's autoloaded instead.
245 ;; :require 'semantic/util-modes
246 (semantic-toggle-minor-mode-globally
247 'semantic-show-unmatched-syntax-mode
248 (if global-semantic-show-unmatched-syntax-mode 1 -1)))
249
250 (defcustom semantic-show-unmatched-syntax-mode-hook nil
251 "Hook run at the end of function `semantic-show-unmatched-syntax-mode'."
252 :group 'semantic
253 :type 'hook)
254
255 (defface semantic-unmatched-syntax-face
256 '((((class color) (background dark))
257 (:underline "red"))
258 (((class color) (background light))
259 (:underline "red")))
260 "Face used to show unmatched syntax in.
261 The face is used in `semantic-show-unmatched-syntax-mode'."
262 :group 'semantic-faces)
263
264 (defsubst semantic-unmatched-syntax-overlay-p (overlay)
265 "Return non-nil if OVERLAY is an unmatched syntax one."
266 (eq (semantic-overlay-get overlay 'semantic) 'unmatched))
267
268 (defun semantic-showing-unmatched-syntax-p ()
269 "Return non-nil if an unmatched syntax overlay was found in buffer."
270 (let ((ol (semantic-overlays-in (point-min) (point-max)))
271 found)
272 (while (and ol (not found))
273 (setq found (semantic-unmatched-syntax-overlay-p (car ol))
274 ol (cdr ol)))
275 found))
276
277 (defun semantic-show-unmatched-lex-tokens-fetch ()
278 "Fetch a list of unmatched lexical tokens from the current buffer.
279 Uses the overlays which have accurate bounds, and rebuilds what was
280 originally passed in."
281 (let ((ol (semantic-overlays-in (point-min) (point-max)))
282 (ustc nil))
283 (while ol
284 (if (semantic-unmatched-syntax-overlay-p (car ol))
285 (setq ustc (cons (cons 'thing
286 (cons (semantic-overlay-start (car ol))
287 (semantic-overlay-end (car ol))))
288 ustc)))
289 (setq ol (cdr ol)))
290 (nreverse ustc))
291 )
292
293 (defun semantic-clean-unmatched-syntax-in-region (beg end)
294 "Remove all unmatched syntax overlays between BEG and END."
295 (let ((ol (semantic-overlays-in beg end)))
296 (while ol
297 (if (semantic-unmatched-syntax-overlay-p (car ol))
298 (semantic-overlay-delete (car ol)))
299 (setq ol (cdr ol)))))
300
301 (defsubst semantic-clean-unmatched-syntax-in-buffer ()
302 "Remove all unmatched syntax overlays found in current buffer."
303 (semantic-clean-unmatched-syntax-in-region
304 (point-min) (point-max)))
305
306 (defsubst semantic-clean-token-of-unmatched-syntax (token)
307 "Clean the area covered by TOKEN of unmatched syntax markers."
308 (semantic-clean-unmatched-syntax-in-region
309 (semantic-tag-start token) (semantic-tag-end token)))
310
311 (defun semantic-show-unmatched-syntax (syntax)
312 "Function set into `semantic-unmatched-syntax-hook'.
313 This will highlight elements in SYNTAX as unmatched syntax."
314 ;; This is called when `semantic-show-unmatched-syntax-mode' is
315 ;; enabled. Highlight the unmatched syntax, and then add a semantic
316 ;; property to that overlay so we can add it to the official list of
317 ;; semantic supported overlays. This gets it cleaned up for errors,
318 ;; buffer cleaning, and the like.
319 (semantic-clean-unmatched-syntax-in-buffer) ;Clear previous highlighting
320 (if syntax
321 (let (o)
322 (while syntax
323 (setq o (semantic-make-overlay (semantic-lex-token-start (car syntax))
324 (semantic-lex-token-end (car syntax))))
325 (semantic-overlay-put o 'semantic 'unmatched)
326 (semantic-overlay-put o 'face 'semantic-unmatched-syntax-face)
327 (setq syntax (cdr syntax))))
328 ))
329
330 (defun semantic-next-unmatched-syntax (point &optional bound)
331 "Find the next overlay for unmatched syntax after POINT.
332 Do not search past BOUND if non-nil."
333 (save-excursion
334 (goto-char point)
335 (let ((os point) (ol nil))
336 (while (and os (< os (or bound (point-max))) (not ol))
337 (setq os (semantic-overlay-next-change os))
338 (when os
339 ;; Get overlays at position
340 (setq ol (semantic-overlays-at os))
341 ;; find the overlay that belongs to semantic
342 ;; and starts at the found position.
343 (while (and ol (listp ol))
344 (and (semantic-unmatched-syntax-overlay-p (car ol))
345 (setq ol (car ol)))
346 (if (listp ol)
347 (setq ol (cdr ol))))))
348 ol)))
349
350 (defvar semantic-show-unmatched-syntax-mode-map
351 (let ((km (make-sparse-keymap)))
352 (define-key km "\C-c,`" 'semantic-show-unmatched-syntax-next)
353 km)
354 "Keymap for command `semantic-show-unmatched-syntax-mode'.")
355
356 ;;;###autoload
357 (define-minor-mode semantic-show-unmatched-syntax-mode
358 "Minor mode to highlight unmatched lexical syntax tokens.
359 When a parser executes, some elements in the buffer may not match any
360 parser rules. These text characters are considered unmatched syntax.
361 Often time, the display of unmatched syntax can expose coding
362 problems before the compiler is run.
363
364 With prefix argument ARG, turn on if positive, otherwise off. The
365 minor mode can be turned on only if semantic feature is available and
366 the current buffer was set up for parsing. Return non-nil if the
367 minor mode is enabled.
368
369 \\{semantic-show-unmatched-syntax-mode-map}"
370 :keymap semantic-show-unmatched-syntax-mode-map
371 (if semantic-show-unmatched-syntax-mode
372 (if (not (and (featurep 'semantic) (semantic-active-p)))
373 (progn
374 ;; Disable minor mode if semantic stuff not available
375 (setq semantic-show-unmatched-syntax-mode nil)
376 (error "Buffer %s was not set up for parsing"
377 (buffer-name)))
378 ;; Add hooks
379 (semantic-make-local-hook 'semantic-unmatched-syntax-hook)
380 (add-hook 'semantic-unmatched-syntax-hook
381 'semantic-show-unmatched-syntax nil t)
382 (semantic-make-local-hook 'semantic-pre-clean-token-hooks)
383 (add-hook 'semantic-pre-clean-token-hooks
384 'semantic-clean-token-of-unmatched-syntax nil t)
385 ;; Show unmatched syntax elements
386 (if (not (semantic--umatched-syntax-needs-refresh-p))
387 (semantic-show-unmatched-syntax
388 (semantic-unmatched-syntax-tokens))))
389 ;; Remove hooks
390 (remove-hook 'semantic-unmatched-syntax-hook
391 'semantic-show-unmatched-syntax t)
392 (remove-hook 'semantic-pre-clean-token-hooks
393 'semantic-clean-token-of-unmatched-syntax t)
394 ;; Cleanup unmatched-syntax highlighting
395 (semantic-clean-unmatched-syntax-in-buffer)))
396
397 (semantic-add-minor-mode 'semantic-show-unmatched-syntax-mode
398 "u")
399
400 (defun semantic-show-unmatched-syntax-next ()
401 "Move forward to the next occurrence of unmatched syntax."
402 (interactive)
403 (let ((o (semantic-next-unmatched-syntax (point))))
404 (if o
405 (goto-char (semantic-overlay-start o)))))
406
407 \f
408 ;;;;
409 ;;;; Minor mode to display the parser state in the modeline.
410 ;;;;
411
412 ;;;###autoload
413 (define-minor-mode global-semantic-show-parser-state-mode
414 "Toggle global use of option `semantic-show-parser-state-mode'.
415 If ARG is positive or nil, enable, if it is negative, disable."
416 :global t :group 'semantic
417 ;; Not needed because it's autoloaded instead.
418 ;; :require 'semantic/util-modes
419 (semantic-toggle-minor-mode-globally
420 'semantic-show-parser-state-mode
421 (if global-semantic-show-parser-state-mode 1 -1)))
422
423 (defcustom semantic-show-parser-state-mode-hook nil
424 "Hook run at the end of function `semantic-show-parser-state-mode'."
425 :group 'semantic
426 :type 'hook)
427
428 (defvar semantic-show-parser-state-mode-map
429 (let ((km (make-sparse-keymap)))
430 km)
431 "Keymap for show-parser-state minor mode.")
432
433 ;;;###autoload
434 (define-minor-mode semantic-show-parser-state-mode
435 "Minor mode for displaying parser cache state in the modeline.
436 The cache can be in one of three states. They are
437 Up to date, Partial reparse needed, and Full reparse needed.
438 The state is indicated in the modeline with the following characters:
439 `-' -> The cache is up to date.
440 `!' -> The cache requires a full update.
441 `~' -> The cache needs to be incrementally parsed.
442 `%' -> The cache is not currently parseable.
443 `@' -> Auto-parse in progress (not set here.)
444 With prefix argument ARG, turn on if positive, otherwise off. The
445 minor mode can be turned on only if semantic feature is available and
446 the current buffer was set up for parsing. Return non-nil if the
447 minor mode is enabled."
448 :keymap semantic-show-parser-state-mode-map
449 (if semantic-show-parser-state-mode
450 (if (not (and (featurep 'semantic) (semantic-active-p)))
451 (progn
452 ;; Disable minor mode if semantic stuff not available
453 (setq semantic-show-parser-state-mode nil)
454 (error "Buffer %s was not set up for parsing"
455 (buffer-name)))
456 ;; Set up mode line
457
458 (when (not
459 (memq 'semantic-show-parser-state-string mode-line-modified))
460 (setq mode-line-modified
461 (append mode-line-modified
462 '(semantic-show-parser-state-string))))
463 ;; Add hooks
464 (semantic-make-local-hook 'semantic-edits-new-change-hooks)
465 (add-hook 'semantic-edits-new-change-hooks
466 'semantic-show-parser-state-marker nil t)
467 (semantic-make-local-hook 'semantic-edits-incremental-reparse-failed-hook)
468 (add-hook 'semantic-edits-incremental-reparse-failed-hook
469 'semantic-show-parser-state-marker nil t)
470 (semantic-make-local-hook 'semantic-after-partial-cache-change-hook)
471 (add-hook 'semantic-after-partial-cache-change-hook
472 'semantic-show-parser-state-marker nil t)
473 (semantic-make-local-hook 'semantic-after-toplevel-cache-change-hook)
474 (add-hook 'semantic-after-toplevel-cache-change-hook
475 'semantic-show-parser-state-marker nil t)
476 (semantic-show-parser-state-marker)
477
478 (semantic-make-local-hook 'semantic-before-auto-parse-hooks)
479 (add-hook 'semantic-before-auto-parse-hooks
480 'semantic-show-parser-state-auto-marker nil t)
481 (semantic-make-local-hook 'semantic-after-auto-parse-hooks)
482 (add-hook 'semantic-after-auto-parse-hooks
483 'semantic-show-parser-state-marker nil t)
484
485 (semantic-make-local-hook 'semantic-before-idle-scheduler-reparse-hook)
486 (add-hook 'semantic-before-idle-scheduler-reparse-hook
487 'semantic-show-parser-state-auto-marker nil t)
488 (semantic-make-local-hook 'semantic-after-idle-scheduler-reparse-hook)
489 (add-hook 'semantic-after-idle-scheduler-reparse-hook
490 'semantic-show-parser-state-marker nil t))
491 ;; Remove parts of mode line
492 (setq mode-line-modified
493 (delq 'semantic-show-parser-state-string mode-line-modified))
494 ;; Remove hooks
495 (remove-hook 'semantic-edits-new-change-hooks
496 'semantic-show-parser-state-marker t)
497 (remove-hook 'semantic-edits-incremental-reparse-failed-hook
498 'semantic-show-parser-state-marker t)
499 (remove-hook 'semantic-after-partial-cache-change-hook
500 'semantic-show-parser-state-marker t)
501 (remove-hook 'semantic-after-toplevel-cache-change-hook
502 'semantic-show-parser-state-marker t)
503
504 (remove-hook 'semantic-before-auto-parse-hooks
505 'semantic-show-parser-state-auto-marker t)
506 (remove-hook 'semantic-after-auto-parse-hooks
507 'semantic-show-parser-state-marker t)
508
509 (remove-hook 'semantic-before-idle-scheduler-reparse-hook
510 'semantic-show-parser-state-auto-marker t)
511 (remove-hook 'semantic-after-idle-scheduler-reparse-hook
512 'semantic-show-parser-state-marker t)))
513
514 (semantic-add-minor-mode 'semantic-show-parser-state-mode
515 "")
516
517 (defvar semantic-show-parser-state-string nil
518 "String showing the parser state for this buffer.
519 See `semantic-show-parser-state-marker' for details.")
520 (make-variable-buffer-local 'semantic-show-parser-state-string)
521
522 (defun semantic-show-parser-state-marker (&rest ignore)
523 "Set `semantic-show-parser-state-string' to indicate parser state.
524 This marker is one of the following:
525 `-' -> The cache is up to date.
526 `!' -> The cache requires a full update.
527 `~' -> The cache needs to be incrementally parsed.
528 `%' -> The cache is not currently parseable.
529 `@' -> Auto-parse in progress (not set here.)
530 Arguments IGNORE are ignored, and accepted so this can be used as a hook
531 in many situations."
532 (setq semantic-show-parser-state-string
533 (cond ((semantic-parse-tree-needs-rebuild-p)
534 "!")
535 ((semantic-parse-tree-needs-update-p)
536 "^")
537 ((semantic-parse-tree-unparseable-p)
538 "%")
539 (t
540 "-")))
541 ;;(message "Setup mode line indicator to [%s]" semantic-show-parser-state-string)
542 )
543
544 (defun semantic-show-parser-state-auto-marker ()
545 "Hook function run before an autoparse.
546 Set up `semantic-show-parser-state-marker' to show `@'
547 to indicate a parse in progress."
548 (unless (semantic-parse-tree-up-to-date-p)
549 (setq semantic-show-parser-state-string "@")
550 ;; For testing.
551 ;;(sit-for 1)
552 ))
553
554 \f
555 ;;;;
556 ;;;; Minor mode to make function decls sticky.
557 ;;;;
558
559 ;;;###autoload
560 (define-minor-mode global-semantic-stickyfunc-mode
561 "Toggle global use of option `semantic-stickyfunc-mode'.
562 If ARG is positive or nil, enable, if it is negative, disable."
563 :global t :group 'semantic :group 'semantic-modes
564 ;; Not needed because it's autoloaded instead.
565 ;; :require 'semantic/util-modes
566 (semantic-toggle-minor-mode-globally
567 'semantic-stickyfunc-mode (if global-semantic-stickyfunc-mode 1 -1)))
568
569 (defcustom semantic-stickyfunc-mode-hook nil
570 "Hook run at the end of function `semantic-stickyfunc-mode'."
571 :group 'semantic
572 :type 'hook)
573
574 (defvar semantic-stickyfunc-mode-map
575 (let ((km (make-sparse-keymap)))
576 (define-key km [ header-line down-mouse-1 ] 'semantic-stickyfunc-menu)
577 km)
578 "Keymap for stickyfunc minor mode.")
579
580 (defvar semantic-stickyfunc-popup-menu nil
581 "Menu used if the user clicks on the header line used by stickyfunc mode.")
582
583 (easy-menu-define
584 semantic-stickyfunc-popup-menu
585 semantic-stickyfunc-mode-map
586 "Stickyfunc Menu"
587 '("Stickyfunc Mode" :visible (progn nil)
588 [ "Copy Headerline Tag" senator-copy-tag
589 :active (semantic-current-tag)
590 :help "Copy the current tag to the tag ring"]
591 [ "Kill Headerline Tag" senator-kill-tag
592 :active (semantic-current-tag)
593 :help "Kill tag text to the kill ring, and copy the tag to the tag ring"
594 ]
595 [ "Copy Headerline Tag to Register" senator-copy-tag-to-register
596 :active (semantic-current-tag)
597 :help "Copy the current tag to a register"
598 ]
599 [ "Narrow To Headerline Tag" senator-narrow-to-defun
600 :active (semantic-current-tag)
601 :help "Narrow to the bounds of the current tag"]
602 [ "Fold Headerline Tag" senator-fold-tag-toggle
603 :active (semantic-current-tag)
604 :style toggle
605 :selected (let ((tag (semantic-current-tag)))
606 (and tag (semantic-tag-folded-p tag)))
607 :help "Fold the current tag to one line"
608 ]
609 "---"
610 [ "About This Header Line"
611 (lambda () (interactive)
612 (describe-function 'semantic-stickyfunc-mode)) t])
613 )
614
615 (defcustom semantic-stickyfunc-indent-string
616 (if (and window-system (not (featurep 'xemacs)))
617 (concat
618 (condition-case nil
619 ;; Test scroll bar location
620 (let ((charwidth (frame-char-width))
621 (scrollpos (frame-parameter (selected-frame)
622 'vertical-scroll-bars))
623 )
624 (if (or (eq scrollpos 'left)
625 ;; Now wait a minute. If you turn scroll-bar-mode
626 ;; on, then off, the new value is t, not left.
627 ;; Will this mess up older emacs where the default
628 ;; was on the right? I don't think so since they don't
629 ;; support a header line.
630 (eq scrollpos t))
631 (let ((w (when (boundp 'scroll-bar-width)
632 (symbol-value 'scroll-bar-width))))
633
634 (if (not w)
635 (setq w (frame-parameter (selected-frame)
636 'scroll-bar-width)))
637
638 ;; in 21.2, the frame parameter is sometimes empty
639 ;; so we need to get the value here.
640 (if (not w)
641 (setq w (+ (get 'scroll-bar-width 'x-frame-parameter)
642 ;; In 21.4, or perhaps 22.1 the x-frame
643 ;; parameter is different from the frame
644 ;; parameter by only 1 pixel.
645 1)))
646
647 (if (not w)
648 " "
649 (setq w (+ 2 w)) ; Some sort of border around
650 ; the scrollbar.
651 (make-string (/ w charwidth) ? )))
652 ""))
653 (error ""))
654 (condition-case nil
655 ;; Test fringe size.
656 (let* ((f (window-fringes))
657 (fw (car f))
658 (numspace (/ fw (frame-char-width)))
659 )
660 (make-string numspace ? ))
661 (error
662 ;; Well, the fancy new Emacs functions failed. Try older
663 ;; tricks.
664 (condition-case nil
665 ;; I'm not so sure what's up with the 21.1-21.3 fringe.
666 ;; It looks to be about 1 space wide.
667 (if (get 'fringe 'face)
668 " "
669 "")
670 (error ""))))
671 )
672 ;; Not Emacs or a window system means no scrollbar or fringe,
673 ;; and perhaps not even a header line to worry about.
674 "")
675 "String used to indent the stickyfunc header.
676 Customize this string to match the space used by scrollbars and
677 fringe so it does not appear that the code is moving left/right
678 when it lands in the sticky line."
679 :group 'semantic
680 :type 'string)
681
682 (defvar semantic-stickyfunc-old-hlf nil
683 "Value of the header line when entering stickyfunc mode.")
684
685 (defconst semantic-stickyfunc-header-line-format
686 (cond ((featurep 'xemacs)
687 nil)
688 ((>= emacs-major-version 22)
689 '(:eval (list
690 ;; Magic bit I found on emacswiki.
691 (propertize " " 'display '((space :align-to 0)))
692 (semantic-stickyfunc-fetch-stickyline))))
693 ((= emacs-major-version 21)
694 '(:eval (list semantic-stickyfunc-indent-string
695 (semantic-stickyfunc-fetch-stickyline))))
696 (t nil))
697 "The header line format used by stickyfunc mode.")
698
699 ;;;###autoload
700 (define-minor-mode semantic-stickyfunc-mode
701 "Minor mode to show the title of a tag in the header line.
702 Enables/disables making the header line of functions sticky.
703 A function (or other tag class specified by
704 `semantic-stickyfunc-sticky-classes') has a header line, meaning the
705 first line which describes the rest of the construct. This first
706 line is what is displayed in the header line.
707
708 With prefix argument ARG, turn on if positive, otherwise off. The
709 minor mode can be turned on only if semantic feature is available and
710 the current buffer was set up for parsing. Return non-nil if the
711 minor mode is enabled."
712 ;; Don't need indicator. It's quite visible
713 :keymap semantic-stickyfunc-mode-map
714 (if semantic-stickyfunc-mode
715 (progn
716 (unless (and (featurep 'semantic) (semantic-active-p))
717 ;; Disable minor mode if semantic stuff not available
718 (setq semantic-stickyfunc-mode nil)
719 (error "Buffer %s was not set up for parsing" (buffer-name)))
720 (unless (boundp 'default-header-line-format)
721 ;; Disable if there are no header lines to use.
722 (setq semantic-stickyfunc-mode nil)
723 (error "Sticky Function mode requires Emacs 21"))
724 ;; Enable the mode
725 ;; Save previous buffer local value of header line format.
726 (when (and (local-variable-p 'header-line-format (current-buffer))
727 (not (eq header-line-format
728 semantic-stickyfunc-header-line-format)))
729 (set (make-local-variable 'semantic-stickyfunc-old-hlf)
730 header-line-format))
731 (setq header-line-format semantic-stickyfunc-header-line-format))
732 ;; Disable sticky func mode
733 ;; Restore previous buffer local value of header line format if
734 ;; the current one is the sticky func one.
735 (when (eq header-line-format semantic-stickyfunc-header-line-format)
736 (kill-local-variable 'header-line-format)
737 (when (local-variable-p 'semantic-stickyfunc-old-hlf (current-buffer))
738 (setq header-line-format semantic-stickyfunc-old-hlf)
739 (kill-local-variable 'semantic-stickyfunc-old-hlf)))))
740
741 (defvar semantic-stickyfunc-sticky-classes
742 '(function type)
743 "List of tag classes which stickyfunc will display in the header line.")
744 (make-variable-buffer-local 'semantic-stickyfunc-sticky-classes)
745
746 (defun semantic-stickyfunc-tag-to-stick ()
747 "Return the tag to stick at the current point."
748 (let ((tags (nreverse (semantic-find-tag-by-overlay (point)))))
749 ;; Get rid of non-matching tags.
750 (while (and tags
751 (not (member
752 (semantic-tag-class (car tags))
753 semantic-stickyfunc-sticky-classes))
754 )
755 (setq tags (cdr tags)))
756 (car tags)))
757
758 (defun semantic-stickyfunc-fetch-stickyline ()
759 "Make the function at the top of the current window sticky.
760 Capture its function declaration, and place it in the header line.
761 If there is no function, disable the header line."
762 (let ((str
763 (save-excursion
764 (goto-char (window-start (selected-window)))
765 (forward-line -1)
766 (end-of-line)
767 ;; Capture this function
768 (let* ((tag (semantic-stickyfunc-tag-to-stick)))
769 ;; TAG is nil if there was nothing of the appropriate type there.
770 (if (not tag)
771 ;; Set it to be the text under the header line
772 (buffer-substring (point-at-bol) (point-at-eol))
773 ;; Get it
774 (goto-char (semantic-tag-start tag))
775 ;; Klaus Berndl <klaus.berndl@sdm.de>:
776 ;; goto the tag name; this is especially needed for languages
777 ;; like c++ where a often used style is like:
778 ;; void
779 ;; ClassX::methodM(arg1...)
780 ;; {
781 ;; ...
782 ;; }
783 ;; Without going to the tag-name we would get"void" in the
784 ;; header line which is IMHO not really useful
785 (search-forward (semantic-tag-name tag) nil t)
786 (buffer-substring (point-at-bol) (point-at-eol))
787 ))))
788 (start 0))
789 (while (string-match "%" str start)
790 (setq str (replace-match "%%" t t str 0)
791 start (1+ (match-end 0)))
792 )
793 ;; In 21.4 (or 22.1) the heder doesn't expand tabs. Hmmmm.
794 ;; We should replace them here.
795 ;;
796 ;; This hack assumes that tabs are kept smartly at tab boundaries
797 ;; instead of in a tab boundary where it might only represent 4 spaces.
798 (while (string-match "\t" str start)
799 (setq str (replace-match " " t t str 0)))
800 str))
801
802 (defun semantic-stickyfunc-menu (event)
803 "Popup a menu that can help a user understand stickyfunc-mode.
804 Argument EVENT describes the event that caused this function to be called."
805 (interactive "e")
806 (let* ((startwin (selected-window))
807 (win (car (car (cdr event))))
808 )
809 (select-window win t)
810 (save-excursion
811 (goto-char (window-start win))
812 (sit-for 0)
813 (popup-menu semantic-stickyfunc-popup-menu event)
814 )
815 (select-window startwin)))
816
817
818 (semantic-add-minor-mode 'semantic-stickyfunc-mode
819 "") ;; Don't need indicator. It's quite visible
820
821
822 \f
823 ;;;;
824 ;;;; Minor mode to make highlight the current function
825 ;;;;
826
827 ;; Highlight the first like of the function we are in if it is different
828 ;; from the tag going off the top of the screen.
829
830 ;;;###autoload
831 (define-minor-mode global-semantic-highlight-func-mode
832 "Toggle global use of option `semantic-highlight-func-mode'.
833 If ARG is positive or nil, enable, if it is negative, disable."
834 :global t :group 'semantic :group 'semantic-modes
835 ;; Not needed because it's autoloaded instead.
836 ;; :require 'semantic/util-modes
837 (semantic-toggle-minor-mode-globally
838 'semantic-highlight-func-mode
839 (if global-semantic-highlight-func-mode 1 -1)))
840
841 (defcustom semantic-highlight-func-mode-hook nil
842 "Hook run at the end of function `semantic-highlight-func-mode'."
843 :group 'semantic
844 :type 'hook)
845
846 (defvar semantic-highlight-func-mode-map
847 (let ((km (make-sparse-keymap))
848 (m3 (if (featurep 'xemacs) [ button3 ] [ mouse-3 ]))
849 )
850 (define-key km m3 'semantic-highlight-func-menu)
851 km)
852 "Keymap for highlight-func minor mode.")
853
854 (defvar semantic-highlight-func-popup-menu nil
855 "Menu used if the user clicks on the header line used by `semantic-highlight-func-mode'.")
856
857 (easy-menu-define
858 semantic-highlight-func-popup-menu
859 semantic-highlight-func-mode-map
860 "Highlight-Func Menu"
861 '("Highlight-Func Mode" :visible (progn nil)
862 [ "Copy Tag" senator-copy-tag
863 :active (semantic-current-tag)
864 :help "Copy the current tag to the tag ring"]
865 [ "Kill Tag" senator-kill-tag
866 :active (semantic-current-tag)
867 :help "Kill tag text to the kill ring, and copy the tag to the tag ring"
868 ]
869 [ "Copy Tag to Register" senator-copy-tag-to-register
870 :active (semantic-current-tag)
871 :help "Copy the current tag to a register"
872 ]
873 [ "Narrow To Tag" senator-narrow-to-defun
874 :active (semantic-current-tag)
875 :help "Narrow to the bounds of the current tag"]
876 [ "Fold Tag" senator-fold-tag-toggle
877 :active (semantic-current-tag)
878 :style toggle
879 :selected (let ((tag (semantic-stickyfunc-tag-to-stick)))
880 (and tag (semantic-tag-folded-p tag)))
881 :help "Fold the current tag to one line"
882 ]
883 "---"
884 [ "About This Tag" semantic-describe-tag t])
885 )
886
887 (defun semantic-highlight-func-menu (event)
888 "Popup a menu that displays things to do to the current tag.
889 Argument EVENT describes the event that caused this function to be called."
890 (interactive "e")
891 (let* ((startwin (selected-window))
892 (win (semantic-event-window event))
893 )
894 (select-window win t)
895 (save-excursion
896 ;(goto-char (window-start win))
897 (mouse-set-point event)
898 (sit-for 0)
899 (semantic-popup-menu semantic-highlight-func-popup-menu)
900 )
901 (select-window startwin)))
902
903 (defvar semantic-highlight-func-ct-overlay nil
904 "Overlay used to highlight the tag the cursor is in.")
905 (make-variable-buffer-local 'semantic-highlight-func-ct-overlay)
906
907 (defface semantic-highlight-func-current-tag-face
908 '((((class color) (background dark))
909 ;; Put this back to something closer to black later.
910 (:background "gray20"))
911 (((class color) (background light))
912 (:background "gray90")))
913 "Face used to show the top of current function."
914 :group 'semantic-faces)
915
916 ;;;###autoload
917 (define-minor-mode semantic-highlight-func-mode
918 "Minor mode to highlight the first line of the current tag.
919 Enables/disables making the current function's first line light up.
920 A function (or other tag class specified by
921 `semantic-stickyfunc-sticky-classes') is highlighted, meaning the
922 first line which describes the rest of the construct.
923
924 See `semantic-stickyfunc-mode' for putting a function in the
925 header line. This mode recycles the stickyfunc configuration
926 classes list.
927
928 With prefix argument ARG, turn on if positive, otherwise off. The
929 minor mode can be turned on only if semantic feature is available and
930 the current buffer was set up for parsing. Return non-nil if the
931 minor mode is enabled."
932 :lighter nil ;; Don't need indicator. It's quite visible.
933 (if semantic-highlight-func-mode
934 (progn
935 (unless (and (featurep 'semantic) (semantic-active-p))
936 ;; Disable minor mode if semantic stuff not available
937 (setq semantic-highlight-func-mode nil)
938 (error "Buffer %s was not set up for parsing" (buffer-name)))
939 ;; Setup our hook
940 (add-hook 'post-command-hook
941 'semantic-highlight-func-highlight-current-tag nil t))
942 ;; Disable highlight func mode
943 (remove-hook 'post-command-hook
944 'semantic-highlight-func-highlight-current-tag t)
945 (semantic-highlight-func-highlight-current-tag t)))
946
947 (defun semantic-highlight-func-highlight-current-tag (&optional disable)
948 "Highlight the current tag under point.
949 Optional argument DISABLE will turn off any active highlight.
950 If the current tag for this buffer is different from the last time this
951 function was called, move the overlay."
952 (when (and (not (minibufferp))
953 (or (not semantic-highlight-func-ct-overlay)
954 (eq (semantic-overlay-buffer
955 semantic-highlight-func-ct-overlay)
956 (current-buffer))))
957 (let* ((tag (semantic-stickyfunc-tag-to-stick))
958 (ol semantic-highlight-func-ct-overlay))
959 (when (not ol)
960 ;; No overlay in this buffer. Make one.
961 (setq ol (semantic-make-overlay (point-min) (point-min)
962 (current-buffer) t nil))
963 (semantic-overlay-put ol 'highlight-func t)
964 (semantic-overlay-put ol 'face 'semantic-highlight-func-current-tag-face)
965 (semantic-overlay-put ol 'keymap semantic-highlight-func-mode-map)
966 (semantic-overlay-put ol 'help-echo
967 "Current Function : mouse-3 - Context menu")
968 (setq semantic-highlight-func-ct-overlay ol)
969 )
970
971 ;; TAG is nil if there was nothing of the appropriate type there.
972 (if (or (not tag) disable)
973 ;; No tag, make the overlay go away.
974 (progn
975 (semantic-overlay-put ol 'tag nil)
976 (semantic-overlay-move ol (point-min) (point-min) (current-buffer))
977 )
978
979 ;; We have a tag, if it is the same, do nothing.
980 (unless (eq (semantic-overlay-get ol 'tag) tag)
981 (save-excursion
982 (goto-char (semantic-tag-start tag))
983 (search-forward (semantic-tag-name tag) nil t)
984 (semantic-overlay-put ol 'tag tag)
985 (semantic-overlay-move ol (point-at-bol) (point-at-eol))
986 )
987 )
988 )))
989 nil)
990
991 (semantic-add-minor-mode 'semantic-highlight-func-mode
992 "") ;; Don't need indicator. It's quite visible
993
994 (provide 'semantic/util-modes)
995
996 ;; Local variables:
997 ;; generated-autoload-file: "loaddefs.el"
998 ;; generated-autoload-load-name: "semantic/util-modes"
999 ;; End:
1000
1001 ;; arch-tag: 18f5a3d8-1fd7-4c17-b149-a313c126987d
1002 ;;; semantic/util-modes.el ends here