X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/d1fa6affefe6ad289f87d07059a53a47a553aba4..8d9cc0b7ea1893059df8788129998e9a71ec07f3:/lisp/progmodes/hideif.el diff --git a/lisp/progmodes/hideif.el b/lisp/progmodes/hideif.el index 4cd538efcf..bb791b18c1 100644 --- a/lisp/progmodes/hideif.el +++ b/lisp/progmodes/hideif.el @@ -1,16 +1,17 @@ -;;; hide-ifdef-mode.el --- hides selected code within ifdef. +;;; hideif.el --- hides selected code within ifdef -;;; Copyright (C) 1988, 1994 Free Software Foundation, Inc. +;; Copyright (C) 1988, 1994, 2001, 2002, 2003, 2004, 2005, 2006, 2007 +;; Free Software Foundation, Inc. -;; Author: Dan LaLiberte +;; Author: Daniel LaLiberte ;; Maintainer: FSF -;; Keywords: c +;; Keywords: c, outlines ;; 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 2, or (at your option) +;; the Free Software Foundation; either version 3, or (at your option) ;; any later version. ;; GNU Emacs is distributed in the hope that it will be useful, @@ -19,312 +20,257 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs; see the file COPYING. If not, write to -;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. ;;; Commentary: -;;; To initialize, toggle the hide-ifdef minor mode with -;;; -;;; M-x hide-ifdef-mode -;;; -;;; This will set up key bindings and call hide-ifdef-mode-hook if it -;;; has a value. To explicitly hide ifdefs using a buffer-local -;;; define list (default empty), type -;;; -;;; M-x hide-ifdefs or C-c h -;;; -;;; Hide-ifdef suppresses the display of code that the preprocessor wouldn't -;;; pass through. The support of constant expressions in #if lines is -;;; limited to identifiers, parens, and the operators: &&, ||, !, and -;;; "defined". Please extend this. -;;; -;;; The hidden code is marked by ellipses (...). Be -;;; cautious when editing near ellipses, since the hidden text is -;;; still in the buffer, and you can move the point into it and modify -;;; text unawares. If you don't want to see the ellipses, set -;;; selective-display-ellipses to nil. But this can be dangerous. -;;; You can make your buffer read-only while hide-ifdef-hiding by setting -;;; hide-ifdef-read-only to a non-nil value. You can toggle this -;;; variable with hide-ifdef-toggle-read-only (C-c C-q). -;;; -;;; You can undo the effect of hide-ifdefs by typing -;;; -;;; M-x show-ifdefs or C-c s -;;; -;;; Use M-x hide-ifdef-define (C-c d) to define a symbol. -;;; Use M-x hide-ifdef-undef (C-c u) to undefine a symbol. -;;; -;;; If you define or undefine a symbol while hide-ifdef-mode is in effect, -;;; the display will be updated. Only the define list for the current -;;; buffer will be affected. You can save changes to the local define -;;; list with hide-ifdef-set-define-alist. This adds entries -;;; to hide-ifdef-define-alist. -;;; -;;; If you have defined a hide-ifdef-mode-hook, you can set -;;; up a list of symbols that may be used by hide-ifdefs as in the -;;; following example: -;;; -;;; (setq hide-ifdef-mode-hook -;;; '(lambda () -;;; (if (not hide-ifdef-define-alist) -;;; (setq hide-ifdef-define-alist -;;; '((list1 ONE TWO) -;;; (list2 TWO THREE) -;;; ))) -;;; (hide-ifdef-use-define-alist 'list2) ; use list2 by default -;;; )) -;;; -;;; You can call hide-ifdef-use-define-alist (C-c u) at any time to specify -;;; another list to use. -;;; -;;; To cause ifdefs to be hidden as soon as hide-ifdef-mode is called, -;;; set hide-ifdef-initially to non-nil. -;;; -;;; If you set hide-ifdef-lines to t, hide-ifdefs hides all the #ifdef lines. -;;; In the absence of highlighting, that might be a bad idea. If you set -;;; hide-ifdef-lines to nil (the default), the surrounding preprocessor -;;; lines will be displayed. That can be confusing in its own -;;; right. Other variations on display are possible, but not much -;;; better. -;;; -;;; You can explicitly hide or show individual ifdef blocks irrespective -;;; of the define list by using hide-ifdef-block and show-ifdef-block. -;;; -;;; You can move the point between ifdefs with forward-ifdef, backward-ifdef, -;;; up-ifdef, down-ifdef, next-ifdef, and previous-ifdef. -;;; -;;; If you have minor-mode-alist in your mode line (the default) two labels -;;; may appear. "Ifdef" will appear when hide-ifdef-mode is active. "Hiding" -;;; will appear when text may be hidden ("hide-ifdef-hiding" is non-nil). -;;; -;;; Written by Brian Marick, at Gould, Computer Systems Division, Urbana IL. -;;; Extensively modified by Daniel LaLiberte (while at Gould). -;;; -;;; You may freely modify and distribute this, but keep a record -;;; of modifications and send comments to: -;;; liberte@a.cs.uiuc.edu or ihnp4!uiucdcs!liberte -;;; I will continue to upgrade hide-ifdef-mode -;;; with your contributions. - -;;; Change Log: -;;; -;;; Revision 1.7 88/02/16 03:12:58 liberte -;;; Fixed comments and doc strings. -;;; Added optional prefix arg for ifdef motion commands. -;;; -;;; Revision 1.6 88/02/05 00:36:18 liberte -;;; Bug fixes. -;;; 1. A multi-line comment that starts on an #ifdef line -;;; now ends on that line. -;;; 2. Fix bad function name: hide-hif-ifdef-toggle-read-only -;;; 3. Make ifdef-block hiding work outside of ifdefs. -;;; -;;; Revision 1.5 88/01/31 23:19:31 liberte -;;; Major clean up. -;;; Prefix internal names with "hif-". -;;; -;;; Revision 1.4 88/01/30 14:09:38 liberte -;;; Add hide-ifdef-hiding and hide-ifdef-mode to minor-mode-alist. -;;; -;;; Revision 1.3 88/01/29 00:38:19 liberte -;;; Fix three bugs. -;;; 1. Function "defined" is just like lookup. -;;; 2. Skip to newline or cr in case text is hidden. -;;; 3. Use car of token list if just one symbol. -;;; -;;; Revision 1.2 88/01/28 23:32:46 liberte -;;; Use hide-ifdef-mode-prefix-key. -;;; Copy current-local-map so other buffers do not get -;;; hide-ifdef-mode bindings. -;;; +;; To initialize, toggle the hide-ifdef minor mode with +;; +;; M-x hide-ifdef-mode +;; +;; This will set up key bindings and call hide-ifdef-mode-hook if it +;; has a value. To explicitly hide ifdefs using a buffer-local +;; define list (default empty), type +;; +;; M-x hide-ifdefs or C-c @ h +;; +;; Hide-ifdef suppresses the display of code that the preprocessor wouldn't +;; pass through. The support of constant expressions in #if lines is +;; limited to identifiers, parens, and the operators: &&, ||, !, and +;; "defined". Please extend this. +;; +;; The hidden code is marked by ellipses (...). Be +;; cautious when editing near ellipses, since the hidden text is +;; still in the buffer, and you can move the point into it and modify +;; text unawares. +;; You can make your buffer read-only while hide-ifdef-hiding by setting +;; hide-ifdef-read-only to a non-nil value. You can toggle this +;; variable with hide-ifdef-toggle-read-only (C-c @ C-q). +;; +;; You can undo the effect of hide-ifdefs by typing +;; +;; M-x show-ifdefs or C-c @ s +;; +;; Use M-x hide-ifdef-define (C-c @ d) to define a symbol. +;; Use M-x hide-ifdef-undef (C-c @ u) to undefine a symbol. +;; +;; If you define or undefine a symbol while hide-ifdef-mode is in effect, +;; the display will be updated. Only the define list for the current +;; buffer will be affected. You can save changes to the local define +;; list with hide-ifdef-set-define-alist. This adds entries +;; to hide-ifdef-define-alist. +;; +;; If you have defined a hide-ifdef-mode-hook, you can set +;; up a list of symbols that may be used by hide-ifdefs as in the +;; following example: +;; +;; (add-hook 'hide-ifdef-mode-hook +;; (lambda () +;; (unless hide-ifdef-define-alist +;; (setq hide-ifdef-define-alist +;; '((list1 ONE TWO) +;; (list2 TWO THREE)))) +;; (hide-ifdef-use-define-alist 'list2))) ; use list2 by default +;; +;; You can call hide-ifdef-use-define-alist (C-c @ U) at any time to specify +;; another list to use. +;; +;; To cause ifdefs to be hidden as soon as hide-ifdef-mode is called, +;; set hide-ifdef-initially to non-nil. +;; +;; If you set hide-ifdef-lines to t, hide-ifdefs hides all the #ifdef lines. +;; In the absence of highlighting, that might be a bad idea. If you set +;; hide-ifdef-lines to nil (the default), the surrounding preprocessor +;; lines will be displayed. That can be confusing in its own +;; right. Other variations on display are possible, but not much +;; better. +;; +;; You can explicitly hide or show individual ifdef blocks irrespective +;; of the define list by using hide-ifdef-block and show-ifdef-block. +;; +;; You can move the point between ifdefs with forward-ifdef, backward-ifdef, +;; up-ifdef, down-ifdef, next-ifdef, and previous-ifdef. +;; +;; If you have minor-mode-alist in your mode line (the default) two labels +;; may appear. "Ifdef" will appear when hide-ifdef-mode is active. "Hiding" +;; will appear when text may be hidden ("hide-ifdef-hiding" is non-nil). +;; +;; Written by Brian Marick, at Gould, Computer Systems Division, Urbana IL. +;; Extensively modified by Daniel LaLiberte (while at Gould). +;; +;; You may freely modify and distribute this, but keep a record +;; of modifications and send comments to: +;; liberte@a.cs.uiuc.edu or ihnp4!uiucdcs!liberte +;; I will continue to upgrade hide-ifdef-mode +;; with your contributions. ;;; Code: -(defvar hide-ifdef-mode-submap nil - "Keymap used with Hide-Ifdef mode.") +(require 'cc-mode) + +(defgroup hide-ifdef nil + "Hide selected code within `ifdef'." + :group 'c) + +(defvar hide-ifdef-mode-submap + ;; Set up the submap that goes after the prefix key. + (let ((map (make-sparse-keymap))) + (define-key map "d" 'hide-ifdef-define) + (define-key map "u" 'hide-ifdef-undef) + (define-key map "D" 'hide-ifdef-set-define-alist) + (define-key map "U" 'hide-ifdef-use-define-alist) + + (define-key map "h" 'hide-ifdefs) + (define-key map "s" 'show-ifdefs) + (define-key map "\C-d" 'hide-ifdef-block) + (define-key map "\C-s" 'show-ifdef-block) -(defvar hide-ifdef-mode-map nil - "Keymap used with Hide-Ifdef mode.") + (define-key map "\C-q" 'hide-ifdef-toggle-read-only) + (substitute-key-definition + 'toggle-read-only 'hide-ifdef-toggle-outside-read-only map) + map) + "Keymap used by `hide-ifdef-mode' under `hide-ifdef-mode-prefix-key'.") -(defconst hide-ifdef-mode-prefix-key "\C-c" +(defconst hide-ifdef-mode-prefix-key "\C-c@" "Prefix key for all Hide-Ifdef mode commands.") -;; Set up the submap that goes after the prefix key. -(if hide-ifdef-mode-submap - () ; dont redefine it. - (setq hide-ifdef-mode-submap (make-sparse-keymap)) - (define-key hide-ifdef-mode-submap "\ed" 'hide-ifdef-define) - (define-key hide-ifdef-mode-submap "\eu" 'hide-ifdef-undef) - (define-key hide-ifdef-mode-submap "\eD" 'hide-ifdef-set-define-alist) - (define-key hide-ifdef-mode-submap "\eU" 'hide-ifdef-use-define-alist) - - (define-key hide-ifdef-mode-submap "\eh" 'hide-ifdefs) - (define-key hide-ifdef-mode-submap "\es" 'show-ifdefs) - (define-key hide-ifdef-mode-submap "\C-d" 'hide-ifdef-block) - (define-key hide-ifdef-mode-submap "\C-s" 'show-ifdef-block) - - (define-key hide-ifdef-mode-submap "\C-q" 'hide-ifdef-toggle-read-only) - (let ((where (where-is-internal 'toggle-read-only '(keymap) t))) - (if where - (define-key hide-ifdef-mode-submap - where - 'hide-ifdef-toggle-outside-read-only))) - ) - -;; Set up the mode's main map, which leads via the prefix key to the submap. -(if hide-ifdef-mode-map - () - (setq hide-ifdef-mode-map (make-sparse-keymap)) - (define-key hide-ifdef-mode-map hide-ifdef-mode-prefix-key - hide-ifdef-mode-submap)) - -(defun hif-update-mode-line () - "Update mode-line by setting buffer-modified to itself." - (set-buffer-modified-p (buffer-modified-p))) - -(defvar hide-ifdef-mode nil - "Non-nil when hide-ifdef-mode is activated.") +(defvar hide-ifdef-mode-map + ;; Set up the mode's main map, which leads via the prefix key to the submap. + (let ((map (make-sparse-keymap))) + (define-key map hide-ifdef-mode-prefix-key hide-ifdef-mode-submap) + map) + "Keymap used with `hide-ifdef-mode'.") (defvar hide-ifdef-hiding nil "Non-nil when text may be hidden.") -;; Arrange to use the mode's map when the mode is enabled. -(or (assq 'hide-ifdef-mode minor-mode-map-alist) - (setq minor-mode-map-alist - (cons (cons 'hide-ifdef-mode hide-ifdef-mode-map) - minor-mode-map-alist))) - (or (assq 'hide-ifdef-hiding minor-mode-alist) (setq minor-mode-alist (cons '(hide-ifdef-hiding " Hiding") minor-mode-alist))) -(or (assq 'hide-ifdef-mode minor-mode-alist) - (setq minor-mode-alist - (cons '(hide-ifdef-mode " Ifdef") - minor-mode-alist))) - ;; fix c-mode syntax table so we can recognize whole symbols. (defvar hide-ifdef-syntax-table - (copy-syntax-table c-mode-syntax-table) + (let ((st (copy-syntax-table c-mode-syntax-table))) + (modify-syntax-entry ?_ "w" st) + (modify-syntax-entry ?& "." st) + (modify-syntax-entry ?\| "." st) + st) "Syntax table used for tokenizing #if expressions.") -(modify-syntax-entry ?_ "w" hide-ifdef-syntax-table) -(modify-syntax-entry ?& "." hide-ifdef-syntax-table) -(modify-syntax-entry ?\| "." hide-ifdef-syntax-table) +(defvar hide-ifdef-env nil + "An alist of defined symbols and their values.") + +(defvar hif-outside-read-only nil + "Internal variable. Saves the value of `buffer-read-only' while hiding.") ;;;###autoload -(defun hide-ifdef-mode (arg) +(define-minor-mode hide-ifdef-mode "Toggle Hide-Ifdef mode. This is a minor mode, albeit a large one. -With ARG, turn Hide-Ifdef mode on iff arg is positive. +With ARG, turn Hide-Ifdef mode on if arg is positive, off otherwise. In Hide-Ifdef mode, code within #ifdef constructs that the C preprocessor would eliminate may be hidden from view. Several variables affect how the hiding is done: -hide-ifdef-env +`hide-ifdef-env' An association list of defined and undefined symbols for the current buffer. Initially, the global value of `hide-ifdef-env' is used. -hide-ifdef-define-alist - An association list of defined symbol lists. +`hide-ifdef-define-alist' + An association list of defined symbol lists. Use `hide-ifdef-set-define-alist' to save the current `hide-ifdef-env' and `hide-ifdef-use-define-alist' to set the current `hide-ifdef-env' from one of the lists in `hide-ifdef-define-alist'. -hide-ifdef-lines +`hide-ifdef-lines' Set to non-nil to not show #if, #ifdef, #ifndef, #else, and #endif lines when hiding. -hide-ifdef-initially +`hide-ifdef-initially' Indicates whether `hide-ifdefs' should be called when Hide-Ifdef mode is activated. -hide-ifdef-read-only +`hide-ifdef-read-only' Set to non-nil if you want to make buffers read only while hiding. After `show-ifdefs', read-only status is restored to previous value. \\{hide-ifdef-mode-map}" - - (interactive "P") - (make-local-variable 'hide-ifdef-mode) - (setq hide-ifdef-mode - (if (null arg) - (not hide-ifdef-mode) - (> (prefix-numeric-value arg) 0))) - - (force-mode-line-update) - + :group 'hide-ifdef :lighter " Ifdef" (if hide-ifdef-mode (progn - ; inherit global values - (make-local-variable 'hide-ifdef-env) - (setq hide-ifdef-env (default-value 'hide-ifdef-env)) - - (make-local-variable 'hide-ifdef-hiding) - (setq hide-ifdef-hiding (default-value 'hide-ifdef-hiding)) - - (make-local-variable 'hif-outside-read-only) - (setq hif-outside-read-only buffer-read-only) - - (run-hooks 'hide-ifdef-mode-hook) + ;; inherit global values + (set (make-local-variable 'hide-ifdef-env) + (default-value 'hide-ifdef-env)) + (set (make-local-variable 'hide-ifdef-hiding) + (default-value 'hide-ifdef-hiding)) + (set (make-local-variable 'hif-outside-read-only) buffer-read-only) + (set (make-local-variable 'line-move-ignore-invisible) t) + (add-hook 'change-major-mode-hook + (lambda () (hide-ifdef-mode -1)) nil t) + + (add-to-invisibility-spec '(hide-ifdef . t)) (if hide-ifdef-initially (hide-ifdefs) - (show-ifdefs)) - (message "Enter hide-ifdef-mode.") - ) - ; else end hide-ifdef-mode + (show-ifdefs))) + ;; else end hide-ifdef-mode + (kill-local-variable 'line-move-ignore-invisible) + (remove-from-invisibility-spec '(hide-ifdef . t)) (if hide-ifdef-hiding - (show-ifdefs)) - (message "Exit hide-ifdef-mode.") - )) - - -;; from outline.el with docstring fixed. -(defun hif-outline-flag-region (from to flag) - "Hides or shows lines from FROM to TO, according to FLAG. If FLAG -is \\n (newline character) then text is shown, while if FLAG is \\^M -\(control-M) the text is hidden." - (let ((modp (buffer-modified-p))) - (unwind-protect (progn - (subst-char-in-region from to - (if (= flag ?\n) ?\^M ?\n) - flag t) ) - (set-buffer-modified-p modp)) - )) + (show-ifdefs)))) + (defun hif-show-all () "Show all of the text in the current buffer." (interactive) - (hif-outline-flag-region (point-min) (point-max) ?\n)) + (hif-show-ifdef-region (point-min) (point-max))) + +;; By putting this on after-revert-hook, we arrange that it only +;; does anything when revert-buffer avoids turning off the mode. +;; (That can happen in VC.) +(defun hif-after-revert-function () + (and hide-ifdef-mode hide-ifdef-hiding + (hide-ifdefs t))) +(add-hook 'after-revert-hook 'hif-after-revert-function) + +(defun hif-end-of-line () + (end-of-line) + (while (= (logand 1 (skip-chars-backward "\\\\")) 1) + (end-of-line 2))) + +(defun hide-ifdef-region-internal (start end) + (remove-overlays start end 'invisible 'hide-ifdef) + (let ((o (make-overlay start end))) + (overlay-put o 'invisible 'hide-ifdef))) (defun hide-ifdef-region (start end) "START is the start of a #if or #else form. END is the ending part. Everything including these lines is made invisible." - (hif-outline-flag-region start end ?\^M) - ) + (save-excursion + (goto-char start) (hif-end-of-line) (setq start (point)) + (goto-char end) (hif-end-of-line) (setq end (point)) + (hide-ifdef-region-internal start end))) (defun hif-show-ifdef-region (start end) "Everything between START and END is made visible." - (hif-outline-flag-region start end ?\n) - ) + (remove-overlays start end 'invisible 'hide-ifdef)) +;;===%%SF%% evaluation (Start) === -;===%%SF%% evaluation (Start) === - +;; It is not useful to set this to anything but `eval'. +;; In fact, the variable might as well be eliminated. (defvar hide-ifdef-evaluator 'eval - "The evaluator is given a canonical form and returns T if text under + "The function to use to evaluate a form. +The evaluator is given a canonical form and returns t if text under that form should be displayed.") (defvar hif-undefined-symbol nil "...is by default considered to be false.") -(defvar hide-ifdef-env nil - "An alist of defined symbols and their values.") - (defun hif-set-var (var value) "Prepend (var value) pair to hide-ifdef-env." @@ -332,26 +278,20 @@ that form should be displayed.") (defun hif-lookup (var) -; (message "hif-lookup %s" var) + ;; (message "hif-lookup %s" var) (let ((val (assoc var hide-ifdef-env))) (if val (cdr val) hif-undefined-symbol))) (defun hif-defined (var) - (hif-lookup var) - ; when #if expressions are fully supported, defined result should be 1 - ; (if (assoc var hide-ifdef-env) - ; 1 - ; nil) -) - + (if (assoc var hide-ifdef-env) 1 0)) -;===%%SF%% evaluation (End) === +;;===%%SF%% evaluation (End) === -;===%%SF%% parsing (Start) === +;;===%%SF%% parsing (Start) === ;;; The code that understands what ifs and ifdef in files look like. (defconst hif-cpp-prefix "\\(^\\|\r\\)[ \t]*#[ \t]*") @@ -362,192 +302,237 @@ that form should be displayed.") (defconst hif-ifx-else-endif-regexp (concat hif-ifx-regexp "\\|" hif-else-regexp "\\|" hif-endif-regexp)) +;; Used to store the current token and the whole token list during parsing. +;; Only bound dynamically. +(defvar hif-token) +(defvar hif-token-list) + +;; pattern to match initial identifier, !, &&, ||, (, or ). +;; Added ==, + and -: garyo@avs.com 8/9/94 +(defconst hif-token-regexp + "\\(&&\\|||\\|[!=]=\\|!\\|[()+?:-]\\|[<>]=?\\|\\w+\\)") -(defun hif-infix-to-prefix (token-list) - "Convert list of tokens in infix into prefix list" -; (message "hif-infix-to-prefix: %s" token-list) - (if (= 1 (length token-list)) - (` (hif-lookup (quote (, (car token-list))))) - (hif-parse-if-exp token-list)) - ) - -; pattern to match initial identifier, !, &&, ||, (, or ). -(defconst hif-token-regexp "^\\(!\\|&&\\|||\\|[()]\\|\\w+\\)") -(defconst hif-end-of-comment "\\*/") - - -(defun hif-tokenize (expr-string) - "Separate string into a list of tokens" - (let ((token-list nil) - (expr-start 0) - (expr-length (length expr-string)) - (current-syntax-table (syntax-table))) - (unwind-protect - (progn - (set-syntax-table hide-ifdef-syntax-table) - (while (< expr-start expr-length) -; (message "expr-start = %d" expr-start) (sit-for 1) - (cond - ((string-match "^[ \t]+" expr-string expr-start) - ;; skip whitespace - (setq expr-start (match-end 0)) - ;; stick newline in string so ^ matches on the next string-match - (aset expr-string (1- expr-start) ?\n)) - - ((string-match "^/\\*" expr-string expr-start) - (setq expr-start (match-end 0)) - (aset expr-string (1- expr-start) ?\n) - (or - (string-match hif-end-of-comment - expr-string expr-start) ; eat comment - (string-match "$" expr-string expr-start)) ; multi-line comment - (setq expr-start (match-end 0)) - (aset expr-string (1- expr-start) ?\n)) - - ((string-match "^//" expr-string expr-start) - (string-match "$" expr-string expr-start) - (setq expr-start (match-end 0))) - - ((string-match hif-token-regexp expr-string expr-start) - (let ((token (substring expr-string expr-start (match-end 0)))) - (setq expr-start (match-end 0)) - (aset expr-string (1- expr-start) ?\n) -; (message "token: %s" token) (sit-for 1) - (setq token-list - (cons - (cond - ((string-equal token "||") 'or) - ((string-equal token "&&") 'and) - ((string-equal token "!") 'not) - ((string-equal token "defined") 'hif-defined) - ((string-equal token "(") 'lparen) - ((string-equal token ")") 'rparen) - (t (intern token))) - token-list)))) - - (t (error "Bad #if expression: %s" expr-string))))) - (set-syntax-table current-syntax-table)) +(defun hif-tokenize (start end) + "Separate string between START and END into a list of tokens." + (let ((token-list nil)) + (with-syntax-table hide-ifdef-syntax-table + (save-excursion + (goto-char start) + (while (progn (forward-comment (point-max)) (< (point) end)) + ;; (message "expr-start = %d" expr-start) (sit-for 1) + (cond + ((looking-at "\\\\\n") + (forward-char 2)) + + ((looking-at hif-token-regexp) + (let ((token (buffer-substring (point) (match-end 0)))) + (goto-char (match-end 0)) + ;; (message "token: %s" token) (sit-for 1) + (push (cond + ((string-equal token "||") 'or) + ((string-equal token "&&") 'and) + ((string-equal token "==") 'equal) + ((string-equal token "!=") 'hif-notequal) + ((string-equal token "!") 'not) + ((string-equal token "defined") 'hif-defined) + ((string-equal token "(") 'lparen) + ((string-equal token ")") 'rparen) + ((string-equal token ">") 'hif-greater) + ((string-equal token "<") 'hif-less) + ((string-equal token ">=") 'hif-greater-equal) + ((string-equal token "<=") 'hif-less-equal) + ((string-equal token "+") 'hif-plus) + ((string-equal token "-") 'hif-minus) + ((string-equal token "?") 'hif-conditional) + ((string-equal token ":") 'hif-colon) + ((string-match "\\`[0-9]*\\'" token) + (string-to-number token)) + (t (intern token))) + token-list))) + (t (error "Bad #if expression: %s" (buffer-string))))))) (nreverse token-list))) ;;;----------------------------------------------------------------- ;;; Translate C preprocessor #if expressions using recursive descent. ;;; This parser is limited to the operators &&, ||, !, and "defined". +;;; Added ==, !=, +, and -. Gary Oberbrunner, garyo@avs.com, 8/9/94 -(defun hif-parse-if-exp (token-list) +(defsubst hif-nexttoken () + "Pop the next token from token-list into the let variable \"hif-token\"." + (setq hif-token (pop hif-token-list))) + +(defun hif-parse-if-exp (hif-token-list) "Parse the TOKEN-LIST. Return translated list in prefix form." (hif-nexttoken) (prog1 (hif-expr) - (if token ; is there still a token? - (error "Error: unexpected token: %s" token)))) - -(defun hif-nexttoken () - "Pop the next token from token-list into the let variable \"token\"." - (setq token (car token-list)) - (setq token-list (cdr token-list)) - token) + (if hif-token ; is there still a token? + (error "Error: unexpected token: %s" hif-token)))) (defun hif-expr () - "Parse and expression of the form - expr : term | expr '||' term." - (let ((result (hif-term))) - (while (eq token 'or) + "Parse an expression as found in #if. + expr : or-expr | or-expr '?' expr ':' expr." + (let ((result (hif-or-expr)) + middle) + (while (eq hif-token 'hif-conditional) (hif-nexttoken) - (setq result (list 'or result (hif-term)))) + (setq middle (hif-expr)) + (if (eq hif-token 'hif-colon) + (progn + (hif-nexttoken) + (setq result (list 'hif-conditional result middle (hif-expr)))) + (error "Error: unexpected token: %s" hif-token))) + result)) + +(defun hif-or-expr () + "Parse n or-expr : and-expr | or-expr '||' and-expr." + (let ((result (hif-and-expr))) + (while (eq hif-token 'or) + (hif-nexttoken) + (setq result (list 'hif-or result (hif-and-expr)))) result)) -(defun hif-term () - "Parse a term of the form - term : factor | term '&&' factor." - (let ((result (hif-factor))) - (while (eq token 'and) +(defun hif-and-expr () + "Parse an and-expr : eq-expr | and-expr '&&' eq-expr." + (let ((result (hif-eq-expr))) + (while (eq hif-token 'and) + (hif-nexttoken) + (setq result (list 'hif-and result (hif-eq-expr)))) + result)) + +(defun hif-eq-expr () + "Parse an eq-expr : math | eq-expr `=='|`!='|`<'|`>'|`>='|`<=' math." + (let ((result (hif-math)) + (eq-token nil)) + (while (memq hif-token '(equal hif-notequal hif-greater hif-less + hif-greater-equal hif-less-equal)) + (setq eq-token hif-token) (hif-nexttoken) - (setq result (list 'and result (hif-factor)))) + (setq result (list eq-token result (hif-math)))) result)) +(defun hif-math () + "Parse an expression with + or - and simpler things. + math : factor | math '+|-' factor." + (let ((result (hif-factor)) + (math-op nil)) + (while (memq hif-token '(hif-plus hif-minus)) + (setq math-op hif-token) + (hif-nexttoken) + (setq result (list math-op result (hif-factor)))) + result)) + (defun hif-factor () - "Parse a factor of the form - factor : '!' factor | '(' expr ')' | 'defined(' id ')' | id." + "Parse a factor: '!' factor | '(' expr ')' | 'defined(' id ')' | id." (cond - ((eq token 'not) - (hif-nexttoken) - (list 'not (hif-factor))) - - ((eq token 'lparen) - (hif-nexttoken) - (let ((result (hif-expr))) - (if (not (eq token 'rparen)) - (error "Bad token in parenthesized expression: %s" token) - (hif-nexttoken) - result))) - - ((eq token 'hif-defined) - (hif-nexttoken) - (if (not (eq token 'lparen)) - (error "Error: expected \"(\" after \"defined\"")) - (hif-nexttoken) - (let ((ident token)) - (if (memq token '(or and not hif-defined lparen rparen)) - (error "Error: unexpected token: %s" token)) - (hif-nexttoken) - (if (not (eq token 'rparen)) - (error "Error: expected \")\" after identifier")) - (hif-nexttoken) - (` (hif-defined (quote (, ident)))) - )) - - (t ; identifier - (let ((ident token)) - (if (memq ident '(or and)) - (error "Error: missing identifier")) + ((eq hif-token 'not) + (hif-nexttoken) + (list 'hif-not (hif-factor))) + + ((eq hif-token 'lparen) + (hif-nexttoken) + (let ((result (hif-expr))) + (if (not (eq hif-token 'rparen)) + (error "Bad token in parenthesized expression: %s" hif-token) + (hif-nexttoken) + result))) + + ((eq hif-token 'hif-defined) + (hif-nexttoken) + (let ((paren (when (eq hif-token 'lparen) (hif-nexttoken) t)) + (ident hif-token)) + (if (memq hif-token '(or and not hif-defined lparen rparen)) + (error "Error: unexpected token: %s" hif-token)) + (when paren (hif-nexttoken) - (` (hif-lookup (quote (, ident)))) - )) - )) + (unless (eq hif-token 'rparen) + (error "Error: expected \")\" after identifier"))) + (hif-nexttoken) + `(hif-defined (quote ,ident)))) + + ((numberp hif-token) + (prog1 hif-token (hif-nexttoken))) + (t ; identifier + (let ((ident hif-token)) + (if (memq ident '(or and)) + (error "Error: missing identifier")) + (hif-nexttoken) + `(hif-lookup (quote ,ident)))))) + +(defun hif-mathify (val) + "Treat VAL as a number: if it's t or nil, use 1 or 0." + (cond ((eq val t) 1) + ((null val) 0) + (t val))) + +(defun hif-conditional (a b c) + (if (not (zerop (hif-mathify a))) (hif-mathify b) (hif-mathify c))) +(defun hif-and (a b) + (and (not (zerop (hif-mathify a))) (not (zerop (hif-mathify b))))) +(defun hif-or (a b) + (or (not (zerop (hif-mathify a))) (not (zerop (hif-mathify b))))) +(defun hif-not (a) + (zerop (hif-mathify a))) +(defun hif-plus (a b) + "Like ordinary plus but treat t and nil as 1 and 0." + (+ (hif-mathify a) (hif-mathify b))) +(defun hif-minus (a b) + "Like ordinary minus but treat t and nil as 1 and 0." + (- (hif-mathify a) (hif-mathify b))) +(defun hif-notequal (a b) + "Like (not (equal A B)) but as one symbol." + (not (equal a b))) +(defun hif-greater (a b) + "Simple comparison." + (> (hif-mathify a) (hif-mathify b))) +(defun hif-less (a b) + "Simple comparison." + (< (hif-mathify a) (hif-mathify b))) +(defun hif-greater-equal (a b) + "Simple comparison." + (>= (hif-mathify a) (hif-mathify b))) +(defun hif-less-equal (a b) + "Simple comparison." + (<= (hif-mathify a) (hif-mathify b))) ;;;----------- end of parser ----------------------- (defun hif-canonicalize () - "When at beginning of #ifX, returns a canonical (evaluatable) - form for the expression." + "When at beginning of #ifX, return a Lisp expression for its condition." (save-excursion (let ((negate (looking-at hif-ifndef-regexp))) (re-search-forward hif-ifx-regexp) - (let* ((expr-string - (buffer-substring (point) - (progn (skip-chars-forward "^\n\r") (point)))) - (expr (hif-infix-to-prefix (hif-tokenize expr-string)))) -; (message "hif-canonicalized: %s" expr) + (let* ((tokens (hif-tokenize (point) + (progn (hif-end-of-line) (point)))) + (expr (hif-parse-if-exp tokens))) + ;; (message "hif-canonicalized: %s" expr) (if negate - (list 'not expr) + (list 'hif-not expr) expr))))) (defun hif-find-any-ifX () - "Position at beginning of next #if, #ifdef, or #ifndef, including one on -this line." -; (message "find ifX at %d" (point)) + "Move to next #if..., or #ifndef, at point or after." + ;; (message "find ifX at %d" (point)) (prog1 (re-search-forward hif-ifx-regexp (point-max) t) (beginning-of-line))) (defun hif-find-next-relevant () - "Position at beginning of next #ifdef, #ifndef, #else, #endif, -NOT including one on this line." -; (message "hif-find-next-relevant at %d" (point)) + "Move to next #if..., #else, or #endif, after the current line." + ;; (message "hif-find-next-relevant at %d" (point)) (end-of-line) - ; avoid infinite recursion by only going to beginning of line if match found + ;; avoid infinite recursion by only going to beginning of line if match found (if (re-search-forward hif-ifx-else-endif-regexp (point-max) t) (beginning-of-line))) (defun hif-find-previous-relevant () - "Position at beginning of previous #ifdef, #ifndef, #else, #endif, -NOT including one on this line." -; (message "hif-find-previous-relevant at %d" (point)) + "Move to previous #if..., #else, or #endif, before the current line." + ;; (message "hif-find-previous-relevant at %d" (point)) (beginning-of-line) - ; avoid infinite recursion by only going to beginning of line if match found + ;; avoid infinite recursion by only going to beginning of line if match found (if (re-search-backward hif-ifx-else-endif-regexp (point-min) t) (beginning-of-line))) @@ -563,7 +548,7 @@ NOT including one on this line." (defun hif-ifdef-to-endif () "If positioned at #ifX or #else form, skip to corresponding #endif." -; (message "hif-ifdef-to-endif at %d" (point)) (sit-for 1) + ;; (message "hif-ifdef-to-endif at %d" (point)) (sit-for 1) (hif-find-next-relevant) (cond ((hif-looking-at-ifX) (hif-ifdef-to-endif) ; find endif of nested if @@ -578,7 +563,7 @@ NOT including one on this line." (defun hif-endif-to-ifdef () "If positioned at #endif form, skip backward to corresponding #ifX." -; (message "hif-endif-to-ifdef at %d" (point)) + ;; (message "hif-endif-to-ifdef at %d" (point)) (let ((start (point))) (hif-find-previous-relevant) (if (= start (point)) @@ -598,18 +583,16 @@ NOT including one on this line." With argument, do this that many times." (interactive "p") (or arg (setq arg 1)) - (if (< arg 0) - (backward-ifdef (- arg))) - (while (< 0 arg) - (setq arg (- arg)) - (let ((start (point))) - (if (not (hif-looking-at-ifX)) + (if (< arg 0) (backward-ifdef (- arg)) + (while (< 0 arg) + (setq arg (- arg)) + (let ((start (point))) + (unless (hif-looking-at-ifX) (hif-find-next-relevant)) - (if (hif-looking-at-ifX) - (hif-ifdef-to-endif) - (goto-char start) - (error "No following #ifdef") - )))) + (if (hif-looking-at-ifX) + (hif-ifdef-to-endif) + (goto-char start) + (error "No following #ifdef")))))) (defun backward-ifdef (&optional arg) @@ -617,18 +600,17 @@ With argument, do this that many times." With argument, do this that many times." (interactive "p") (or arg (setq arg 1)) - (if (< arg 0) - (forward-ifdef (- arg))) - (while (< 0 arg) - (setq arg (1- arg)) - (beginning-of-line) - (let ((start (point))) - (if (not (hif-looking-at-endif)) + (if (< arg 0) (forward-ifdef (- arg)) + (while (< 0 arg) + (setq arg (1- arg)) + (beginning-of-line) + (let ((start (point))) + (unless (hif-looking-at-endif) (hif-find-previous-relevant)) - (if (hif-looking-at-endif) - (hif-endif-to-ifdef) - (goto-char start) - (error "No previous #ifdef"))))) + (if (hif-looking-at-endif) + (hif-endif-to-ifdef) + (goto-char start) + (error "No previous #ifdef")))))) (defun down-ifdef () @@ -647,8 +629,8 @@ With argument, do this that many times." (interactive) (beginning-of-line) (let ((start (point))) - (if (not (hif-looking-at-endif)) - (hif-find-previous-relevant)) + (unless (hif-looking-at-endif) + (hif-find-previous-relevant)) (if (hif-looking-at-endif) (hif-endif-to-ifdef)) (if (= start (point)) @@ -659,36 +641,32 @@ With argument, do this that many times." With argument, do this that many times." (interactive "p") (or arg (setq arg 1)) - (if (< arg 0) - (previous-ifdef (- arg))) - (while (< 0 arg) - (setq arg (1- arg)) - (hif-find-next-relevant) - (if (eolp) - (progn - (beginning-of-line) - (error "No following #ifdefs, #elses, or #endifs"))))) + (if (< arg 0) (previous-ifdef (- arg)) + (while (< 0 arg) + (setq arg (1- arg)) + (hif-find-next-relevant) + (when (eolp) + (beginning-of-line) + (error "No following #ifdefs, #elses, or #endifs"))))) (defun previous-ifdef (&optional arg) "Move to the beginning of the previous #ifX, #else, or #endif. With argument, do this that many times." (interactive "p") (or arg (setq arg 1)) - (if (< arg 0) - (next-ifdef (- arg))) - (while (< 0 arg) - (setq arg (1- arg)) - (let ((start (point))) - (hif-find-previous-relevant) - (if (= start (point)) - (error "No previous #ifdefs, #elses, or #endifs") - )))) + (if (< arg 0) (next-ifdef (- arg)) + (while (< 0 arg) + (setq arg (1- arg)) + (let ((start (point))) + (hif-find-previous-relevant) + (if (= start (point)) + (error "No previous #ifdefs, #elses, or #endifs")))))) -;===%%SF%% parsing (End) === +;;===%%SF%% parsing (End) === -;===%%SF%% hide-ifdef-hiding (Start) === +;;===%%SF%% hide-ifdef-hiding (Start) === ;;; A range is a structure with four components: @@ -698,13 +676,12 @@ With argument, do this that many times." ;;; Only valid if ELSE-P is true. ;;; END The end of the range. (beginning of line) -(defun hif-make-range (else-p start end &optional else) - (list else-p start else end)) +(defsubst hif-make-range (start end &optional else) + (list start else end)) -(defun hif-range-else-p (range) (elt range 0)) -(defun hif-range-start (range) (elt range 1)) -(defun hif-range-else (range) (elt range 2)) -(defun hif-range-end (range) (elt range 3)) +(defsubst hif-range-start (range) (elt range 0)) +(defsubst hif-range-else (range) (elt range 1)) +(defsubst hif-range-end (range) (elt range 2)) @@ -714,68 +691,53 @@ With argument, do this that many times." ;;; an #else was found, skip some more, looking for the true #endif. (defun hif-find-range () - "Returns a Range structure describing the current #if region. + "Return a Range structure describing the current #if region. Point is left unchanged." -; (message "hif-find-range at %d" (point)) + ;; (message "hif-find-range at %d" (point)) (save-excursion (beginning-of-line) (let ((start (point)) - (else-p nil) (else nil) (end nil)) ;; Part one. Look for either #endif or #else. ;; This loop-and-a-half dedicated to E. Dijkstra. - (hif-find-next-relevant) - (while (hif-looking-at-ifX) ; Skip nested ifdef - (hif-ifdef-to-endif) - (hif-find-next-relevant)) + (while (progn + (hif-find-next-relevant) + (hif-looking-at-ifX)) ; Skip nested ifdef + (hif-ifdef-to-endif)) ;; Found either a #else or an #endif. (cond ((hif-looking-at-else) - (setq else-p t) (setq else (point))) (t - (setq end (point)) ; (save-excursion (end-of-line) (point)) - )) + (setq end (point)))) ; (save-excursion (end-of-line) (point)) ;; If found #else, look for #endif. - (if else-p - (progn - (hif-find-next-relevant) - (while (hif-looking-at-ifX) ; Skip nested ifdef - (hif-ifdef-to-endif) - (hif-find-next-relevant)) - (if (hif-looking-at-else) - (error "Found two elses in a row? Broken!")) - (setq end (point)) ; (save-excursion (end-of-line) (point)) - )) - (hif-make-range else-p start end else)))) + (when else + (while (progn + (hif-find-next-relevant) + (hif-looking-at-ifX)) ; Skip nested ifdef + (hif-ifdef-to-endif)) + (if (hif-looking-at-else) + (error "Found two elses in a row? Broken!")) + (setq end (point))) ; (save-excursion (end-of-line) (point)) + (hif-make-range start end else)))) + - ;;; A bit slimy. -;;; NOTE: If there's an #ifdef at the beginning of the file, we can't -;;; hide it. There's no previous newline to replace. If we added -;;; one, we'd throw off all the counts. Feh. (defun hif-hide-line (point) "Hide the line containing point. Does nothing if `hide-ifdef-lines' is nil." (if hide-ifdef-lines (save-excursion (goto-char point) - (let ((modp (buffer-modified-p))) - (unwind-protect - (progn - (beginning-of-line) - (if (not (= (point) 1)) - (hide-ifdef-region (1- (point)) (point)))) - (set-buffer-modified-p modp)) - )) - )) - + (hide-ifdef-region-internal (line-beginning-position) + (progn (hif-end-of-line) (point)))))) + ;;; Hif-Possibly-Hide ;;; There are four cases. The #ifX expression is "taken" if it ;;; the hide-ifdef-evaluator returns T. Presumably, this means the code ;;; inside the #ifdef would be included when the program was -;;; compiled. +;;; compiled. ;;; ;;; Case 1: #ifX taken, and there's an #else. ;;; The #else part must be hidden. The #if (then) part must be @@ -804,101 +766,97 @@ Point is left unchanged." (hide-ifdef-guts)))) (defun hif-possibly-hide () - "Called at #ifX expression, this hides those parts that should be -hidden, according to judgement of `hide-ifdef-evaluator'." -; (message "hif-possibly-hide") (sit-for 1) - (let ((test (hif-canonicalize)) - (range (hif-find-range))) -; (message "test = %s" test) (sit-for 1) - - (hif-hide-line (hif-range-end range)) - (if (funcall hide-ifdef-evaluator test) - (cond ((hif-range-else-p range) ; case 1 - (hif-hide-line (hif-range-else range)) - (hide-ifdef-region (hif-range-else range) - (1- (hif-range-end range))) - (hif-recurse-on (hif-range-start range) - (hif-range-else range))) - (t ; case 2 - (hif-recurse-on (hif-range-start range) - (hif-range-end range)))) - (cond ((hif-range-else-p range) ; case 3 + "Called at #ifX expression, this hides those parts that should be hidden. +It uses the judgement of `hide-ifdef-evaluator'." + ;; (message "hif-possibly-hide") (sit-for 1) + (let ((test (hif-canonicalize)) + (range (hif-find-range))) + ;; (message "test = %s" test) (sit-for 1) + + (hif-hide-line (hif-range-end range)) + (if (not (hif-not (funcall hide-ifdef-evaluator test))) + (cond ((hif-range-else range) ; case 1 (hif-hide-line (hif-range-else range)) - (hide-ifdef-region (hif-range-start range) - (1- (hif-range-else range))) - (hif-recurse-on (hif-range-else range) - (hif-range-end range))) - (t ; case 4 - (hide-ifdef-region (point) - (1- (hif-range-end range)))) - )) - (hif-hide-line (hif-range-start range)) ; Always hide start. - (goto-char (hif-range-end range)) - (end-of-line) - )) + (hide-ifdef-region (hif-range-else range) + (1- (hif-range-end range))) + (hif-recurse-on (hif-range-start range) + (hif-range-else range))) + (t ; case 2 + (hif-recurse-on (hif-range-start range) + (hif-range-end range)))) + (cond ((hif-range-else range) ; case 3 + (hif-hide-line (hif-range-else range)) + (hide-ifdef-region (hif-range-start range) + (1- (hif-range-else range))) + (hif-recurse-on (hif-range-else range) + (hif-range-end range))) + (t ; case 4 + (hide-ifdef-region (point) + (1- (hif-range-end range)))))) + (hif-hide-line (hif-range-start range)) ; Always hide start. + (goto-char (hif-range-end range)) + (end-of-line))) (defun hide-ifdef-guts () - "Does the work of `hide-ifdefs', except for the work that's pointless -to redo on a recursive entry." -; (message "hide-ifdef-guts") + "Does most of the work of `hide-ifdefs'. +It does not do the work that's pointless to redo on a recursive entry." + ;; (message "hide-ifdef-guts") (save-excursion (goto-char (point-min)) (while (hif-find-any-ifX) (hif-possibly-hide)))) -;===%%SF%% hide-ifdef-hiding (End) === +;;===%%SF%% hide-ifdef-hiding (End) === -;===%%SF%% exports (Start) === +;;===%%SF%% exports (Start) === ;;;###autoload -(defvar hide-ifdef-initially nil - "*Non-nil if `hide-ifdefs' should be called when Hide-Ifdef mode -is first activated.") - -(defvar hide-ifdef-hiding nil - "Non-nil if text might be hidden.") +(defcustom hide-ifdef-initially nil + "*Non-nil means call `hide-ifdefs' when Hide-Ifdef mode is first activated." + :type 'boolean + :group 'hide-ifdef) ;;;###autoload -(defvar hide-ifdef-read-only nil - "*Set to non-nil if you want buffer to be read-only while hiding text.") - -(defvar hif-outside-read-only nil - "Internal variable. Saves the value of `buffer-read-only' while hiding.") +(defcustom hide-ifdef-read-only nil + "*Set to non-nil if you want buffer to be read-only while hiding text." + :type 'boolean + :group 'hide-ifdef) ;;;###autoload -(defvar hide-ifdef-lines nil - "*Set to t if you don't want to see the #ifX, #else, and #endif lines.") +(defcustom hide-ifdef-lines nil + "*Non-nil means hide the #ifX, #else, and #endif lines." + :type 'boolean + :group 'hide-ifdef) (defun hide-ifdef-toggle-read-only () - "Toggle hide-ifdef-read-only." + "Toggle `hide-ifdef-read-only'." (interactive) (setq hide-ifdef-read-only (not hide-ifdef-read-only)) (message "Hide-Read-Only %s" (if hide-ifdef-read-only "ON" "OFF")) (if hide-ifdef-hiding (setq buffer-read-only (or hide-ifdef-read-only hif-outside-read-only))) - (hif-update-mode-line)) + (force-mode-line-update)) (defun hide-ifdef-toggle-outside-read-only () - "Replacement for `toggle-read-only' within Hide Ifdef mode." + "Replacement for `toggle-read-only' within Hide-Ifdef mode." (interactive) (setq hif-outside-read-only (not hif-outside-read-only)) (message "Read only %s" (if hif-outside-read-only "ON" "OFF")) (setq buffer-read-only (or (and hide-ifdef-hiding hide-ifdef-read-only) - hif-outside-read-only) - ) - (hif-update-mode-line)) + hif-outside-read-only)) + (force-mode-line-update)) + - (defun hide-ifdef-define (var) "Define a VAR so that #ifdef VAR would be included." (interactive "SDefine what? ") - (hif-set-var var t) + (hif-set-var var 1) (if hide-ifdef-hiding (hide-ifdefs))) (defun hide-ifdef-undef (var) @@ -908,9 +866,9 @@ is first activated.") (if hide-ifdef-hiding (hide-ifdefs))) -(defun hide-ifdefs () - "Hide the contents of some #ifdefs. -Assume that defined symbols have been added to `hide-ifdef-env'. +(defun hide-ifdefs (&optional nomsg) + "Hide the contents of some #ifdefs. +Assume that defined symbols have been added to `hide-ifdef-env'. The text hidden is the text that would not be included by the C preprocessor if it were given the file with those symbols defined. @@ -918,115 +876,106 @@ Turn off hiding by calling `show-ifdefs'." (interactive) (message "Hiding...") - (if (not hide-ifdef-mode) - (hide-ifdef-mode 1)) ; turn on hide-ifdef-mode + (setq hif-outside-read-only buffer-read-only) + (unless hide-ifdef-mode (hide-ifdef-mode 1)) ; turn on hide-ifdef-mode (if hide-ifdef-hiding (show-ifdefs)) ; Otherwise, deep confusion. - (let ((inhibit-read-only t)) - (setq selective-display t) - (setq hide-ifdef-hiding t) - (hide-ifdef-guts)) + (setq hide-ifdef-hiding t) + (hide-ifdef-guts) (setq buffer-read-only (or hide-ifdef-read-only hif-outside-read-only)) - (message "Hiding done")) + (or nomsg + (message "Hiding done"))) (defun show-ifdefs () - "Cancel the effects of `hide-ifdef'. The contents of all #ifdefs is shown." + "Cancel the effects of `hide-ifdef': show the contents of all #ifdefs." (interactive) (setq buffer-read-only hif-outside-read-only) - (setq selective-display nil) ; defaults - (let ((inhibit-read-only t)) - (hif-show-all)) + (hif-show-all) (setq hide-ifdef-hiding nil)) (defun hif-find-ifdef-block () "Utility for hide and show `ifdef-block'. -Set top and bottom of ifdef block." +Return as (TOP . BOTTOM) the extent of ifdef block." (let (max-bottom) - (save-excursion - (beginning-of-line) - (if (not (or (hif-looking-at-else) (hif-looking-at-ifX))) - (up-ifdef)) - (setq top (point)) - (hif-ifdef-to-endif) - (setq max-bottom (1- (point)))) - (save-excursion - (beginning-of-line) - (if (not (hif-looking-at-endif)) - (hif-find-next-relevant)) - (while (hif-looking-at-ifX) - (hif-ifdef-to-endif) - (hif-find-next-relevant)) - (setq bottom (min max-bottom (1- (point)))))) - ) + (cons (save-excursion + (beginning-of-line) + (unless (or (hif-looking-at-else) (hif-looking-at-ifX)) + (up-ifdef)) + (prog1 (point) + (hif-ifdef-to-endif) + (setq max-bottom (1- (point))))) + (save-excursion + (beginning-of-line) + (unless (hif-looking-at-endif) + (hif-find-next-relevant)) + (while (hif-looking-at-ifX) + (hif-ifdef-to-endif) + (hif-find-next-relevant)) + (min max-bottom (1- (point))))))) (defun hide-ifdef-block () "Hide the ifdef block (true or false part) enclosing or before the cursor." (interactive) - (if (not hide-ifdef-mode) - (hide-ifdef-mode 1)) - (setq selective-display t) - (let (top bottom (inhibit-read-only t)) - (hif-find-ifdef-block) ; set top and bottom - dynamic scoping - (hide-ifdef-region top bottom) - (if hide-ifdef-lines - (progn - (hif-hide-line top) - (hif-hide-line (1+ bottom)))) + (unless hide-ifdef-mode (hide-ifdef-mode 1)) + (let ((top-bottom (hif-find-ifdef-block))) + (hide-ifdef-region (car top-bottom) (cdr top-bottom)) + (when hide-ifdef-lines + (hif-hide-line (car top-bottom)) + (hif-hide-line (1+ (cdr top-bottom)))) (setq hide-ifdef-hiding t)) (setq buffer-read-only (or hide-ifdef-read-only hif-outside-read-only))) - (defun show-ifdef-block () "Show the ifdef block (true or false part) enclosing or before the cursor." (interactive) - (let ((inhibit-read-only t)) + (let ((top-bottom (hif-find-ifdef-block))) (if hide-ifdef-lines - (save-excursion - (beginning-of-line) - (hif-show-ifdef-region (1- (point)) (progn (end-of-line) (point)))) - - (let (top bottom) - (hif-find-ifdef-block) - (hif-show-ifdef-region (1- top) bottom))))) + (hif-show-ifdef-region + (save-excursion + (goto-char (car top-bottom)) (line-beginning-position)) + (save-excursion + (goto-char (1+ (cdr top-bottom))) + (hif-end-of-line) (point))) + (hif-show-ifdef-region (1- (car top-bottom)) (cdr top-bottom))))) ;;; definition alist support (defvar hide-ifdef-define-alist nil - "A global assoc list of pre-defined symbol lists") + "A global assoc list of pre-defined symbol lists.") (defun hif-compress-define-list (env) "Compress the define list ENV into a list of defined symbols only." - (let ((defs (mapcar '(lambda (arg) - (if (hif-lookup (car arg)) (car arg))) - env)) - (new-defs nil)) - (while defs - (if (car defs) - (setq new-defs (cons (car defs) new-defs))) - (setq defs (cdr defs))) - new-defs)) + (let ((new-defs nil)) + (dolist (def env new-defs) + (if (hif-lookup (car def)) (push (car env) new-defs))))) (defun hide-ifdef-set-define-alist (name) "Set the association for NAME to `hide-ifdef-env'." (interactive "SSet define list: ") - (setq hide-ifdef-define-alist - (cons (cons name (hif-compress-define-list hide-ifdef-env)) - hide-ifdef-define-alist))) + (push (cons name (hif-compress-define-list hide-ifdef-env)) + hide-ifdef-define-alist)) (defun hide-ifdef-use-define-alist (name) "Set `hide-ifdef-env' to the define list specified by NAME." - (interactive "SUse define list: ") + (interactive + (list (completing-read "Use define list: " + (mapcar (lambda (x) (symbol-name (car x))) + hide-ifdef-define-alist) + nil t))) + (if (stringp name) (setq name (intern name))) (let ((define-list (assoc name hide-ifdef-define-alist))) (if define-list (setq hide-ifdef-env - (mapcar '(lambda (arg) (cons arg t)) + (mapcar (lambda (arg) (cons arg t)) (cdr define-list))) (error "No define list for %s" name)) (if hide-ifdef-hiding (hide-ifdefs)))) -;;; hideif.el ends here +(provide 'hideif) +;; arch-tag: c6381d17-a59a-483a-b945-658f22277981 +;;; hideif.el ends here