diff options
| author | Richard M. Stallman | 1994-09-14 09:03:27 +0000 |
|---|---|---|
| committer | Richard M. Stallman | 1994-09-14 09:03:27 +0000 |
| commit | 20f5d14570100629044c03d915653cec9214f42a (patch) | |
| tree | 37cb7836683f2223dc059fad3523bf5d565cb9a9 /lisp/progmodes/cpp.el | |
| parent | 7908d27ce0ca21164af1e6ea4918f21f542d399a (diff) | |
| download | emacs-20f5d14570100629044c03d915653cec9214f42a.tar.gz emacs-20f5d14570100629044c03d915653cec9214f42a.zip | |
Initial revision
Diffstat (limited to 'lisp/progmodes/cpp.el')
| -rw-r--r-- | lisp/progmodes/cpp.el | 773 |
1 files changed, 773 insertions, 0 deletions
diff --git a/lisp/progmodes/cpp.el b/lisp/progmodes/cpp.el new file mode 100644 index 00000000000..0d21c22f683 --- /dev/null +++ b/lisp/progmodes/cpp.el | |||
| @@ -0,0 +1,773 @@ | |||
| 1 | ;;; cpp.el --- Highlight or hide text according to cpp conditionals. | ||
| 2 | |||
| 3 | ;; Copyright (C) 1994 Free Software Foundation | ||
| 4 | |||
| 5 | ;; Author: Per Abrahamsen <abraham@iesd.auc.dk> | ||
| 6 | ;; Version: $Id: 0.2 ALPHA RELEASE WITH BUGS $ | ||
| 7 | ;; Keywords: c, faces, tools | ||
| 8 | |||
| 9 | ;; LCD Archive Entry: | ||
| 10 | ;; cpp|Per Abrahamsen|abraham@iesd.auc.dk| | ||
| 11 | ;; Highlight or hide text according to cpp conditionals| | ||
| 12 | ;; $Date: 1994-07-20 $|$Revision: 0.2 $|~/misc/cpp.Z| | ||
| 13 | |||
| 14 | ;; This program is free software; you can redistribute it and/or modify | ||
| 15 | ;; it under the terms of the GNU General Public License as published by | ||
| 16 | ;; the Free Software Foundation; either version 2, or (at your option) | ||
| 17 | ;; any later version. | ||
| 18 | ;; | ||
| 19 | ;; This program is distributed in the hope that it will be useful, | ||
| 20 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 21 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 22 | ;; GNU General Public License for more details. | ||
| 23 | ;; | ||
| 24 | ;; You should have received a copy of the GNU General Public License | ||
| 25 | ;; along with this program; if not, write to the Free Software | ||
| 26 | ;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 27 | |||
| 28 | ;;; Comments: | ||
| 29 | |||
| 30 | ;; Parse a text for C preprocessor conditionals, and highlight or hide | ||
| 31 | ;; the text inside the conditionals as you wish. | ||
| 32 | |||
| 33 | ;; Insert the following in your `emacs' to activate it. This assumes | ||
| 34 | ;; you use BAW's superior cc-mode instead of Boring Old C-Mode. | ||
| 35 | |||
| 36 | ;; (autoload 'cpp-parse-buffer "cpp" "Parse and display cpp conditionals." t) | ||
| 37 | |||
| 38 | ;; (eval-after-load "cc-mode" | ||
| 39 | ;; '(progn | ||
| 40 | ;; (define-key c-mode-map "\C-c\C-x" 'cpp-parse-buffer) | ||
| 41 | ;; (define-key-after (bar (lookup-key c-mode-map [ menu-bar c ])) | ||
| 42 | ;; [ cpp-parse ] '("Parse Conditionals" . cpp-parse-buffer) 'up)))) | ||
| 43 | |||
| 44 | ;; Requires GNU Emacs 19. | ||
| 45 | |||
| 46 | ;;; Todo: | ||
| 47 | |||
| 48 | ;; Should parse "#if" and "#elif" expressions and merge the faces | ||
| 49 | ;; somehow. | ||
| 50 | |||
| 51 | ;; Somehow it is sometimes possible to make changes near a read only | ||
| 52 | ;; area which you can't undo. Their are other strange effects in that | ||
| 53 | ;; area. | ||
| 54 | |||
| 55 | ;; The Edit buffer should -- optionally -- appear in its own frame. | ||
| 56 | |||
| 57 | ;; Conditionals seem to be rear-sticky. They shouldn't be. | ||
| 58 | |||
| 59 | ;; Restore window configurations when exiting CPP Edit buffer. | ||
| 60 | |||
| 61 | ;;; Code: | ||
| 62 | |||
| 63 | ;;; Customization: | ||
| 64 | |||
| 65 | (defvar cpp-known-face 'invisible | ||
| 66 | "*Face used for known cpp symbols.") | ||
| 67 | |||
| 68 | (defvar cpp-unknown-face 'highlight | ||
| 69 | "*Face used for unknown cpp cymbols.") | ||
| 70 | |||
| 71 | (defvar cpp-face-type 'light | ||
| 72 | "*Indicate what background face type you prefer. | ||
| 73 | Can be either light or dark for color screens, mono for monochrome | ||
| 74 | screens, and none if you don't use a window system.") | ||
| 75 | |||
| 76 | (defvar cpp-known-writable t | ||
| 77 | "*Non-nil means you are allowed to modify the known conditionals.") | ||
| 78 | |||
| 79 | (defvar cpp-unknown-writable t | ||
| 80 | "*Non-nil means you are allowed to modify the unknown conditionals.") | ||
| 81 | |||
| 82 | ;;; Parse Buffer: | ||
| 83 | |||
| 84 | (defvar cpp-parse-symbols nil | ||
| 85 | "List of cpp macros used in the local buffer.") | ||
| 86 | (make-variable-buffer-local 'cpp-parse-symbols) | ||
| 87 | |||
| 88 | (defconst cpp-parse-regexp | ||
| 89 | ;; Regexp matching all tokens needed to find conditionals. | ||
| 90 | (concat | ||
| 91 | "'\\|\"\\|/\\*\\|//\\|" | ||
| 92 | "\\(^[ \t]*#[ \t]*\\(ifdef\\|ifndef\\|if\\|" | ||
| 93 | "elif\\|else\\|endif\\)\\b\\)")) | ||
| 94 | |||
| 95 | ;;;###autoload | ||
| 96 | (defun cpp-parse-buffer (arg) | ||
| 97 | "Parse all conditionals in the current buffer end edit symbols. | ||
| 98 | A prefix arg supress editing the symbols." | ||
| 99 | (interactive "P") | ||
| 100 | (setq cpp-parse-symbols nil) | ||
| 101 | (cpp-parse-reset) | ||
| 102 | (if (null cpp-edit-list) | ||
| 103 | (cpp-edit-load)) | ||
| 104 | (let (stack) | ||
| 105 | (save-excursion | ||
| 106 | (goto-char (point-min)) | ||
| 107 | (cpp-progress-message "Parsing...") | ||
| 108 | (while (re-search-forward cpp-parse-regexp nil t) | ||
| 109 | (cpp-progress-message "Parsing...%d%%" | ||
| 110 | (/ (* 100 (- (point) (point-min))) (buffer-size))) | ||
| 111 | (let ((match (buffer-substring (match-beginning 0) (match-end 0)))) | ||
| 112 | (cond ((or (string-equal match "'") | ||
| 113 | (string-equal match "\"")) | ||
| 114 | (goto-char (match-beginning 0)) | ||
| 115 | (condition-case nil | ||
| 116 | (forward-sexp) | ||
| 117 | (error (cpp-parse-error | ||
| 118 | "Unterminated string or character")))) | ||
| 119 | ((string-equal match "/*") | ||
| 120 | (or (search-forward "*/" nil t) | ||
| 121 | (error "Unterminated comment"))) | ||
| 122 | ((string-equal match "//") | ||
| 123 | (skip-chars-forward "^\n\r")) | ||
| 124 | (t | ||
| 125 | (end-of-line 1) | ||
| 126 | (let ((from (match-beginning 1)) | ||
| 127 | (to (1+ (point))) | ||
| 128 | (type (buffer-substring (match-beginning 2) | ||
| 129 | (match-end 2))) | ||
| 130 | (expr (buffer-substring (match-end 1) (point)))) | ||
| 131 | (cond ((string-equal type "ifdef") | ||
| 132 | (cpp-parse-open t expr from to)) | ||
| 133 | ((string-equal type "ifndef") | ||
| 134 | (cpp-parse-open nil expr from to)) | ||
| 135 | ((string-equal type "if") | ||
| 136 | (cpp-parse-open t expr from to)) | ||
| 137 | ((string-equal type "elif") | ||
| 138 | (let (cpp-known-face cpp-unknown-face) | ||
| 139 | (cpp-parse-close from to)) | ||
| 140 | (cpp-parse-open t expr from to)) | ||
| 141 | ((string-equal type "else") | ||
| 142 | (or stack (cpp-parse-error "Top level #else")) | ||
| 143 | (let ((entry (list (not (nth 0 (car stack))) | ||
| 144 | (nth 1 (car stack)) | ||
| 145 | from to))) | ||
| 146 | (cpp-parse-close from to) | ||
| 147 | (setq stack (cons entry stack)))) | ||
| 148 | ((string-equal type "endif") | ||
| 149 | (cpp-parse-close from to)) | ||
| 150 | (t | ||
| 151 | (cpp-parse-error "Parser error")))))))) | ||
| 152 | (message "Parsing...done")) | ||
| 153 | (if stack | ||
| 154 | (save-excursion | ||
| 155 | (goto-char (nth 3 (car stack))) | ||
| 156 | (cpp-parse-error "Unclosed conditional")))) | ||
| 157 | (or arg | ||
| 158 | (null cpp-parse-symbols) | ||
| 159 | (cpp-parse-edit))) | ||
| 160 | |||
| 161 | (defun cpp-parse-open (branch expr begin end) | ||
| 162 | ;; Push information about conditional to stack. | ||
| 163 | (while (string-match "\\b[ \t]*/\\*.*\\*/[ \t]*\\b" expr) | ||
| 164 | (setq expr (concat (substring expr 0 (match-beginning 0)) | ||
| 165 | (substring expr (match-end 0))))) | ||
| 166 | (if (string-match "\\b[ \t]*\\(//.*\\)?$" expr) | ||
| 167 | (setq expr (substring expr 0 (match-beginning 0)))) | ||
| 168 | (while (string-match "[ \t]+" expr) | ||
| 169 | (setq expr (concat (substring expr 0 (match-beginning 0)) | ||
| 170 | (substring expr (match-end 0))))) | ||
| 171 | (setq stack (cons (list branch expr begin end) stack)) | ||
| 172 | (or (member expr cpp-parse-symbols) | ||
| 173 | (setq cpp-parse-symbols | ||
| 174 | (cons expr cpp-parse-symbols))) | ||
| 175 | (if (assoc expr cpp-edit-list) | ||
| 176 | (cpp-make-known-overlay begin end) | ||
| 177 | (cpp-make-unknown-overlay begin end))) | ||
| 178 | |||
| 179 | (defun cpp-parse-close (from to) | ||
| 180 | ;; Pop top of stack and create overlay. | ||
| 181 | (let ((entry (assoc (nth 1 (car stack)) cpp-edit-list)) | ||
| 182 | (branch (nth 0 (car stack))) | ||
| 183 | (begin (nth 2 (car stack))) | ||
| 184 | (end (nth 3 (car stack)))) | ||
| 185 | (setq stack (cdr stack)) | ||
| 186 | (if entry | ||
| 187 | (let ((face (nth (if branch 1 2) entry)) | ||
| 188 | (read-only (eq (not branch) (nth 3 entry))) | ||
| 189 | (priority (length stack)) | ||
| 190 | (overlay (make-overlay end from))) | ||
| 191 | (cpp-make-known-overlay from to) | ||
| 192 | (setq cpp-overlay-list (cons overlay cpp-overlay-list)) | ||
| 193 | (if priority (overlay-put overlay 'priority priority)) | ||
| 194 | (cond ((eq face 'invisible) | ||
| 195 | (cpp-make-overlay-hidden overlay)) | ||
| 196 | ((eq face 'default)) | ||
| 197 | (t | ||
| 198 | (overlay-put overlay 'face face))) | ||
| 199 | (if read-only | ||
| 200 | (cpp-make-overlay-read-only overlay) | ||
| 201 | (cpp-make-overlay-sticky overlay))) | ||
| 202 | (cpp-make-unknown-overlay from to)))) | ||
| 203 | |||
| 204 | (defun cpp-parse-error (error) | ||
| 205 | ;; Error message issued by the cpp parser. | ||
| 206 | (error (concat error " at line %d") (count-lines (point-min) (point)))) | ||
| 207 | |||
| 208 | (defun cpp-parse-reset () | ||
| 209 | "Reset display of cpp conditionals to normal." | ||
| 210 | (interactive) | ||
| 211 | (while cpp-overlay-list | ||
| 212 | (delete-overlay (car cpp-overlay-list)) | ||
| 213 | (setq cpp-overlay-list (cdr cpp-overlay-list)))) | ||
| 214 | |||
| 215 | ;;;###autoload | ||
| 216 | (defun cpp-parse-edit () | ||
| 217 | "Edit display information for cpp conditionals." | ||
| 218 | (interactive) | ||
| 219 | (or cpp-parse-symbols | ||
| 220 | (cpp-parse-buffer t)) | ||
| 221 | (let ((buffer (current-buffer))) | ||
| 222 | (pop-to-buffer "*CPP Edit*") | ||
| 223 | (cpp-edit-mode) | ||
| 224 | (setq cpp-edit-buffer buffer) | ||
| 225 | (cpp-edit-reset))) | ||
| 226 | |||
| 227 | ;;; Overlays: | ||
| 228 | |||
| 229 | (defvar cpp-overlay-list nil) | ||
| 230 | ;; List of cpp overlays active in the current buffer. | ||
| 231 | (make-variable-buffer-local 'cpp-overlay-list) | ||
| 232 | |||
| 233 | (defun cpp-make-known-overlay (start end) | ||
| 234 | ;; Create an overlay for a known cpp command from START to END. | ||
| 235 | (let ((overlay (make-overlay start end))) | ||
| 236 | (if (eq cpp-known-face 'invisible) | ||
| 237 | (cpp-make-overlay-hidden overlay) | ||
| 238 | (or (eq cpp-known-face 'default) | ||
| 239 | (overlay-put overlay 'face cpp-known-face)) | ||
| 240 | (if cpp-known-writable | ||
| 241 | () | ||
| 242 | (overlay-put overlay 'modification-hooks '(cpp-signal-read-only)) | ||
| 243 | (overlay-put overlay 'insert-in-front-hooks '(cpp-signal-read-only)))) | ||
| 244 | (setq cpp-overlay-list (cons overlay cpp-overlay-list)))) | ||
| 245 | |||
| 246 | (defun cpp-make-unknown-overlay (start end) | ||
| 247 | ;; Create an overlay for an unknown cpp command from START to END. | ||
| 248 | (let ((overlay (make-overlay start end))) | ||
| 249 | (cond ((eq cpp-unknown-face 'invisible) | ||
| 250 | (cpp-make-overlay-hidden overlay)) | ||
| 251 | ((eq cpp-unknown-face 'default)) | ||
| 252 | (t | ||
| 253 | (overlay-put overlay 'face cpp-unknown-face))) | ||
| 254 | (if cpp-unknown-writable | ||
| 255 | () | ||
| 256 | (overlay-put overlay 'modification-hooks '(cpp-signal-read-only)) | ||
| 257 | (overlay-put overlay 'insert-in-front-hooks '(cpp-signal-read-only))) | ||
| 258 | (setq cpp-overlay-list (cons overlay cpp-overlay-list)))) | ||
| 259 | |||
| 260 | (defun cpp-make-overlay-hidden (overlay) | ||
| 261 | ;; Make overlay hidden and intangible. | ||
| 262 | (overlay-put overlay 'invisible t) | ||
| 263 | (overlay-put overlay 'intangible t) | ||
| 264 | ;; Unfortunately `intangible' is not implemented for overlays yet, | ||
| 265 | ;; so we make is read-only instead. | ||
| 266 | (overlay-put overlay 'modification-hooks '(cpp-signal-read-only))) | ||
| 267 | |||
| 268 | (defun cpp-make-overlay-read-only (overlay) | ||
| 269 | ;; Make overlay read only. | ||
| 270 | (overlay-put overlay 'modification-hooks '(cpp-signal-read-only)) | ||
| 271 | (overlay-put overlay 'insert-in-front-hooks '(cpp-signal-read-only)) | ||
| 272 | (overlay-put overlay 'insert-behind-hooks '(cpp-signal-read-only))) | ||
| 273 | |||
| 274 | (defun cpp-make-overlay-sticky (overlay) | ||
| 275 | ;; Make OVERLAY grow when you insert text at either end. | ||
| 276 | (overlay-put overlay 'insert-in-front-hooks '(cpp-grow-overlay)) | ||
| 277 | (overlay-put overlay 'insert-behind-hooks '(cpp-grow-overlay))) | ||
| 278 | |||
| 279 | (defun cpp-signal-read-only (overlay start end) | ||
| 280 | ;; Only allow deleting the whole overlay. | ||
| 281 | ;; Trying to change a read-only overlay. | ||
| 282 | (if (or (< (overlay-start overlay) start) | ||
| 283 | (> (overlay-end overlay) end)) | ||
| 284 | (error "This text is read only"))) | ||
| 285 | |||
| 286 | (defun cpp-grow-overlay (overlay start end) | ||
| 287 | ;; Make OVERLAY grow to contain range START to END. | ||
| 288 | (move-overlay overlay | ||
| 289 | (min start (overlay-start overlay)) | ||
| 290 | (max end (overlay-end overlay)))) | ||
| 291 | |||
| 292 | ;;; Edit Buffer: | ||
| 293 | |||
| 294 | (defvar cpp-edit-list nil | ||
| 295 | "Alist of cpp macros and information about how they should be displayed. | ||
| 296 | Each entry is a list with the following elements: | ||
| 297 | 0. The name of the macro (a string). | ||
| 298 | 1. Face used for text that is `ifdef' the macro. | ||
| 299 | 2. Face used for text that is `ifndef' the macro. | ||
| 300 | 3. `t', `nil', or `both' depending on what text may be edited.") | ||
| 301 | |||
| 302 | (defvar cpp-edit-map nil) | ||
| 303 | ;; Keymap for `cpp-edit-mode'. | ||
| 304 | |||
| 305 | (if cpp-edit-map | ||
| 306 | () | ||
| 307 | (setq cpp-edit-map (make-keymap)) | ||
| 308 | (suppress-keymap cpp-edit-map) | ||
| 309 | (define-key cpp-edit-map [ down-mouse-2 ] 'cpp-push-button) | ||
| 310 | (define-key cpp-edit-map [ mouse-2 ] 'ignore) | ||
| 311 | (define-key cpp-edit-map " " 'scroll-up) | ||
| 312 | (define-key cpp-edit-map "\C-?" 'scroll-down) | ||
| 313 | (define-key cpp-edit-map [ delete ] 'scroll-down) | ||
| 314 | (define-key cpp-edit-map "\C-c\C-c" 'cpp-edit-apply) | ||
| 315 | (define-key cpp-edit-map "a" 'cpp-edit-apply) | ||
| 316 | (define-key cpp-edit-map "A" 'cpp-edit-apply) | ||
| 317 | (define-key cpp-edit-map "r" 'cpp-edit-reset) | ||
| 318 | (define-key cpp-edit-map "R" 'cpp-edit-reset) | ||
| 319 | (define-key cpp-edit-map "s" 'cpp-edit-save) | ||
| 320 | (define-key cpp-edit-map "S" 'cpp-edit-save) | ||
| 321 | (define-key cpp-edit-map "l" 'cpp-edit-load) | ||
| 322 | (define-key cpp-edit-map "L" 'cpp-edit-load) | ||
| 323 | (define-key cpp-edit-map "h" 'cpp-edit-home) | ||
| 324 | (define-key cpp-edit-map "H" 'cpp-edit-home) | ||
| 325 | (define-key cpp-edit-map "b" 'cpp-edit-background) | ||
| 326 | (define-key cpp-edit-map "B" 'cpp-edit-background) | ||
| 327 | (define-key cpp-edit-map "k" 'cpp-edit-known) | ||
| 328 | (define-key cpp-edit-map "K" 'cpp-edit-known) | ||
| 329 | (define-key cpp-edit-map "u" 'cpp-edit-unknown) | ||
| 330 | (define-key cpp-edit-map "u" 'cpp-edit-unknown) | ||
| 331 | (define-key cpp-edit-map "t" 'cpp-edit-true) | ||
| 332 | (define-key cpp-edit-map "T" 'cpp-edit-true) | ||
| 333 | (define-key cpp-edit-map "f" 'cpp-edit-false) | ||
| 334 | (define-key cpp-edit-map "F" 'cpp-edit-false) | ||
| 335 | (define-key cpp-edit-map "w" 'cpp-edit-write) | ||
| 336 | (define-key cpp-edit-map "W" 'cpp-edit-write) | ||
| 337 | (define-key cpp-edit-map "X" 'cpp-edit-toggle-known) | ||
| 338 | (define-key cpp-edit-map "x" 'cpp-edit-toggle-known) | ||
| 339 | (define-key cpp-edit-map "Y" 'cpp-edit-toggle-unknown) | ||
| 340 | (define-key cpp-edit-map "y" 'cpp-edit-toggle-unknown) | ||
| 341 | (define-key cpp-edit-map "q" 'bury-buffer) | ||
| 342 | (define-key cpp-edit-map "Q" 'bury-buffer)) | ||
| 343 | |||
| 344 | (defvar cpp-edit-buffer nil) | ||
| 345 | ;; Real buffer whose cpp display information we are editing. | ||
| 346 | (make-variable-buffer-local 'cpp-edit-buffer) | ||
| 347 | |||
| 348 | (defvar cpp-edit-symbols nil) | ||
| 349 | ;; Symbols defined in the edit buffer. | ||
| 350 | (make-variable-buffer-local 'cpp-edit-symbols) | ||
| 351 | |||
| 352 | (defun cpp-edit-mode () | ||
| 353 | "Major mode for editing cpp display information. | ||
| 354 | Click on objects to change them. | ||
| 355 | You can also use the keyboard accelerators indicated like this: [K]ey." | ||
| 356 | (kill-all-local-variables) | ||
| 357 | (buffer-disable-undo) | ||
| 358 | (auto-save-mode -1) | ||
| 359 | (setq buffer-read-only t) | ||
| 360 | (setq major-mode 'cpp-edit-mode) | ||
| 361 | (setq mode-name "CPP Edit") | ||
| 362 | (use-local-map cpp-edit-map)) | ||
| 363 | |||
| 364 | (defun cpp-edit-apply () | ||
| 365 | "Apply edited display information to original buffer." | ||
| 366 | (interactive) | ||
| 367 | (cpp-edit-home) | ||
| 368 | (cpp-parse-buffer t)) | ||
| 369 | |||
| 370 | (defun cpp-edit-reset () | ||
| 371 | "Reset display information from original buffer." | ||
| 372 | (interactive) | ||
| 373 | (let ((buffer (current-buffer)) | ||
| 374 | (buffer-read-only nil) | ||
| 375 | (start (window-start)) | ||
| 376 | (pos (point)) | ||
| 377 | symbols) | ||
| 378 | (set-buffer cpp-edit-buffer) | ||
| 379 | (setq symbols cpp-parse-symbols) | ||
| 380 | (set-buffer buffer) | ||
| 381 | (setq cpp-edit-symbols symbols) | ||
| 382 | (erase-buffer) | ||
| 383 | (insert "CPP Display Information for `") | ||
| 384 | (cpp-make-button (buffer-name cpp-edit-buffer) 'cpp-edit-home) | ||
| 385 | (insert "' ") | ||
| 386 | (cpp-make-button "[H]ome" 'cpp-edit-home) | ||
| 387 | (insert " ") | ||
| 388 | (cpp-make-button "[A]pply" 'cpp-edit-apply) | ||
| 389 | (insert " ") | ||
| 390 | (cpp-make-button "[S]ave" 'cpp-edit-save) | ||
| 391 | (insert " ") | ||
| 392 | (cpp-make-button "[L]oad" 'cpp-edit-load) | ||
| 393 | (insert "\n\nClick mouse-2 on item you want to change or use\n" | ||
| 394 | "keyboard equivalent indicated with brackets like [T]his.\n\n") | ||
| 395 | (insert "[B]ackground: ") | ||
| 396 | (cpp-make-button (car (rassq cpp-face-type cpp-face-type-list)) | ||
| 397 | 'cpp-edit-background) | ||
| 398 | (insert "\n[K]nown conditionals: ") | ||
| 399 | (cpp-make-button (cpp-face-name cpp-known-face) | ||
| 400 | 'cpp-edit-known nil t) | ||
| 401 | (insert " [X] ") | ||
| 402 | (cpp-make-button (car (rassq cpp-known-writable cpp-writable-list)) | ||
| 403 | 'cpp-edit-toggle-known) | ||
| 404 | (insert "\n[U]nknown conditionals: ") | ||
| 405 | (cpp-make-button (cpp-face-name cpp-unknown-face) | ||
| 406 | 'cpp-edit-unknown nil t) | ||
| 407 | (insert " [Y] ") | ||
| 408 | (cpp-make-button (car (rassq cpp-unknown-writable cpp-writable-list)) | ||
| 409 | 'cpp-edit-toggle-unknown) | ||
| 410 | (insert (format "\n\n\n%39s: %14s %14s %7s\n\n" "Expression" | ||
| 411 | "[T]rue Face" "[F]alse Face" "[W]rite")) | ||
| 412 | (while symbols | ||
| 413 | (let* ((symbol (car symbols)) | ||
| 414 | (entry (assoc symbol cpp-edit-list)) | ||
| 415 | (true (nth 1 entry)) | ||
| 416 | (false (nth 2 entry)) | ||
| 417 | (write (if entry (nth 3 entry) 'both))) | ||
| 418 | (setq symbols (cdr symbols)) | ||
| 419 | |||
| 420 | (if (and entry ; Make default entries unknown. | ||
| 421 | (or (null true) (eq true 'default)) | ||
| 422 | (or (null false) (eq false 'default)) | ||
| 423 | (eq write 'both)) | ||
| 424 | (setq cpp-edit-list (delq entry cpp-edit-list) | ||
| 425 | entry nil)) | ||
| 426 | |||
| 427 | (if (> (length symbol) 29) | ||
| 428 | (insert (substring symbol 0 39) ": ") | ||
| 429 | (insert (format "%39s: " symbol))) | ||
| 430 | |||
| 431 | (cpp-make-button (cpp-face-name true) | ||
| 432 | 'cpp-edit-true symbol t 14) | ||
| 433 | (insert " ") | ||
| 434 | (cpp-make-button (cpp-face-name false) | ||
| 435 | 'cpp-edit-false symbol t 14) | ||
| 436 | (insert " ") | ||
| 437 | (cpp-make-button (car (rassq write cpp-branch-list)) | ||
| 438 | 'cpp-edit-write symbol nil 6) | ||
| 439 | (insert "\n"))) | ||
| 440 | (insert "\n\n") | ||
| 441 | (set-window-start nil start) | ||
| 442 | (goto-char pos))) | ||
| 443 | |||
| 444 | (defun cpp-edit-load () | ||
| 445 | "Load cpp configuration." | ||
| 446 | (interactive) | ||
| 447 | (cond ((file-readable-p ".cpp.el") | ||
| 448 | (load-file ".cpp.el")) | ||
| 449 | ((file-readable-p "~/.cpp.el") | ||
| 450 | (load-file ".cpp.el"))) | ||
| 451 | (cpp-edit-reset)) | ||
| 452 | |||
| 453 | (defun cpp-edit-save () | ||
| 454 | "Load cpp configuration." | ||
| 455 | (interactive) | ||
| 456 | (require 'pp) | ||
| 457 | (save-excursion | ||
| 458 | (set-buffer cpp-edit-buffer) | ||
| 459 | (let ((buffer (find-file-noselect ".cpp.el"))) | ||
| 460 | (set-buffer buffer) | ||
| 461 | (erase-buffer) | ||
| 462 | (pp (list 'setq 'cpp-known-face | ||
| 463 | (list 'quote cpp-known-face)) buffer) | ||
| 464 | (pp (list 'setq 'cpp-unknown-face | ||
| 465 | (list 'quote cpp-unknown-face)) buffer) | ||
| 466 | (pp (list 'setq 'cpp-face-type | ||
| 467 | (list 'quote cpp-face-type)) buffer) | ||
| 468 | (pp (list 'setq 'cpp-known-writable | ||
| 469 | (list 'quote cpp-known-writable)) buffer) | ||
| 470 | (pp (list 'setq 'cpp-unknown-writable | ||
| 471 | (list 'quote cpp-unknown-writable)) buffer) | ||
| 472 | (pp (list 'setq 'cpp-edit-list | ||
| 473 | (list 'quote cpp-edit-list)) buffer) | ||
| 474 | (write-file ".cpp.el")))) | ||
| 475 | |||
| 476 | (defun cpp-edit-home () | ||
| 477 | "Switch back to original buffer." | ||
| 478 | (interactive) | ||
| 479 | (if cpp-button-event | ||
| 480 | (read-event)) | ||
| 481 | (pop-to-buffer cpp-edit-buffer)) | ||
| 482 | |||
| 483 | (defun cpp-edit-background () | ||
| 484 | "Change default face collection." | ||
| 485 | (interactive) | ||
| 486 | (call-interactively 'cpp-choose-default-face) | ||
| 487 | (cpp-edit-reset)) | ||
| 488 | |||
| 489 | (defun cpp-edit-known () | ||
| 490 | "Select default for known conditionals." | ||
| 491 | (interactive) | ||
| 492 | (setq cpp-known-face (cpp-choose-face "Known face" cpp-known-face)) | ||
| 493 | (cpp-edit-reset)) | ||
| 494 | |||
| 495 | (defun cpp-edit-unknown () | ||
| 496 | "Select default for unknown conditionals." | ||
| 497 | (interactive) | ||
| 498 | (setq cpp-unknown-face (cpp-choose-face "Unknown face" cpp-unknown-face)) | ||
| 499 | (cpp-edit-reset)) | ||
| 500 | |||
| 501 | (defconst cpp-writable-list | ||
| 502 | ;; Names used for the writable property. | ||
| 503 | '(("writable" . t) | ||
| 504 | ("read-only" . nil))) | ||
| 505 | |||
| 506 | (defun cpp-edit-toggle-known (arg) | ||
| 507 | "Toggle writable status for known conditionals. | ||
| 508 | With optional argument ARG, make them writable iff ARG is positive." | ||
| 509 | (interactive "@P") | ||
| 510 | (if (or (and (null arg) cpp-known-writable) | ||
| 511 | (<= (prefix-numeric-value arg) 0)) | ||
| 512 | (setq cpp-known-writable nil) | ||
| 513 | (setq cpp-known-writable t)) | ||
| 514 | (cpp-edit-reset)) | ||
| 515 | |||
| 516 | (defun cpp-edit-toggle-unknown (arg) | ||
| 517 | "Toggle writable status for unknown conditionals. | ||
| 518 | With optional argument ARG, make them writable iff ARG is positive." | ||
| 519 | (interactive "@P") | ||
| 520 | (if (or (and (null arg) cpp-unknown-writable) | ||
| 521 | (<= (prefix-numeric-value arg) 0)) | ||
| 522 | (setq cpp-unknown-writable nil) | ||
| 523 | (setq cpp-unknown-writable t)) | ||
| 524 | (cpp-edit-reset)) | ||
| 525 | |||
| 526 | (defun cpp-edit-true (symbol face) | ||
| 527 | "Select SYMBOL's true FACE used for highlighting taken conditionals." | ||
| 528 | (interactive | ||
| 529 | (let ((symbol (cpp-choose-symbol))) | ||
| 530 | (list symbol | ||
| 531 | (cpp-choose-face "True face" | ||
| 532 | (nth 1 (assoc symbol cpp-edit-list)))))) | ||
| 533 | (setcar (nthcdr 1 (cpp-edit-list-entry-get-or-create symbol)) face) | ||
| 534 | (cpp-edit-reset)) | ||
| 535 | |||
| 536 | (defun cpp-edit-false (symbol face) | ||
| 537 | "Select SYMBOL's false FACE used for highlighting untaken conditionals." | ||
| 538 | (interactive | ||
| 539 | (let ((symbol (cpp-choose-symbol))) | ||
| 540 | (list symbol | ||
| 541 | (cpp-choose-face "False face" | ||
| 542 | (nth 2 (assoc symbol cpp-edit-list)))))) | ||
| 543 | (setcar (nthcdr 2 (cpp-edit-list-entry-get-or-create symbol)) face) | ||
| 544 | (cpp-edit-reset)) | ||
| 545 | |||
| 546 | (defun cpp-edit-write (symbol branch) | ||
| 547 | "Set which branches of SYMBOL should be writable to BRANCH. | ||
| 548 | BRANCH should be either nil (false branch), t (true branch) or 'both." | ||
| 549 | (interactive (list (cpp-choose-symbol) (cpp-choose-branch))) | ||
| 550 | (setcar (nthcdr 3 (cpp-edit-list-entry-get-or-create symbol)) branch) | ||
| 551 | (cpp-edit-reset)) | ||
| 552 | |||
| 553 | (defun cpp-edit-list-entry-get-or-create (symbol) | ||
| 554 | ;; Return the entry for SYMBOL in `cpp-edit-list'. | ||
| 555 | ;; If it does not exist, create it. | ||
| 556 | (let ((entry (assoc symbol cpp-edit-list))) | ||
| 557 | (or entry | ||
| 558 | (setq entry (list symbol nil nil 'both nil) | ||
| 559 | cpp-edit-list (cons entry cpp-edit-list))) | ||
| 560 | entry)) | ||
| 561 | |||
| 562 | ;;; Prompts: | ||
| 563 | |||
| 564 | (defun cpp-choose-symbol () | ||
| 565 | ;; Choose a symbol if called from keyboard, otherwise use the one clicked on. | ||
| 566 | (if cpp-button-event | ||
| 567 | data | ||
| 568 | (completing-read "Symbol: " (mapcar 'list cpp-edit-symbols) nil t))) | ||
| 569 | |||
| 570 | (defconst cpp-branch-list | ||
| 571 | ;; Alist of branches. | ||
| 572 | '(("false" . nil) | ||
| 573 | ("true" . t) | ||
| 574 | ("both" . both))) | ||
| 575 | |||
| 576 | (defun cpp-choose-branch () | ||
| 577 | ;; Choose a branch, either nil, t, or both. | ||
| 578 | (if cpp-button-event | ||
| 579 | (x-popup-menu cpp-button-event | ||
| 580 | (list "Branch" (cons "Branch" cpp-branch-list))) | ||
| 581 | (cdr (assoc (completing-read "Branch: " cpp-branch-list nil t) | ||
| 582 | cpp-branch-list)))) | ||
| 583 | |||
| 584 | (defun cpp-choose-face (prompt default) | ||
| 585 | ;; Choose a face from cpp-face-defalt-list. | ||
| 586 | ;; PROMPT is what to say to the user. | ||
| 587 | ;; DEFAULT is the default face. | ||
| 588 | (or (if cpp-button-event | ||
| 589 | (x-popup-menu cpp-button-event | ||
| 590 | (list prompt (cons prompt cpp-face-default-list))) | ||
| 591 | (let ((name (car (rassq default cpp-face-default-list)))) | ||
| 592 | (cdr (assoc (completing-read (if name | ||
| 593 | (concat prompt | ||
| 594 | " (default " name "): ") | ||
| 595 | (concat prompt ": ")) | ||
| 596 | cpp-face-default-list nil t) | ||
| 597 | cpp-face-all-list)))) | ||
| 598 | default)) | ||
| 599 | |||
| 600 | (defconst cpp-face-type-list | ||
| 601 | '(("light color background" . light) | ||
| 602 | ("dark color background" . dark) | ||
| 603 | ("monochrome" . mono) | ||
| 604 | ("tty" . none)) | ||
| 605 | "Alist of strings and names of the defined face collections.") | ||
| 606 | |||
| 607 | (defun cpp-choose-default-face (type) | ||
| 608 | ;; Choose default face list for screen of TYPE. | ||
| 609 | ;; Type must be one of the types defined in `cpp-face-type-list'. | ||
| 610 | (interactive (list (if cpp-button-event | ||
| 611 | (x-popup-menu cpp-button-event | ||
| 612 | (list "Screen type" | ||
| 613 | (cons "Screen type" | ||
| 614 | cpp-face-type-list))) | ||
| 615 | (cdr (assoc (completing-read "Screen type: " | ||
| 616 | cpp-face-type-list | ||
| 617 | nil t) | ||
| 618 | cpp-face-type-list))))) | ||
| 619 | (cond ((null type)) | ||
| 620 | ((eq type 'light) | ||
| 621 | (if cpp-face-light-list | ||
| 622 | () | ||
| 623 | (setq cpp-face-light-list | ||
| 624 | (mapcar 'cpp-create-bg-face cpp-face-light-name-list)) | ||
| 625 | (setq cpp-face-all-list | ||
| 626 | (append cpp-face-all-list cpp-face-light-list))) | ||
| 627 | (setq cpp-face-type 'light) | ||
| 628 | (setq cpp-face-default-list | ||
| 629 | (append cpp-face-light-list cpp-face-none-list))) | ||
| 630 | ((eq type 'dark) | ||
| 631 | (if cpp-face-dark-list | ||
| 632 | () | ||
| 633 | (setq cpp-face-dark-list | ||
| 634 | (mapcar 'cpp-create-bg-face cpp-face-dark-name-list)) | ||
| 635 | (setq cpp-face-all-list | ||
| 636 | (append cpp-face-all-list cpp-face-dark-list))) | ||
| 637 | (setq cpp-face-type 'dark) | ||
| 638 | (setq cpp-face-default-list | ||
| 639 | (append cpp-face-dark-list cpp-face-none-list))) | ||
| 640 | ((eq type 'mono) | ||
| 641 | (setq cpp-face-type 'mono) | ||
| 642 | (setq cpp-face-default-list | ||
| 643 | (append cpp-face-mono-list cpp-face-none-list))) | ||
| 644 | (t | ||
| 645 | (setq cpp-face-type 'none) | ||
| 646 | (setq cpp-face-default-list cpp-face-none-list)))) | ||
| 647 | |||
| 648 | ;;; Buttons: | ||
| 649 | |||
| 650 | (defvar cpp-button-event nil) | ||
| 651 | ;; This will be t in the callback for `cpp-make-button'. | ||
| 652 | |||
| 653 | (defun cpp-make-button (name callback &optional data face padding) | ||
| 654 | ;; Create a button at point. | ||
| 655 | ;; NAME is the name of the button. | ||
| 656 | ;; CALLBACK is the function to call when the button is pushed. | ||
| 657 | ;; DATA will be available to CALLBACK as a free variable. | ||
| 658 | ;; FACE means that NAME is the name of a face in `cpp-face-all-list'. | ||
| 659 | ;; PADDING means NAME will be right justified at that length. | ||
| 660 | (let ((name (format "%s" name)) | ||
| 661 | from to) | ||
| 662 | (cond ((null padding) | ||
| 663 | (setq from (point)) | ||
| 664 | (insert name)) | ||
| 665 | ((> (length name) padding) | ||
| 666 | (setq from (point)) | ||
| 667 | (insert (substring name 0 padding))) | ||
| 668 | (t | ||
| 669 | (insert (make-string (- padding (length name)) ? )) | ||
| 670 | (setq from (point)) | ||
| 671 | (insert name))) | ||
| 672 | (setq to (point)) | ||
| 673 | (setq face | ||
| 674 | (if face | ||
| 675 | (let ((check (cdr (assoc name cpp-face-all-list)))) | ||
| 676 | (if (memq check '(default invisible)) | ||
| 677 | 'bold | ||
| 678 | check)) | ||
| 679 | 'bold)) | ||
| 680 | (add-text-properties from to | ||
| 681 | (append (list 'face face) | ||
| 682 | '(mouse-face highlight) | ||
| 683 | (list 'cpp-callback callback) | ||
| 684 | (if data (list 'cpp-data data)))))) | ||
| 685 | |||
| 686 | (defun cpp-push-button (event) | ||
| 687 | ;; Pushed a CPP button. | ||
| 688 | (interactive "@e") | ||
| 689 | (set-buffer (window-buffer (posn-window (event-start event)))) | ||
| 690 | (let ((pos (posn-point (event-start event)))) | ||
| 691 | (let ((data (get-text-property pos 'cpp-data)) | ||
| 692 | (fun (get-text-property pos 'cpp-callback)) | ||
| 693 | (cpp-button-event event)) | ||
| 694 | (cond (fun | ||
| 695 | (call-interactively (get-text-property pos 'cpp-callback))) | ||
| 696 | ((lookup-key global-map [ down-mouse-2]) | ||
| 697 | (call-interactively (lookup-key global-map [ down-mouse-2]))))))) | ||
| 698 | |||
| 699 | ;;; Faces: | ||
| 700 | |||
| 701 | (defvar cpp-face-light-name-list | ||
| 702 | '("light gray" "light blue" "light cyan" "light yellow" "light pink" | ||
| 703 | "pale green" "beige" "orange" "magenta" "violet" "medium purple" | ||
| 704 | "turquoise") | ||
| 705 | "Background colours useful with dark foreground colors.") | ||
| 706 | |||
| 707 | (defvar cpp-face-dark-name-list | ||
| 708 | '("dim gray" "blue" "cyan" "yellow" "red" | ||
| 709 | "dark green" "brown" "dark orange" "dark khaki" "dark violet" "purple" | ||
| 710 | "dark turquoise") | ||
| 711 | "Background colours useful with light foreground colors.") | ||
| 712 | |||
| 713 | (defvar cpp-face-light-list nil | ||
| 714 | "Alist of names and faces to be used for light backgrounds.") | ||
| 715 | |||
| 716 | (defvar cpp-face-dark-list nil | ||
| 717 | "Alist of names and faces to be used for dark backgrounds.") | ||
| 718 | |||
| 719 | (defvar cpp-face-mono-list | ||
| 720 | '(("bold" . 'bold) | ||
| 721 | ("bold-italic" . 'bold-italic) | ||
| 722 | ("italic" . 'italic) | ||
| 723 | ("underline" . 'underline)) | ||
| 724 | "Alist of names and faces to be used for monocrome screens.") | ||
| 725 | |||
| 726 | (defvar cpp-face-none-list | ||
| 727 | '(("default" . default) | ||
| 728 | ("invisible" . invisible)) | ||
| 729 | "Alist of names and faces available even if you don't use a window system.") | ||
| 730 | |||
| 731 | (defvar cpp-face-all-list | ||
| 732 | (append cpp-face-light-list | ||
| 733 | cpp-face-dark-list | ||
| 734 | cpp-face-mono-list | ||
| 735 | cpp-face-none-list) | ||
| 736 | "All faces used for highligting text inside cpp conditionals.") | ||
| 737 | |||
| 738 | (defvar cpp-face-default-list nil | ||
| 739 | "List of faces you can choose from for cpp conditionals.") | ||
| 740 | |||
| 741 | (defun cpp-create-bg-face (color) | ||
| 742 | ;; Create entry for face with background COLOR. | ||
| 743 | (let ((name (intern (concat "cpp " color)))) | ||
| 744 | (make-face name) | ||
| 745 | (set-face-background name color) | ||
| 746 | (cons color name))) | ||
| 747 | |||
| 748 | (cpp-choose-default-face (if window-system cpp-face-type 'none)) | ||
| 749 | |||
| 750 | (defun cpp-face-name (face) | ||
| 751 | ;; Return the name of FACE from `cpp-face-all-list'. | ||
| 752 | (let ((entry (rassq (if face face 'default) cpp-face-all-list))) | ||
| 753 | (if entry | ||
| 754 | (car entry) | ||
| 755 | (format "<%s>" face)))) | ||
| 756 | |||
| 757 | ;;; Utilities: | ||
| 758 | |||
| 759 | (defvar cpp-progress-time 0) | ||
| 760 | ;; Last time we issued a progress message. | ||
| 761 | |||
| 762 | (defun cpp-progress-message (&rest args) | ||
| 763 | ;; Report progress at most once a second. Take same ARGS as `message'. | ||
| 764 | (let ((time (nth 1 (current-time)))) | ||
| 765 | (if (= time cpp-progress-time) | ||
| 766 | () | ||
| 767 | (setq cpp-progress-time time) | ||
| 768 | (apply 'message args)))) | ||
| 769 | |||
| 770 | (provide 'cpp) | ||
| 771 | |||
| 772 | ;;; cpp.el ends here | ||
| 773 | |||