1 | ;;; Boxed comments for C mode.
|
---|
2 | ;;; Copyright (C) 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
|
---|
3 | ;;; Francois Pinard <pinard@iro.umontreal.ca>, April 1991.
|
---|
4 | ;;;
|
---|
5 | ;;; I often refill paragraphs inside C comments, while stretching or
|
---|
6 | ;;; shrinking the surrounding box as needed. This is a real pain to
|
---|
7 | ;;; do by hand. Here is the code I made to ease my life on this,
|
---|
8 | ;;; usable from within GNU Emacs. It would not be fair giving all
|
---|
9 | ;;; sources for a product without also giving the means for nicely
|
---|
10 | ;;; modifying them.
|
---|
11 | ;;;
|
---|
12 | ;;; The function rebox-c-comment adjust comment boxes without
|
---|
13 | ;;; refilling comment paragraphs, while reindent-c-comment adjust
|
---|
14 | ;;; comment boxes after refilling. Numeric prefixes are used to add,
|
---|
15 | ;;; remove, or change the style of the box surrounding the comment.
|
---|
16 | ;;; Since refilling paragraphs in C mode does make sense only for
|
---|
17 | ;;; comments, this code redefines the M-q command in C mode. I use
|
---|
18 | ;;; this hack by putting, in my .emacs file:
|
---|
19 | ;;;
|
---|
20 | ;;; (setq c-mode-hook
|
---|
21 | ;;; '(lambda ()
|
---|
22 | ;;; (define-key c-mode-map "\M-q" 'reindent-c-comment)))
|
---|
23 | ;;; (autoload 'rebox-c-comment "c-boxes" nil t)
|
---|
24 | ;;; (autoload 'reindent-c-comment "c-boxes" nil t)
|
---|
25 | ;;;
|
---|
26 | ;;; The cursor should be within a comment before any of these
|
---|
27 | ;;; commands, or else it should be between two comments, in which case
|
---|
28 | ;;; the command applies to the next comment. When the command is
|
---|
29 | ;;; given without prefix, the current comment box type is recognized
|
---|
30 | ;;; and preserved. Given 0 as a prefix, the comment box disappears
|
---|
31 | ;;; and the comment stays between a single opening `/*' and a single
|
---|
32 | ;;; closing `*/'. Given 1 or 2 as a prefix, a single or doubled lined
|
---|
33 | ;;; comment box is forced. Given 3 as a prefix, a Taarna style box is
|
---|
34 | ;;; forced, but you do not even want to hear about those. When a
|
---|
35 | ;;; negative prefix is given, the absolute value is used, but the
|
---|
36 | ;;; default style is changed. Any other value (like C-u alone) forces
|
---|
37 | ;;; the default box style.
|
---|
38 | ;;;
|
---|
39 | ;;; I observed rounded corners first in some code from Warren Tucker
|
---|
40 | ;;; <wht@n4hgf.mt-park.ga.us>.
|
---|
41 |
|
---|
42 | (defvar c-box-default-style 'single "*Preferred style for box comments.")
|
---|
43 | (defvar c-mode-taarna-style nil "*Non-nil for Taarna team C-style.")
|
---|
44 |
|
---|
45 | ;;; Set or reset the Taarna team's own way for a C style.
|
---|
46 |
|
---|
47 | (defun taarna-mode ()
|
---|
48 | (interactive)
|
---|
49 | (if c-mode-taarna-style
|
---|
50 | (progn
|
---|
51 |
|
---|
52 | (setq c-mode-taarna-style nil)
|
---|
53 | (setq c-indent-level 2)
|
---|
54 | (setq c-continued-statement-offset 2)
|
---|
55 | (setq c-brace-offset 0)
|
---|
56 | (setq c-argdecl-indent 5)
|
---|
57 | (setq c-label-offset -2)
|
---|
58 | (setq c-tab-always-indent t)
|
---|
59 | (setq c-box-default-style 'single)
|
---|
60 | (message "C mode: GNU style"))
|
---|
61 |
|
---|
62 | (setq c-mode-taarna-style t)
|
---|
63 | (setq c-indent-level 4)
|
---|
64 | (setq c-continued-statement-offset 4)
|
---|
65 | (setq c-brace-offset -4)
|
---|
66 | (setq c-argdecl-indent 4)
|
---|
67 | (setq c-label-offset -4)
|
---|
68 | (setq c-tab-always-indent t)
|
---|
69 | (setq c-box-default-style 'taarna)
|
---|
70 | (message "C mode: Taarna style")))
|
---|
71 |
|
---|
72 | ;;; Return the minimum value of the left margin of all lines, or -1 if
|
---|
73 | ;;; all lines are empty.
|
---|
74 |
|
---|
75 | (defun buffer-left-margin ()
|
---|
76 | (let ((margin -1))
|
---|
77 | (goto-char (point-min))
|
---|
78 | (while (not (eobp))
|
---|
79 | (skip-chars-forward " \t")
|
---|
80 | (if (not (looking-at "\n"))
|
---|
81 | (setq margin
|
---|
82 | (if (< margin 0)
|
---|
83 | (current-column)
|
---|
84 | (min margin (current-column)))))
|
---|
85 | (forward-line 1))
|
---|
86 | margin))
|
---|
87 |
|
---|
88 | ;;; Return the maximum value of the right margin of all lines. Any
|
---|
89 | ;;; sentence ending a line has a space guaranteed before the margin.
|
---|
90 |
|
---|
91 | (defun buffer-right-margin ()
|
---|
92 | (let ((margin 0) period)
|
---|
93 | (goto-char (point-min))
|
---|
94 | (while (not (eobp))
|
---|
95 | (end-of-line)
|
---|
96 | (if (bobp)
|
---|
97 | (setq period 0)
|
---|
98 | (backward-char 1)
|
---|
99 | (setq period (if (looking-at "[.?!]") 1 0))
|
---|
100 | (forward-char 1))
|
---|
101 | (setq margin (max margin (+ (current-column) period)))
|
---|
102 | (forward-char 1))
|
---|
103 | margin))
|
---|
104 |
|
---|
105 | ;;; Add, delete or adjust a C comment box. If FLAG is nil, the
|
---|
106 | ;;; current boxing style is recognized and preserved. When 0, the box
|
---|
107 | ;;; is removed; when 1, a single lined box is forced; when 2, a double
|
---|
108 | ;;; lined box is forced; when 3, a Taarna style box is forced. If
|
---|
109 | ;;; negative, the absolute value is used, but the default style is
|
---|
110 | ;;; changed. For any other value (like C-u), the default style is
|
---|
111 | ;;; forced. If REFILL is not nil, refill the comment paragraphs prior
|
---|
112 | ;;; to reboxing.
|
---|
113 |
|
---|
114 | (defun rebox-c-comment-engine (flag refill)
|
---|
115 | (save-restriction
|
---|
116 | (let ((undo-list buffer-undo-list)
|
---|
117 | (marked-point (point-marker))
|
---|
118 | (saved-point (point))
|
---|
119 | box-style left-margin right-margin)
|
---|
120 |
|
---|
121 | ;; First, find the limits of the block of comments following or
|
---|
122 | ;; enclosing the cursor, or return an error if the cursor is not
|
---|
123 | ;; within such a block of comments, narrow the buffer, and
|
---|
124 | ;; untabify it.
|
---|
125 |
|
---|
126 | ;; - insure the point is into the following comment, if any
|
---|
127 |
|
---|
128 | (skip-chars-forward " \t\n")
|
---|
129 | (if (looking-at "/\\*")
|
---|
130 | (forward-char 2))
|
---|
131 |
|
---|
132 | (let ((here (point)) start end temp)
|
---|
133 |
|
---|
134 | ;; - identify a minimal comment block
|
---|
135 |
|
---|
136 | (search-backward "/*")
|
---|
137 | (setq temp (point))
|
---|
138 | (beginning-of-line)
|
---|
139 | (setq start (point))
|
---|
140 | (skip-chars-forward " \t")
|
---|
141 | (if (< (point) temp)
|
---|
142 | (progn
|
---|
143 | (goto-char saved-point)
|
---|
144 | (error "text before comment's start")))
|
---|
145 | (search-forward "*/")
|
---|
146 | (setq temp (point))
|
---|
147 | (end-of-line)
|
---|
148 | (if (looking-at "\n")
|
---|
149 | (forward-char 1))
|
---|
150 | (setq end (point))
|
---|
151 | (skip-chars-backward " \t\n")
|
---|
152 | (if (> (point) temp)
|
---|
153 | (progn
|
---|
154 | (goto-char saved-point)
|
---|
155 | (error "text after comment's end")))
|
---|
156 | (if (< end here)
|
---|
157 | (progn
|
---|
158 | (goto-char saved-point)
|
---|
159 | (error "outside any comment block")))
|
---|
160 |
|
---|
161 | ;; - try to extend the comment block backwards
|
---|
162 |
|
---|
163 | (goto-char start)
|
---|
164 | (while (and (not (bobp))
|
---|
165 | (progn (previous-line 1)
|
---|
166 | (beginning-of-line)
|
---|
167 | (looking-at "[ \t]*/\\*.*\\*/[ \t]*$")))
|
---|
168 | (setq start (point)))
|
---|
169 |
|
---|
170 | ;; - try to extend the comment block forward
|
---|
171 |
|
---|
172 | (goto-char end)
|
---|
173 | (while (looking-at "[ \t]*/\\*.*\\*/[ \t]*$")
|
---|
174 | (forward-line 1)
|
---|
175 | (beginning-of-line)
|
---|
176 | (setq end (point)))
|
---|
177 |
|
---|
178 | ;; - narrow to the whole block of comments
|
---|
179 |
|
---|
180 | (narrow-to-region start end))
|
---|
181 |
|
---|
182 | ;; Second, remove all the comment marks, and move all the text
|
---|
183 | ;; rigidly to the left to insure the left margin stays at the
|
---|
184 | ;; same place. At the same time, recognize and save the box
|
---|
185 | ;; style in BOX-STYLE.
|
---|
186 |
|
---|
187 | (let ((previous-margin (buffer-left-margin))
|
---|
188 | actual-margin)
|
---|
189 |
|
---|
190 | ;; - remove all comment marks
|
---|
191 |
|
---|
192 | (goto-char (point-min))
|
---|
193 | (replace-regexp "^\\([ \t]*\\)/\\*" "\\1 ")
|
---|
194 | (goto-char (point-min))
|
---|
195 | (replace-regexp "^\\([ \t]*\\)|" "\\1 ")
|
---|
196 | (goto-char (point-min))
|
---|
197 | (replace-regexp "\\(\\*/\\||\\)[ \t]*" "")
|
---|
198 | (goto-char (point-min))
|
---|
199 | (replace-regexp "\\*/[ \t]*/\\*" " ")
|
---|
200 |
|
---|
201 | ;; - remove the first and last dashed lines
|
---|
202 |
|
---|
203 | (setq box-style 'plain)
|
---|
204 | (goto-char (point-min))
|
---|
205 | (if (looking-at "^[ \t]*-*[.\+\\]?[ \t]*\n")
|
---|
206 | (progn
|
---|
207 | (setq box-style 'single)
|
---|
208 | (replace-match ""))
|
---|
209 | (if (looking-at "^[ \t]*=*[.\+\\]?[ \t]*\n")
|
---|
210 | (progn
|
---|
211 | (setq box-style 'double)
|
---|
212 | (replace-match ""))))
|
---|
213 | (goto-char (point-max))
|
---|
214 | (previous-line 1)
|
---|
215 | (beginning-of-line)
|
---|
216 | (if (looking-at "^[ \t]*[`\+\\]?*[-=]+[ \t]*\n")
|
---|
217 | (progn
|
---|
218 | (if (eq box-style 'plain)
|
---|
219 | (setq box-style 'taarna))
|
---|
220 | (replace-match "")))
|
---|
221 |
|
---|
222 | ;; - remove all spurious whitespace
|
---|
223 |
|
---|
224 | (goto-char (point-min))
|
---|
225 | (replace-regexp "[ \t]+$" "")
|
---|
226 | (goto-char (point-min))
|
---|
227 | (if (looking-at "\n+")
|
---|
228 | (replace-match ""))
|
---|
229 | (goto-char (point-max))
|
---|
230 | (skip-chars-backward "\n")
|
---|
231 | (if (looking-at "\n\n+")
|
---|
232 | (replace-match "\n"))
|
---|
233 | (goto-char (point-min))
|
---|
234 | (replace-regexp "\n\n\n+" "\n\n")
|
---|
235 |
|
---|
236 | ;; - move the text left is adequate
|
---|
237 |
|
---|
238 | (setq actual-margin (buffer-left-margin))
|
---|
239 | (if (not (= previous-margin actual-margin))
|
---|
240 | (indent-rigidly (point-min) (point-max)
|
---|
241 | (- previous-margin actual-margin))))
|
---|
242 |
|
---|
243 | ;; Third, select the new box style from the old box style and
|
---|
244 | ;; the argument, choose the margins for this style and refill
|
---|
245 | ;; each paragraph.
|
---|
246 |
|
---|
247 | ;; - modify box-style only if flag is defined
|
---|
248 |
|
---|
249 | (if flag
|
---|
250 | (setq box-style
|
---|
251 | (cond ((eq flag 0) 'plain)
|
---|
252 | ((eq flag 1) 'single)
|
---|
253 | ((eq flag 2) 'double)
|
---|
254 | ((eq flag 3) 'taarna)
|
---|
255 | ((eq flag '-) (setq c-box-default-style 'plain) 'plain)
|
---|
256 | ((eq flag -1) (setq c-box-default-style 'single) 'single)
|
---|
257 | ((eq flag -2) (setq c-box-default-style 'double) 'double)
|
---|
258 | ((eq flag -3) (setq c-box-default-style 'taarna) 'taarna)
|
---|
259 | (t c-box-default-style))))
|
---|
260 |
|
---|
261 | ;; - compute the left margin
|
---|
262 |
|
---|
263 | (setq left-margin (buffer-left-margin))
|
---|
264 |
|
---|
265 | ;; - temporarily set the fill prefix and column, then refill
|
---|
266 |
|
---|
267 | (untabify (point-min) (point-max))
|
---|
268 |
|
---|
269 | (if refill
|
---|
270 | (let ((fill-prefix (make-string left-margin ? ))
|
---|
271 | (fill-column (- fill-column
|
---|
272 | (if (memq box-style '(single double)) 4 6))))
|
---|
273 | (fill-region (point-min) (point-max))))
|
---|
274 |
|
---|
275 | ;; - compute the right margin after refill
|
---|
276 |
|
---|
277 | (setq right-margin (buffer-right-margin))
|
---|
278 |
|
---|
279 | ;; Fourth, put the narrowed buffer back into a comment box,
|
---|
280 | ;; according to the value of box-style. Values may be:
|
---|
281 | ;; plain: insert between a single pair of comment delimiters
|
---|
282 | ;; single: complete box, overline and underline with dashes
|
---|
283 | ;; double: complete box, overline and underline with equal signs
|
---|
284 | ;; taarna: comment delimiters on each line, underline with dashes
|
---|
285 |
|
---|
286 | ;; - move the right margin to account for left inserts
|
---|
287 |
|
---|
288 | (setq right-margin (+ right-margin
|
---|
289 | (if (memq box-style '(single double))
|
---|
290 | 2
|
---|
291 | 3)))
|
---|
292 |
|
---|
293 | ;; - construct the box comment, from top to bottom
|
---|
294 |
|
---|
295 | (goto-char (point-min))
|
---|
296 | (cond ((eq box-style 'plain)
|
---|
297 |
|
---|
298 | ;; - construct a plain style comment
|
---|
299 |
|
---|
300 | (skip-chars-forward " " (+ (point) left-margin))
|
---|
301 | (insert (make-string (- left-margin (current-column)) ? )
|
---|
302 | "/* ")
|
---|
303 | (end-of-line)
|
---|
304 | (forward-char 1)
|
---|
305 | (while (not (eobp))
|
---|
306 | (skip-chars-forward " " (+ (point) left-margin))
|
---|
307 | (insert (make-string (- left-margin (current-column)) ? )
|
---|
308 | " ")
|
---|
309 | (end-of-line)
|
---|
310 | (forward-char 1))
|
---|
311 | (backward-char 1)
|
---|
312 | (insert " */"))
|
---|
313 | ((eq box-style 'single)
|
---|
314 |
|
---|
315 | ;; - construct a single line style comment
|
---|
316 |
|
---|
317 | (indent-to left-margin)
|
---|
318 | (insert "/*")
|
---|
319 | (insert (make-string (- right-margin (current-column)) ?-)
|
---|
320 | "-.\n")
|
---|
321 | (while (not (eobp))
|
---|
322 | (skip-chars-forward " " (+ (point) left-margin))
|
---|
323 | (insert (make-string (- left-margin (current-column)) ? )
|
---|
324 | "| ")
|
---|
325 | (end-of-line)
|
---|
326 | (indent-to right-margin)
|
---|
327 | (insert " |")
|
---|
328 | (forward-char 1))
|
---|
329 | (indent-to left-margin)
|
---|
330 | (insert "`")
|
---|
331 | (insert (make-string (- right-margin (current-column)) ?-)
|
---|
332 | "*/\n"))
|
---|
333 | ((eq box-style 'double)
|
---|
334 |
|
---|
335 | ;; - construct a double line style comment
|
---|
336 |
|
---|
337 | (indent-to left-margin)
|
---|
338 | (insert "/*")
|
---|
339 | (insert (make-string (- right-margin (current-column)) ?=)
|
---|
340 | "=\\\n")
|
---|
341 | (while (not (eobp))
|
---|
342 | (skip-chars-forward " " (+ (point) left-margin))
|
---|
343 | (insert (make-string (- left-margin (current-column)) ? )
|
---|
344 | "| ")
|
---|
345 | (end-of-line)
|
---|
346 | (indent-to right-margin)
|
---|
347 | (insert " |")
|
---|
348 | (forward-char 1))
|
---|
349 | (indent-to left-margin)
|
---|
350 | (insert "\\")
|
---|
351 | (insert (make-string (- right-margin (current-column)) ?=)
|
---|
352 | "*/\n"))
|
---|
353 | ((eq box-style 'taarna)
|
---|
354 |
|
---|
355 | ;; - construct a Taarna style comment
|
---|
356 |
|
---|
357 | (while (not (eobp))
|
---|
358 | (skip-chars-forward " " (+ (point) left-margin))
|
---|
359 | (insert (make-string (- left-margin (current-column)) ? )
|
---|
360 | "/* ")
|
---|
361 | (end-of-line)
|
---|
362 | (indent-to right-margin)
|
---|
363 | (insert " */")
|
---|
364 | (forward-char 1))
|
---|
365 | (indent-to left-margin)
|
---|
366 | (insert "/* ")
|
---|
367 | (insert (make-string (- right-margin (current-column)) ?-)
|
---|
368 | " */\n"))
|
---|
369 | (t (error "unknown box style")))
|
---|
370 |
|
---|
371 | ;; Fifth, retabify, restore the point position, then cleanup the
|
---|
372 | ;; undo list of any boundary since we started.
|
---|
373 |
|
---|
374 | ;; - retabify before left margin only (adapted from tabify.el)
|
---|
375 |
|
---|
376 | (goto-char (point-min))
|
---|
377 | (while (re-search-forward "^[ \t][ \t][ \t]*" nil t)
|
---|
378 | (let ((column (current-column))
|
---|
379 | (indent-tabs-mode t))
|
---|
380 | (delete-region (match-beginning 0) (point))
|
---|
381 | (indent-to column)))
|
---|
382 |
|
---|
383 | ;; - restore the point position
|
---|
384 |
|
---|
385 | (goto-char (marker-position marked-point))
|
---|
386 |
|
---|
387 | ;; - remove all intermediate boundaries from the undo list
|
---|
388 |
|
---|
389 | (if (not (eq buffer-undo-list undo-list))
|
---|
390 | (let ((cursor buffer-undo-list))
|
---|
391 | (while (not (eq (cdr cursor) undo-list))
|
---|
392 | (if (car (cdr cursor))
|
---|
393 | (setq cursor (cdr cursor))
|
---|
394 | (rplacd cursor (cdr (cdr cursor))))))))))
|
---|
395 |
|
---|
396 | ;;; Rebox a C comment without refilling it.
|
---|
397 |
|
---|
398 | (defun rebox-c-comment (flag)
|
---|
399 | (interactive "P")
|
---|
400 | (rebox-c-comment-engine flag nil))
|
---|
401 |
|
---|
402 | ;;; Rebox a C comment after refilling.
|
---|
403 |
|
---|
404 | (defun reindent-c-comment (flag)
|
---|
405 | (interactive "P")
|
---|
406 | (rebox-c-comment-engine flag t))
|
---|