>I hope that the version you install will actually not change the >whitespace, rather than that just being hidden with diff -w. Sure, I will. However, my hideif modification was splitted into 3 patches and I already submitted 2 so I'll keep those white space changes that should went to the earlier 2 patches. I learnt this rule "no white space change alone" too late. For thosecodes that I did not touch I will keep the white spaces. Sorry about that. >> + :version "24.4") > >Why is the :version changing? >In any case, it is the wrong :version, since this won't be in 24.4. Isn't the Emacs trunk currently at version 24.4.XX.X? IIUC, according to the document of ":version" shouldn't this be the Emacs version that I introduced those variables? Since I consider the 3 patches as one so I use current version. >"This behavior is generally undesirable. If this option is non-nil, the >outermost #if is always visible." > >(I wonder: why would anyone want to set this option to nil?) IMHO usually don't, but I don't know if there will be cases that some header files are written as: #if XXXXXXXXXXX ... #elif YYYYYYYYY ... #elif ZZZZZZZZZZ ... #endif And each part is very long, maybe someone would like only one portion to be visible? If so, maybe making this variable a buffer local would make more sense? What do you think? >This would be better written as > >"\\.[hH]\\([hH]\\|[xX][xX]\\|[pP][pP]\\)?\\'" Thanks, followed >(why not just case-fold?) That variable is used only once in `hide-ifdef-guts' and it already bound case fold as nil with `let' (for matching lower-cased ifdef) so I use [hH] to match both cases. But, after a second thought since it is a customizable variable that users might forget about the upper/lower case so using case-fold could help users from making this kind of errors. So I change `hide-ifdef-guts' to use `let*' instead of `let' and bind `case-fold-search' twice once with `'t' for this and another with `nil' for lower-cased ifdef. >Also, you match it against buffer-name, which is fragile to things like >uniquify. Seems it would be better to match the file name. Great! I changed it to `buffer-file-name' instead. >> +(defun hif-clear-all-ifdef-defined () >> + "Clears all symbols defined in `hide-ifdef-env'. >... >Is that backup really necessary, given that you ask for confirmation? When we hide 10+ headers and save 5000 symbols in `hide-ifdef-env', it's really painful to clear it without saving it (I did that). Before I added my TODO: `automatically search for all header files using "#include"', I would like to have this backup there. Once we can have #include search works, it's okay to clear this variable without any backup. >Suggestion: >"With optional prefix agument ARG, also hide the #ifdefs themselves." >> (interactive) >> - (message "Hiding...") >> + (let ((hide-ifdef-lines current-prefix-arg)) > >I think this should take an explicit prefix argument. Originally, I followed, adding optional argument "arg" added and applied `interactive "P"'. Change all the callers to include one more argument. However, I need to keep the `current-prefix-arg' since locally I bind "C-c @ C-h" (compare with the default hide-ifdefs shortcut key "C-c @ h") for "strong-hide-ifdefs" to invoke hide-ifdefs with a prefix command automatically: (defun strong-hide-ifdefs () "Perform hideif-defs including the #ifdef themselves." (interactive) (let ((current-prefix-arg t)) (hide-ifdefs))) Thus, "C-u C-c @ h" or the shorter "C-c @ C-h" both works. If I use use ARG in the let binding of `hide-ifdefs', strong-hide-ifdefs won't work so I kept the `current-prefix-arg'. Therefore, 'arg' become an unused argument so I roll my code back. If you got better idea about how to implement things like `strong-hide-ifdefs', please tell me. Others might meet the same problem. >> +(defun hide-ifdef-block (&optional start end) >> + "Hide the ifdef block (true or false part) enclosing or before the cursor. >> +If prefixed, it will also hide #ifdefs themselves." > >Suggestion: >"With optional prefix agument ARG, also hide the #ifdefs themselves." It's nice but I can make it work with either `interactive "Pr"' or `interactive "rP" so I keep it unchanged. Also thanks for all those doc-string/comment corrections, I'm not a good English tech writer :-) Everything you suggested is great and I followed them all. The following is the new patch #3 in plain texts. Best regards, Luke Lee =========================================== diff --git a/lisp/progmodes/hideif.el b/lisp/progmodes/hideif.el index 6585668..713d330 100644 --- a/lisp/progmodes/hideif.el +++ b/lisp/progmodes/hideif.el @@ -138,7 +138,38 @@ (defcustom hide-ifdef-exclude-define-regexp nil "Ignore #define names if those names match this exclusion pattern." - :type 'string) + :type 'string + :version "24.4") + +(defcustom hide-ifdef-expand-reinclusion-protection t + "Non-nil means don't hide an entire header file enclused 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.4") + +(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.4") (defvar hide-ifdef-mode-submap ;; Set up the submap that goes after the prefix key. @@ -152,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) @@ -216,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,8 +271,12 @@ 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. + 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. @@ -259,8 +301,14 @@ Several variables affect how the hiding is done: (if hide-ifdef-mode (progn ;; inherit global values - (set (make-local-variable 'hide-ifdef-env) - (default-value 'hide-ifdef-env)) + + ;; `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)) (set (make-local-variable 'hide-ifdef-hiding) (default-value 'hide-ifdef-hiding)) (set (make-local-variable 'hif-outside-read-only) buffer-read-only) @@ -279,6 +327,14 @@ Several variables affect how the hiding is done: (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." @@ -298,16 +354,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 '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)) @@ -316,7 +420,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) === @@ -375,10 +481,8 @@ that form should be displayed.") (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-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 "\\(" @@ -499,6 +603,8 @@ that form should be displayed.") (setq hif-simple-token-only nil))) token-list))) + ((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))) @@ -1173,13 +1279,16 @@ Do this when cursor is at the beginning of `regexp' (i.e. #ifX)." (if (= start (point)) (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-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))) ; never gets here + (t + (error "Mismatched #endif")))) ; never gets here (defun forward-ifdef (&optional arg) @@ -1273,26 +1382,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. @@ -1301,19 +1409,23 @@ Point is left unchanged." (save-excursion (beginning-of-line) (let ((start (point)) + (elif nil) (else nil) (end nil)) - ;; Part one. Look for either #endif or #else. + ;; Part one. Look for either #elif, #else or #endif. ;; This loop-and-a-half dedicated to E. Dijkstra. + (while (and (not else) (not end)) (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) + ;; Found either a #else, #elif, or an #endif. + (cond ((hif-looking-at-elif) + (setq elif (nconc elif (list (point))))) + ((hif-looking-at-else) (setq else (point))) (t - (setq end (point)))) ; (line-end-position) + (setq end (point))))) ;; If found #else, look for #endif. (when else (while (progn @@ -1323,7 +1435,7 @@ Point is left unchanged." (if (hif-looking-at-else) (error "Found two elses in a row? Broken!")) (setq end (point))) ; (line-end-position) - (hif-make-range start end else)))) + (hif-make-range start end else elif)))) ;; A bit slimy. @@ -1338,70 +1450,180 @@ Does nothing if `hide-ifdef-lines' is nil." (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. -;;; -;;; Case 1: #ifX taken, and there's an #else. -;;; The #else part must be hidden. The #if (then) part must be -;;; processed for nested #ifX's. -;;; Case 2: #ifX taken, and there's no #else. -;;; The #if part must be processed for nested #ifX's. -;;; Case 3: #ifX not taken, and there's an #else. -;;; The #if part must be hidden. The #else part must be processed -;;; for nested #ifs. -;;; Case 4: #ifX not taken, and there's no #else. -;;; The #ifX part must be hidden. -;;; -;;; Further processing is done by narrowing to the relevant region -;;; and just recursively calling hide-ifdef-guts. -;;; -;;; When hif-possibly-hide returns, point is at the end of the -;;; possibly-hidden range. - -(defun hif-recurse-on (start end) +;; 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. +;; +;; Case 1: #ifX taken, and there's an #else. +;; The #else part must be hidden. The #if (then) part must be +;; processed for nested #ifX's. +;; Case 2: #ifX taken, and there's no #else. +;; The #if part must be processed for nested #ifX's. +;; Case 3: #ifX not taken, and there's an #elif +;; The #if part must be hidden, and then evaluate +;; the #elif condition like a new #ifX. +;; Case 4: #ifX not taken, and there's just an #else. +;; The #if part must be hidden. The #else part must be processed +;; for nested #ifs. +;; Case 5: #ifX not taken, and there's no #else. +;; The #ifX part must be hidden. +;; +;; Further processing is done by narrowing to the relevant region +;; and just recursively calling hide-ifdef-guts. +;; +;; When hif-possibly-hide returns, point is at the end of the +;; possibly-hidden range. + +(defvar hif-recurse-level 0) + +(defun hif-recurse-on (start end &optional dont-go-eol) "Call `hide-ifdef-guts' after narrowing to end of START line and END line." (save-excursion (save-restriction (goto-char start) - (end-of-line) + (unless dont-go-eol + (end-of-line)) (narrow-to-region (point) end) - (hide-ifdef-guts)))) + (let ((hif-recurse-level (1+ hif-recurse-level))) + (hide-ifdef-guts))))) -(defun hif-possibly-hide () +(defun hif-possibly-hide (expand-reinclusion) "Called at #ifX expression, this hides those parts that should be hidden. -It uses the judgment of `hide-ifdef-evaluator'." +It uses the judgment of `hide-ifdef-evaluator'. EXPAND-REINCLUSION is a flag +indicating that we should expand the #ifdef even if it should be hidden. +Refer to `hide-ifdef-expand-reinclusion-protection' for more details." ;; (message "hif-possibly-hide") (sit-for 1) - (let ((test (hif-canonicalize hif-ifx-regexp)) - (range (hif-find-range))) + (let* ((case-fold-search nil) + (test (hif-canonicalize hif-ifx-regexp)) + (range (hif-find-range)) + (elifs (hif-range-elif range)) + (if-part t) ; Everytime we start from if-part + (complete nil)) ;; (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 + (while (not complete) + (if (and (not (and expand-reinclusion if-part)) + (hif-not (funcall hide-ifdef-evaluator test))) + ;; ifX/elif is FALSE + (if elifs + ;; Case 3 - Hide the #ifX and eval #elif + (let ((newstart (car elifs))) + (hif-hide-line (hif-range-start range)) + (hide-ifdef-region (hif-range-start range) + (1- newstart)) + (setcar range newstart) + (goto-char newstart) + (setq elifs (cdr elifs)) + (setq test (hif-canonicalize hif-elif-regexp))) + + ;; Check for #else + (cond ((hif-range-else range) + ;; Case 4 - #else block visible + (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 5 - No #else block, hide #ifX + (hide-ifdef-region (point) + (1- (hif-range-end range))))) + (setq complete t)) + + ;; ifX/elif is TRUE + (cond (elifs + ;; Luke fix: distinguish from #elif..#elif to #elif..#else + (let ((elif (car elifs))) + ;; hide all elifs + (hif-hide-line elif) + (hide-ifdef-region elif (1- (hif-range-end range))) + (hif-recurse-on (hif-range-start range) + elif))) + ((hif-range-else range) + ;; Case 1 - Hide #elif and #else blocks, recurse #ifX (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 + (t + ;; Case 2 - No #else, just recurse #ifX (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)))))) + (setq complete t)) + (setq if-part nil)) + + ;; complete = t (hif-hide-line (hif-range-start range)) ; Always hide start. (goto-char (hif-range-end range)) (end-of-line))) +(defun hif-evaluate-region (start end) + (let* ((tokens (ignore-errors ; Prevent C statement things like + ; 'do { ... } while (0)' + (hif-tokenize start end))) + (expr (and tokens + (condition-case nil + (hif-parse-exp tokens) + (error + tokens)))) + (result (funcall hide-ifdef-evaluator expr))) + result)) + +(defun hif-evaluate-macro (rstart rend) + "Evaluate the macro expansion result for a region. +If no region active, find the current #ifdefs and evaluate the result. +Currently it supports only math calculations, strings or argumented macros can +not be expanded." + (interactive "r") + (let ((case-fold-search nil)) + (save-excursion + (unless mark-active + (setq rstart nil rend nil) + (beginning-of-line) + (when (and (re-search-forward hif-macro-expr-prefix-regexp nil t) + (string= "define" (match-string 2))) + (re-search-forward hif-macroref-regexp nil t))) + (let* ((start (or rstart (point))) + (end (or rend (progn (hif-end-of-line) (point)))) + (defined nil) + (simple 't) + (tokens (ignore-errors ; Prevent C statement things like + ; 'do { ... } while (0)' + (hif-tokenize start end))) + (expr (or (and (<= (length tokens) 1) ; Simple token + (setq defined (assoc (car tokens) hide-ifdef-env)) + (setq simple (atom (hif-lookup (car tokens)))) + (hif-lookup (car tokens))) + (and tokens + (condition-case nil + (hif-parse-exp tokens) + (error + nil))))) + (result (funcall hide-ifdef-evaluator expr)) + (exprstring (replace-regexp-in-string + ;; Trim off leading/trailing whites + "^[ \t]*\\([^ \t]+\\)[ \t]*" "\\1" + (replace-regexp-in-string + "\\(//.*\\)" "" ; Trim off end-of-line comments + (buffer-substring-no-properties start end))))) + (cond + ((and (<= (length tokens) 1) simple) ; Simple token + (if defined + (message "%S <= `%s'" result exprstring) + (message "`%s' is not defined" exprstring))) + ((integerp result) + (if (or (= 0 result) (= 1 result)) + (message "%S <= `%s'" result exprstring) + (message "%S (0x%x) <= `%s'" result result exprstring))) + ((null result) (message "%S <= `%s'" 'false exprstring)) + ((eq t result) (message "%S <= `%s'" 'true exprstring)) + (t (message "%S <= `%s'" result exprstring))) + result)))) + (defun hif-parse-macro-arglist (str) "Parse argument list formatted as '( arg1 [ , argn] [...] )'. The '...' is also included. Return a list of the arguments, if '...' exists the @@ -1529,7 +1751,12 @@ first arg will be `hif-etc'." It does not do the work that's pointless to redo on a recursive entry." ;; (message "hide-ifdef-guts") (save-excursion - (let ((case-fold-search nil) + (let* ((case-fold-search t) ; Ignore case for `hide-ifdef-header-regexp' + (expand-header (and hide-ifdef-expand-reinclusion-protection + (string-match hide-ifdef-header-regexp + (buffer-file-name)) + (zerop hif-recurse-level))) + (case-fold-search nil) min max) (goto-char (point-min)) (setf min (point)) @@ -1537,7 +1764,7 @@ It does not do the work that's pointless to redo on a recursive entry." (setf max (hif-find-any-ifX)) (hif-add-new-defines min max) (if max - (hif-possibly-hide)) + (hif-possibly-hide expand-header)) (setf min (point)) while max)))) @@ -1584,17 +1811,30 @@ It does not do the work that's pointless to redo on a recursive entry." (overlay-put overlay 'face nil) (overlay-put overlay 'invisible 'hide-ifdef)))))) -(defun hide-ifdef-define (var) - "Define a VAR so that #ifdef VAR would be included." - (interactive "SDefine what? ") - (hif-set-var var 1) +(defun hide-ifdef-define (var &optional val) + "Define a VAR to VAL (DEFAULT 1) in `hide-ifdef-env'. +This allows #ifdef VAR to be hidden." + (interactive + (let* ((default (save-excursion + (beginning-of-line) + (cond ((looking-at hif-ifx-else-endif-regexp) + (forward-word 2) + (current-word 'strict)) + (t + nil)))) + (var (read-minibuffer "Define what? " default)) + (val (read-from-minibuffer (format "Set %s to? (default 1): " var) + nil nil t nil "1"))) + (list var val))) + (hif-set-var var (or val 1)) + (message "%s set to %s" var (or val 1)) + (sleep-for 1) (if hide-ifdef-hiding (hide-ifdefs))) (defun hif-undefine-symbol (var) (setq hide-ifdef-env (delete (assoc var hide-ifdef-env) hide-ifdef-env))) - (defun hide-ifdef-undef (start end) "Undefine a VAR so that #ifdef VAR would not be included." (interactive "r") @@ -1615,20 +1855,23 @@ It does not do the work that's pointless to redo on a recursive entry." 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. +With prefix command presents it will also hide the #ifdefs themselves. Turn off hiding by calling `show-ifdefs'." (interactive) - (message "Hiding...") + (let ((hide-ifdef-lines current-prefix-arg)) + (or nomsg + (message "Hiding...")) (setq hif-outside-read-only buffer-read-only) - (unless hide-ifdef-mode (hide-ifdef-mode 1)) ; turn on hide-ifdef-mode + (unless hide-ifdef-mode (hide-ifdef-mode 1)) ; Turn on hide-ifdef-mode (if hide-ifdef-hiding (show-ifdefs)) ; Otherwise, deep confusion. (setq hide-ifdef-hiding t) (hide-ifdef-guts) (setq buffer-read-only (or hide-ifdef-read-only hif-outside-read-only)) (or nomsg - (message "Hiding done"))) + (message "Hiding done")))) (defun show-ifdefs () @@ -1660,9 +1903,15 @@ Return as (TOP . BOTTOM) the extent of ifdef block." (min max-bottom (1- (point))))))) -(defun hide-ifdef-block () - "Hide the ifdef block (true or false part) enclosing or before the cursor." - (interactive) +(defun hide-ifdef-block (&optional start end) + "Hide the ifdef block (true or false part) enclosing or before the cursor. +With prefix command presents it will also hide the #ifdefs themselves." + (interactive "r") + (let ((hide-ifdef-lines current-prefix-arg)) + (if mark-active + (let ((hif-recurse-level (1+ hif-recurse-level))) + (hif-recurse-on start end t) + (setq mark-active nil)) (unless hide-ifdef-mode (hide-ifdef-mode 1)) (let ((top-bottom (hif-find-ifdef-block))) (hide-ifdef-region (car top-bottom) (cdr top-bottom)) @@ -1670,12 +1919,26 @@ Return as (TOP . BOTTOM) the extent of ifdef block." (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))) + (setq buffer-read-only + (or hide-ifdef-read-only hif-outside-read-only))))) -(defun show-ifdef-block () +(defun show-ifdef-block (&optional start end) "Show the ifdef block (true or false part) enclosing or before the cursor." - (interactive) - (let ((top-bottom (hif-find-ifdef-block))) + (interactive "r") + (if mark-active + (progn + (dolist (o (overlays-in start end)) + (if (overlay-get o 'hide-ifdef) + (delete-overlay o))) + (setq mark-active nil)) + (let ((top-bottom (condition-case nil + (hif-find-ifdef-block) + (error + nil))) + (ovrs (overlays-in (max (point-min) (1- (point))) + (min (point-max) (1+ (point))))) + (del nil)) + (if top-bottom (if hide-ifdef-lines (hif-show-ifdef-region (save-excursion @@ -1683,7 +1946,15 @@ Return as (TOP . BOTTOM) the extent of ifdef block." (save-excursion (goto-char (1+ (cdr top-bottom))) (hif-end-of-line) (point))) - (hif-show-ifdef-region (1- (car top-bottom)) (cdr top-bottom))))) + (setf del (hif-show-ifdef-region + (1- (car top-bottom)) (cdr top-bottom))))) + (if (not (and top-bottom + del)) + (dolist (o ovrs) + ;;(dolist (o (overlays-in (1- (point)) (1+ (point)))) + ;; (if (overlay-get o 'hide-ifdef) (message "%S" o))) + (if (overlay-get o 'hide-ifdef) + (delete-overlay o))))))) ;;; definition alist support