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