Mercurial > hg > xemacs-beta
comparison lisp/hyperbole/kotl/kfill.el @ 0:376386a54a3c r19-14
Import from CVS: tag r19-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:45:50 +0200 |
parents | |
children | 4103f0995bd7 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:376386a54a3c |
---|---|
1 ;;!emacs | |
2 ;; | |
3 ;; FILE: kfill.el | |
4 ;; SUMMARY: Fill and justify koutline cells (adapted from Kyle Jones' filladapt). | |
5 ;; USAGE: GNU Emacs Lisp Library | |
6 ;; KEYWORDS: outlines, wp | |
7 ;; | |
8 ;; AUTHOR: Bob Weiner | |
9 ;; ORIG-DATE: 23-Jan-94 | |
10 ;; LAST-MOD: 4-Nov-95 at 04:53:42 by Bob Weiner | |
11 ;;; ************************************************************************ | |
12 ;;; Public variables | |
13 ;;; ************************************************************************ | |
14 | |
15 (defvar kfill:function-table | |
16 (progn | |
17 (if (featurep 'filladapt) | |
18 (progn (load "fill") ;; Save basic fill-paragraph function. | |
19 (load "simple"))) ;; Save basic do-auto-fill function. | |
20 (list (cons 'fill-paragraph (symbol-function 'fill-paragraph)) | |
21 (cons 'do-auto-fill (symbol-function 'do-auto-fill)))) | |
22 "Table containing the old function definitions that kfill overrides.") | |
23 | |
24 (defvar kfill:prefix-table | |
25 '( | |
26 ;; Lists with hanging indents, e.g. | |
27 ;; 1. xxxxx or 1) xxxxx etc. | |
28 ;; xxxxx xxx | |
29 ;; | |
30 ;; Be sure pattern does not match to: (last word in parens starts | |
31 ;; newline) | |
32 (" *(?\\([0-9][0-9a-z.]*\\|[a-z][0-9a-z.]\\)) +" . kfill:hanging-list) | |
33 (" *\\([0-9]+[a-z.]+[0-9a-z.]*\\|[0-9]+\\|[a-z]\\)\\([.>] +\\| +\\)" | |
34 . kfill:hanging-list) | |
35 ;; Included text in news or mail replies | |
36 ("[ \t]*\\(>+ *\\)+" . kfill:normal-included-text) | |
37 ;; Included text generated by SUPERCITE. We can't hope to match all | |
38 ;; the possible variations, your mileage may vary. | |
39 ("[ \t]*[A-Za-z0-9][^'`\"< \t\n]*>[ \t]*" . kfill:supercite-included-text) | |
40 ;; Lisp comments | |
41 ("[ \t]*\\(;+[ \t]*\\)+" . kfill:lisp-comment) | |
42 ;; UNIX shell comments | |
43 ("[ \t]*\\(#+[ \t]*\\)+" . kfill:sh-comment) | |
44 ;; Postscript comments | |
45 ("[ \t]*\\(%+[ \t]*\\)+" . kfill:postscript-comment) | |
46 ;; C++ comments | |
47 ("[ \t]*//[/ \t]*" . kfill:c++-comment) | |
48 ("[?!~*+ -]+ " . kfill:hanging-list) | |
49 ;; This keeps normal paragraphs from interacting unpleasantly with | |
50 ;; the types given above. | |
51 ("[^ \t/#%?!~*+-]" . kfill:normal) | |
52 ) | |
53 "Value is an alist of the form | |
54 | |
55 ((REGXP . FUNCTION) ...) | |
56 | |
57 When fill-paragraph or do-auto-fill is called, the REGEXP of each alist | |
58 element is compared with the beginning of the current line. If a match | |
59 is found the corresponding FUNCTION is called. FUNCTION is called with | |
60 one argument, which is non-nil when invoked on the behalf of | |
61 fill-paragraph, nil for do-auto-fill. It is the job of FUNCTION to set | |
62 the values of the paragraph-* variables (or set a clipping region, if | |
63 paragraph-start and paragraph-separate cannot be made discerning enough) | |
64 so that fill-paragraph and do-auto-fill work correctly in various | |
65 contexts.") | |
66 | |
67 ;;; ************************************************************************ | |
68 ;;; Public functions | |
69 ;;; ************************************************************************ | |
70 | |
71 (defun do-auto-fill () | |
72 (save-restriction | |
73 (if (null fill-prefix) | |
74 (let ((paragraph-ignore-fill-prefix nil) | |
75 ;; Need this or Emacs 19 ignores fill-prefix when | |
76 ;; inside a comment. | |
77 (comment-multi-line t) | |
78 fill-prefix) | |
79 (kfill:adapt nil) | |
80 (kfill:funcall 'do-auto-fill)) | |
81 (kfill:funcall 'do-auto-fill)))) | |
82 | |
83 (defun fill-paragraph (arg &optional skip-prefix-remove) | |
84 "Fill paragraph at or after point. Prefix ARG means justify as well." | |
85 (interactive "*P") | |
86 ;; Emacs 19 expects a specific symbol here. | |
87 (if (and arg (not (symbolp arg))) (setq arg 'full)) | |
88 (or skip-prefix-remove (kfill:remove-paragraph-prefix)) | |
89 (save-restriction | |
90 (catch 'done | |
91 (if (null fill-prefix) | |
92 (let ((paragraph-ignore-fill-prefix nil) | |
93 ;; Need this or Emacs 19 ignores fill-prefix when | |
94 ;; inside a comment. | |
95 (comment-multi-line t) | |
96 (paragraph-start paragraph-start) | |
97 (paragraph-separate paragraph-separate) | |
98 fill-prefix) | |
99 (if (kfill:adapt t) | |
100 (throw 'done (kfill:funcall 'fill-paragraph arg))))) | |
101 ;; Kfill:adapt failed or fill-prefix is set, so do a basic | |
102 ;; paragraph fill as adapted from par-align.el. | |
103 (kfill:fill-paragraph arg skip-prefix-remove)))) | |
104 | |
105 ;;; | |
106 ;;; Redefine this function so that it sets 'fill-prefix-prev' also. | |
107 ;;; | |
108 (defun set-fill-prefix (&optional turn-off) | |
109 "Set the fill-prefix to the current line up to point. | |
110 Also sets fill-prefix-prev to previous value of fill-prefix. | |
111 Filling expects lines to start with the fill prefix and reinserts the fill | |
112 prefix in each resulting line." | |
113 (interactive) | |
114 (setq fill-prefix-prev fill-prefix | |
115 fill-prefix (if turn-off | |
116 nil | |
117 (buffer-substring | |
118 (save-excursion (beginning-of-line) (point)) | |
119 (point)))) | |
120 (if (equal fill-prefix-prev "") | |
121 (setq fill-prefix-prev nil)) | |
122 (if (equal fill-prefix "") | |
123 (setq fill-prefix nil)) | |
124 (if fill-prefix | |
125 (message "fill-prefix: \"%s\"" fill-prefix) | |
126 (message "fill-prefix cancelled"))) | |
127 | |
128 ;;; ************************************************************************ | |
129 ;;; Private functions | |
130 ;;; ************************************************************************ | |
131 | |
132 (defun kfill:adapt (paragraph) | |
133 (let ((table kfill:prefix-table) | |
134 case-fold-search | |
135 success ) | |
136 (save-excursion | |
137 (beginning-of-line) | |
138 (while table | |
139 (if (not (looking-at (car (car table)))) | |
140 (setq table (cdr table)) | |
141 (funcall (cdr (car table)) paragraph) | |
142 (setq success t table nil)))) | |
143 success )) | |
144 | |
145 (defun kfill:c++-comment (paragraph) | |
146 (setq fill-prefix (buffer-substring (match-beginning 0) (match-end 0))) | |
147 (if paragraph | |
148 (setq paragraph-separate "^[^ \t/]"))) | |
149 | |
150 (defun kfill:fill-paragraph (justify-flag &optional leave-prefix) | |
151 (save-excursion | |
152 (end-of-line) | |
153 ;; Backward to para begin | |
154 (re-search-backward (concat "\\`\\|" paragraph-separate)) | |
155 (forward-line 1) | |
156 (let ((region-start (point))) | |
157 (forward-line -1) | |
158 (let ((from (point))) | |
159 (forward-paragraph) | |
160 ;; Forward to real paragraph end | |
161 (re-search-forward (concat "\\'\\|" paragraph-separate)) | |
162 (or (= (point) (point-max)) (beginning-of-line)) | |
163 (or leave-prefix | |
164 (kfill:replace-string | |
165 (or fill-prefix fill-prefix-prev) | |
166 "" nil region-start (point))) | |
167 (fill-region-as-paragraph from (point) justify-flag))))) | |
168 | |
169 (defun kfill:funcall (function &rest args) | |
170 (apply (cdr (assq function kfill:function-table)) args)) | |
171 | |
172 (defun kfill:hanging-list (paragraph) | |
173 (let (prefix match beg end) | |
174 (setq prefix (make-string (- (match-end 0) (match-beginning 0)) ?\ )) | |
175 (if paragraph | |
176 (progn | |
177 (setq match (buffer-substring (match-beginning 0) (match-end 0))) | |
178 (if (string-match "^ +$" match) | |
179 (save-excursion | |
180 (while (and (not (bobp)) (looking-at prefix)) | |
181 (forward-line -1)) | |
182 | |
183 (cond ((kfill:hanging-p) | |
184 (setq beg (point))) | |
185 (t (setq beg (progn (forward-line 1) (point)))))) | |
186 (setq beg (point))) | |
187 (save-excursion | |
188 (forward-line) | |
189 (while (and (looking-at prefix) | |
190 (not (equal (char-after (match-end 0)) ?\ ))) | |
191 (forward-line)) | |
192 (setq end (point))) | |
193 (narrow-to-region beg end))) | |
194 (setq fill-prefix prefix))) | |
195 | |
196 (defun kfill:hanging-p () | |
197 "Return non-nil iff point is in front of a hanging list." | |
198 (eval kfill:hanging-expression)) | |
199 | |
200 (defun kfill:lisp-comment (paragraph) | |
201 (setq fill-prefix (buffer-substring (match-beginning 0) (match-end 0))) | |
202 (if paragraph | |
203 (setq paragraph-separate | |
204 (concat "^" fill-prefix " *;\\|^" | |
205 (kfill:negate-string fill-prefix))))) | |
206 | |
207 (defun kfill:negate-string (string) | |
208 (let ((len (length string)) | |
209 (i 0) string-list) | |
210 (setq string-list (cons "\\(" nil)) | |
211 (while (< i len) | |
212 (setq string-list | |
213 (cons (if (= i (1- len)) "" "\\|") | |
214 (cons "]" | |
215 (cons (substring string i (1+ i)) | |
216 (cons "[^" | |
217 (cons (regexp-quote (substring string 0 i)) | |
218 string-list))))) | |
219 i (1+ i))) | |
220 (setq string-list (cons "\\)" string-list)) | |
221 (apply 'concat (nreverse string-list)))) | |
222 | |
223 (defun kfill:normal (paragraph) | |
224 (if paragraph | |
225 (setq paragraph-separate | |
226 (concat paragraph-separate "\\|^[ \t/#%?!~*+-]")))) | |
227 | |
228 (defun kfill:normal-included-text (paragraph) | |
229 (setq fill-prefix (buffer-substring (match-beginning 0) (match-end 0))) | |
230 (if paragraph | |
231 (setq paragraph-separate | |
232 (concat "^" fill-prefix " *>\\|^" | |
233 (kfill:negate-string fill-prefix))))) | |
234 | |
235 (defun kfill:postscript-comment (paragraph) | |
236 (setq fill-prefix (buffer-substring (match-beginning 0) (match-end 0))) | |
237 (if paragraph | |
238 (setq paragraph-separate | |
239 (concat "^" fill-prefix " *%\\|^" | |
240 (kfill:negate-string fill-prefix))))) | |
241 | |
242 (defun kfill:remove-paragraph-prefix (&optional indent-str) | |
243 "Remove fill prefix from current paragraph." | |
244 (save-excursion | |
245 (end-of-line) | |
246 ;; Backward to para begin | |
247 (re-search-backward (concat "\\`\\|" paragraph-separate)) | |
248 (forward-line 1) | |
249 (let ((region-start (point))) | |
250 (forward-line -1) | |
251 (forward-paragraph) | |
252 ;; Forward to real paragraph end | |
253 (re-search-forward (concat "\\'\\|" paragraph-separate)) | |
254 (or (= (point) (point-max)) (beginning-of-line)) | |
255 (kfill:replace-string (or fill-prefix fill-prefix-prev) | |
256 (if (eq major-mode 'kotl-mode) | |
257 (or indent-str | |
258 (make-string (kcell-view:indent) ? )) | |
259 "") | |
260 nil region-start (point))))) | |
261 | |
262 (defun kfill:replace-string (fill-str-prev fill-str &optional suffix start end) | |
263 "Replace whitespace separated FILL-STR-PREV with FILL-STR. | |
264 Optional SUFFIX non-nil means replace at ends of lines, default is beginnings. | |
265 Optional arguments START and END specify the replace region, default is the | |
266 current region." | |
267 (if fill-str-prev | |
268 (progn (if start | |
269 (let ((s (min start end))) | |
270 (setq end (max start end) | |
271 start s)) | |
272 (setq start (region-beginning) | |
273 end (region-end))) | |
274 (if (not fill-str) (setq fill-str "")) | |
275 (save-excursion | |
276 (save-restriction | |
277 (narrow-to-region start end) | |
278 (goto-char (point-min)) | |
279 (let ((prefix | |
280 (concat | |
281 (if suffix nil "^") | |
282 "[ \t]*" | |
283 (regexp-quote | |
284 ;; Get non-whitespace separated fill-str-prev | |
285 (substring | |
286 fill-str-prev | |
287 (or (string-match "[^ \t]" fill-str-prev) 0) | |
288 (if (string-match | |
289 "[ \t]*\\(.*[^ \t]\\)[ \t]*$" | |
290 fill-str-prev) | |
291 (match-end 1)))) | |
292 "[ \t]*" | |
293 (if suffix "$")))) | |
294 (while (re-search-forward prefix nil t) | |
295 (replace-match fill-str nil t)))))))) | |
296 | |
297 (defun kfill:sh-comment (paragraph) | |
298 (setq fill-prefix (buffer-substring (match-beginning 0) (match-end 0))) | |
299 (if paragraph | |
300 (setq paragraph-separate | |
301 (concat "^" fill-prefix " *#\\|^" | |
302 (kfill:negate-string fill-prefix))))) | |
303 | |
304 (defun kfill:supercite-included-text (paragraph) | |
305 (setq fill-prefix (buffer-substring (match-beginning 0) (match-end 0))) | |
306 (if paragraph | |
307 (setq paragraph-separate | |
308 (concat "^" (kfill:negate-string fill-prefix))))) | |
309 | |
310 ;;; ************************************************************************ | |
311 ;;; Private variables | |
312 ;;; ************************************************************************ | |
313 | |
314 (defconst kfill:hanging-expression | |
315 (cons 'or | |
316 (delq nil (mapcar (function | |
317 (lambda (pattern-type) | |
318 (if (eq (cdr pattern-type) 'kfill:hanging-list) | |
319 (list 'looking-at (car pattern-type))))) | |
320 kfill:prefix-table))) | |
321 "Conditional expression used to test for hanging indented lists.") | |
322 | |
323 (defvar fill-prefix-prev nil | |
324 "Prior string inserted at front of new line during filling, or nil for none. | |
325 Setting this variable automatically makes it local to the current buffer.") | |
326 (make-variable-buffer-local 'fill-prefix-prev) | |
327 | |
328 | |
329 (provide 'kfill) |