unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
From: Luke Lee <luke.yx.lee@gmail.com>
To: 17854@debbugs.gnu.org
Subject: bug#17854: The patch #3 of 3 for hideif.el, a lot of bug fixes and enhancements
Date: Fri, 27 Jun 2014 17:37:56 +0800	[thread overview]
Message-ID: <CAA=xLRPOpaV5HhjONej_=wMH5t2sXvF_XnZ5_G84CQvU6vQZpA@mail.gmail.com> (raw)
In-Reply-To: <CAA=xLRMBMnu0eaor7uxHEVRLugKqqG5rcgcbUQwn9shr2nG2RQ@mail.gmail.com>


[-- Attachment #1.1: Type: text/plain, Size: 4513 bytes --]

Resubmit my fixed patch #3 for stylistic changes with white space changes
removed (git diff -w) as attached.

[PATCH] Other hideif enhancements and bug fixes:
* Add macro evaluation function and key binding.
* Merge continuous "..." into one on hiding.
* Fix original hideif bug that sometimes fail to hide the correct portion
in a
  long ifdefs containing #elif and #else.
* Support hide/show commands in a marked region.
* Expand top level #ifdefs for C/C++ header files to prevent header files
  always got hidden.
* Others.



2014-06-27 0:56 GMT+08:00 Glenn Morris <rgm@gnu.org>:


> Some stylistic comments only:
>
> It needs a ChangeLog entry, and probably a NEWS entry.
>
> > -;;   Daniel LaLiberte <liberte@holonexus.org>
> > +;;      Daniel LaLiberte <liberte@holonexus.org>
>
> Please don't change existing whitespace in areas that you are not
> otherwise touching.
>
> > -;;    (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
> > +;;       (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
>
> Again, this is just whitespace.
>
> > @@ -129,16 +129,44 @@
> >    "Non-nil means shadow text instead of hiding it."
> >    :type 'boolean
> >    :group 'hide-ifdef
> > -  :version "23.1")
> > +  :version "24.5")
> >
> >  (defface hide-ifdef-shadow '((t (:inherit shadow)))
> >    "Face for shadowing ifdef blocks."
> >    :group 'hide-ifdef
> > -  :version "23.1")
> > +  :version "24.5")
>
> Why is the :version changing, when the defaults are unchanged?
>
> >   (defcustom hide-ifdef-exclude-define-regexp nil
> >    "Ignore #define names if those names match this exclusion pattern."
> >    :type 'string)
> > +(defcustom hide-ifdef-expand-reinclusion-protection t
> > +  "When hiding header files, enabling this flag allows hideif always
> try to
> > +expand the re-inclusion protected ifdefs.  Disabling this flag those
> headers
> > +are usually hidden to a top level #ifdef...#endif due to those defined
> symbols
>
> The first line of a doc-string should be a complete sentence that fits
> in < 80 columns. All the doc should fit within the standard fill-column.
>
>  > +  :type 'boolean
> > +  :group 'hide-ifdef)
> > +
> > +(defcustom hide-ifdef-header-regexp-pattern
> > +  "^.*\\.[hH]\\([hH]\\|[xX][xX]\\|[pP][pP]\\)?"
> > +  "C/C++ header file name patterns. Effective only if
> > +`hide-ifdef-expand-reinclusion-protection' is t."
> > +  :type 'string
> > +  :group 'hide-ifdef)
>
> Again, the first line of the doc should be a complete sentence.
> New defcustoms need :version tags (and probably NEWS entries).
>
> > +(defvar hide-ifdef-env-backup nil
> > +  "A backup variable to prevent `hide-ifdef-env' accidentally cleared by
> > +`hif-clear-all-ifdef-defined'.")
>
> First line of doc too long. Also, this is ungrammatical.
>
> >  `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 but is now a
> > +        global variable since we've extend hideif to support
> project-based
>
> s/extend/extended.
> "project-based across all-buffers" doesn't make sense.
> I'm not sure that describing how things used to work is helpful.
>
> > +        across all-buffers.  To simulate the original buffer local
> behavior
> > +        we need to clear this variable (C-c @ C) then hide current
> buffer.
>
> >  `hide-ifdef-define-alist'
> > -     An association list of defined symbol lists.
> > +        An association list of defined symbol lists.
>
> whitespace.
>
> > -     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.
>
> whitespace.
>
>
> At this point, I'll give up, and ask you to send a version that does not
> have pointless whitespace changes. :)
>



-- 
Best regards,
Luke Lee




-- 
Best regards,
Luke Lee

[-- Attachment #1.2: Type: text/html, Size: 6369 bytes --]

[-- Attachment #2: 0003-Other-hideif-enhancements-and-bug-fixes.patch --]
[-- Type: application/octet-stream, Size: 28301 bytes --]

diff --git a/lisp/progmodes/hideif.el b/lisp/progmodes/hideif.el
index 4b78c08..5063710 100644
--- a/lisp/progmodes/hideif.el
+++ b/lisp/progmodes/hideif.el
@@ -138,7 +138,45 @@
 
 (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
+  "Prevent hiding the whole C/C++ header file protected by a big #ifdef..#endif.
+Most C/C++ headers are usually wrapped with ifdefs to prevent re-inclusion:
+
+  ----- beginning of file -----
+  #ifdef _XXX_HEADER_FILE_INCLUDED_
+  #define _XXX_HEADER_FILE_INCLUDED_
+     xxx
+     xxx
+     xxx...
+  #endif
+  ----- end of file -----
+
+If we try to hide this header file, for the first time hideif will find
+_XXX_HEADER_FILE_INCLUDED_ and have it defined.  Everything between #ifdef
+to #endif are not hidden.  For the second time since _XXX_HEADER_FILE_INCLUDED_
+is defined everything between the outermost #ifdef..#endif will be hidden:
+
+  ----- beginning of file -----
+  #ifdef _XXX_HEADER_FILE_INCLUDED_
+     ...
+  #endif
+  ----- end of file -----
+
+This is not the behavior we expected, we still would like to see the content
+of this header file.  With this flag enabled we can have the outermost #if
+always not hidden."
+  :type 'boolean
+  :version "24.4")
+
+(defcustom hide-ifdef-header-regexp
+  "^.*\\.[hH]\\([hH]\\|[xX][xX]\\|[pP][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)
 
 (defvar hide-ifdef-mode-submap
   ;; Set up the submap that goes after the prefix key.
@@ -152,6 +190,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 +256,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 +278,16 @@ 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.
+
+        We can still simulate the behavior of elder hideif versions (i.e.
+        `hide-ifdef-env' being buffer local) by clearing this variable
+        (C-c @ C) everytime before hiding current buffer.
 
 `hide-ifdef-define-alist'
         An association list of defined symbol lists.
@@ -259,8 +312,9 @@ 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))
+;;      (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 +333,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 +360,63 @@ 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."
+  ;; Genernally 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 +425,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 +486,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 +608,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 don't stuck here.
            (t (error "Bad #if expression: %s" (buffer-string)))))))
 
     (nreverse token-list)))
@@ -1175,13 +1286,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)
@@ -1275,26 +1389,26 @@ 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.
@@ -1303,19 +1417,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
@@ -1325,7 +1443,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.
@@ -1340,69 +1458,176 @@ 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'."
   ;; (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 support 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] [...] )'.
@@ -1533,6 +1758,10 @@ 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)
+          (expand-header (and hide-ifdef-expand-reinclusion-protection
+                              (string-match hide-ifdef-header-regexp
+                                            (buffer-name (current-buffer)))
+                              (zerop hif-recurse-level)))
           min max)
     (goto-char (point-min))
       (setf min (point))
@@ -1540,7 +1769,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))))
 
@@ -1587,17 +1816,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 val)
+  "Define a VAR optionally to a specific value VAL into `hide-ifdef-env'.
+This allows #ifdef VAR from being 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")
@@ -1618,11 +1860,14 @@ 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.
+If this command is prefixed, hide also 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
   (if hide-ifdef-hiding
@@ -1631,7 +1876,7 @@ Turn off hiding by calling `show-ifdefs'."
   (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 ()
@@ -1663,9 +1908,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.
+If prefixed, it will also hide #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))
@@ -1673,12 +1924,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
@@ -1686,7 +1951,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

  parent reply	other threads:[~2014-06-27  9:37 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-06-26 13:51 bug#17854: The patch #3 of 3 for hideif.el, a lot of bug fixes and enhancements Luke Lee
2014-06-26 16:56 ` Glenn Morris
2014-06-26 16:59   ` Glenn Morris
2014-06-27  9:08     ` Luke Lee
2014-06-27  9:26   ` Luke Lee
2014-06-27  9:37 ` Luke Lee [this message]
2014-06-28  1:53   ` Glenn Morris
2014-06-28  3:22     ` Glenn Morris
2014-06-30 14:42     ` Luke Lee
2014-06-30 21:47       ` Stefan Monnier
2014-07-01  1:55         ` Luke Lee
2014-07-01  6:44       ` Glenn Morris
2014-07-03  2:37         ` Luke Lee
2014-07-07  0:02           ` Glenn Morris
2014-07-07  1:00             ` Glenn Morris
2014-07-07  9:05               ` Luke Lee
2014-07-07  9:04             ` Luke Lee
2014-07-07 16:10               ` Glenn Morris
2014-07-08  2:10                 ` Luke Lee
2014-07-07  9:04 ` bug#17854: Completed Luke Lee

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CAA=xLRPOpaV5HhjONej_=wMH5t2sXvF_XnZ5_G84CQvU6vQZpA@mail.gmail.com' \
    --to=luke.yx.lee@gmail.com \
    --cc=17854@debbugs.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).