Nuke arch-tags.
[emacs.git] / lisp / cedet / semantic / util-modes.el
blob36d1479ac65ee123af095b131cdbc5d950af39c5
1 ;;; semantic/util-modes.el --- Semantic minor modes
3 ;; Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011
4 ;; Free Software Foundation, Inc.
6 ;; Authors: Eric M. Ludlam <zappo@gnu.org>
7 ;; David Ponce <david@dponce.com>
8 ;; Keywords: syntax
10 ;; This file is part of GNU Emacs.
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.
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.
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/>.
25 ;;; Commentary:
27 ;; Semantic utility minor modes.
30 ;;; Code:
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)
37 ;;; Group for all semantic enhancing modes
38 (defgroup semantic-modes nil
39 "Minor modes associated with the Semantic architecture."
40 :group 'semantic)
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)))
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)
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)
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'.")
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)))))))))
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)
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.
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)
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))))
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
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))))
168 ;;;;
169 ;;;; Minor mode to highlight areas that a user edits.
170 ;;;;
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)))
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)
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)
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))
201 (defvar semantic-highlight-edits-mode-map
202 (let ((km (make-sparse-keymap)))
204 "Keymap for highlight-edits minor mode.")
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)))
232 (semantic-add-minor-mode 'semantic-highlight-edits-mode
233 "e")
235 ;;;;
236 ;;;; Minor mode to show unmatched-syntax elements
237 ;;;;
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)))
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)
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)
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))
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))
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))
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)))))
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)))
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)))
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))))
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)))
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)
354 "Keymap for command `semantic-show-unmatched-syntax-mode'.")
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.
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.
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)))
397 (semantic-add-minor-mode 'semantic-show-unmatched-syntax-mode
398 "u")
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)))))
408 ;;;;
409 ;;;; Minor mode to display the parser state in the modeline.
410 ;;;;
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)))
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)
428 (defvar semantic-show-parser-state-mode-map
429 (let ((km (make-sparse-keymap)))
431 "Keymap for show-parser-state minor mode.")
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
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)
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)
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)
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)
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)))
514 (semantic-add-minor-mode 'semantic-show-parser-state-mode
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)
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 "%")
540 "-")))
541 ;;(message "Setup mode line indicator to [%s]" semantic-show-parser-state-string)
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)
555 ;;;;
556 ;;;; Minor mode to make function decls sticky.
557 ;;;;
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)))
569 (defcustom semantic-stickyfunc-mode-hook nil
570 "Hook run at the end of function `semantic-stickyfunc-mode'."
571 :group 'semantic
572 :type 'hook)
574 (defvar semantic-stickyfunc-mode-map
575 (let ((km (make-sparse-keymap)))
576 (define-key km [ header-line down-mouse-1 ] 'semantic-stickyfunc-menu)
578 "Keymap for stickyfunc minor mode.")
580 (defvar semantic-stickyfunc-popup-menu nil
581 "Menu used if the user clicks on the header line used by stickyfunc mode.")
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"
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"
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"
609 "---"
610 [ "About This Header Line"
611 (lambda () (interactive)
612 (describe-function 'semantic-stickyfunc-mode)) t])
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))
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))))
634 (if (not w)
635 (setq w (frame-parameter (selected-frame)
636 'scroll-bar-width)))
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)))
647 (if (not w)
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)))
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)
670 (error ""))))
672 ;; Not Emacs or a window system means no scrollbar or fringe,
673 ;; and perhaps not even a header line to worry about.
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)
682 (defvar semantic-stickyfunc-old-hlf nil
683 "Value of the header line when entering stickyfunc mode.")
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.")
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.
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)))))
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)
746 (defcustom semantic-stickyfunc-show-only-functions-p nil
747 "Non-nil means don't show lines that aren't part of a tag.
748 If this is nil, then comments or other text between tags that is
749 1 line above the top of the current window will be shown."
750 :group 'semantic
751 :type 'boolean)
753 (defun semantic-stickyfunc-tag-to-stick ()
754 "Return the tag to stick at the current point."
755 (let ((tags (nreverse (semantic-find-tag-by-overlay (point)))))
756 ;; Get rid of non-matching tags.
757 (while (and tags
758 (not (member
759 (semantic-tag-class (car tags))
760 semantic-stickyfunc-sticky-classes))
762 (setq tags (cdr tags)))
763 (car tags)))
765 (defun semantic-stickyfunc-fetch-stickyline ()
766 "Make the function at the top of the current window sticky.
767 Capture its function declaration, and place it in the header line.
768 If there is no function, disable the header line."
769 (save-excursion
770 (goto-char (window-start (selected-window)))
771 (let* ((noshow (bobp))
772 (str
773 (progn
774 (forward-line -1)
775 (end-of-line)
776 ;; Capture this function
777 (let* ((tag (semantic-stickyfunc-tag-to-stick)))
778 ;; TAG is nil if there was nothing of the appropriate type there.
779 (if (not tag)
780 ;; Set it to be the text under the header line
781 (if noshow
783 (if semantic-stickyfunc-show-only-functions-p ""
784 (buffer-substring (point-at-bol) (point-at-eol))
786 ;; Go get the first line of this tag.
787 (goto-char (semantic-tag-start tag))
788 ;; Klaus Berndl <klaus.berndl@sdm.de>:
789 ;; goto the tag name; this is especially needed for languages
790 ;; like c++ where a often used style is like:
791 ;; void
792 ;; ClassX::methodM(arg1...)
793 ;; {
794 ;; ...
795 ;; }
796 ;; Without going to the tag-name we would get"void" in the
797 ;; header line which is IMHO not really useful
798 (search-forward (semantic-tag-name tag) nil t)
799 (buffer-substring (point-at-bol) (point-at-eol))
800 ))))
801 (start 0))
802 (while (string-match "%" str start)
803 (setq str (replace-match "%%" t t str 0)
804 start (1+ (match-end 0)))
806 ;; In 21.4 (or 22.1) the header doesn't expand tabs. Hmmmm.
807 ;; We should replace them here.
809 ;; This hack assumes that tabs are kept smartly at tab boundaries
810 ;; instead of in a tab boundary where it might only represent 4 spaces.
811 (while (string-match "\t" str start)
812 (setq str (replace-match " " t t str 0)))
813 str)))
815 (defun semantic-stickyfunc-menu (event)
816 "Popup a menu that can help a user understand stickyfunc-mode.
817 Argument EVENT describes the event that caused this function to be called."
818 (interactive "e")
819 (let* ((startwin (selected-window))
820 (win (car (car (cdr event))))
822 (select-window win t)
823 (save-excursion
824 (goto-char (window-start win))
825 (sit-for 0)
826 (popup-menu semantic-stickyfunc-popup-menu event)
828 (select-window startwin)))
831 (semantic-add-minor-mode 'semantic-stickyfunc-mode
832 "") ;; Don't need indicator. It's quite visible
836 ;;;;
837 ;;;; Minor mode to make highlight the current function
838 ;;;;
840 ;; Highlight the first like of the function we are in if it is different
841 ;; from the tag going off the top of the screen.
843 ;;;###autoload
844 (define-minor-mode global-semantic-highlight-func-mode
845 "Toggle global use of option `semantic-highlight-func-mode'.
846 If ARG is positive or nil, enable, if it is negative, disable."
847 :global t :group 'semantic :group 'semantic-modes
848 ;; Not needed because it's autoloaded instead.
849 ;; :require 'semantic/util-modes
850 (semantic-toggle-minor-mode-globally
851 'semantic-highlight-func-mode
852 (if global-semantic-highlight-func-mode 1 -1)))
854 (defcustom semantic-highlight-func-mode-hook nil
855 "Hook run at the end of function `semantic-highlight-func-mode'."
856 :group 'semantic
857 :type 'hook)
859 (defvar semantic-highlight-func-mode-map
860 (let ((km (make-sparse-keymap))
861 (m3 (if (featurep 'xemacs) [ button3 ] [ mouse-3 ]))
863 (define-key km m3 'semantic-highlight-func-menu)
865 "Keymap for highlight-func minor mode.")
867 (defvar semantic-highlight-func-popup-menu nil
868 "Menu used if the user clicks on the header line used by `semantic-highlight-func-mode'.")
870 (easy-menu-define
871 semantic-highlight-func-popup-menu
872 semantic-highlight-func-mode-map
873 "Highlight-Func Menu"
874 '("Highlight-Func Mode" :visible (progn nil)
875 [ "Copy Tag" senator-copy-tag
876 :active (semantic-current-tag)
877 :help "Copy the current tag to the tag ring"]
878 [ "Kill Tag" senator-kill-tag
879 :active (semantic-current-tag)
880 :help "Kill tag text to the kill ring, and copy the tag to the tag ring"
882 [ "Copy Tag to Register" senator-copy-tag-to-register
883 :active (semantic-current-tag)
884 :help "Copy the current tag to a register"
886 [ "Narrow To Tag" senator-narrow-to-defun
887 :active (semantic-current-tag)
888 :help "Narrow to the bounds of the current tag"]
889 [ "Fold Tag" senator-fold-tag-toggle
890 :active (semantic-current-tag)
891 :style toggle
892 :selected (let ((tag (semantic-stickyfunc-tag-to-stick)))
893 (and tag (semantic-tag-folded-p tag)))
894 :help "Fold the current tag to one line"
896 "---"
897 [ "About This Tag" semantic-describe-tag t])
900 (defun semantic-highlight-func-menu (event)
901 "Popup a menu that displays things to do to the current tag.
902 Argument EVENT describes the event that caused this function to be called."
903 (interactive "e")
904 (let* ((startwin (selected-window))
905 (win (semantic-event-window event))
907 (select-window win t)
908 (save-excursion
909 ;(goto-char (window-start win))
910 (mouse-set-point event)
911 (sit-for 0)
912 (semantic-popup-menu semantic-highlight-func-popup-menu)
914 (select-window startwin)))
916 (defvar semantic-highlight-func-ct-overlay nil
917 "Overlay used to highlight the tag the cursor is in.")
918 (make-variable-buffer-local 'semantic-highlight-func-ct-overlay)
920 (defface semantic-highlight-func-current-tag-face
921 '((((class color) (background dark))
922 ;; Put this back to something closer to black later.
923 (:background "gray20"))
924 (((class color) (background light))
925 (:background "gray90")))
926 "Face used to show the top of current function."
927 :group 'semantic-faces)
929 ;;;###autoload
930 (define-minor-mode semantic-highlight-func-mode
931 "Minor mode to highlight the first line of the current tag.
932 Enables/disables making the current function's first line light up.
933 A function (or other tag class specified by
934 `semantic-stickyfunc-sticky-classes') is highlighted, meaning the
935 first line which describes the rest of the construct.
937 See `semantic-stickyfunc-mode' for putting a function in the
938 header line. This mode recycles the stickyfunc configuration
939 classes list.
941 With prefix argument ARG, turn on if positive, otherwise off. The
942 minor mode can be turned on only if semantic feature is available and
943 the current buffer was set up for parsing. Return non-nil if the
944 minor mode is enabled."
945 :lighter nil ;; Don't need indicator. It's quite visible.
946 (if semantic-highlight-func-mode
947 (progn
948 (unless (and (featurep 'semantic) (semantic-active-p))
949 ;; Disable minor mode if semantic stuff not available
950 (setq semantic-highlight-func-mode nil)
951 (error "Buffer %s was not set up for parsing" (buffer-name)))
952 ;; Setup our hook
953 (add-hook 'post-command-hook
954 'semantic-highlight-func-highlight-current-tag nil t))
955 ;; Disable highlight func mode
956 (remove-hook 'post-command-hook
957 'semantic-highlight-func-highlight-current-tag t)
958 (semantic-highlight-func-highlight-current-tag t)))
960 (defun semantic-highlight-func-highlight-current-tag (&optional disable)
961 "Highlight the current tag under point.
962 Optional argument DISABLE will turn off any active highlight.
963 If the current tag for this buffer is different from the last time this
964 function was called, move the overlay."
965 (when (and (not (minibufferp))
966 (or (not semantic-highlight-func-ct-overlay)
967 (eq (semantic-overlay-buffer
968 semantic-highlight-func-ct-overlay)
969 (current-buffer))))
970 (let* ((tag (semantic-stickyfunc-tag-to-stick))
971 (ol semantic-highlight-func-ct-overlay))
972 (when (not ol)
973 ;; No overlay in this buffer. Make one.
974 (setq ol (semantic-make-overlay (point-min) (point-min)
975 (current-buffer) t nil))
976 (semantic-overlay-put ol 'highlight-func t)
977 (semantic-overlay-put ol 'face 'semantic-highlight-func-current-tag-face)
978 (semantic-overlay-put ol 'keymap semantic-highlight-func-mode-map)
979 (semantic-overlay-put ol 'help-echo
980 "Current Function : mouse-3 - Context menu")
981 (setq semantic-highlight-func-ct-overlay ol)
984 ;; TAG is nil if there was nothing of the appropriate type there.
985 (if (or (not tag) disable)
986 ;; No tag, make the overlay go away.
987 (progn
988 (semantic-overlay-put ol 'tag nil)
989 (semantic-overlay-move ol (point-min) (point-min) (current-buffer))
992 ;; We have a tag, if it is the same, do nothing.
993 (unless (eq (semantic-overlay-get ol 'tag) tag)
994 (save-excursion
995 (goto-char (semantic-tag-start tag))
996 (search-forward (semantic-tag-name tag) nil t)
997 (semantic-overlay-put ol 'tag tag)
998 (semantic-overlay-move ol (point-at-bol) (point-at-eol))
1002 nil)
1004 (semantic-add-minor-mode 'semantic-highlight-func-mode
1005 "") ;; Don't need indicator. It's quite visible
1007 (provide 'semantic/util-modes)
1009 ;; Local variables:
1010 ;; generated-autoload-file: "loaddefs.el"
1011 ;; generated-autoload-load-name: "semantic/util-modes"
1012 ;; End:
1014 ;;; semantic/util-modes.el ends here