Commit 2c578850 authored by Luke Lee's avatar Luke Lee

HideIfDef mode bug fixes and enhancements. This is #3 of 3 patches based

on the completed work posted on http://www.emacswiki.org/emacs/HideIfDef.

- Add macro evaluation function and key binding for a marked region.
- Merge continuous "..." lines into one.
- Fix old hideif bugs that fail to hide the correct #elif regions
- Support hide/show commands in a marked region.
- Expand top level for .h files to prevent re-inclusion protection.
- Change maintainer.

* lisp/progmodes/hideif.el (hide-ifdef-env): Change to global.
(hide-ifdef-env-backup): New variable.
(hide-ifdef-expand-reinclusion-protection, hide-ifdef-header-regexp):
New customizable variables.
(hif-clear-all-ifdef-defined): New defun.
(hif-merge-ifdef-region, hide-ifdef-region-internal, hide-ifdef-region)
(hif-show-ifdef-region): Merge hidden regions to prevent continuous "...".
(hif-tokenize): Fix for MS-DOS/Win EOL style.
(hif-endif-to-ifdef, hif-make-range, hif-find-range, hif-possibly-hide):
Fix bug to hide the correct #elif region(s).
(hif-range-elif): New defun.
(hif-recurse-level): New var.
(hif-evaluate-region, hif-evaluate-macro): New defun.
(hide-ifdef-guts): Prevent reinclusion protected C/C++ headers from
fully hidden.
(hide-ifdef-define, hide-ifdefs, hide-ifdef-block, show-ifdef-block):
Better interaction.
parent 4cf00b8c
......@@ -119,6 +119,16 @@ protocols as well as for "telnet" and "ftp" are passed to Tramp.
fitting for use in money calculations; factorial works with
non-integer inputs.
** HideIfDef mode now support full C/C++ expressions, argumented macro expansions
, interactive macro evaluation and automatic scanning of #defined symbols.
*** New custom variable `hide-ifdef-header-regexp' to define C/C++ header file
name patterns. Default case-insensitive .h, .hh, .hpp and .hxx.
*** New custom variable `hide-ifdef-expand-reinclusion-protection' to prevent
reinclusion protected header files from being fully hidden.
*** New custom variable `hide-ifdef-exclude-define-regexp' to define symbol
name patterns (e.x. all "FOR_DOXYGEN_ONLY_*") to be excluded.
** Obsolete packages
---
......
2014-07-07 Luke Lee <luke.yx.lee@gmail.com>
* lisp/progmodes/hideif.el (hide-ifdef-env): Change to global.
(hide-ifdef-env-backup): New variable.
(hide-ifdef-expand-reinclusion-protection, hide-ifdef-header-regexp):
New customizable variables.
(hif-clear-all-ifdef-defined): New defun.
(hif-merge-ifdef-region, hide-ifdef-region-internal, hide-ifdef-region)
(hif-show-ifdef-region): Merge hidden regions to prevent continuous "...".
(hif-tokenize): Fix for MS-DOS/Win EOL style.
(hif-endif-to-ifdef, hif-make-range, hif-find-range, hif-possibly-hide):
Fix bug to hide the correct #elif region(s).
(hif-range-elif): New defun.
(hif-recurse-level): New var.
(hif-evaluate-region, hif-evaluate-macro): New defun.
(hide-ifdef-guts): Prevent reinclusion protected C/C++ headers from
fully hidden.
(hide-ifdef-define, hide-ifdefs, hide-ifdef-block, show-ifdef-block):
Better interaction.
2014-07-04 Michael Albinus <michael.albinus@gmx.de>
* net/dbus.el (dbus-peer-handler): New defun.
......
......@@ -4,7 +4,7 @@
;; Author: Brian Marick
;; Daniel LaLiberte <liberte@holonexus.org>
;; Maintainer: emacs-devel@gnu.org
;; Maintainer: Luke Lee <luke.yx.lee@gmail.com>
;; Keywords: c, outlines
;; This file is part of GNU Emacs.
......@@ -141,6 +141,36 @@
:type 'string
:version "24.5")
(defcustom hide-ifdef-expand-reinclusion-protection t
"Non-nil means don't hide an entire header file enclosed by #ifndef...#endif.
Most C/C++ headers are usually wrapped with ifdefs to prevent re-inclusion:
----- beginning of file -----
#ifndef _XXX_HEADER_FILE_INCLUDED_
#define _XXX_HEADER_FILE_INCLUDED_
xxx
xxx
xxx...
#endif
----- end of file -----
The first time we visit such a file, _XXX_HEADER_FILE_INCLUDED_ is
undefined, and so nothing is hidden. The next time we visit it, everything will
be hidden.
This behavior is generally undesirable. If this option is non-nil, the outermost
#if is always visible."
:type 'boolean
:version "24.5")
(defcustom hide-ifdef-header-regexp
"\\.h\\(h\\|xx\\|pp\\)?\\'"
"C/C++ header file name patterns to determine if current buffer is a header.
Effective only if `hide-ifdef-expand-reinclusion-protection' is t."
:type 'string
:group 'hide-ifdef
:version "24.5")
(defvar hide-ifdef-mode-submap
;; Set up the submap that goes after the prefix key.
(let ((map (make-sparse-keymap)))
......@@ -153,6 +183,8 @@
(define-key map "s" 'show-ifdefs)
(define-key map "\C-d" 'hide-ifdef-block)
(define-key map "\C-s" 'show-ifdef-block)
(define-key map "e" 'hif-evaluate-macro)
(define-key map "C" 'hif-clear-all-ifdef-defined)
(define-key map "\C-q" 'hide-ifdef-toggle-read-only)
(define-key map "\C-w" 'hide-ifdef-toggle-shadowing)
......@@ -217,6 +249,11 @@
(defvar hide-ifdef-env nil
"An alist of defined symbols and their values.")
(defvar hide-ifdef-env-backup nil
"This variable is a backup of the previously cleared `hide-ifdef-env'.
This backup prevents any accidental clearance of `hide-fidef-env' by
`hif-clear-all-ifdef-defined'.")
(defvar hif-outside-read-only nil
"Internal variable. Saves the value of `buffer-read-only' while hiding.")
......@@ -233,53 +270,75 @@ that the C preprocessor would eliminate may be hidden from view.
Several variables affect how the hiding is done:
`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.
An association list of defined and undefined symbols for the
current project. Initially, the global value of `hide-ifdef-env'
is used. This variable was a buffer-local variable, which limits
hideif to parse only one C/C++ file at a time. We've extended
hideif to support parsing a C/C++ project containing multiple C/C++
source files opened simultaneously in different buffers. Therefore
`hide-ifdef-env' can no longer be buffer local but must be global.
`hide-ifdef-define-alist'
An association list of defined symbol lists.
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'
Set to non-nil to not show #if, #ifdef, #ifndef, #else, and
#endif lines when hiding.
Set to non-nil to not show #if, #ifdef, #ifndef, #else, and
#endif lines when hiding.
`hide-ifdef-initially'
Indicates whether `hide-ifdefs' should be called when Hide-Ifdef mode
is activated.
Indicates whether `hide-ifdefs' should be called when Hide-Ifdef mode
is activated.
`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.
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}"
:group 'hide-ifdef :lighter " Ifdef"
(if hide-ifdef-mode
(progn
;; 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)))
;; inherit global values
;; `hide-ifdef-env' is now a global variable.
;; We can still simulate the behavior of older hideif versions (i.e.
;; `hide-ifdef-env' being buffer local) by clearing this variable
;; (C-c @ C) everytime before hiding current buffer.
;; (set (make-local-variable 'hide-ifdef-env)
;; (default-value 'hide-ifdef-env))
(set 'hide-ifdef-env (default-value 'hide-ifdef-env))
;; Some C/C++ headers might have other ways to prevent reinclusion and
;; thus would like `hide-ifdef-expand-reinclusion-protection' to be nil.
(set (make-local-variable 'hide-ifdef-expand-reinclusion-protection)
(default-value 'hide-ifdef-expand-reinclusion-protection))
(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)))
;; else end hide-ifdef-mode
(kill-local-variable 'line-move-ignore-invisible)
(remove-from-invisibility-spec '(hide-ifdef . t))
(when hide-ifdef-hiding
(show-ifdefs))))
(defun hif-clear-all-ifdef-defined ()
"Clears all symbols defined in `hide-ifdef-env'.
It will backup this variable to `hide-ifdef-env-backup' before clearing to
prevent accidental clearance."
(interactive)
(when (y-or-n-p "Clear all #defined symbols? ")
(setq hide-ifdef-env-backup hide-ifdef-env)
(setq hide-ifdef-env nil)))
(defun hif-show-all ()
"Show all of the text in the current buffer."
......@@ -299,16 +358,64 @@ Several variables affect how the hiding is done:
(while (= (logand 1 (skip-chars-backward "\\\\")) 1)
(end-of-line 2)))
(defun hif-merge-ifdef-region (start end)
"This function merges nearby ifdef regions to form a bigger overlay.
The region is defined by START and END. This will decrease the number of
overlays created."
;; Generally there is no need to call itself recursively since there should
;; originally exists no un-merged regions; however, if a part of the file is
;; hidden with `hide-ifdef-lines' equals to nil while another part with 't,
;; this case happens.
;; TODO: Should we merge? or just create a container overlay? -- this can
;; prevent `hideif-show-ifdef' expanding too many hidden contents since there
;; is only a big overlay exists there without any smaller overlays.
(save-restriction
(widen) ; Otherwise `point-min' and `point-max' will be restricted and thus
; fail to find neighbor overlays
(let ((begovrs (overlays-in
(max (- start 2) (point-min))
(max (- start 1) (point-min))))
(endovrs (overlays-in
(min (+ end 1) (point-max))
(min (+ end 2) (point-max))))
(ob nil)
(oe nil)
b e)
;; Merge overlays before START
(dolist (o begovrs)
(when (overlay-get o 'hide-ifdef)
(setq b (min start (overlay-start o))
e (max end (overlay-end o)))
(move-overlay o b e)
(hif-merge-ifdef-region b e)
(setq ob o)))
;; Merge overlays after END
(dolist (o endovrs)
(when (overlay-get o 'hide-ifdef)
(setq b (min start (overlay-start o))
e (max end (overlay-end o)))
(move-overlay o b e)
(hif-merge-ifdef-region b e)
(setf oe o)))
;; If both START and END merging happens, merge into bigger one
(when (and ob oe)
(let ((b (min (overlay-start ob) (overlay-start oe)))
(e (max (overlay-end ob) (overlay-end oe))))
(delete-overlay oe)
(move-overlay ob b e)
(hif-merge-ifdef-region b e)))
(or ob oe))))
(defun hide-ifdef-region-internal (start end)
(remove-overlays start end 'hide-ifdef t)
(unless (hif-merge-ifdef-region start end)
(let ((o (make-overlay start end)))
(overlay-put o 'hide-ifdef t)
(if hide-ifdef-shadow
(overlay-put o 'face 'hide-ifdef-shadow)
(overlay-put o 'invisible 'hide-ifdef))))
(overlay-put o 'face 'hide-ifdef-shadow)
(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.
"START is the start of a #if, #elif, or #else form. END is the ending part.
Everything including these lines is made invisible."
(save-excursion
(goto-char start) (hif-end-of-line) (setq start (point))
......@@ -317,7 +424,9 @@ Everything including these lines is made invisible."
(defun hif-show-ifdef-region (start end)
"Everything between START and END is made visible."
(remove-overlays start end 'hide-ifdef t))
(let ((onum (length (overlays-in start end))))
(remove-overlays start end 'hide-ifdef t)
(/= onum (length (overlays-in start end)))))
;;===%%SF%% evaluation (Start) ===
......@@ -342,11 +451,11 @@ that form should be displayed.")
(defun hif-lookup (var)
(or (when (bound-and-true-p semantic-c-takeover-hideif)
(semantic-c-hideif-lookup var))
(semantic-c-hideif-lookup var))
(let ((val (assoc var hide-ifdef-env)))
(if val
(cdr val)
hif-undefined-symbol))))
(if val
(cdr val)
hif-undefined-symbol))))
(defun hif-defined (var)
(cond
......@@ -362,24 +471,22 @@ that form should be displayed.")
;;===%%SF%% parsing (Start) ===
;;; The code that understands what ifs and ifdef in files look like.
(defconst hif-cpp-prefix "\\(^\\|\r\\)[ \t]*#[ \t]*")
(defconst hif-ifxdef-regexp (concat hif-cpp-prefix "if\\(n\\)?def"))
(defconst hif-ifndef-regexp (concat hif-cpp-prefix "ifndef"))
(defconst hif-ifx-regexp (concat hif-cpp-prefix "if\\(n?def\\)?[ \t]+"))
(defconst hif-elif-regexp (concat hif-cpp-prefix "elif"))
(defconst hif-else-regexp (concat hif-cpp-prefix "else"))
(defconst hif-endif-regexp (concat hif-cpp-prefix "endif"))
(defconst hif-cpp-prefix "\\(^\\|\r\\)[ \t]*#[ \t]*")
(defconst hif-ifxdef-regexp (concat hif-cpp-prefix "if\\(n\\)?def"))
(defconst hif-ifndef-regexp (concat hif-cpp-prefix "ifndef"))
(defconst hif-ifx-regexp (concat hif-cpp-prefix "if\\(n?def\\)?[ \t]+"))
(defconst hif-elif-regexp (concat hif-cpp-prefix "elif"))
(defconst hif-else-regexp (concat hif-cpp-prefix "else"))
(defconst hif-endif-regexp (concat hif-cpp-prefix "endif"))
(defconst hif-ifx-else-endif-regexp
(concat hif-ifx-regexp "\\|" hif-elif-regexp "\\|" hif-else-regexp "\\|"
hif-endif-regexp))
(defconst hif-macro-expr-prefix-regexp
(concat hif-cpp-prefix "\\(if\\(n?def\\)?\\|elif\\|define\\)[ \t]+"))
(defconst hif-white-regexp "[ \t]*")
(defconst hif-define-regexp
(concat hif-cpp-prefix "\\(define\\|undef\\)"))
(defconst hif-id-regexp
(concat "[[:alpha:]_][[:alnum:]_]*"))
(defconst hif-white-regexp "[ \t]*")
(defconst hif-define-regexp (concat hif-cpp-prefix "\\(define\\|undef\\)"))
(defconst hif-id-regexp (concat "[[:alpha:]_][[:alnum:]_]*"))
(defconst hif-macroref-regexp
(concat hif-white-regexp "\\(" hif-id-regexp "\\)" hif-white-regexp
"\\("
......@@ -398,9 +505,9 @@ that form should be displayed.")
(defconst hif-token-alist
'(("||" . hif-or)
("&&" . hif-and)
("|" . hif-logior)
("|" . hif-logior)
("^" . hif-logxor)
("&" . hif-logand)
("&" . hif-logand)
("<<" . hif-shiftleft)
(">>" . hif-shiftright)
("==" . hif-equal)
......@@ -408,22 +515,22 @@ that form should be displayed.")
;; expression syntax, because they are still relevant for the tokenizer,
;; especially in conjunction with ##.
("=" . hif-assign)
("!=" . hif-notequal)
("!=" . hif-notequal)
("##" . hif-token-concat)
("!" . hif-not)
("~" . hif-lognot)
("(" . hif-lparen)
(")" . hif-rparen)
(">" . hif-greater)
("<" . hif-less)
(">=" . hif-greater-equal)
("<=" . hif-less-equal)
("+" . hif-plus)
("-" . hif-minus)
(">" . hif-greater)
("<" . hif-less)
(">=" . hif-greater-equal)
("<=" . hif-less-equal)
("+" . hif-plus)
("-" . hif-minus)
("*" . hif-multiply)
("/" . hif-divide)
("%" . hif-modulo)
("?" . hif-conditional)
("?" . hif-conditional)
(":" . hif-colon)
("," . hif-comma)
("#" . hif-stringify)
......@@ -465,23 +572,23 @@ that form should be displayed.")
(setq hif-simple-token-only t)
(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))
(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-string-literal-regexp)
(push (substring-no-properties (match-string 1)) token-list)
(goto-char (match-end 0)))
((looking-at hif-token-regexp)
((looking-at hif-token-regexp)
(let ((token (buffer-substring-no-properties
(point) (match-end 0))))
(goto-char (match-end 0))
;; (message "token: %s" token) (sit-for 1)
(push
(goto-char (match-end 0))
;; (message "token: %s" token) (sit-for 1)
(push
(or (cdr (assoc token hif-token-alist))
(if (string-equal token "defined") 'hif-defined)
;; TODO:
......@@ -500,7 +607,9 @@ that form should be displayed.")
(setq hif-simple-token-only nil)))
token-list)))
(t (error "Bad #if expression: %s" (buffer-string)))))))
((looking-at "\r") ; Sometimes MS-Windows user will leave CR in
(forward-char 1)) ; the source code. Let's not get stuck here.
(t (error "Bad #if expression: %s" (buffer-string)))))))
(nreverse token-list)))
......@@ -573,7 +682,7 @@ that form should be displayed.")
(defun hif-expand-token-list (tokens &optional macroname expand_list)
"Perform expansion on TOKENS till everything expanded.
Self-reference (directly or indirectly) tokens are not expanded.
EXPAND_LIST is the list of macro names currently being expanded, use for
EXPAND_LIST is the list of macro names currently being expanded, used for
detecting self-reference."
(catch 'self-referencing
(let ((expanded nil)
......@@ -657,28 +766,28 @@ macros to prevent self-reference."
"Parse an exprlist: expr { ',' expr}."
(let ((result (hif-expr)))
(if (eq hif-token 'hif-comma)
(let ((temp (list result)))
(while
(progn
(hif-nexttoken)
(push (hif-expr) temp)
(eq hif-token 'hif-comma)))
(cons 'hif-comma (nreverse temp)))
(let ((temp (list result)))
(while
(progn
(hif-nexttoken)
(push (hif-expr) temp)
(eq hif-token 'hif-comma)))
(cons 'hif-comma (nreverse temp)))
result)))
(defun hif-expr ()
"Parse an expression as found in #if.
expr : or-expr | or-expr '?' expr ':' expr."
expr : or-expr | or-expr '?' expr ':' expr."
(let ((result (hif-or-expr))
middle)
middle)
(while (eq hif-token 'hif-conditional)
(hif-nexttoken)
(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)))
(progn
(hif-nexttoken)
(setq result (list 'hif-conditional result middle (hif-expr))))
(error "Error: unexpected token: %s" hif-token)))
result))
(defun hif-or-expr ()
......@@ -767,7 +876,7 @@ macros to prevent self-reference."
"Parse an expression with *,/,%.
muldiv : factor | muldiv '*|/|%' factor."
(let ((result (hif-factor))
(math-op nil))
(math-op nil))
(while (memq hif-token '(hif-multiply hif-divide hif-modulo))
(setq math-op hif-token)
(hif-nexttoken)
......@@ -791,20 +900,20 @@ factor : '!' factor | '~' factor | '(' expr ')' | 'defined(' id ')' |
(hif-nexttoken)
(let ((result (hif-exprlist)))
(if (not (eq hif-token 'hif-rparen))
(error "Bad token in parenthesized expression: %s" hif-token)
(hif-nexttoken)
result)))
(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 'hif-lparen) (hif-nexttoken) t))
(ident hif-token))
(ident hif-token))
(if (memq hif-token '(or and not hif-defined hif-lparen hif-rparen))
(error "Error: unexpected token: %s" hif-token))
(error "Error: unexpected token: %s" hif-token))
(when paren
(hif-nexttoken)
(hif-nexttoken)
(unless (eq hif-token 'hif-rparen)
(error "Error: expected \")\" after identifier")))
(error "Error: expected \")\" after identifier")))
(hif-nexttoken)
`(hif-defined (quote ,ident))))
......@@ -817,7 +926,7 @@ factor : '!' factor | '~' factor | '(' expr ')' | 'defined(' id ')' |
((memq hif-token '(hif-minus hif-plus))
(list (prog1 hif-token (hif-nexttoken)) 0 (hif-factor)))
(t ; identifier
(t ; identifier
(let ((ident hif-token))
(hif-nexttoken)
(if (eq hif-token 'hif-lparen)
......@@ -994,7 +1103,7 @@ preprocessing token"
(setq prev (hif-token-concat prev (cadr l)))
(setq l (cddr l)))
(if prev
(setq result (append result (list prev))))
(setq result (append result (list prev))))
(setq prev (car l)
l (cdr l)))
(if prev
......@@ -1068,11 +1177,11 @@ preprocessing token"
(defun hif-invoke (macro-name actual-parms)
"Invoke a macro by expanding it, reparse macro-body and finally invoke it."
;; Reparse the macro body and evaluate it
(funcall hide-ifdef-evaluator
(hif-parse-exp
(hif-macro-supply-arguments macro-name actual-parms)
macro-name)))
;; Reparse the macro body and evaluate it
(funcall hide-ifdef-evaluator
(hif-parse-exp
(hif-macro-supply-arguments macro-name actual-parms)
macro-name)))
;;;----------- end of parser -----------------------
......@@ -1158,12 +1267,12 @@ Do this when cursor is at the beginning of `regexp' (i.e. #ifX)."
(hif-ifdef-to-endif)) ; Find outer endif or else
((hif-looking-at-elif)
(hif-ifdef-to-endif))
((hif-looking-at-else)
((hif-looking-at-else)
(hif-ifdef-to-endif)) ; Find endif following else
((hif-looking-at-endif)
'done)
(t
(error "Mismatched #ifdef #endif pair"))))
((hif-looking-at-endif)
'done)
(t
(error "Mismatched #ifdef #endif pair"))))
(defun hif-endif-to-ifdef ()
......@@ -1172,15 +1281,18 @@ Do this when cursor is at the beginning of `regexp' (i.e. #ifX)."
(let ((start (point)))
(hif-find-previous-relevant)
(if (= start (point))
(error "Mismatched #ifdef #endif pair")))
(error "Mismatched #ifdef #endif pair")))
(cond ((hif-looking-at-endif)
(hif-endif-to-ifdef) ; find beginning of nested if
(hif-endif-to-ifdef)) ; find beginning of outer if or else
((hif-looking-at-else)
(hif-endif-to-ifdef))
((hif-looking-at-ifX)
'done)
(t))) ; never gets here
(hif-endif-to-ifdef) ; Find beginning of nested if
(hif-endif-to-ifdef)) ; Find beginning of outer if or else
((hif-looking-at-elif)
(hif-endif-to-ifdef))
((hif-looking-at-else)
(hif-endif-to-ifdef))
((hif-looking-at-ifX)
'done)
(t
(error "Mismatched #endif")))) ; never gets here
(defun forward-ifdef (&optional arg)
......@@ -1274,26 +1386,25 @@ With argument, do this that many times."
;;===%%SF%% hide-ifdef-hiding (Start) ===
;;; A range is a structure with four components:
;;; ELSE-P True if there was an else clause for the ifdef.
;;; START The start of the range. (beginning of line)
;;; ELSE The else marker (beginning of line)
;;; Only valid if ELSE-P is true.
;;; END The end of the range. (beginning of line)
;; A range is a structure with four components:
;; START The start of the range. (beginning of line)
;; ELSE The else marker (beginning of line)
;; END The end of the range. (beginning of line)
;; ELIF A sequence of #elif markers (beginning of line)
(defsubst hif-make-range (start end &optional else)
(list start else end))
(defsubst hif-make-range (start end &optional else elif)
(list start else end elif))
(defsubst hif-range-start (range) (elt range 0))
(defsubst hif-range-else (range) (elt range 1))
(defsubst hif-range-end (range) (elt range 2))
(defsubst hif-range-elif (range) (elt range 3))
;;; Find-Range
;;; The workhorse, it delimits the #if region. Reasonably simple:
;;; Skip until an #else or #endif is found, remembering positions. If
;;; an #else was found, skip some more, looking for the true #endif.
;; Find-Range
;; The workhorse, it delimits the #if region. Reasonably simple:
;; Skip until an #else or #endif is found, remembering positions. If
;; an #else was found, skip some more, looking for the true #endif.
(defun hif-find-range ()
"Return a Range structure describing the current #if region.
......@@ -1302,29 +1413,33 @@ Point is left unchanged."
(save-excursion
(beginning-of-line)
(let ((start (point))
(else nil)
(end nil))
;; Part one. Look for either #endif or #else.
(elif nil)
(else nil)
(end nil))
;; Part one. Look for either #elif, #else or #endif.
;; This loop-and-a-half dedicated to E. Dijkstra.