diff options
author | Chong Yidong <cyd@stupidchicken.com> | 2009-08-28 15:19:20 +0000 |
---|---|---|
committer | Chong Yidong <cyd@stupidchicken.com> | 2009-08-28 15:19:20 +0000 |
commit | 7a0e7d3387b5b675042878e5e2e5878b94b2487a (patch) | |
tree | 48f1d7c4af09bbc4abfb968332cfc74c5cc1087f /lisp/cedet/semantic/util-modes.el | |
parent | 57e622d92b9538b2302c51ef993766276dfc7569 (diff) | |
download | emacs-7a0e7d3387b5b675042878e5e2e5878b94b2487a.tar.gz |
cedet/semantic/db.el, cedet/semantic/decorate.el,
cedet/semantic/lex-spp.el, cedet/semantic/util-modes.el: New files.
Diffstat (limited to 'lisp/cedet/semantic/util-modes.el')
-rw-r--r-- | lisp/cedet/semantic/util-modes.el | 1228 |
1 files changed, 1228 insertions, 0 deletions
diff --git a/lisp/cedet/semantic/util-modes.el b/lisp/cedet/semantic/util-modes.el new file mode 100644 index 00000000000..e38e1b94637 --- /dev/null +++ b/lisp/cedet/semantic/util-modes.el @@ -0,0 +1,1228 @@ +;;; semantic-util-modes.el --- Semantic minor modes + +;;; Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009 +;;; Free Software Foundation, Inc. + +;; Authors: Eric M. Ludlam <zappo@gnu.org> +;; David Ponce <david@dponce.com> +;; Keywords: syntax + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. + +;;; Commentary: +;; +;; Semantic utility minor modes. +;; + +;;; Code: +(require 'semantic) + +(eval-when-compile + (require 'semantic/decorate) + ) + +;;; Compatibility +(if (fboundp 'propertize) + (defalias 'semantic-propertize 'propertize) + (defsubst semantic-propertize (string &rest properties) + "Return a copy of STRING with text properties added. +Dummy implementation for compatibility which just return STRING and +ignore PROPERTIES." + string) + ) + +;;; Group for all semantic enhancing modes +(defgroup semantic-modes nil + "Minor modes associated with the Semantic architecture." + :group 'semantic) + +;;;; +;;;; Semantic minor modes stuff +;;;; +(defcustom semantic-update-mode-line t + "*If non-nil, show enabled minor modes in the mode line. +Only minor modes that are not turned on globally are shown in the mode +line." + :group 'semantic + :type 'boolean + :require 'semantic/util-modes + :initialize 'custom-initialize-default + :set (lambda (sym val) + (set-default sym val) + ;; Update status of all Semantic enabled buffers + (semantic-map-buffers + #'semantic-mode-line-update))) + +(defcustom semantic-mode-line-prefix + (semantic-propertize "S" 'face 'bold) + "*Prefix added to minor mode indicators in the mode line." + :group 'semantic + :type 'string + :require 'semantic/util-modes + :initialize 'custom-initialize-default) + +(defvar semantic-minor-modes-status nil + "String showing Semantic minor modes which are locally enabled. +It is displayed in the mode line.") +(make-variable-buffer-local 'semantic-minor-modes-status) + +(defvar semantic-minor-mode-alist nil + "Alist saying how to show Semantic minor modes in the mode line. +Like variable `minor-mode-alist'.") + +(defun semantic-mode-line-update () + "Update display of Semantic minor modes in the mode line. +Only minor modes that are locally enabled are shown in the mode line." + (setq semantic-minor-modes-status nil) + (if semantic-update-mode-line + (let ((ml semantic-minor-mode-alist) + mm ms see) + (while ml + (setq mm (car ml) + ms (cadr mm) + mm (car mm) + ml (cdr ml)) + (when (and (symbol-value mm) + ;; Only show local minor mode status + (not (memq mm semantic-init-hooks))) + (and ms + (symbolp ms) + (setq ms (symbol-value ms))) + (and (stringp ms) + (not (member ms see)) ;; Don't duplicate same status + (setq see (cons ms see) + ms (if (string-match "^[ ]*\\(.+\\)" ms) + (match-string 1 ms))) + (setq semantic-minor-modes-status + (if semantic-minor-modes-status + (concat semantic-minor-modes-status "/" ms) + ms))))) + (if semantic-minor-modes-status + (setq semantic-minor-modes-status + (concat + " " + (if (string-match "^[ ]*\\(.+\\)" + semantic-mode-line-prefix) + (match-string 1 semantic-mode-line-prefix) + "S") + "/" + semantic-minor-modes-status)))))) + +(defun semantic-desktop-ignore-this-minor-mode (buffer) + "Installed as a minor-mode initializer for Desktop mode. +BUFFER is the buffer to not initialize a Semantic minor mode in." + nil) + +(defun semantic-add-minor-mode (toggle name &optional keymap) + "Register a new Semantic minor mode. +TOGGLE is a symbol which is the name of a buffer-local variable that +is toggled on or off to say whether the minor mode is active or not. +It is also an interactive function to toggle the mode. + +NAME specifies what will appear in the mode line when the minor mode +is active. NAME should be either a string starting with a space, or a +symbol whose value is such a string. + +Optional KEYMAP is the keymap for the minor mode that will be added to +`minor-mode-map-alist'." + ;; Add a dymmy semantic minor mode to display the status + (or (assq 'semantic-minor-modes-status minor-mode-alist) + (setq minor-mode-alist (cons (list 'semantic-minor-modes-status + 'semantic-minor-modes-status) + minor-mode-alist))) + (if (fboundp 'add-minor-mode) + ;; Emacs 21 & XEmacs + (add-minor-mode toggle "" keymap) + ;; Emacs 20 + (or (assq toggle minor-mode-alist) + (setq minor-mode-alist (cons (list toggle "") minor-mode-alist))) + (or (not keymap) + (assq toggle minor-mode-map-alist) + (setq minor-mode-map-alist (cons (cons toggle keymap) + minor-mode-map-alist)))) + ;; Record how to display this minor mode in the mode line + (let ((mm (assq toggle semantic-minor-mode-alist))) + (if mm + (setcdr mm (list name)) + (setq semantic-minor-mode-alist (cons (list toggle name) + semantic-minor-mode-alist)))) + + ;; Semantic minor modes don't work w/ Desktop restore. + ;; This line will disable this minor mode from being restored + ;; by Desktop. + (when (boundp 'desktop-minor-mode-handlers) + (add-to-list 'desktop-minor-mode-handlers + (cons toggle 'semantic-desktop-ignore-this-minor-mode))) + ) + +(defun semantic-toggle-minor-mode-globally (mode &optional arg) + "Toggle minor mode MODE in every Semantic enabled buffer. +Return non-nil if MODE is turned on in every Semantic enabled buffer. +If ARG is positive, enable, if it is negative, disable. If ARG is +nil, then toggle. Otherwise do nothing. MODE must be a valid minor +mode defined in `minor-mode-alist' and must be too an interactive +function used to toggle the mode." + (or (and (fboundp mode) (assq mode minor-mode-alist)) + (error "Semantic minor mode %s not found" mode)) + (if (not arg) + (if (memq mode semantic-init-hooks) + (setq arg -1) + (setq arg 1))) + ;; Add or remove the MODE toggle function from + ;; `semantic-init-hooks'. Then turn MODE on or off in every + ;; Semantic enabled buffer. + (cond + ;; Turn off if ARG < 0 + ((< arg 0) + (remove-hook 'semantic-init-hooks mode) + (semantic-map-buffers #'(lambda () (funcall mode -1))) + nil) + ;; Turn on if ARG > 0 + ((> arg 0) + (add-hook 'semantic-init-hooks mode) + (semantic-map-buffers #'(lambda () (funcall mode 1))) + t) + ;; Otherwise just check MODE state + (t + (memq mode semantic-init-hooks)) + )) + +;;;; +;;;; Minor mode to highlight areas that a user edits. +;;;; + +(defun global-semantic-highlight-edits-mode (&optional arg) + "Toggle global use of option `semantic-highlight-edits-mode'. +If ARG is positive, enable, if it is negative, disable. +If ARG is nil, then toggle." + (interactive "P") + (setq global-semantic-highlight-edits-mode + (semantic-toggle-minor-mode-globally + 'semantic-highlight-edits-mode arg))) + +(defcustom global-semantic-highlight-edits-mode nil + "*If non-nil enable global use of variable `semantic-highlight-edits-mode'. +When this mode is enabled, changes made to a buffer are highlighted +until the buffer is reparsed." + :group 'semantic + :group 'semantic-modes + :type 'boolean + :require 'semantic/util-modes + :initialize 'custom-initialize-default + :set (lambda (sym val) + (global-semantic-highlight-edits-mode (if val 1 -1)))) + +(defcustom semantic-highlight-edits-mode-hook nil + "*Hook run at the end of function `semantic-highlight-edits-mode'." + :group 'semantic + :type 'hook) + +(defface semantic-highlight-edits-face + '((((class color) (background dark)) + ;; Put this back to something closer to black later. + (:background "gray20")) + (((class color) (background light)) + (:background "gray90"))) + "*Face used to show dirty tokens in `semantic-highlight-edits-mode'." + :group 'semantic-faces) + +(defun semantic-highlight-edits-new-change-hook-fcn (overlay) + "Function set into `semantic-edits-new-change-hook'. +Argument OVERLAY is the overlay created to mark the change. +This function will set the face property on this overlay." + (semantic-overlay-put overlay 'face 'semantic-highlight-edits-face)) + +(defvar semantic-highlight-edits-mode-map + (let ((km (make-sparse-keymap))) + km) + "Keymap for highlight-edits minor mode.") + +(defvar semantic-highlight-edits-mode nil + "Non-nil if highlight-edits minor mode is enabled. +Use the command `semantic-highlight-edits-mode' to change this variable.") +(make-variable-buffer-local 'semantic-highlight-edits-mode) + +(defun semantic-highlight-edits-mode-setup () + "Setup option `semantic-highlight-edits-mode'. +The minor mode can be turned on only if semantic feature is available +and the current buffer was set up for parsing. When minor mode is +enabled parse the current buffer if needed. Return non-nil if the +minor mode is enabled." + (if semantic-highlight-edits-mode + (if (not (and (featurep 'semantic) (semantic-active-p))) + (progn + ;; Disable minor mode if semantic stuff not available + (setq semantic-highlight-edits-mode nil) + (error "Buffer %s was not set up for parsing" + (buffer-name))) + (semantic-make-local-hook 'semantic-edits-new-change-hooks) + (add-hook 'semantic-edits-new-change-hooks + 'semantic-highlight-edits-new-change-hook-fcn nil t) + ) + ;; Remove hooks + (remove-hook 'semantic-edits-new-change-hooks + 'semantic-highlight-edits-new-change-hook-fcn t) + ) + semantic-highlight-edits-mode) + +(defun semantic-highlight-edits-mode (&optional arg) + "Minor mode for highlighting changes made in a buffer. +Changes are tracked by semantic so that the incremental parser can work +properly. +This mode will highlight those changes as they are made, and clear them +when the incremental parser accounts for those edits. +With prefix argument ARG, turn on if positive, otherwise off. The +minor mode can be turned on only if semantic feature is available and +the current buffer was set up for parsing. Return non-nil if the +minor mode is enabled." + (interactive + (list (or current-prefix-arg + (if semantic-highlight-edits-mode 0 1)))) + (setq semantic-highlight-edits-mode + (if arg + (> + (prefix-numeric-value arg) + 0) + (not semantic-highlight-edits-mode))) + (semantic-highlight-edits-mode-setup) + (run-hooks 'semantic-highlight-edits-mode-hook) + (if (interactive-p) + (message "highlight-edits minor mode %sabled" + (if semantic-highlight-edits-mode "en" "dis"))) + (semantic-mode-line-update) + semantic-highlight-edits-mode) + +(semantic-add-minor-mode 'semantic-highlight-edits-mode + "e" + semantic-highlight-edits-mode-map) + + +;;;; +;;;; Minor mode to show unmatched-syntax elements +;;;; +(defun global-semantic-show-unmatched-syntax-mode (&optional arg) + "Toggle global use of option `semantic-show-unmatched-syntax-mode'. +If ARG is positive, enable, if it is negative, disable. +If ARG is nil, then toggle." + (interactive "P") + (setq global-semantic-show-unmatched-syntax-mode + (semantic-toggle-minor-mode-globally + 'semantic-show-unmatched-syntax-mode arg))) + +(defcustom global-semantic-show-unmatched-syntax-mode nil + "*If non-nil, enable global use of `semantic-show-unmatched-syntax-mode'. +When this mode is enabled, syntax in the current buffer which the +semantic parser cannot match is highlighted with a red underline." + :group 'semantic + :group 'semantic-modes + :type 'boolean + :require 'semantic/util-modes + :initialize 'custom-initialize-default + :set (lambda (sym val) + (global-semantic-show-unmatched-syntax-mode (if val 1 -1)))) + +(defcustom semantic-show-unmatched-syntax-mode-hook nil + "*Hook run at the end of function `semantic-show-unmatched-syntax-mode'." + :group 'semantic + :type 'hook) + +(defface semantic-unmatched-syntax-face + '((((class color) (background dark)) + (:underline "red")) + (((class color) (background light)) + (:underline "red"))) + "*Face used to show unmatched syntax in. +The face is used in `semantic-show-unmatched-syntax-mode'." + :group 'semantic-faces) + +(defsubst semantic-unmatched-syntax-overlay-p (overlay) + "Return non-nil if OVERLAY is an unmatched syntax one." + (eq (semantic-overlay-get overlay 'semantic) 'unmatched)) + +(defun semantic-showing-unmatched-syntax-p () + "Return non-nil if an unmatched syntax overlay was found in buffer." + (let ((ol (semantic-overlays-in (point-min) (point-max))) + found) + (while (and ol (not found)) + (setq found (semantic-unmatched-syntax-overlay-p (car ol)) + ol (cdr ol))) + found)) + +(defun semantic-show-unmatched-lex-tokens-fetch () + "Fetch a list of unmatched lexical tokens from the current buffer. +Uses the overlays which have accurate bounds, and rebuilds what was +originally passed in." + (let ((ol (semantic-overlays-in (point-min) (point-max))) + (ustc nil)) + (while ol + (if (semantic-unmatched-syntax-overlay-p (car ol)) + (setq ustc (cons (cons 'thing + (cons (semantic-overlay-start (car ol)) + (semantic-overlay-end (car ol)))) + ustc))) + (setq ol (cdr ol))) + (nreverse ustc)) + ) + +(defun semantic-clean-unmatched-syntax-in-region (beg end) + "Remove all unmatched syntax overlays between BEG and END." + (let ((ol (semantic-overlays-in beg end))) + (while ol + (if (semantic-unmatched-syntax-overlay-p (car ol)) + (semantic-overlay-delete (car ol))) + (setq ol (cdr ol))))) + +(defsubst semantic-clean-unmatched-syntax-in-buffer () + "Remove all unmatched syntax overlays found in current buffer." + (semantic-clean-unmatched-syntax-in-region + (point-min) (point-max))) + +(defsubst semantic-clean-token-of-unmatched-syntax (token) + "Clean the area covered by TOKEN of unmatched syntax markers." + (semantic-clean-unmatched-syntax-in-region + (semantic-tag-start token) (semantic-tag-end token))) + +(defun semantic-show-unmatched-syntax (syntax) + "Function set into `semantic-unmatched-syntax-hook'. +This will highlight elements in SYNTAX as unmatched syntax." + ;; This is called when `semantic-show-unmatched-syntax-mode' is + ;; enabled. Highlight the unmatched syntax, and then add a semantic + ;; property to that overlay so we can add it to the official list of + ;; semantic supported overlays. This gets it cleaned up for errors, + ;; buffer cleaning, and the like. + (semantic-clean-unmatched-syntax-in-buffer) ;Clear previous highlighting + (if syntax + (let (o) + (while syntax + (setq o (semantic-make-overlay (semantic-lex-token-start (car syntax)) + (semantic-lex-token-end (car syntax)))) + (semantic-overlay-put o 'semantic 'unmatched) + (semantic-overlay-put o 'face 'semantic-unmatched-syntax-face) + (setq syntax (cdr syntax)))) + )) + +(defun semantic-next-unmatched-syntax (point &optional bound) + "Find the next overlay for unmatched syntax after POINT. +Do not search past BOUND if non-nil." + (save-excursion + (goto-char point) + (let ((os point) (ol nil)) + (while (and os (< os (or bound (point-max))) (not ol)) + (setq os (semantic-overlay-next-change os)) + (when os + ;; Get overlays at position + (setq ol (semantic-overlays-at os)) + ;; find the overlay that belongs to semantic + ;; and starts at the found position. + (while (and ol (listp ol)) + (and (semantic-unmatched-syntax-overlay-p (car ol)) + (setq ol (car ol))) + (if (listp ol) + (setq ol (cdr ol)))))) + ol))) + +(defvar semantic-show-unmatched-syntax-mode-map + (let ((km (make-sparse-keymap))) + (define-key km "\C-c,`" 'semantic-show-unmatched-syntax-next) + km) + "Keymap for command `semantic-show-unmatched-syntax-mode'.") + +(defvar semantic-show-unmatched-syntax-mode nil + "Non-nil if show-unmatched-syntax minor mode is enabled. +Use the command `semantic-show-unmatched-syntax-mode' to change this +variable.") +(make-variable-buffer-local 'semantic-show-unmatched-syntax-mode) + +(defun semantic-show-unmatched-syntax-mode-setup () + "Setup the `semantic-show-unmatched-syntax' minor mode. +The minor mode can be turned on only if semantic feature is available +and the current buffer was set up for parsing. When minor mode is +enabled parse the current buffer if needed. Return non-nil if the +minor mode is enabled." + (if semantic-show-unmatched-syntax-mode + (if (not (and (featurep 'semantic) (semantic-active-p))) + (progn + ;; Disable minor mode if semantic stuff not available + (setq semantic-show-unmatched-syntax-mode nil) + (error "Buffer %s was not set up for parsing" + (buffer-name))) + ;; Add hooks + (semantic-make-local-hook 'semantic-unmatched-syntax-hook) + (add-hook 'semantic-unmatched-syntax-hook + 'semantic-show-unmatched-syntax nil t) + (semantic-make-local-hook 'semantic-pre-clean-token-hooks) + (add-hook 'semantic-pre-clean-token-hooks + 'semantic-clean-token-of-unmatched-syntax nil t) + ;; Show unmatched syntax elements + (if (not (semantic--umatched-syntax-needs-refresh-p)) + (semantic-show-unmatched-syntax + (semantic-unmatched-syntax-tokens)))) + ;; Remove hooks + (remove-hook 'semantic-unmatched-syntax-hook + 'semantic-show-unmatched-syntax t) + (remove-hook 'semantic-pre-clean-token-hooks + 'semantic-clean-token-of-unmatched-syntax t) + ;; Cleanup unmatched-syntax highlighting + (semantic-clean-unmatched-syntax-in-buffer)) + semantic-show-unmatched-syntax-mode) + +(defun semantic-show-unmatched-syntax-mode (&optional arg) + "Minor mode to highlight unmatched lexical syntax tokens. +When a parser executes, some elements in the buffer may not match any +parser rules. These text characters are considered unmatched syntax. +Often time, the display of unmatched syntax can expose coding +problems before the compiler is run. + +With prefix argument ARG, turn on if positive, otherwise off. The +minor mode can be turned on only if semantic feature is available and +the current buffer was set up for parsing. Return non-nil if the +minor mode is enabled. + +\\{semantic-show-unmatched-syntax-mode-map}" + (interactive + (list (or current-prefix-arg + (if semantic-show-unmatched-syntax-mode 0 1)))) + (setq semantic-show-unmatched-syntax-mode + (if arg + (> + (prefix-numeric-value arg) + 0) + (not semantic-show-unmatched-syntax-mode))) + (semantic-show-unmatched-syntax-mode-setup) + (run-hooks 'semantic-show-unmatched-syntax-mode-hook) + (if (interactive-p) + (message "show-unmatched-syntax minor mode %sabled" + (if semantic-show-unmatched-syntax-mode "en" "dis"))) + (semantic-mode-line-update) + semantic-show-unmatched-syntax-mode) + +(semantic-add-minor-mode 'semantic-show-unmatched-syntax-mode + "u" + semantic-show-unmatched-syntax-mode-map) + +(defun semantic-show-unmatched-syntax-next () + "Move forward to the next occurrence of unmatched syntax." + (interactive) + (let ((o (semantic-next-unmatched-syntax (point)))) + (if o + (goto-char (semantic-overlay-start o))))) + + +;;;; +;;;; Minor mode to display the parser state in the modeline. +;;;; + +(defcustom global-semantic-show-parser-state-mode nil + "*If non-nil enable global use of `semantic-show-parser-state-mode'. +When enabled, the current parse state of the current buffer is displayed +in the mode line. See `semantic-show-parser-state-marker' for details +on what is displayed." + :group 'semantic + :type 'boolean + :require 'semantic/util-modes + :initialize 'custom-initialize-default + :set (lambda (sym val) + (global-semantic-show-parser-state-mode (if val 1 -1)))) + +(defun global-semantic-show-parser-state-mode (&optional arg) + "Toggle global use of option `semantic-show-parser-state-mode'. +If ARG is positive, enable, if it is negative, disable. +If ARG is nil, then toggle." + (interactive "P") + (setq global-semantic-show-parser-state-mode + (semantic-toggle-minor-mode-globally + 'semantic-show-parser-state-mode arg))) + +(defcustom semantic-show-parser-state-mode-hook nil + "*Hook run at the end of function `semantic-show-parser-state-mode'." + :group 'semantic + :type 'hook) + +(defvar semantic-show-parser-state-mode-map + (let ((km (make-sparse-keymap))) + km) + "Keymap for show-parser-state minor mode.") + +(defvar semantic-show-parser-state-mode nil + "Non-nil if show-parser-state minor mode is enabled. +Use the command `semantic-show-parser-state-mode' to change this variable.") +(make-variable-buffer-local 'semantic-show-parser-state-mode) + +(defun semantic-show-parser-state-mode-setup () + "Setup option `semantic-show-parser-state-mode'. +The minor mode can be turned on only if semantic feature is available +and the current buffer was set up for parsing. When minor mode is +enabled parse the current buffer if needed. Return non-nil if the +minor mode is enabled." + (if semantic-show-parser-state-mode + (if (not (and (featurep 'semantic) (semantic-active-p))) + (progn + ;; Disable minor mode if semantic stuff not available + (setq semantic-show-parser-state-mode nil) + (error "Buffer %s was not set up for parsing" + (buffer-name))) + ;; Set up mode line + + (when (not + (memq 'semantic-show-parser-state-string mode-line-modified)) + (setq mode-line-modified + (append mode-line-modified + '(semantic-show-parser-state-string)))) + ;; Add hooks + (semantic-make-local-hook 'semantic-edits-new-change-hooks) + (add-hook 'semantic-edits-new-change-hooks + 'semantic-show-parser-state-marker nil t) + (semantic-make-local-hook 'semantic-edits-incremental-reparse-failed-hooks) + (add-hook 'semantic-edits-incremental-reparse-failed-hooks + 'semantic-show-parser-state-marker nil t) + (semantic-make-local-hook 'semantic-after-partial-cache-change-hook) + (add-hook 'semantic-after-partial-cache-change-hook + 'semantic-show-parser-state-marker nil t) + (semantic-make-local-hook 'semantic-after-toplevel-cache-change-hook) + (add-hook 'semantic-after-toplevel-cache-change-hook + 'semantic-show-parser-state-marker nil t) + (semantic-show-parser-state-marker) + + (semantic-make-local-hook 'semantic-before-auto-parse-hooks) + (add-hook 'semantic-before-auto-parse-hooks + 'semantic-show-parser-state-auto-marker nil t) + (semantic-make-local-hook 'semantic-after-auto-parse-hooks) + (add-hook 'semantic-after-auto-parse-hooks + 'semantic-show-parser-state-marker nil t) + + (semantic-make-local-hook 'semantic-before-idle-scheduler-reparse-hooks) + (add-hook 'semantic-before-idle-scheduler-reparse-hooks + 'semantic-show-parser-state-auto-marker nil t) + (semantic-make-local-hook 'semantic-after-idle-scheduler-reparse-hooks) + (add-hook 'semantic-after-idle-scheduler-reparse-hooks + 'semantic-show-parser-state-marker nil t) + ) + ;; Remove parts of mode line + (setq mode-line-modified + (delq 'semantic-show-parser-state-string mode-line-modified)) + ;; Remove hooks + (remove-hook 'semantic-edits-new-change-hooks + 'semantic-show-parser-state-marker t) + (remove-hook 'semantic-edits-incremental-reparse-failed-hooks + 'semantic-show-parser-state-marker t) + (remove-hook 'semantic-after-partial-cache-change-hook + 'semantic-show-parser-state-marker t) + (remove-hook 'semantic-after-toplevel-cache-change-hook + 'semantic-show-parser-state-marker t) + + (remove-hook 'semantic-before-auto-parse-hooks + 'semantic-show-parser-state-auto-marker t) + (remove-hook 'semantic-after-auto-parse-hooks + 'semantic-show-parser-state-marker t) + + (remove-hook 'semantic-before-idle-scheduler-reparse-hooks + 'semantic-show-parser-state-auto-marker t) + (remove-hook 'semantic-after-idle-scheduler-reparse-hooks + 'semantic-show-parser-state-marker t) + ) + semantic-show-parser-state-mode) + +(defun semantic-show-parser-state-mode (&optional arg) + "Minor mode for displaying parser cache state in the modeline. +The cache can be in one of three states. They are +Up to date, Partial reprase needed, and Full reparse needed. +The state is indicated in the modeline with the following characters: + `-' -> The cache is up to date. + `!' -> The cache requires a full update. + `~' -> The cache needs to be incrementally parsed. + `%' -> The cache is not currently parseable. + `@' -> Auto-parse in progress (not set here.) +With prefix argument ARG, turn on if positive, otherwise off. The +minor mode can be turned on only if semantic feature is available and +the current buffer was set up for parsing. Return non-nil if the +minor mode is enabled." + (interactive + (list (or current-prefix-arg + (if semantic-show-parser-state-mode 0 1)))) + (setq semantic-show-parser-state-mode + (if arg + (> + (prefix-numeric-value arg) + 0) + (not semantic-show-parser-state-mode))) + (semantic-show-parser-state-mode-setup) + (run-hooks 'semantic-show-parser-state-mode-hook) + (if (interactive-p) + (message "show-parser-state minor mode %sabled" + (if semantic-show-parser-state-mode "en" "dis"))) + (semantic-mode-line-update) + semantic-show-parser-state-mode) + +(semantic-add-minor-mode 'semantic-show-parser-state-mode + "" + semantic-show-parser-state-mode-map) + +(defvar semantic-show-parser-state-string nil + "String showing the parser state for this buffer. +See `semantic-show-parser-state-marker' for details.") +(make-variable-buffer-local 'semantic-show-parser-state-string) + +(defun semantic-show-parser-state-marker (&rest ignore) + "Set `semantic-show-parser-state-string' to indicate parser state. +This marker is one of the following: + `-' -> The cache is up to date. + `!' -> The cache requires a full update. + `~' -> The cache needs to be incrementally parsed. + `%' -> The cache is not currently parseable. + `@' -> Auto-parse in progress (not set here.) +Arguments IGNORE are ignored, and accepted so this can be used as a hook +in many situations." + (setq semantic-show-parser-state-string + (cond ((semantic-parse-tree-needs-rebuild-p) + "!") + ((semantic-parse-tree-needs-update-p) + "^") + ((semantic-parse-tree-unparseable-p) + "%") + (t + "-"))) + ;;(message "Setup mode line indicator to [%s]" semantic-show-parser-state-string) + (semantic-mode-line-update)) + +(defun semantic-show-parser-state-auto-marker () + "Hook function run before an autoparse. +Set up `semantic-show-parser-state-marker' to show `@' +to indicate a parse in progress." + (unless (semantic-parse-tree-up-to-date-p) + (setq semantic-show-parser-state-string "@") + (semantic-mode-line-update) + ;; For testing. + ;;(sit-for 1) + )) + + +;;;; +;;;; Minor mode to make function decls sticky. +;;;; + +(defun global-semantic-stickyfunc-mode (&optional arg) + "Toggle global use of option `semantic-stickyfunc-mode'. +If ARG is positive, enable, if it is negative, disable. +If ARG is nil, then toggle." + (interactive "P") + (setq global-semantic-stickyfunc-mode + (semantic-toggle-minor-mode-globally + 'semantic-stickyfunc-mode arg))) + +(defcustom global-semantic-stickyfunc-mode nil + "*If non-nil, enable global use of `semantic-stickyfunc-mode'. +This minor mode only works for Emacs 21 or later. +When enabled, the header line is enabled, and the first line +of the current function or method is displayed in it. +This makes it appear that the first line of that tag is +`sticky' to the top of the window." + :group 'semantic + :group 'semantic-modes + :type 'boolean + :require 'semantic/util-modes + :initialize 'custom-initialize-default + :set (lambda (sym val) + (global-semantic-stickyfunc-mode (if val 1 -1)))) + +(defcustom semantic-stickyfunc-mode-hook nil + "*Hook run at the end of function `semantic-stickyfunc-mode'." + :group 'semantic + :type 'hook) + +(defvar semantic-stickyfunc-mode-map + (let ((km (make-sparse-keymap))) + (define-key km [ header-line down-mouse-1 ] 'semantic-stickyfunc-menu) + km) + "Keymap for stickyfunc minor mode.") + +(defvar semantic-stickyfunc-popup-menu nil + "Menu used if the user clicks on the header line used by stickyfunc mode.") + +(easy-menu-define + semantic-stickyfunc-popup-menu + semantic-stickyfunc-mode-map + "Stickyfunc Menu" + '("Stickyfunc Mode" :visible (progn nil) + [ "Copy Headerline Tag" senator-copy-tag + :active (semantic-current-tag) + :help "Copy the current tag to the tag ring"] + [ "Kill Headerline Tag" senator-kill-tag + :active (semantic-current-tag) + :help "Kill tag text to the kill ring, and copy the tag to the tag ring" + ] + [ "Copy Headerline Tag to Register" senator-copy-tag-to-register + :active (semantic-current-tag) + :help "Copy the current tag to a register" + ] + [ "Narrow To Headerline Tag" senator-narrow-to-defun + :active (semantic-current-tag) + :help "Narrow to the bounds of the current tag."] + [ "Fold Headerline Tag" senator-fold-tag-toggle + :active (semantic-current-tag) + :style toggle + :selected (let ((tag (semantic-current-tag))) + (and tag (semantic-tag-folded-p tag))) + :help "Fold the current tag to one line" + ] + "---" + [ "About This Header Line" + (lambda () (interactive) + (describe-function 'semantic-stickyfunc-mode)) t]) + ) + +(defvar semantic-stickyfunc-mode nil + "Non-nil if stickyfunc minor mode is enabled. +Use the command `semantic-stickyfunc-mode' to change this variable.") +(make-variable-buffer-local 'semantic-stickyfunc-mode) + +(defcustom semantic-stickyfunc-indent-string + (if (and window-system (not (featurep 'xemacs))) + (concat + (condition-case nil + ;; Test scroll bar location + (let ((charwidth (frame-char-width)) + (scrollpos (frame-parameter (selected-frame) + 'vertical-scroll-bars)) + ) + (if (or (eq scrollpos 'left) + ;; Now wait a minute. If you turn scroll-bar-mode + ;; on, then off, the new value is t, not left. + ;; Will this mess up older emacs where the default + ;; was on the right? I don't think so since they don't + ;; support a header line. + (eq scrollpos t)) + (let ((w (when (boundp 'scroll-bar-width) + (symbol-value 'scroll-bar-width)))) + + (if (not w) + (setq w (frame-parameter (selected-frame) + 'scroll-bar-width))) + + ;; in 21.2, the frame parameter is sometimes empty + ;; so we need to get the value here. + (if (not w) + (setq w (+ (get 'scroll-bar-width 'x-frame-parameter) + ;; In 21.4, or perhaps 22.1 the x-frame + ;; parameter is different from the frame + ;; parameter by only 1 pixel. + 1))) + + (if (not w) + " " + (setq w (+ 2 w)) ; Some sort of border around + ; the scrollbar. + (make-string (/ w charwidth) ? ))) + "")) + (error "")) + (condition-case nil + ;; Test fringe size. + (let* ((f (window-fringes)) + (fw (car f)) + (numspace (/ fw (frame-char-width))) + ) + (make-string numspace ? )) + (error + ;; Well, the fancy new Emacs functions failed. Try older + ;; tricks. + (condition-case nil + ;; I'm not so sure what's up with the 21.1-21.3 fringe. + ;; It looks to be about 1 space wide. + (if (get 'fringe 'face) + " " + "") + (error "")))) + ) + ;; Not Emacs or a window system means no scrollbar or fringe, + ;; and perhaps not even a header line to worry about. + "") + "*String used to indent the stickyfunc header. +Customize this string to match the space used by scrollbars and +fringe so it does not appear that the code is moving left/right +when it lands in the sticky line." + :group 'semantic + :type 'string) + +(defvar semantic-stickyfunc-old-hlf nil + "Value of the header line when entering sticky func mode.") + +(defconst semantic-stickyfunc-header-line-format + (cond ((featurep 'xemacs) + nil) + ((>= emacs-major-version 22) + '(:eval (list + ;; Magic bit I found on emacswiki. + (propertize " " 'display '((space :align-to 0))) + (semantic-stickyfunc-fetch-stickyline)))) + ((= emacs-major-version 21) + '(:eval (list semantic-stickyfunc-indent-string + (semantic-stickyfunc-fetch-stickyline)))) + (t nil)) + "The header line format used by sticky func mode.") + +(defun semantic-stickyfunc-mode-setup () + "Setup option `semantic-stickyfunc-mode'. +For semantic enabled buffers, make the function declaration for the top most +function \"sticky\". This is accomplished by putting the first line of +text for that function in Emacs 21's header line." + (if semantic-stickyfunc-mode + (progn + (unless (and (featurep 'semantic) (semantic-active-p)) + ;; Disable minor mode if semantic stuff not available + (setq semantic-stickyfunc-mode nil) + (error "Buffer %s was not set up for parsing" (buffer-name))) + (unless (boundp 'default-header-line-format) + ;; Disable if there are no header lines to use. + (setq semantic-stickyfunc-mode nil) + (error "Sticky Function mode requires Emacs 21")) + ;; Enable the mode + ;; Save previous buffer local value of header line format. + (when (and (local-variable-p 'header-line-format (current-buffer)) + (not (eq header-line-format + semantic-stickyfunc-header-line-format))) + (set (make-local-variable 'semantic-stickyfunc-old-hlf) + header-line-format)) + (setq header-line-format semantic-stickyfunc-header-line-format) + ) + ;; Disable sticky func mode + ;; Restore previous buffer local value of header line format if + ;; the current one is the sticky func one. + (when (eq header-line-format semantic-stickyfunc-header-line-format) + (kill-local-variable 'header-line-format) + (when (local-variable-p 'semantic-stickyfunc-old-hlf (current-buffer)) + (setq header-line-format semantic-stickyfunc-old-hlf) + (kill-local-variable 'semantic-stickyfunc-old-hlf)))) + semantic-stickyfunc-mode) + +(defun semantic-stickyfunc-mode (&optional arg) + "Minor mode to show the title of a tag in the header line. +Enables/disables making the header line of functions sticky. +A function (or other tag class specified by +`semantic-stickyfunc-sticky-classes') has a header line, meaning the +first line which describes the rest of the construct. This first +line is what is displayed in the Emacs 21 header line. + +With prefix argument ARG, turn on if positive, otherwise off. The +minor mode can be turned on only if semantic feature is available and +the current buffer was set up for parsing. Return non-nil if the +minor mode is enabled." + (interactive + (list (or current-prefix-arg + (if semantic-stickyfunc-mode 0 1)))) + (setq semantic-stickyfunc-mode + (if arg + (> + (prefix-numeric-value arg) + 0) + (not semantic-stickyfunc-mode))) + (semantic-stickyfunc-mode-setup) + (run-hooks 'semantic-stickyfunc-mode-hook) + (if (interactive-p) + (message "Stickyfunc minor mode %sabled" + (if semantic-stickyfunc-mode "en" "dis"))) + (semantic-mode-line-update) + semantic-stickyfunc-mode) + +(defvar semantic-stickyfunc-sticky-classes + '(function type) + "List of tag classes which sticky func will display in the header line.") +(make-variable-buffer-local 'semantic-stickyfunc-sticky-classes) + +(defun semantic-stickyfunc-tag-to-stick () + "Return the tag to stick at the current point." + (let ((tags (nreverse (semantic-find-tag-by-overlay (point))))) + ;; Get rid of non-matching tags. + (while (and tags + (not (member + (semantic-tag-class (car tags)) + semantic-stickyfunc-sticky-classes)) + ) + (setq tags (cdr tags))) + (car tags))) + +(defun semantic-stickyfunc-fetch-stickyline () + "Make the function at the top of the current window sticky. +Capture it's function declaration, and place it in the header line. +If there is no function, disable the header line." + (let ((str + (save-excursion + (goto-char (window-start (selected-window))) + (forward-line -1) + (end-of-line) + ;; Capture this function + (let* ((tag (semantic-stickyfunc-tag-to-stick))) + ;; TAG is nil if there was nothing of the apropriate type there. + (if (not tag) + ;; Set it to be the text under the header line + (buffer-substring (point-at-bol) (point-at-eol)) + ;; Get it + (goto-char (semantic-tag-start tag)) + ;; Klaus Berndl <klaus.berndl@sdm.de>: + ;; goto the tag name; this is especially needed for languages + ;; like c++ where a often used style is like: + ;; void + ;; ClassX::methodM(arg1...) + ;; { + ;; ... + ;; } + ;; Without going to the tag-name we would get"void" in the + ;; header line which is IMHO not really useful + (search-forward (semantic-tag-name tag) nil t) + (buffer-substring (point-at-bol) (point-at-eol)) + )))) + (start 0)) + (while (string-match "%" str start) + (setq str (replace-match "%%" t t str 0) + start (1+ (match-end 0))) + ) + ;; In 21.4 (or 22.1) the heder doesn't expand tabs. Hmmmm. + ;; We should replace them here. + ;; + ;; This hack assumes that tabs are kept smartly at tab boundaries + ;; instead of in a tab boundary where it might only represent 4 spaces. + (while (string-match "\t" str start) + (setq str (replace-match " " t t str 0))) + str)) + +(defun semantic-stickyfunc-menu (event) + "Popup a menu that can help a user understand stickyfunc-mode. +Argument EVENT describes the event that caused this function to be called." + (interactive "e") + (let* ((startwin (selected-window)) + (win (car (car (cdr event)))) + ) + (select-window win t) + (save-excursion + (goto-char (window-start win)) + (sit-for 0) + (popup-menu semantic-stickyfunc-popup-menu event) + ) + (select-window startwin))) + + +(semantic-add-minor-mode 'semantic-stickyfunc-mode + "" ;; Don't need indicator. It's quite visible + semantic-stickyfunc-mode-map) + + + +;;;; +;;;; Minor mode to make highlight the current function +;;;; + +;; Highlight the first like of the function we are in if it is different +;; from the the tag going off the top of the screen. +(defun global-semantic-highlight-func-mode (&optional arg) + "Toggle global use of option `semantic-highlight-func-mode'. +If ARG is positive, enable, if it is negative, disable. +If ARG is nil, then toggle." + (interactive "P") + (setq global-semantic-highlight-func-mode + (semantic-toggle-minor-mode-globally + 'semantic-highlight-func-mode arg))) + +(defcustom global-semantic-highlight-func-mode nil + "*If non-nil, enable global use of `semantic-highlight-func-mode'. +When enabled, the first line of the current tag is highlighted." + :group 'semantic + :group 'semantic-modes + :type 'boolean + :require 'semantic/util-modes + :initialize 'custom-initialize-default + :set (lambda (sym val) + (global-semantic-highlight-func-mode (if val 1 -1)))) + +(defcustom semantic-highlight-func-mode-hook nil + "*Hook run at the end of function `semantic-highlight-func-mode'." + :group 'semantic + :type 'hook) + +(defvar semantic-highlight-func-mode-map + (let ((km (make-sparse-keymap)) + (m3 (if (featurep 'xemacs) [ button3 ] [ mouse-3 ])) + ) + (define-key km m3 'semantic-highlight-func-menu) + km) + "Keymap for highlight-func minor mode.") + +(defvar semantic-highlight-func-popup-menu nil + "Menu used if the user clicks on the header line used by `semantic-highlight-func-mode'.") + +(easy-menu-define + semantic-highlight-func-popup-menu + semantic-highlight-func-mode-map + "Highlight-Func Menu" + '("Highlight-Func Mode" :visible (progn nil) + [ "Copy Tag" senator-copy-tag + :active (semantic-current-tag) + :help "Copy the current tag to the tag ring"] + [ "Kill Tag" senator-kill-tag + :active (semantic-current-tag) + :help "Kill tag text to the kill ring, and copy the tag to the tag ring" + ] + [ "Copy Tag to Register" senator-copy-tag-to-register + :active (semantic-current-tag) + :help "Copy the current tag to a register" + ] + [ "Narrow To Tag" senator-narrow-to-defun + :active (semantic-current-tag) + :help "Narrow to the bounds of the current tag."] + [ "Fold Tag" senator-fold-tag-toggle + :active (semantic-current-tag) + :style toggle + :selected (let ((tag (semantic-stickyfunc-tag-to-stick))) + (and tag (semantic-tag-folded-p tag))) + :help "Fold the current tag to one line" + ] + "---" + [ "About This Tag" semantic-describe-tag t]) + ) + +(defun semantic-highlight-func-menu (event) + "Popup a menu that displays things to do to the current tag. +Argument EVENT describes the event that caused this function to be called." + (interactive "e") + (let* ((startwin (selected-window)) + (win (semantic-event-window event)) + ) + (select-window win t) + (save-excursion + ;(goto-char (window-start win)) + (mouse-set-point event) + (sit-for 0) + (semantic-popup-menu semantic-highlight-func-popup-menu) + ) + (select-window startwin))) + +(defvar semantic-highlight-func-mode nil + "Non-nil if highlight-func minor mode is enabled. +Use the command `semantic-highlight-func-mode' to change this variable.") +(make-variable-buffer-local 'semantic-highlight-func-mode) + +(defvar semantic-highlight-func-ct-overlay nil + "Overlay used to highlight the tag the cursor is in.") +(make-variable-buffer-local 'semantic-highlight-func-ct-overlay) + +(defface semantic-highlight-func-current-tag-face + '((((class color) (background dark)) + ;; Put this back to something closer to black later. + (:background "gray20")) + (((class color) (background light)) + (:background "gray90"))) + "Face used to show the top of current function." + :group 'semantic-faces) + + +(defun semantic-highlight-func-mode-setup () + "Setup option `semantic-highlight-func-mode'. +For semantic enabled buffers, highlight the first line of the +current tag declaration." + (if semantic-highlight-func-mode + (progn + (unless (and (featurep 'semantic) (semantic-active-p)) + ;; Disable minor mode if semantic stuff not available + (setq semantic-highlight-func-mode nil) + (error "Buffer %s was not set up for parsing" (buffer-name))) + ;; Setup our hook + (add-hook 'post-command-hook 'semantic-highlight-func-highlight-current-tag nil t) + ) + ;; Disable highlight func mode + (remove-hook 'post-command-hook 'semantic-highlight-func-highlight-current-tag t) + (semantic-highlight-func-highlight-current-tag t) + ) + semantic-highlight-func-mode) + +(defun semantic-highlight-func-mode (&optional arg) + "Minor mode to highlight the first line of the current tag. +Enables/disables making the header line of functions sticky. +A function (or other tag class specified by +`semantic-stickfunc-sticky-classes') is highlighted, meaning the +first line which describes the rest of the construct. + +See `semantic-stickfunc-mode' for putting a function in the +header line. This mode recycles the stickyfunc configuration +classes list. + +With prefix argument ARG, turn on if positive, otherwise off. The +minor mode can be turned on only if semantic feature is available and +the current buffer was set up for parsing. Return non-nil if the +minor mode is enabled." + (interactive + (list (or current-prefix-arg + (if semantic-highlight-func-mode 0 1)))) + (setq semantic-highlight-func-mode + (if arg + (> + (prefix-numeric-value arg) + 0) + (not semantic-highlight-func-mode))) + (semantic-highlight-func-mode-setup) + (run-hooks 'semantic-highlight-func-mode-hook) + (if (interactive-p) + (message "Highlight-Func minor mode %sabled" + (if semantic-highlight-func-mode "en" "dis"))) + semantic-highlight-func-mode) + +(defun semantic-highlight-func-highlight-current-tag (&optional disable) + "Highlight the current tag under point. +Optional argument DISABLE will turn off any active highlight. +If the current tag for this buffer is different from the last time this +function was called, move the overlay." + (when (and (not (minibufferp)) + (or (not semantic-highlight-func-ct-overlay) + (eq (semantic-overlay-buffer + semantic-highlight-func-ct-overlay) + (current-buffer)))) + (let* ((tag (semantic-stickyfunc-tag-to-stick)) + (ol semantic-highlight-func-ct-overlay)) + (when (not ol) + ;; No overlay in this buffer. Make one. + (setq ol (semantic-make-overlay (point-min) (point-min) + (current-buffer) t nil)) + (semantic-overlay-put ol 'highlight-func t) + (semantic-overlay-put ol 'face 'semantic-highlight-func-current-tag-face) + (semantic-overlay-put ol 'keymap semantic-highlight-func-mode-map) + (semantic-overlay-put ol 'help-echo + "Current Function : mouse-3 - Context menu") + (setq semantic-highlight-func-ct-overlay ol) + ) + + ;; TAG is nil if there was nothing of the apropriate type there. + (if (or (not tag) disable) + ;; No tag, make the overlay go away. + (progn + (semantic-overlay-put ol 'tag nil) + (semantic-overlay-move ol (point-min) (point-min) (current-buffer)) + ) + + ;; We have a tag, if it is the same, do nothing. + (unless (eq (semantic-overlay-get ol 'tag) tag) + (save-excursion + (goto-char (semantic-tag-start tag)) + (search-forward (semantic-tag-name tag) nil t) + (semantic-overlay-put ol 'tag tag) + (semantic-overlay-move ol (point-at-bol) (point-at-eol)) + ) + ) + ))) + nil) + +(semantic-add-minor-mode 'semantic-highlight-func-mode + "" ;; Don't need indicator. It's quite visible + nil) + +(provide 'semantic/util-modes) + +;;; semantic-util-modes.el ends here |