|
|
1.1 root 1: ;;; hide-ifdef-mode.el Hides selected code within ifdef.
2: ;;;
3: ;;; Copyright (C) 1988 Brian Marick and Daniel LaLiberte
4: ;;; Written by Brian Marick, at Gould, Computer Systems Division, Urbana IL.
5: ;;; Extensively modified by Daniel LaLiberte (while at Gould).
6: ;;;
7: ;;; You may freely modify and distribute this, but keep a record
8: ;;; of modifications and send comments to:
9: ;;; [email protected] or ihnp4!uiucdcs!liberte
10: ;;; I will continue to upgrade hide-ifdef-mode
11: ;;; with your contributions and will eventually offer it to FSF.
12: ;;;
13: ;;; $Header: hide-ifdef-mode.el,v 1.7 88/02/16 03:12:58 liberte Exp $
14: ;;;
15: ;;; $Log: hide-ifdef-mode.el,v $
16: ;;; Revision 1.7 88/02/16 03:12:58 liberte
17: ;;; Fixed comments and doc strings.
18: ;;; Added optional prefix arg for ifdef motion commands.
19: ;;;
20: ;;; Revision 1.6 88/02/05 00:36:18 liberte
21: ;;; Bug fixes.
22: ;;; 1. A multi-line comment that starts on an #ifdef line
23: ;;; now ends on that line.
24: ;;; 2. Fix bad function name: hide-hif-ifdef-toggle-read-only
25: ;;; 3. Make ifdef-block hiding work outside of ifdefs.
26: ;;;
27: ;;; Revision 1.5 88/01/31 23:19:31 liberte
28: ;;; Major clean up.
29: ;;; Prefix internal names with "hif-".
30: ;;;
31: ;;; Revision 1.4 88/01/30 14:09:38 liberte
32: ;;; Add hide-ifdef-hiding and hide-ifdef-mode to minor-mode-alist.
33: ;;;
34: ;;; Revision 1.3 88/01/29 00:38:19 liberte
35: ;;; Fix three bugs.
36: ;;; 1. Function "defined" is just like lookup.
37: ;;; 2. Skip to newline or cr in case text is hidden.
38: ;;; 3. Use car of token list if just one symbol.
39: ;;;
40: ;;; Revision 1.2 88/01/28 23:32:46 liberte
41: ;;; Use hide-ifdef-mode-prefix-key.
42: ;;; Copy current-local-map so other buffers do not get
43: ;;; hide-ifdef-mode bindings.
44: ;;;
45: ;;;--------------------------------------------------------------
46: ;;; To initialize, toggle the hide-ifdef minor mode with
47: ;;;
48: ;;; M-x hide-ifdef-mode
49: ;;;
50: ;;; This will set up key bindings and call hide-ifdef-mode-hook if it
51: ;;; has a value. To explicitly hide ifdefs using a buffer-local
52: ;;; define list (default empty), type
53: ;;;
54: ;;; M-x hide-ifdefs or C-c h
55: ;;;
56: ;;; Hide-ifdef suppresses the display of code that the preprocessor wouldn't
57: ;;; pass through. The support of constant expressions in #if lines is
58: ;;; limited to identifiers, parens, and the operators: &&, ||, !, and
59: ;;; "defined". Please extend this.
60: ;;;
61: ;;; The hidden code is marked by ellipses (...). Be
62: ;;; cautious when editing near ellipses, since the hidden text is
63: ;;; still in the buffer, and you can move the point into it and modify
64: ;;; text unawares. If you don't want to see the ellipses, set
65: ;;; selective-display-ellipses to nil. But this can be dangerous.
66: ;;; You can make your buffer read-only while hide-ifdef-hiding by setting
67: ;;; hide-ifdef-read-only to a non-nil value. You can toggle this
68: ;;; variable with hide-ifdef-toggle-read-only (C-c C-q).
69: ;;;
70: ;;; You can undo the effect of hide-ifdefs by typing
71: ;;;
72: ;;; M-x show-ifdefs or C-c s
73: ;;;
74: ;;; Use M-x hide-ifdef-define (C-c d) to define a symbol.
75: ;;; Use M-x hide-ifdef-undef (C-c u) to undefine a symbol.
76: ;;;
77: ;;; If you define or undefine a symbol while hide-ifdef-mode is in effect,
78: ;;; the display will be updated. Only the define list for the current
79: ;;; buffer will be affected. You can save changes to the local define
80: ;;; list with hide-ifdef-set-define-alist. This adds entries
81: ;;; to hide-ifdef-define-alist.
82: ;;;
83: ;;; If you have defined a hide-ifdef-mode-hook, you can set
84: ;;; up a list of symbols that may be used by hide-ifdefs as in the
85: ;;; following example:
86: ;;;
87: ;;; (setq hide-ifdef-mode-hook
88: ;;; '(lambda ()
89: ;;; (if (not hide-ifdef-define-alist)
90: ;;; (setq hide-ifdef-define-alist
91: ;;; '((list1 ONE TWO)
92: ;;; (list2 TWO THREE)
93: ;;; )))
94: ;;; (hide-ifdef-use-define-alist 'list2) ; use list2 by default
95: ;;; ))
96: ;;;
97: ;;; You can call hide-ifdef-use-define-alist (C-c u) at any time to specify
98: ;;; another list to use.
99: ;;;
100: ;;; To cause ifdefs to be hidden as soon as hide-ifdef-mode is called,
101: ;;; set hide-ifdef-initially to non-nil.
102: ;;;
103: ;;; If you set hide-ifdef-lines to t, hide-ifdefs hides all the #ifdef lines.
104: ;;; In the absence of highlighting, that might be a bad idea. If you set
105: ;;; hide-ifdef-lines to nil (the default), the surrounding preprocessor
106: ;;; lines will be displayed. That can be confusing in its own
107: ;;; right. Other variations on display are possible, but not much
108: ;;; better.
109: ;;;
110: ;;; You can explicitly hide or show individual ifdef blocks irrespective
111: ;;; of the define list by using hide-ifdef-block and show-ifdef-block.
112: ;;;
113: ;;; You can move the point between ifdefs with forward-ifdef, backward-ifdef,
114: ;;; up-ifdef, down-ifdef, next-ifdef, and previous-ifdef.
115: ;;;
116: ;;; If you have minor-mode-alist in your mode line (the default) two labels
117: ;;; may appear. "Ifdef" will appear when hide-ifdef-mode is active. "Hiding"
118: ;;; will appear when text may be hidden ("hide-ifdef-hiding" is non-nil).
119:
120:
121:
122: (defvar hide-ifdef-mode-map nil
123: "Keymap used with hide-ifdef mode")
124:
125: (defconst hide-ifdef-mode-prefix-key "\C-c"
126: "Prefix key for all hide-ifdef-mode commands.")
127:
128: (defvar hide-ifdef-mode-map-before nil
129: "Buffer-local variable to store a copy of the local keymap
130: before hide-ifdef-mode modifies it.")
131:
132: (defun define-hide-ifdef-mode-map ()
133: (if hide-ifdef-mode-map
134: () ; dont redefine it.
135: (setq hide-ifdef-mode-map (make-sparse-keymap))
136: (define-key hide-ifdef-mode-map "d" 'hide-ifdef-define)
137: (define-key hide-ifdef-mode-map "u" 'hide-ifdef-undef)
138: (define-key hide-ifdef-mode-map "D" 'hide-ifdef-set-define-alist)
139: (define-key hide-ifdef-mode-map "U" 'hide-ifdef-use-define-alist)
140:
141: (define-key hide-ifdef-mode-map "h" 'hide-ifdefs)
142: (define-key hide-ifdef-mode-map "s" 'show-ifdefs)
143: (define-key hide-ifdef-mode-map "\C-h" 'hide-ifdef-block)
144: (define-key hide-ifdef-mode-map "\C-s" 'show-ifdef-block)
145:
146: (define-key hide-ifdef-mode-map "\C-f" 'forward-ifdef)
147: (define-key hide-ifdef-mode-map "\C-b" 'backward-ifdef)
148: (define-key hide-ifdef-mode-map "\C-d" 'down-ifdef)
149: (define-key hide-ifdef-mode-map "\C-u" 'up-ifdef)
150: (define-key hide-ifdef-mode-map "\C-n" 'next-ifdef)
151: (define-key hide-ifdef-mode-map "\C-p" 'previous-ifdef)
152: (define-key hide-ifdef-mode-map "\C-q" 'hide-ifdef-toggle-read-only)
153: (define-key hide-ifdef-mode-map
154: (where-is-internal 'toggle-read-only nil t)
155: 'hide-ifdef-toggle-outside-read-only)
156: )
157: (fset 'hide-ifdef-mode-map hide-ifdef-mode-map) ; the function is the map
158: )
159:
160: (defun hif-update-mode-line ()
161: "Update mode-line by setting buffer-modified to itself."
162: (set-buffer-modified-p (buffer-modified-p)))
163:
164:
165: (defvar hide-ifdef-mode nil
166: "non-nil when hide-ifdef-mode is activated.")
167:
168: (defvar hide-ifdef-hiding nil
169: "non-nil when text may be hidden.")
170:
171: (or (assq 'hide-ifdef-hiding minor-mode-alist)
172: (setq minor-mode-alist
173: (cons '(hide-ifdef-hiding " Hiding")
174: minor-mode-alist)))
175:
176: (or (assq 'hide-ifdef-mode minor-mode-alist)
177: (setq minor-mode-alist
178: (cons '(hide-ifdef-mode " Ifdef")
179: minor-mode-alist)))
180:
181:
182: (defun hide-ifdef-mode (arg)
183: "Toggle hide-ifdef-mode. Thus this is a minor mode, albeit a large one.
184: With arg, turn hide-ifdef-mode on iff arg is positive.
185: In hide-ifdef-mode, code within #ifdef constructs that the C preprocessor
186: would eliminate may be hidden from view. Several variables affect
187: how the hiding is done:
188:
189: hide-ifdef-env
190: An association list of defined and undefined symbols for the
191: current buffer. Initially, the global value of hide-ifdef-env is used.
192:
193: hide-ifdef-define-alist
194: An association list of defined symbol lists.
195: Use hide-ifdef-set-define-alist to save the current hide-ifdef-env
196: and hide-ifdef-use-define-alist to set the current hide-ifdef-env
197: from one of the lists in hide-ifdef-define-alist.
198:
199: hide-ifdef-lines
200: Set to non-nil to not show #if, #ifdef, #ifndef, #else, and
201: #endif lines when hiding.
202:
203: hide-ifdef-initially
204: Indicates whether hide-ifdefs should be called when hide-ifdef-mode
205: is activated.
206:
207: hide-ifdef-read-only
208: Set to non-nil if you want to make buffers read only while hiding.
209: After show-ifdefs, read-only status is restored to previous value.
210:
211: \\{hide-ifdef-mode-map}"
212:
213: (interactive "P")
214: (make-local-variable 'hide-ifdef-mode)
215: (setq hide-ifdef-mode
216: (if (null arg)
217: (not hide-ifdef-mode)
218: (> (prefix-numeric-value arg) 0)))
219:
220: (hif-update-mode-line)
221:
222: (if hide-ifdef-mode
223: (progn
224: ; fix c-mode syntax table so we can recognize whole symbols.
225: (modify-syntax-entry ?_ "w")
226: (modify-syntax-entry ?& ".")
227: (modify-syntax-entry ?\| ".")
228:
229: ; inherit global values
230: (make-local-variable 'hide-ifdef-env)
231: (setq hide-ifdef-env (default-value 'hide-ifdef-env))
232:
233: (make-local-variable 'hide-ifdef-hiding)
234: (setq hide-ifdef-hiding (default-value 'hide-ifdef-hiding))
235:
236: (make-local-variable 'hif-outside-read-only)
237: (setq hif-outside-read-only buffer-read-only)
238:
239: (make-local-variable 'ide-ifdef-mode-map-before)
240: (setq hide-ifdef-mode-map-before (current-local-map))
241: (use-local-map (copy-keymap (current-local-map)))
242: (local-unset-key hide-ifdef-mode-prefix-key)
243: (local-set-key hide-ifdef-mode-prefix-key 'hide-ifdef-mode-map)
244: (define-hide-ifdef-mode-map)
245:
246: (run-hooks 'hide-ifdef-mode-hook)
247:
248: (if hide-ifdef-initially
249: (hide-ifdefs)
250: (show-ifdefs))
251: (message "Enter hide-ifdef-mode.")
252: )
253: ; else end hide-ifdef-mode
254: (if hide-ifdef-hiding
255: (show-ifdefs))
256: (use-local-map hide-ifdef-mode-map-before)
257: (message "Exit hide-ifdef-mode.")
258: ))
259:
260:
261: ;; from outline.el with docstring fixed.
262: (defun hif-outline-flag-region (from to flag)
263: "Hides or shows lines from FROM to TO, according to FLAG. If FLAG
264: is \\n (newline character) then text is shown, while if FLAG is \\^M
265: \(control-M) the text is hidden."
266: (let ((modp (buffer-modified-p)))
267: (unwind-protect (progn
268: (subst-char-in-region from to
269: (if (= flag ?\n) ?\^M ?\n)
270: flag t) )
271: (set-buffer-modified-p modp))
272: ))
273:
274: (defun hif-show-all ()
275: "Show all of the text in the current buffer."
276: (interactive)
277: (hif-outline-flag-region (point-min) (point-max) ?\n))
278:
279: (defun hide-ifdef-region (start end)
280: "START is the start of a #if or #else form. END is the ending part.
281: Everything including these lines is made invisible."
282: (hif-outline-flag-region start end ?\^M)
283: )
284:
285: (defun hif-show-ifdef-region (start end)
286: "Everything between START and END is made visible."
287: (hif-outline-flag-region start end ?\n)
288: )
289:
290:
291:
292: ;===%%SF%% evaluation (Start) ===
293:
294: (defvar hide-ifdef-evaluator 'eval
295: "The evaluator is given a canonical form and returns T if text under
296: that form should be displayed.")
297:
298: (defvar hif-undefined-symbol nil
299: "...is by default considered to be false.")
300:
301: (defvar hide-ifdef-env nil
302: "An alist of defined symbols and their values.")
303:
304:
305: (defun hif-set-var (var value)
306: "Prepend (var value) pair to hide-ifdef-env."
307: (setq hide-ifdef-env (cons (cons var value) hide-ifdef-env)))
308:
309:
310: (defun hif-lookup (var)
311: ; (message "hif-lookup %s" var)
312: (let ((val (assoc var hide-ifdef-env)))
313: (if val
314: (cdr val)
315: hif-undefined-symbol)))
316:
317: (defun hif-defined (var)
318: (hif-lookup var)
319: ; when #if expressions are fully supported, defined result should be 1
320: ; (if (assoc var hide-ifdef-env)
321: ; 1
322: ; nil)
323: )
324:
325:
326: ;===%%SF%% evaluation (End) ===
327:
328:
329:
330: ;===%%SF%% parsing (Start) ===
331: ;;; The code that understands what ifs and ifdef in files look like.
332:
333: (defconst hif-cpp-prefix "\\(^\\|\r\\)[ \t]*#[ \t]*")
334: (defconst hif-ifndef-regexp (concat hif-cpp-prefix "ifndef"))
335: (defconst hif-ifx-regexp (concat hif-cpp-prefix "if\\(n?def\\)?[ \t]+"))
336: (defconst hif-else-regexp (concat hif-cpp-prefix "else"))
337: (defconst hif-endif-regexp (concat hif-cpp-prefix "endif"))
338: (defconst hif-ifx-else-endif-regexp
339: (concat hif-ifx-regexp "\\|" hif-else-regexp "\\|" hif-endif-regexp))
340:
341:
342: (defun hif-infix-to-prefix (token-list)
343: "Convert list of tokens in infix into prefix list"
344: ; (message "hif-infix-to-prefix: %s" token-list)
345: (if (= 1 (length token-list))
346: (` (hif-lookup (quote (, (car token-list)))))
347: (hif-parse-if-exp token-list))
348: )
349:
350: ; pattern to match initial identifier, !, &&, ||, (, or ).
351: (defconst hif-token-regexp "^\\(!\\|&&\\|||\\|[()]\\|\\w+\\)")
352: (defconst hif-end-of-comment "\\*/")
353:
354:
355: (defun hif-tokenize (expr-string)
356: "Separate string into a list of tokens"
357: (let ((token-list nil)
358: (expr-start 0)
359: (expr-length (length expr-string)))
360:
361: (while (< expr-start expr-length)
362: ; (message "expr-start = %d" expr-start) (sit-for 1)
363: (cond
364: ((string-match "^[ \t]+" expr-string expr-start)
365: ; skip whitespace
366: (setq expr-start (match-end 0))
367: ; stick newline in string so ^ matches on the next string-match
368: (aset expr-string (1- expr-start) ?\n)
369: )
370:
371: ((string-match "^/\\*" expr-string expr-start)
372: (setq expr-start (match-end 0))
373: (aset expr-string (1- expr-start) ?\n)
374: (or
375: (string-match hif-end-of-comment
376: expr-string expr-start) ; eat comment
377: (string-match "$" expr-string expr-start)) ; multi-line comment
378: (setq expr-start (match-end 0))
379: (aset expr-string (1- expr-start) ?\n)
380: )
381:
382: ((string-match hif-token-regexp expr-string expr-start)
383: (let ((token (substring expr-string expr-start (match-end 0))))
384: (setq expr-start (match-end 0))
385: (aset expr-string (1- expr-start) ?\n)
386: ; (message "token: %s" token) (sit-for 1)
387: (setq token-list
388: (cons
389: (cond
390: ((string-equal token "||") 'or)
391: ((string-equal token "&&") 'and)
392: ((string-equal token "!") 'not)
393: ((string-equal token "defined") 'hif-defined)
394: ((string-equal token "(") 'lparen)
395: ((string-equal token ")") 'rparen)
396: (t (intern token)))
397: token-list))
398: ))
399: (t (error "Bad #if expression: %s" expr-string))
400: ))
401: (nreverse token-list)
402: ))
403:
404: ;;;-----------------------------------------------------------------
405: ;;; Translate C preprocessor #if expressions using recursive descent.
406: ;;; This parser is limited to the operators &&, ||, !, and "defined".
407:
408: (defun hif-parse-if-exp (token-list)
409: "Parse the TOKEN-LIST. Return translated list in prefix form."
410: (hif-nexttoken)
411: (prog1
412: (hif-expr)
413: (if token ; is there still a token?
414: (error "Error: unexpected token: %s" token)))
415: )
416:
417: (defun hif-nexttoken ()
418: "Pop the next token from token-list into the let variable \"token\"."
419: (setq token (car token-list))
420: (setq token-list (cdr token-list))
421: token
422: )
423:
424: (defun hif-expr ()
425: "Parse and expression of the form
426: expr : term | expr '||' term."
427: (let ((result (hif-term)))
428: (while (eq token 'or)
429: (hif-nexttoken)
430: (setq result (list 'or result (hif-term))))
431: result
432: ))
433:
434: (defun hif-term ()
435: "Parse a term of the form
436: term : factor | term '&&' factor."
437: (let ((result (hif-factor)))
438: (while (eq token 'and)
439: (hif-nexttoken)
440: (setq result (list 'and result (hif-factor))))
441: result
442: ))
443:
444: (defun hif-factor ()
445: "Parse a factor of the form
446: factor : '!' factor | '(' expr ')' | 'defined(' id ')' | id."
447: (cond
448: ((eq token 'not)
449: (hif-nexttoken)
450: (list 'not (hif-factor)))
451:
452: ((eq token 'lparen)
453: (hif-nexttoken)
454: (let ((result (hif-expr)))
455: (if (not (eq token 'rparen))
456: (error "Bad token in parenthesized expression: %s" token)
457: (hif-nexttoken)
458: result)))
459:
460: ((eq token 'hif-defined)
461: (hif-nexttoken)
462: (if (not (eq token 'lparen))
463: (error "Error: expected \"(\" after \"define\""))
464: (hif-nexttoken)
465: (let ((ident token))
466: (if (memq token '(or and not hif-defined lparen rparen))
467: (error "Error: unexpected token: %s" token))
468: (hif-nexttoken)
469: (if (not (eq token 'rparen))
470: (error "Error: expected \")\" after identifier"))
471: (hif-nexttoken)
472: (` (hif-defined (quote (, ident))))
473: ))
474:
475: (t ; identifier
476: (let ((ident token))
477: (if (memq ident '(or and))
478: (error "Error: missing identifier"))
479: (hif-nexttoken)
480: (` (hif-lookup (quote (, ident))))
481: ))
482:
483: ))
484:
485: ;;;----------- end of parser -----------------------
486:
487:
488: (defun hif-canonicalize ()
489: "When at beginning of #ifX, returns a canonical (evaluatable)
490: form for the expression."
491: (save-excursion
492: (let ((negate (looking-at hif-ifndef-regexp)))
493: (re-search-forward hif-ifx-regexp)
494: (let* ((expr-string
495: (buffer-substring (point)
496: (progn (skip-chars-forward "^\n\r") (point))))
497: (expr (hif-infix-to-prefix (hif-tokenize expr-string))))
498: ; (message "hif-canonicalized: %s" expr)
499: (if negate
500: (list 'not expr)
501: expr)))))
502:
503:
504: (defun hif-find-any-ifX ()
505: "Position at beginning of next #if, #ifdef, or #ifndef, including one on
506: this line."
507: ; (message "find ifX at %d" (point))
508: (prog1
509: (re-search-forward hif-ifx-regexp (point-max) t)
510: (beginning-of-line)))
511:
512:
513: (defun hif-find-next-relevant ()
514: "Position at beginning of next #ifdef, #ifndef, #else, #endif,
515: NOT including one on this line."
516: ; (message "hif-find-next-relevant at %d" (point))
517: (end-of-line)
518: ; avoid infinite recursion by only going to beginning of line if match found
519: (if (re-search-forward hif-ifx-else-endif-regexp (point-max) t)
520: (beginning-of-line))
521: )
522:
523: (defun hif-find-previous-relevant ()
524: "Position at beginning of previous #ifdef, #ifndef, #else, #endif,
525: NOT including one on this line."
526: ; (message "hif-find-previous-relevant at %d" (point))
527: (beginning-of-line)
528: ; avoid infinite recursion by only going to beginning of line if match found
529: (if (re-search-backward hif-ifx-else-endif-regexp (point-min) t)
530: (beginning-of-line)
531: )
532: )
533:
534:
535: (defun hif-looking-at-ifX () ;; Should eventually see #if
536: (looking-at hif-ifx-regexp))
537: (defun hif-looking-at-endif ()
538: (looking-at hif-endif-regexp))
539: (defun hif-looking-at-else ()
540: (looking-at hif-else-regexp))
541:
542:
543:
544: (defun hif-ifdef-to-endif ()
545: "If positioned at #ifX or #else form, skip to corresponding #endif."
546: ; (message "hif-ifdef-to-endif at %d" (point)) (sit-for 1)
547: (hif-find-next-relevant)
548: (cond ((hif-looking-at-ifX)
549: (hif-ifdef-to-endif) ; find endif of nested if
550: (hif-ifdef-to-endif)) ; find outer endif or else
551: ((hif-looking-at-else)
552: (hif-ifdef-to-endif)) ; find endif following else
553: ((hif-looking-at-endif)
554: 'done)
555: (t
556: (error "Missmatched #ifdef #endif pair"))
557: ))
558:
559:
560: (defun hif-endif-to-ifdef ()
561: "If positioned at #endif form, skip backward to corresponding #ifX."
562: ; (message "hif-endif-to-ifdef at %d" (point))
563: (let ((start (point)))
564: (hif-find-previous-relevant)
565: (if (= start (point))
566: (error "Missmatched #ifdef #endif pair")))
567: (cond ((hif-looking-at-endif)
568: (hif-endif-to-ifdef) ; find beginning of nested if
569: (hif-endif-to-ifdef)) ; find beginning of outer if or else
570: ((hif-looking-at-else)
571: (hif-endif-to-ifdef))
572: ((hif-looking-at-ifX)
573: 'done)
574: (t ; never gets here
575: )))
576:
577:
578: (defun forward-ifdef (&optional arg)
579: "Move point to beginning of line of the next ifdef-endif.
580: With argument, do this that many times."
581: (interactive "p")
582: (or arg (setq arg 1))
583: (if (< arg 0)
584: (backward-ifdef (- arg)))
585: (while (< 0 arg)
586: (setq arg (- arg))
587: (let ((start (point)))
588: (if (not (hif-looking-at-ifX))
589: (hif-find-next-relevant))
590: (if (hif-looking-at-ifX)
591: (hif-ifdef-to-endif)
592: (goto-char start)
593: (error "No following #ifdef")
594: ))))
595:
596:
597: (defun backward-ifdef (&optional arg)
598: "Move point to beginning of the previous ifdef-endif.
599: With argument, do this that many times."
600: (interactive "p")
601: (or arg (setq arg 1))
602: (if (< arg 0)
603: (forward-ifdef (- arg)))
604: (while (< 0 arg)
605: (setq arg (1- arg))
606: (beginning-of-line)
607: (let ((start (point)))
608: (if (not (hif-looking-at-endif))
609: (hif-find-previous-relevant))
610: (if (hif-looking-at-endif)
611: (hif-endif-to-ifdef)
612: (goto-char start)
613: (error "No previous #ifdef")
614: ))))
615:
616:
617:
618: (defun down-ifdef ()
619: "Move point to beginning of nested ifdef or else-part."
620: (interactive)
621: (let ((start (point)))
622: (hif-find-next-relevant)
623: (if (or (hif-looking-at-ifX) (hif-looking-at-else))
624: ()
625: (goto-char start)
626: (error "No following #ifdef")
627: )))
628:
629:
630: (defun up-ifdef ()
631: "Move point to beginning of enclosing ifdef or else-part."
632: (interactive)
633: (beginning-of-line)
634: (let ((start (point)))
635: (if (not (hif-looking-at-endif))
636: (hif-find-previous-relevant))
637: (if (hif-looking-at-endif)
638: (hif-endif-to-ifdef))
639: (if (= start (point))
640: (error "No previous #ifdef")
641: )))
642:
643: (defun next-ifdef (&optional arg)
644: "Move to the beginning of the next #ifX, #else, or #endif.
645: With argument, do this that many times."
646: (interactive "p")
647: (or arg (setq arg 1))
648: (if (< arg 0)
649: (previous-ifdef (- arg)))
650: (while (< 0 arg)
651: (setq arg (1- arg))
652: (hif-find-next-relevant)
653: (if (eolp)
654: (progn
655: (beginning-of-line)
656: (error "No following #ifdefs, #elses, or #endifs")
657: ))))
658:
659: (defun previous-ifdef (&optional arg)
660: "Move to the beginning of the previous #ifX, #else, or #endif.
661: With argument, do this that many times."
662: (interactive "p")
663: (or arg (setq arg 1))
664: (if (< arg 0)
665: (next-ifdef (- arg)))
666: (while (< 0 arg)
667: (setq arg (1- arg))
668: (let ((start (point)))
669: (hif-find-previous-relevant)
670: (if (= start (point))
671: (error "No previous #ifdefs, #elses, or #endifs")
672: ))))
673:
674:
675: ;===%%SF%% parsing (End) ===
676:
677:
678: ;===%%SF%% hide-ifdef-hiding (Start) ===
679:
680:
681: ;;; A range is a structure with four components:
682: ;;; ELSE-P True if there was an else clause for the ifdef.
683: ;;; START The start of the range. (beginning of line)
684: ;;; ELSE The else marker (beginning of line)
685: ;;; Only valid if ELSE-P is true.
686: ;;; END The end of the range. (beginning of line)
687:
688: (defun hif-make-range (else-p start end &optional else)
689: (list else-p start else end))
690:
691: (defun hif-range-else-p (range) (elt range 0))
692: (defun hif-range-start (range) (elt range 1))
693: (defun hif-range-else (range) (elt range 2))
694: (defun hif-range-end (range) (elt range 3))
695:
696:
697:
698: ;;; Find-Range
699: ;;; The workhorse, it delimits the #if region. Reasonably simple:
700: ;;; Skip until an #else or #endif is found, remembering positions. If
701: ;;; an #else was found, skip some more, looking for the true #endif.
702:
703: (defun hif-find-range ()
704: "Returns a Range structure describing the current #if region.
705: Point is left unchanged."
706: ; (message "hif-find-range at %d" (point))
707: (save-excursion
708: (beginning-of-line)
709: (let ((start (point))
710: (else-p nil)
711: (else nil)
712: (end nil))
713: ;; Part one. Look for either #endif or #else.
714: ;; This loop-and-a-half dedicated to E. Dijkstra.
715: (hif-find-next-relevant)
716: (while (hif-looking-at-ifX) ; Skip nested ifdef
717: (hif-ifdef-to-endif)
718: (hif-find-next-relevant))
719: ;; Found either a #else or an #endif.
720: (cond ((hif-looking-at-else)
721: (setq else-p t)
722: (setq else (point)))
723: (t
724: (setq end (point)) ; (save-excursion (end-of-line) (point))
725: ))
726: ;; If found #else, look for #endif.
727: (if else-p
728: (progn
729: (hif-find-next-relevant)
730: (while (hif-looking-at-ifX) ; Skip nested ifdef
731: (hif-ifdef-to-endif)
732: (hif-find-next-relevant))
733: (if (hif-looking-at-else)
734: (error "Found two elses in a row? Broken!"))
735: (setq end (point)) ; (save-excursion (end-of-line) (point))
736: ))
737: (hif-make-range else-p start end else))))
738:
739:
740: ;;; A bit slimy.
741: ;;; NOTE: If there's an #ifdef at the beginning of the file, we can't
742: ;;; hide it. There's no previous newline to replace. If we added
743: ;;; one, we'd throw off all the counts. Feh.
744:
745: (defun hif-hide-line (point)
746: "Hide the line containing point. Does nothing if
747: hide-ifdef-lines is nil."
748: (if hide-ifdef-lines
749: (save-excursion
750: (goto-char point)
751: (let ((modp (buffer-modified-p)))
752: (unwind-protect
753: (progn
754: (beginning-of-line)
755: (if (not (= (point) 1))
756: (hide-ifdef-region (1- (point)) (point))))
757: (set-buffer-modified-p modp))
758: ))
759: ))
760:
761:
762: ;;; Hif-Possibly-Hide
763: ;;; There are four cases. The #ifX expression is "taken" if it
764: ;;; the hide-ifdef-evaluator returns T. Presumably, this means the code
765: ;;; inside the #ifdef would be included when the program was
766: ;;; compiled.
767: ;;;
768: ;;; Case 1: #ifX taken, and there's an #else.
769: ;;; The #else part must be hidden. The #if (then) part must be
770: ;;; processed for nested #ifX's.
771: ;;; Case 2: #ifX taken, and there's no #else.
772: ;;; The #if part must be processed for nested #ifX's.
773: ;;; Case 3: #ifX not taken, and there's an #else.
774: ;;; The #if part must be hidden. The #else part must be processed
775: ;;; for nested #ifs.
776: ;;; Case 4: #ifX not taken, and there's no #else.
777: ;;; The #ifX part must be hidden.
778: ;;;
779: ;;; Further processing is done by narrowing to the relevant region
780: ;;; and just recursively calling hide-ifdef-guts.
781: ;;;
782: ;;; When hif-possibly-hide returns, point is at the end of the
783: ;;; possibly-hidden range.
784:
785: (defun hif-recurse-on (start end)
786: "Call hide-ifdef-guts after narrowing to end of START line and END
787: line."
788: (save-excursion
789: (save-restriction
790: (goto-char start)
791: (end-of-line)
792: (narrow-to-region (point) end)
793: (hide-ifdef-guts))))
794:
795: (defun hif-possibly-hide ()
796: "Called at #ifX expression, this hides those parts that should be
797: hidden, according to judgement of hide-ifdef-evaluator."
798: ; (message "hif-possibly-hide") (sit-for 1)
799: (let ((test (hif-canonicalize))
800: (range (hif-find-range)))
801: ; (message "test = %s" test) (sit-for 1)
802:
803: (hif-hide-line (hif-range-end range))
804: (if (funcall hide-ifdef-evaluator test)
805: (cond ((hif-range-else-p range) ; case 1
806: (hif-hide-line (hif-range-else range))
807: (hide-ifdef-region (hif-range-else range)
808: (1- (hif-range-end range)))
809: (hif-recurse-on (hif-range-start range)
810: (hif-range-else range)))
811: (t ; case 2
812: (hif-recurse-on (hif-range-start range)
813: (hif-range-end range))))
814: (cond ((hif-range-else-p range) ; case 3
815: (hif-hide-line (hif-range-else range))
816: (hide-ifdef-region (hif-range-start range)
817: (1- (hif-range-else range)))
818: (hif-recurse-on (hif-range-else range)
819: (hif-range-end range)))
820: (t ; case 4
821: (hide-ifdef-region (point)
822: (1- (hif-range-end range))))
823: ))
824: (hif-hide-line (hif-range-start range)) ; Always hide start.
825: (goto-char (hif-range-end range))
826: (end-of-line)
827: ))
828:
829:
830:
831: (defun hide-ifdef-guts ()
832: "Does the work of hide-ifdefs, except for the work that's pointless
833: to redo on a recursive entry."
834: ; (message "hide-ifdef-guts")
835: (save-excursion
836: (goto-char (point-min))
837: (while (hif-find-any-ifX)
838: (hif-possibly-hide))))
839:
840: ;===%%SF%% hide-ifdef-hiding (End) ===
841:
842:
843: ;===%%SF%% exports (Start) ===
844:
845: (defvar hide-ifdef-initially nil
846: "*Non-nil if hide-ifdefs should be called when hide-ifdef-mode
847: is first activated.")
848:
849: (defvar hide-ifdef-hiding nil
850: "Non-nil if text might be hidden.")
851:
852: (defvar hide-ifdef-read-only nil
853: "*Set to non-nil if you want buffer to be read-only while hiding text.")
854:
855: (defvar hif-outside-read-only nil
856: "Internal variable. Saves the value of buffer-read-only while hiding.")
857:
858: (defvar hide-ifdef-lines nil
859: "*Set to t if you don't want to see the #ifX, #else, and #endif lines.")
860:
861: (defun hide-ifdef-toggle-read-only ()
862: "Toggle hide-ifdef-read-only."
863: (interactive)
864: (setq hide-ifdef-read-only (not hide-ifdef-read-only))
865: (message "Hide-Read-Only %s"
866: (if hide-ifdef-read-only "ON" "OFF"))
867: (if hide-ifdef-hiding
868: (setq buffer-read-only (or hide-ifdef-read-only hif-outside-read-only)))
869: (hif-update-mode-line)
870: )
871:
872: (defun hide-ifdef-toggle-outside-read-only ()
873: "Replacement for toggle-read-only within hide-ifdef-mode."
874: (interactive)
875: (setq hif-outside-read-only (not hif-outside-read-only))
876: (message "Read only %s"
877: (if hif-outside-read-only "ON" "OFF"))
878: (setq buffer-read-only
879: (or (and hide-ifdef-hiding hide-ifdef-read-only)
880: hif-outside-read-only)
881: )
882: (hif-update-mode-line)
883: )
884:
885:
886: (defun hide-ifdef-define (var)
887: "Define a VAR so that #ifdef VAR would be included."
888: (interactive "SDefine what? ")
889: (hif-set-var var t)
890: (if hide-ifdef-hiding (hide-ifdefs)))
891:
892: (defun hide-ifdef-undef (var)
893: "Undefine a VAR so that #ifdef VAR would not be included."
894: (interactive "SUndefine what? ")
895: (hif-set-var var nil)
896: (if hide-ifdef-hiding (hide-ifdefs)))
897:
898:
899: (defun hide-ifdefs ()
900: "Hide the contents of some #ifdefs. Assume that defined symbols have
901: been added to hide-ifdef-env. The text hidden is the text that would not
902: be included by the C preprocessor if it were given the file with those
903: symbols defined.
904:
905: Turn off hiding by calling show-ifdef."
906:
907: (interactive)
908: (message "Hiding...")
909: (if (not hide-ifdef-mode)
910: (hide-ifdef-mode 1)) ; turn on hide-ifdef-mode
911: (if hide-ifdef-hiding
912: (show-ifdefs)) ; Otherwise, deep confusion.
913: (if buffer-read-only (toggle-read-only)) ; make it writable temporarily
914: (setq selective-display t)
915: (setq hide-ifdef-hiding t)
916: (hide-ifdef-guts)
917: (if (or hide-ifdef-read-only hif-outside-read-only)
918: (toggle-read-only) ; make it read only
919: )
920: (message "Hiding done")
921: )
922:
923:
924: (defun show-ifdefs ()
925: "Cancel the effects of hide-ifdef. The contents of all #ifdefs is shown."
926: (interactive)
927: (if buffer-read-only (toggle-read-only)) ; make it writable temporarily
928: (setq selective-display nil) ; defaults
929: (hif-show-all)
930: (if hif-outside-read-only
931: (toggle-read-only)) ; make it read only
932: (setq hide-ifdef-hiding nil)
933: )
934:
935:
936: (defun hif-find-ifdef-block ()
937: "Utilitiy for hide and show ifdef-block. Set top and bottom of ifdef block."
938: (let (max-bottom)
939: (save-excursion
940: (beginning-of-line)
941: (if (not (or (hif-looking-at-else) (hif-looking-at-ifX)))
942: (up-ifdef))
943: (setq top (point))
944: (hif-ifdef-to-endif)
945: (setq max-bottom (1- (point)))
946: )
947: (save-excursion
948: (beginning-of-line)
949: (if (not (hif-looking-at-endif))
950: (hif-find-next-relevant))
951: (while (hif-looking-at-ifX)
952: (hif-ifdef-to-endif)
953: (hif-find-next-relevant)
954: )
955: (setq bottom (min max-bottom (1- (point))))
956: ))
957: )
958:
959:
960: (defun hide-ifdef-block ()
961: "Hide the ifdef block (true or false part) enclosing or before the cursor."
962: (interactive)
963: (if (not hide-ifdef-mode)
964: (hide-ifdef-mode 1))
965: (if buffer-read-only (toggle-read-only))
966: (setq selective-display t)
967: (let (top bottom)
968: (hif-find-ifdef-block) ; set top and bottom - dynamic scoping
969: (hide-ifdef-region top bottom)
970: (if hide-ifdef-lines
971: (progn
972: (hif-hide-line top)
973: (hif-hide-line (1+ bottom))))
974: (setq hide-ifdef-hiding t)
975: )
976: (if (or hide-ifdef-read-only hif-outside-read-only)
977: (toggle-read-only))
978: )
979:
980:
981: (defun show-ifdef-block ()
982: "Show the ifdef block (true or false part) enclosing or before the cursor."
983: (interactive)
984: (let ((old-read-only buffer-read-only))
985: (if old-read-only (toggle-read-only))
986: (if hide-ifdef-lines
987: (save-excursion
988: (beginning-of-line)
989: (hif-show-ifdef-region (1- (point)) (progn (end-of-line) (point))))
990:
991: (let (top bottom)
992: (hif-find-ifdef-block)
993: (hif-show-ifdef-region (1- top) bottom))
994: )
995:
996: ; restore read only status since we dont know if all is shown.
997: (if old-read-only (toggle-read-only))
998: ))
999:
1000:
1001:
1002: ;;; defininition alist support
1003:
1004: (defvar hide-ifdef-define-alist nil
1005: "A global assoc list of pre-defined symbol lists")
1006:
1007: (defun hif-compress-define-list (env)
1008: "Compress the define list ENV into a list of defined symbols only."
1009: (let ((defs (mapcar '(lambda (arg)
1010: (if (hif-lookup (car arg)) (car arg)))
1011: env))
1012: (new-defs nil))
1013: (while defs
1014: (if (car defs)
1015: (setq new-defs (cons (car defs) new-defs)))
1016: (setq defs (cdr defs)))
1017: new-defs
1018: ))
1019:
1020: (defun hide-ifdef-set-define-alist (name)
1021: "Set the association for NAME to hide-ifdef-env."
1022: (interactive "SSet define list: ")
1023: (setq hide-ifdef-define-alist
1024: (cons (cons name (hif-compress-define-list hide-ifdef-env))
1025: hide-ifdef-define-alist))
1026: )
1027:
1028: (defun hide-ifdef-use-define-alist (name)
1029: "Set hide-ifdef-env to the define list specified by NAME."
1030: (interactive "SUse define list: ")
1031: (let ((define-list (assoc name hide-ifdef-define-alist)))
1032: (if define-list
1033: (setq hide-ifdef-env
1034: (mapcar '(lambda (arg) (cons arg t))
1035: (cdr define-list)))
1036: (error "No define list for %s" name))
1037: (if hide-ifdef-hiding (hide-ifdefs))
1038: )
1039: )
1040:
1041: ;===%%SF%% exports (End) ===
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.