Mercurial > hg > xemacs-beta
comparison lisp/packages/filladapt.el @ 0:376386a54a3c r19-14
Import from CVS: tag r19-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:45:50 +0200 |
parents | |
children | ec9a17fef872 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:376386a54a3c |
---|---|
1 ;;; filladapt.el --- adaptive fill; replacement for fill commands | |
2 | |
3 ;; Keywords: wp | |
4 | |
5 ;;; Copyright (C) 1989, 1995, 1996 Kyle E. Jones | |
6 ;;; | |
7 ;;; This program is free software; you can redistribute it and/or modify | |
8 ;;; it under the terms of the GNU General Public License as published by | |
9 ;;; the Free Software Foundation; either version 2, or (at your option) | |
10 ;;; any later version. | |
11 ;;; | |
12 ;;; This program is distributed in the hope that it will be useful, | |
13 ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 ;;; GNU General Public License for more details. | |
16 ;;; | |
17 ;;; A copy of the GNU General Public License can be obtained from this | |
18 ;;; program's author (send electronic mail to kyle@uunet.uu.net) or from | |
19 ;;; the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA | |
20 ;;; 02139, USA. | |
21 ;;; | |
22 ;;; Send bug reports to kyle@wonderworks.com | |
23 | |
24 ;;; Synched up with: Not in FSF. | |
25 | |
26 ;; LCD Archive Entry: | |
27 ;; filladapt|Kyle Jones|kyle_jones@wonderworks.com| | |
28 ;; Minor mode to adaptively set fill-prefix and overload filling functions| | |
29 ;; 10-June-1996|2.08|~/packages/filladapt.el| | |
30 | |
31 ;; These functions enhance the default behavior of Emacs' Auto Fill | |
32 ;; mode and the commands fill-paragraph, lisp-fill-paragraph and | |
33 ;; fill-region-as-paragraph. | |
34 ;; | |
35 ;; The chief improvement is that the beginning of a line to be | |
36 ;; filled is examined and, based on information gathered, an | |
37 ;; appropriate value for fill-prefix is constructed. Also the | |
38 ;; boundaries of the current paragraph are located. This occurs | |
39 ;; only if the fill prefix is not already non-nil. | |
40 ;; | |
41 ;; The net result of this is that blurbs of text that are offset | |
42 ;; from left margin by asterisks, dashes, and/or spaces, numbered | |
43 ;; examples, included text from USENET news articles, etc. are | |
44 ;; generally filled correctly with no fuss. | |
45 ;; | |
46 ;; Since this package replaces existing Emacs functions, it cannot | |
47 ;; be autoloaded. Save this in a file named filladapt.el in a | |
48 ;; Lisp directory that Emacs knows about, byte-compile it and put | |
49 ;; (require 'filladapt) | |
50 ;; in your .emacs file. | |
51 ;; | |
52 ;; Note that in this release Filladapt mode is a minor mode and it is | |
53 ;; _off_ by default. If you want it to be on by default, use | |
54 ;; (setq-default filladapt-mode t) | |
55 ;; | |
56 ;; M-x filladapt-mode toggles Filladapt mode on/off in the current | |
57 ;; buffer. | |
58 ;; | |
59 ;; Use | |
60 ;; (add-hook 'text-mode-hook 'turn-on-filladapt-mode) | |
61 ;; to have Filladapt always enabled in Text mode. | |
62 ;; | |
63 ;; Use | |
64 ;; (add-hook 'c-mode-hook 'turn-off-filladapt-mode) | |
65 ;; to have Filladapt always disabled in C mode. | |
66 ;; | |
67 ;; In many cases, you can extend Filladapt by adding appropriate | |
68 ;; entries to the following three `defvar's. See `postscript-comment' | |
69 ;; or `texinfo-comment' as a sample of what needs to be done. | |
70 ;; | |
71 ;; filladapt-token-table | |
72 ;; filladapt-token-match-table | |
73 ;; filladapt-token-conversion-table | |
74 | |
75 (provide 'filladapt) | |
76 | |
77 (defvar filladapt-version "2.08" | |
78 "Version string for filladapt.") | |
79 | |
80 (defvar filladapt-mode nil | |
81 "*Non-nil means that Filladapt minor mode is enabled. | |
82 Use the filladapt-mode command to toggle the mode on/off.") | |
83 (make-variable-buffer-local 'filladapt-mode) | |
84 | |
85 (defvar filladapt-mode-line-string " Filladapt" | |
86 "*String to display in the modeline when Filladapt mode is active. | |
87 Set this to nil if you don't want a modeline indicator for Filladapt.") | |
88 | |
89 ;; install on minor-mode-alist | |
90 (or (assq 'filladapt-mode minor-mode-alist) | |
91 (setq minor-mode-alist (cons (list 'filladapt-mode | |
92 'filladapt-mode-line-string) | |
93 minor-mode-alist))) | |
94 | |
95 (defvar filladapt-token-table | |
96 '( | |
97 ;; Included text in news or mail replies | |
98 (">+" . citation->) | |
99 ;; Included text generated by SUPERCITE. We can't hope to match all | |
100 ;; the possible variations, your mileage may vary. | |
101 ("[A-Za-z0-9][^'`\"< \t\n]*>[ \t]*" . supercite-citation) | |
102 ;; Lisp comments | |
103 (";+" . lisp-comment) | |
104 ;; UNIX shell comments | |
105 ("#+" . sh-comment) | |
106 ;; Postscript comments | |
107 ("%+" . postscript-comment) | |
108 ;; C++ comments | |
109 ("///*" . c++-comment) | |
110 ;; Texinfo comments | |
111 ("@c[ \t]" . texinfo-comment) | |
112 ("@comment[ \t]" . texinfo-comment) | |
113 ;; Bullet types. | |
114 ;; | |
115 ;; 1. xxxxx | |
116 ;; xxxxx | |
117 ;; | |
118 ("[0-9]+\\.[ \t]" . bullet) | |
119 ;; | |
120 ;; 2.1.3 xxxxx xx x xx x | |
121 ;; xxx | |
122 ;; | |
123 ("[0-9]+\\(\\.[0-9]+\\)+[ \t]" . bullet) | |
124 ;; | |
125 ;; a. xxxxxx xx | |
126 ;; xxx xxx | |
127 ;; | |
128 ("[A-Za-z]\\.[ \t]" . bullet) | |
129 ;; | |
130 ;; 1) xxxx x xx x xx or (1) xx xx x x xx xx | |
131 ;; xx xx xxxx xxx xx x x xx x | |
132 ;; | |
133 ("(?[0-9]+)[ \t]" . bullet) | |
134 ;; | |
135 ;; a) xxxx x xx x xx or (a) xx xx x x xx xx | |
136 ;; xx xx xxxx xxx xx x x xx x | |
137 ;; | |
138 ("(?[A-Za-z])[ \t]" . bullet) | |
139 ;; | |
140 ;; 2a. xx x xxx x x xxx | |
141 ;; xxx xx x xx x | |
142 ;; | |
143 ("[0-9]+[A-Za-z]\\.[ \t]" . bullet) | |
144 ;; | |
145 ;; 1a) xxxx x xx x xx or (1a) xx xx x x xx xx | |
146 ;; xx xx xxxx xxx xx x x xx x | |
147 ;; | |
148 ("(?[0-9]+[A-Za-z])[ \t]" . bullet) | |
149 ;; | |
150 ;; - xx xxx xxxx or * xx xx x xxx xxx | |
151 ;; xxx xx xx x xxx x xx x x x | |
152 ;; | |
153 ("[-~*+]+[ \t]" . bullet) | |
154 ;; | |
155 ;; o xx xxx xxxx xx x xx xxx x xxx xx x xxx | |
156 ;; xxx xx xx | |
157 ;; | |
158 ("o[ \t]" . bullet) | |
159 ;; don't touch | |
160 ("[ \t]+" . space) | |
161 ("$" . end-of-line) | |
162 ) | |
163 "Table of tokens filladapt knows about. | |
164 Format is | |
165 | |
166 ((REGEXP . SYM) ...) | |
167 | |
168 filladapt uses this table to build a tokenized representation of | |
169 the beginning of the current line. Each REGEXP is matched | |
170 against the beginning of the line until a match is found. | |
171 Matching is done case-sensitively. The corresponding SYM is | |
172 added to the list, point is moved to (match-end 0) and the | |
173 process is repeated. The process ends when there is no REGEXP in | |
174 the table that matches what is at point.") | |
175 | |
176 (defvar filladapt-not-token-table | |
177 '( | |
178 "[Ee].g." | |
179 "[Ii].e." | |
180 ;; end-of-line isn't a token if whole line is empty | |
181 "^$" | |
182 ) | |
183 "List of regexps that can never be a token. | |
184 Before trying the regular expressions in filladapt-token-table, | |
185 the regexps in this list are tried. If any regexp in this list | |
186 matches what is at point then the token generator gives up and | |
187 doesn't try any of the regexps in filladapt-token-table. | |
188 | |
189 Regexp matching is done case-sensitively.") | |
190 | |
191 (defvar filladapt-token-match-table | |
192 '( | |
193 (citation-> citation->) | |
194 (supercite-citation supercite-citation) | |
195 (lisp-comment lisp-comment) | |
196 (sh-comment sh-comment) | |
197 (postscript-comment postscript-comment) | |
198 (c++-comment c++-comment) | |
199 (texinfo-comment texinfo-comment) | |
200 (bullet) | |
201 (space bullet space) | |
202 ) | |
203 "Table describing what tokens a certain token will match. | |
204 | |
205 To decide whether a line belongs in the current paragraph, | |
206 filladapt creates a token list for the fill prefix of both lines. | |
207 Tokens and the columns where tokens end are compared. This table | |
208 specifies what a certain token will match. | |
209 | |
210 Table format is | |
211 | |
212 (SYM [SYM1 [SYM2 ...]]) | |
213 | |
214 The first symbol SYM is the token, subsequent symbols are the | |
215 tokens that SYM will match.") | |
216 | |
217 (defvar filladapt-token-match-many-table | |
218 '( | |
219 space | |
220 ) | |
221 "List of tokens that can match multiple tokens. | |
222 If one of these tokens appears in a token list, it will eat all | |
223 matching tokens in a token list being matched against it until it | |
224 encounters a token that doesn't match or a token that ends on | |
225 a greater column number.") | |
226 | |
227 (defvar filladapt-token-paragraph-start-table | |
228 '( | |
229 bullet | |
230 ) | |
231 "List of tokens that indicate the start of a paragraph. | |
232 If parsing a line generates a token list containing one of | |
233 these tokens, then the line is considered to be the start of a | |
234 paragraph.") | |
235 | |
236 (defvar filladapt-token-conversion-table | |
237 '( | |
238 (citation-> . exact) | |
239 (supercite-citation . exact) | |
240 (lisp-comment . exact) | |
241 (sh-comment . exact) | |
242 (postscript-comment . exact) | |
243 (c++-comment . exact) | |
244 (texinfo-comment . exact) | |
245 (bullet . spaces) | |
246 (space . exact) | |
247 (end-of-line . exact) | |
248 ) | |
249 "Table that specifies how to convert a token into a fill prefix. | |
250 Table format is | |
251 | |
252 ((SYM . HOWTO) ...) | |
253 | |
254 SYM is the symbol naming the token to be converted. | |
255 HOWTO specifies how to do the conversion. | |
256 `exact' means copy the token's string directly into the fill prefix. | |
257 `spaces' means convert all characters in the token string that are | |
258 not a TAB or a space into spaces and copy the resulting string into | |
259 the fill prefix.") | |
260 | |
261 (defvar filladapt-function-table | |
262 (let ((assoc-list | |
263 (list (cons 'fill-paragraph (symbol-function 'fill-paragraph)) | |
264 (cons 'fill-region-as-paragraph | |
265 (symbol-function 'fill-region-as-paragraph)) | |
266 (cons 'do-auto-fill (symbol-function 'do-auto-fill))))) | |
267 ;; v18 Emacs doesn't have lisp-fill-paragraph | |
268 (if (fboundp 'lisp-fill-paragraph) | |
269 (nconc assoc-list | |
270 (list (cons 'lisp-fill-paragraph | |
271 (symbol-function 'lisp-fill-paragraph))))) | |
272 assoc-list ) | |
273 "Table containing the old function definitions that filladapt usurps.") | |
274 | |
275 (defvar filladapt-fill-paragraph-post-hook nil | |
276 "Hooks run after filladapt runs fill-paragraph.") | |
277 | |
278 (defvar filladapt-inside-filladapt nil | |
279 "Non-nil if the filladapt version of a fill function executing. | |
280 Currently this is only checked by the filladapt version of | |
281 fill-region-as-paragraph to avoid this infinite recursion: | |
282 | |
283 fill-region-as-paragraph -> fill-paragraph -> fill-region-as-paragraph ...") | |
284 | |
285 (defvar filladapt-debug nil | |
286 "Non-nil means filladapt debugging is enabled. | |
287 Use the filladapt-debug command to turn on debugging. | |
288 | |
289 With debugging enabled, filladapt will | |
290 | |
291 a. display the proposed indentation with the tokens highlighted | |
292 using filladapt-debug-indentation-face-1 and | |
293 filladapt-debug-indentation-face-2. | |
294 b. display the current paragraph using the face specified by | |
295 filladapt-debug-paragraph-face.") | |
296 | |
297 (if filladapt-debug | |
298 (add-hook 'post-command-hook 'filladapt-display-debug-info-maybe)) | |
299 | |
300 (defvar filladapt-debug-indentation-face-1 'highlight | |
301 "Face used to display the indentation when debugging is enabled.") | |
302 | |
303 (defvar filladapt-debug-indentation-face-2 'secondary-selection | |
304 "Another face used to display the indentation when debugging is enabled.") | |
305 | |
306 (defvar filladapt-debug-paragraph-face 'bold | |
307 "Face used to display the current paragraph when debugging is enabled.") | |
308 | |
309 (defvar filladapt-debug-indentation-extents nil) | |
310 (make-variable-buffer-local 'filladapt-debug-indentation-extents) | |
311 (defvar filladapt-debug-paragraph-extent nil) | |
312 (make-variable-buffer-local 'filladapt-debug-paragraph-extent) | |
313 | |
314 ;; kludge city, see references in code. | |
315 (defvar filladapt-old-line-prefix) | |
316 | |
317 (defun do-auto-fill () | |
318 (catch 'done | |
319 (if (and filladapt-mode (null fill-prefix)) | |
320 (save-restriction | |
321 (let ((paragraph-ignore-fill-prefix nil) | |
322 ;; if the user wanted this stuff, they probably | |
323 ;; wouldn't be using filladapt-mode. | |
324 (adaptive-fill-mode nil) | |
325 (adaptive-fill-regexp nil) | |
326 ;; need this or Emacs 19 ignores fill-prefix when | |
327 ;; inside a comment. | |
328 (comment-multi-line t) | |
329 (filladapt-inside-filladapt t) | |
330 fill-prefix retval) | |
331 (if (filladapt-adapt nil nil) | |
332 (progn | |
333 (setq retval (filladapt-funcall 'do-auto-fill)) | |
334 (throw 'done retval)))))) | |
335 (filladapt-funcall 'do-auto-fill))) | |
336 | |
337 (defun filladapt-fill-paragraph (function arg) | |
338 (catch 'done | |
339 (if (and filladapt-mode (null fill-prefix)) | |
340 (save-restriction | |
341 (let ((paragraph-ignore-fill-prefix nil) | |
342 ;; if the user wanted this stuff, they probably | |
343 ;; wouldn't be using filladapt-mode. | |
344 (adaptive-fill-mode nil) | |
345 (adaptive-fill-regexp nil) | |
346 ;; need this or Emacs 19 ignores fill-prefix when | |
347 ;; inside a comment. | |
348 (comment-multi-line t) | |
349 fill-prefix retval) | |
350 (if (filladapt-adapt t nil) | |
351 (progn | |
352 (setq retval (filladapt-funcall function arg)) | |
353 (run-hooks 'filladapt-fill-paragraph-post-hook) | |
354 (throw 'done retval)))))) | |
355 ;; filladapt-adapt failed, so do fill-paragraph normally. | |
356 (filladapt-funcall function arg))) | |
357 | |
358 (defun fill-paragraph (arg) | |
359 (interactive "*P") | |
360 (let ((filladapt-inside-filladapt t)) | |
361 (filladapt-fill-paragraph 'fill-paragraph arg))) | |
362 | |
363 (defun lisp-fill-paragraph (&optional arg) | |
364 (interactive "*P") | |
365 (let ((filladapt-inside-filladapt t)) | |
366 (filladapt-fill-paragraph 'lisp-fill-paragraph arg))) | |
367 | |
368 (defun fill-region-as-paragraph (beg end &optional justify nosqueeze squeeze-after) | |
369 (interactive "*r\nP") | |
370 (if (and filladapt-mode (not filladapt-inside-filladapt)) | |
371 (save-restriction | |
372 (narrow-to-region beg end) | |
373 (let ((filladapt-inside-filladapt t) | |
374 line-start last-token) | |
375 (goto-char beg) | |
376 (end-of-line) | |
377 (while (zerop (forward-line)) | |
378 (if (setq last-token | |
379 (car (filladapt-tail (filladapt-parse-prefixes)))) | |
380 (progn | |
381 (setq line-start (point)) | |
382 (move-to-column (nth 1 last-token)) | |
383 (delete-region line-start (point)))) | |
384 ;; Dance... | |
385 ;; | |
386 ;; Do this instead of (delete-char -1) to keep | |
387 ;; markers on the correct side of the whitespace. | |
388 (goto-char (1- (point))) | |
389 (insert " ") | |
390 (delete-char 1) | |
391 | |
392 (end-of-line)) | |
393 (goto-char beg) | |
394 (fill-paragraph justify)) | |
395 ;; In XEmacs 19.12 and Emacs 18.59 fill-region relies on | |
396 ;; fill-region-as-paragraph to do this. If we don't do | |
397 ;; it, fill-region will spin in an endless loop. | |
398 (goto-char (point-max))) | |
399 (condition-case nil | |
400 ;; five args for Emacs 19.31 | |
401 (filladapt-funcall 'fill-region-as-paragraph beg end | |
402 justify nosqueeze squeeze-after) | |
403 (wrong-number-of-arguments | |
404 (condition-case nil | |
405 ;; four args for Emacs 19.29 | |
406 (filladapt-funcall 'fill-region-as-paragraph beg end | |
407 justify nosqueeze) | |
408 ;; three args for the rest of the world. | |
409 (wrong-number-of-arguments | |
410 (filladapt-funcall 'fill-region-as-paragraph beg end justify))))))) | |
411 | |
412 (defvar zmacs-region-stays) ; for XEmacs | |
413 | |
414 (defun filladapt-mode (&optional arg) | |
415 "Toggle Filladapt minor mode. | |
416 With arg, turn Filladapt mode on iff arg is positive. When | |
417 Filladapt mode is enabled, auto-fill-mode and the fill-paragraph | |
418 command are both smarter about guessing a proper fill-prefix and | |
419 finding paragraph boundaries when bulleted and indented lines and | |
420 paragraphs are used." | |
421 (interactive "P") | |
422 ;; don't deactivate the region. | |
423 (setq zmacs-region-stays t) | |
424 (setq filladapt-mode (or (and arg (> (prefix-numeric-value arg) 0)) | |
425 (and (null arg) (null filladapt-mode)))) | |
426 (if (fboundp 'force-mode-line-update) | |
427 (force-mode-line-update) | |
428 (set-buffer-modified-p (buffer-modified-p)))) | |
429 | |
430 (defun turn-on-filladapt-mode () | |
431 "Unconditionally turn on Filladapt mode in the current buffer." | |
432 (filladapt-mode 1)) | |
433 | |
434 (defun turn-off-filladapt-mode () | |
435 "Unconditionally turn off Filladapt mode in the current buffer." | |
436 (filladapt-mode -1)) | |
437 | |
438 (defun filladapt-funcall (function &rest args) | |
439 "Call the old definition of a function that filladapt has usurped." | |
440 (apply (cdr (assoc function filladapt-function-table)) args)) | |
441 | |
442 (defun filladapt-paragraph-start (list) | |
443 "Returns non-nil if LIST contains a paragraph starting token. | |
444 LIST should be a token list as returned by filladapt-parse-prefixes." | |
445 (catch 'done | |
446 (while list | |
447 (if (memq (car (car list)) filladapt-token-paragraph-start-table) | |
448 (throw 'done t)) | |
449 (setq list (cdr list))))) | |
450 | |
451 (defun filladapt-parse-prefixes () | |
452 "Parse all the tokens after point and return a list of them. | |
453 The tokens regular expressions are specified in | |
454 filladapt-token-table. The list returned is of this form | |
455 | |
456 ((SYM COL STRING) ...) | |
457 | |
458 SYM is a token symbol as found in filladapt-token-table. | |
459 COL is the column at which the token ended. | |
460 STRING is the token's text." | |
461 (save-excursion | |
462 (let ((token-list nil) | |
463 (done nil) | |
464 (old-point (point)) | |
465 (case-fold-search nil) | |
466 token-table not-token-table) | |
467 (catch 'done | |
468 (while (not done) | |
469 (setq not-token-table filladapt-not-token-table) | |
470 (while not-token-table | |
471 (if (looking-at (car not-token-table)) | |
472 (throw 'done t)) | |
473 (setq not-token-table (cdr not-token-table))) | |
474 (setq token-table filladapt-token-table | |
475 done t) | |
476 (while token-table | |
477 (if (null (looking-at (car (car token-table)))) | |
478 (setq token-table (cdr token-table)) | |
479 (goto-char (match-end 0)) | |
480 (setq token-list (cons (list (cdr (car token-table)) | |
481 (current-column) | |
482 (buffer-substring | |
483 (match-beginning 0) | |
484 (match-end 0))) | |
485 token-list) | |
486 token-table nil | |
487 done (eq (point) old-point) | |
488 old-point (point)))))) | |
489 (nreverse token-list)))) | |
490 | |
491 (defun filladapt-tokens-match-p (list1 list2) | |
492 "Compare two token lists and return non-nil if they match, nil otherwise. | |
493 The lists are walked through in lockstep, comparing tokens. | |
494 | |
495 When two tokens A and B are compared, they are considered to | |
496 match if | |
497 | |
498 1. A appears in B's list of matching tokens or | |
499 B appears in A's list of matching tokens | |
500 and | |
501 2. A and B both end at the same column | |
502 or | |
503 A can match multiple tokens and ends at a column > than B | |
504 or | |
505 B can match multiple tokens and ends at a column > than A | |
506 | |
507 In the case where the end columns differ the list pointer for the | |
508 token with the greater end column is not moved forward, which | |
509 allows its current token to be matched against the next token in | |
510 the other list in the next iteration of the matching loop. | |
511 | |
512 All tokens must be matched in order for the lists to be considered | |
513 matching." | |
514 (let ((matched t) | |
515 (done nil)) | |
516 (while (and (not done) list1 list2) | |
517 (let* ((token1 (car (car list1))) | |
518 (token1-matches-many-p | |
519 (memq token1 filladapt-token-match-many-table)) | |
520 (token1-matches (cdr (assq token1 filladapt-token-match-table))) | |
521 (token1-endcol (nth 1 (car list1))) | |
522 (token2 (car (car list2))) | |
523 (token2-matches-many-p | |
524 (memq token2 filladapt-token-match-many-table)) | |
525 (token2-matches (cdr (assq token2 filladapt-token-match-table))) | |
526 (token2-endcol (nth 1 (car list2))) | |
527 (tokens-match (or (memq token1 token2-matches) | |
528 (memq token2 token1-matches)))) | |
529 (cond ((not tokens-match) | |
530 (setq matched nil | |
531 done t)) | |
532 ((and token1-matches-many-p token2-matches-many-p) | |
533 (cond ((= token1-endcol token2-endcol) | |
534 (setq list1 (cdr list1) | |
535 list2 (cdr list2))) | |
536 ((< token1-endcol token2-endcol) | |
537 (setq list1 (cdr list1))) | |
538 (t | |
539 (setq list2 (cdr list2))))) | |
540 (token1-matches-many-p | |
541 (cond ((= token1-endcol token2-endcol) | |
542 (setq list1 (cdr list1) | |
543 list2 (cdr list2))) | |
544 ((< token1-endcol token2-endcol) | |
545 (setq matched nil | |
546 done t)) | |
547 (t | |
548 (setq list2 (cdr list2))))) | |
549 (token2-matches-many-p | |
550 (cond ((= token1-endcol token2-endcol) | |
551 (setq list1 (cdr list1) | |
552 list2 (cdr list2))) | |
553 ((< token2-endcol token1-endcol) | |
554 (setq matched nil | |
555 done t)) | |
556 (t | |
557 (setq list1 (cdr list1))))) | |
558 ((= token1-endcol token2-endcol) | |
559 (setq list1 (cdr list1) | |
560 list2 (cdr list2))) | |
561 (t | |
562 (setq matched nil | |
563 done t))))) | |
564 (and matched (null list1) (null list2)) )) | |
565 | |
566 (defun filladapt-make-fill-prefix (list) | |
567 "Build a fill-prefix for a token LIST. | |
568 filladapt-token-conversion-table specifies how this is done." | |
569 (let ((prefix-list nil) | |
570 (conversion-spec nil)) | |
571 (while list | |
572 (setq conversion-spec (cdr (assq (car (car list)) | |
573 filladapt-token-conversion-table))) | |
574 (cond ((eq conversion-spec 'spaces) | |
575 (setq prefix-list | |
576 (cons | |
577 (filladapt-convert-to-spaces (nth 2 (car list))) | |
578 prefix-list))) | |
579 ((eq conversion-spec 'exact) | |
580 (setq prefix-list | |
581 (cons | |
582 (nth 2 (car list)) | |
583 prefix-list)))) | |
584 (setq list (cdr list))) | |
585 (apply (function concat) (nreverse prefix-list)) )) | |
586 | |
587 (defun filladapt-convert-to-spaces (string) | |
588 "Return a copy of STRING, with all non-tabs and non-space changed to spaces." | |
589 (let ((i 0) | |
590 (space-list '(?\ ?\t)) | |
591 (space ?\ ) | |
592 (lim (length string))) | |
593 (setq string (copy-sequence string)) | |
594 (while (< i lim) | |
595 (if (not (memq (aref string i) space-list)) | |
596 (aset string i space)) | |
597 (setq i (1+ i))) | |
598 string )) | |
599 | |
600 (defun filladapt-adapt (paragraph debugging) | |
601 "Set fill-prefix based on the contents of the current line. | |
602 | |
603 If the first arg PARAGRAPH is non-nil, also set a clipping region | |
604 around the current paragraph. | |
605 | |
606 If the second arg DEBUGGING is non-nil, don't do the kludge that's | |
607 necessary to make certain paragraph fills work properly." | |
608 (save-excursion | |
609 (beginning-of-line) | |
610 (let ((token-list (filladapt-parse-prefixes)) | |
611 curr-list done) | |
612 (if (null token-list) | |
613 nil | |
614 (setq fill-prefix (filladapt-make-fill-prefix token-list)) | |
615 (if paragraph | |
616 (let (beg end) | |
617 (if (filladapt-paragraph-start token-list) | |
618 (setq beg (point)) | |
619 (save-excursion | |
620 (setq done nil) | |
621 (while (not done) | |
622 (cond ((not (= 0 (forward-line -1))) | |
623 (setq done t | |
624 beg (point))) | |
625 ((not (filladapt-tokens-match-p | |
626 token-list | |
627 (setq curr-list (filladapt-parse-prefixes)))) | |
628 (forward-line 1) | |
629 (setq done t | |
630 beg (point))) | |
631 ((filladapt-paragraph-start curr-list) | |
632 (setq done t | |
633 beg (point))))))) | |
634 (save-excursion | |
635 (setq done nil) | |
636 (while (not done) | |
637 (cond ((not (= 0 (progn (end-of-line) (forward-line 1)))) | |
638 (setq done t | |
639 end (point))) | |
640 ((not (filladapt-tokens-match-p | |
641 token-list | |
642 (setq curr-list (filladapt-parse-prefixes)))) | |
643 (setq done t | |
644 end (point))) | |
645 ((filladapt-paragraph-start curr-list) | |
646 (setq done t | |
647 end (point)))))) | |
648 (narrow-to-region beg end) | |
649 ;; Multiple spaces after the bullet at the start of | |
650 ;; a hanging list paragraph get squashed by | |
651 ;; fill-paragraph. We kludge around this by | |
652 ;; replacing the line prefix with the fill-prefix | |
653 ;; used by the rest of the lines in the paragraph. | |
654 ;; fill-paragraph will not alter the fill prefix so | |
655 ;; we win. The post hook restores the old line prefix | |
656 ;; after fill-paragraph has been called. | |
657 (if (and paragraph (not debugging)) | |
658 (let (col) | |
659 (setq col (nth 1 (car (filladapt-tail token-list)))) | |
660 (goto-char (point-min)) | |
661 (move-to-column col) | |
662 (setq filladapt-old-line-prefix | |
663 (buffer-substring (point-min) (point))) | |
664 (delete-region (point-min) (point)) | |
665 (insert fill-prefix) | |
666 (add-hook 'filladapt-fill-paragraph-post-hook | |
667 'filladapt-cleanup-kludge-at-point-min))))) | |
668 t )))) | |
669 | |
670 (defun filladapt-cleanup-kludge-at-point-min () | |
671 "Cleanup the paragraph fill kludge. | |
672 See filladapt-adapt." | |
673 (save-excursion | |
674 (goto-char (point-min)) | |
675 (insert filladapt-old-line-prefix) | |
676 (delete-char (length fill-prefix)) | |
677 (remove-hook 'filladapt-fill-paragraph-post-hook | |
678 'filladapt-cleanup-kludge-at-point-min))) | |
679 | |
680 (defun filladapt-tail (list) | |
681 "Returns the last cons in LIST." | |
682 (if (null list) | |
683 nil | |
684 (while (consp (cdr list)) | |
685 (setq list (cdr list))) | |
686 list )) | |
687 | |
688 (defun filladapt-delete-extent (e) | |
689 (if (fboundp 'delete-extent) | |
690 (delete-extent e) | |
691 (delete-overlay e))) | |
692 | |
693 (defun filladapt-make-extent (beg end) | |
694 (if (fboundp 'make-extent) | |
695 (make-extent beg end) | |
696 (make-overlay beg end))) | |
697 | |
698 (defun filladapt-set-extent-endpoints (e beg end) | |
699 (if (fboundp 'set-extent-endpoints) | |
700 (set-extent-endpoints e beg end) | |
701 (move-overlay e beg end))) | |
702 | |
703 (defun filladapt-set-extent-property (e prop val) | |
704 (if (fboundp 'set-extent-property) | |
705 (set-extent-property e prop val) | |
706 (overlay-put e prop val))) | |
707 | |
708 (defun filladapt-debug () | |
709 "Toggle filladapt debugging on/off in the current buffer." | |
710 ;; (interactive) | |
711 (make-local-variable 'filladapt-debug) | |
712 (setq filladapt-debug (not filladapt-debug)) | |
713 ;; make sure these faces exist at least | |
714 (make-face 'filladapt-debug-indentation-face-1) | |
715 (make-face 'filladapt-debug-indentation-face-2) | |
716 (make-face 'filladapt-debug-paragraph-face) | |
717 (if (null filladapt-debug) | |
718 (progn | |
719 (mapcar (function (lambda (e) (filladapt-set-extent-endpoints e 1 1))) | |
720 filladapt-debug-indentation-extents) | |
721 (if filladapt-debug-paragraph-extent | |
722 (progn | |
723 (filladapt-delete-extent filladapt-debug-paragraph-extent) | |
724 (setq filladapt-debug-paragraph-extent nil))))) | |
725 (add-hook 'post-command-hook 'filladapt-display-debug-info-maybe)) | |
726 | |
727 (defun filladapt-display-debug-info-maybe () | |
728 (cond ((null filladapt-debug) nil) | |
729 (fill-prefix nil) | |
730 (t | |
731 (if (null filladapt-debug-paragraph-extent) | |
732 (let ((e (filladapt-make-extent 1 1))) | |
733 (filladapt-set-extent-property e 'detachable nil) | |
734 (filladapt-set-extent-property e 'evaporate nil) | |
735 (filladapt-set-extent-property e 'face | |
736 filladapt-debug-paragraph-face) | |
737 (setq filladapt-debug-paragraph-extent e))) | |
738 (save-excursion | |
739 (save-restriction | |
740 (let ((ei-list filladapt-debug-indentation-extents) | |
741 (ep filladapt-debug-paragraph-extent) | |
742 (face filladapt-debug-indentation-face-1) | |
743 fill-prefix token-list) | |
744 (if (null (filladapt-adapt t t)) | |
745 (progn | |
746 (filladapt-set-extent-endpoints ep 1 1) | |
747 (while ei-list | |
748 (filladapt-set-extent-endpoints (car ei-list) 1 1) | |
749 (setq ei-list (cdr ei-list)))) | |
750 (filladapt-set-extent-endpoints ep (point-min) (point-max)) | |
751 (beginning-of-line) | |
752 (setq token-list (filladapt-parse-prefixes)) | |
753 (message "(%s)" (mapconcat (function | |
754 (lambda (q) (symbol-name (car q)))) | |
755 token-list | |
756 " ")) | |
757 (while token-list | |
758 (if ei-list | |
759 (setq e (car ei-list) | |
760 ei-list (cdr ei-list)) | |
761 (setq e (filladapt-make-extent 1 1)) | |
762 (filladapt-set-extent-property e 'detachable nil) | |
763 (filladapt-set-extent-property e 'evaporate nil) | |
764 (setq filladapt-debug-indentation-extents | |
765 (cons e filladapt-debug-indentation-extents))) | |
766 (filladapt-set-extent-property e 'face face) | |
767 (filladapt-set-extent-endpoints e (point) | |
768 (progn | |
769 (move-to-column | |
770 (nth 1 | |
771 (car token-list))) | |
772 (point))) | |
773 (if (eq face filladapt-debug-indentation-face-1) | |
774 (setq face filladapt-debug-indentation-face-2) | |
775 (setq face filladapt-debug-indentation-face-1)) | |
776 (setq token-list (cdr token-list))) | |
777 (while ei-list | |
778 (filladapt-set-extent-endpoints (car ei-list) 1 1) | |
779 (setq ei-list (cdr ei-list)))))))))) |