Mercurial > hg > xemacs-beta
comparison lisp/prim/fill.el @ 0:376386a54a3c r19-14
Import from CVS: tag r19-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:45:50 +0200 |
parents | |
children | ac2d302a0011 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:376386a54a3c |
---|---|
1 ;;; fill.el --- fill commands for XEmacs. | |
2 | |
3 ;; Copyright (C) 1985, 1986, 1992-1995 Free Software Foundation, Inc. | |
4 | |
5 ;; Keywords: wp | |
6 | |
7 ;; This file is part of XEmacs. | |
8 | |
9 ;; XEmacs is free software; you can redistribute it and/or modify it | |
10 ;; under the terms of the GNU General Public License as published by | |
11 ;; the Free Software Foundation; either version 2, or (at your option) | |
12 ;; any later version. | |
13 | |
14 ;; XEmacs is distributed in the hope that it will be useful, but | |
15 ;; WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 ;; General Public License for more details. | |
18 | |
19 ;; You should have received a copy of the GNU General Public License | |
20 ;; along with XEmacs; see the file COPYING. If not, write to the Free | |
21 ;; Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | |
22 | |
23 ;;; Synched up with: FSF 19.30. | |
24 | |
25 ;;; Commentary: | |
26 | |
27 ;; All the commands for filling text. These are documented in the XEmacs | |
28 ;; Reference Manual. | |
29 | |
30 ;;; Code: | |
31 | |
32 (defvar fill-individual-varying-indent nil | |
33 "*Controls criterion for a new paragraph in `fill-individual-paragraphs'. | |
34 Non-nil means changing indent doesn't end a paragraph. | |
35 That mode can handle paragraphs with extra indentation on the first line, | |
36 but it requires separator lines between paragraphs. | |
37 A value of nil means that any change in indentation starts a new paragraph.") | |
38 | |
39 (defvar sentence-end-double-space t | |
40 "*Non-nil means a single space does not end a sentence.") | |
41 | |
42 (defconst colon-double-space nil | |
43 "*Non-nil means put two spaces after a colon when filling.") | |
44 | |
45 (defvar fill-paragraph-function nil | |
46 "Mode-specific function to fill a paragraph.") | |
47 | |
48 (defun set-fill-prefix () | |
49 "Set the fill prefix to the current line up to point. | |
50 Filling expects lines to start with the fill prefix | |
51 and reinserts the fill prefix in each resulting line." | |
52 (interactive) | |
53 (setq fill-prefix (buffer-substring | |
54 (save-excursion (move-to-left-margin) (point)) | |
55 (point))) | |
56 (if (equal fill-prefix "") | |
57 (setq fill-prefix nil)) | |
58 (if fill-prefix | |
59 (message "fill-prefix: \"%s\"" fill-prefix) | |
60 (message "fill-prefix cancelled"))) | |
61 | |
62 (defvar adaptive-fill-mode t | |
63 "*Non-nil means determine a paragraph's fill prefix from its text.") | |
64 | |
65 ;; #### - this is still weak. Yeah, there's filladapt, but this should | |
66 ;; still be better... --Stig | |
67 (defvar adaptive-fill-regexp (purecopy "[ \t]*\\([#;>*]+ +\\)?") | |
68 "*Regexp to match text at start of line that constitutes indentation. | |
69 If Adaptive Fill mode is enabled, whatever text matches this pattern | |
70 on the second line of a paragraph is used as the standard indentation | |
71 for the paragraph. If the paragraph has just one line, the indentation | |
72 is taken from that line.") | |
73 | |
74 (defvar adaptive-fill-function nil | |
75 "*Function to call to choose a fill prefix for a paragraph. | |
76 This function is used when `adaptive-fill-regexp' does not match.") | |
77 | |
78 (defun current-fill-column () | |
79 "Return the fill-column to use for this line. | |
80 The fill-column to use for a buffer is stored in the variable `fill-column', | |
81 but can be locally modified by the `right-margin' text property, which is | |
82 subtracted from `fill-column'. | |
83 | |
84 The fill column to use for a line is the first column at which the column | |
85 number equals or exceeds the local fill-column - right-margin difference." | |
86 (save-excursion | |
87 (if fill-column | |
88 (let* ((here (progn (beginning-of-line) (point))) | |
89 (here-col 0) | |
90 (eol (progn (end-of-line) (point))) | |
91 margin fill-col change col) | |
92 ;; Look separately at each region of line with a different right-margin. | |
93 (while (and (setq margin (get-text-property here 'right-margin) | |
94 fill-col (- fill-column (or margin 0)) | |
95 change (text-property-not-all | |
96 here eol 'right-margin margin)) | |
97 (progn (goto-char (1- change)) | |
98 (setq col (current-column)) | |
99 (< col fill-col))) | |
100 (setq here change | |
101 here-col col)) | |
102 (max here-col fill-col))))) | |
103 | |
104 (defun canonically-space-region (beg end) | |
105 "Remove extra spaces between words in region. | |
106 Puts one space between words in region; two between sentences. | |
107 Remove indentation from each line." | |
108 (interactive "r") | |
109 (save-excursion | |
110 (goto-char beg) | |
111 ;; XEmacs - (ENE/stig from fa-extras.el): Skip the start of a comment. | |
112 (and comment-start-skip | |
113 (looking-at comment-start-skip) | |
114 (goto-char (match-end 0))) | |
115 ;; Nuke tabs; they get screwed up in a fill. | |
116 ;; This is quick, but loses when a tab follows the end of a sentence. | |
117 ;; Actually, it is difficult to tell that from "Mr.\tSmith". | |
118 ;; Blame the typist. | |
119 (subst-char-in-region beg end ?\t ?\ ) | |
120 (while (and (< (point) end) | |
121 (re-search-forward " *" end t)) | |
122 (delete-region | |
123 (+ (match-beginning 0) | |
124 ;; Determine number of spaces to leave: | |
125 (save-excursion | |
126 (skip-chars-backward " ]})\"'") | |
127 (cond ((and sentence-end-double-space | |
128 (memq (preceding-char) '(?. ?? ?!))) 2) | |
129 ((and colon-double-space | |
130 (= (preceding-char) ?:)) 2) | |
131 ((char-equal (preceding-char) ?\n) 0) | |
132 (t 1)))) | |
133 (match-end 0))) | |
134 ;; Make sure sentences ending at end of line get an extra space. | |
135 ;; loses on split abbrevs ("Mr.\nSmith") | |
136 (goto-char beg) | |
137 (while (and (< (point) end) | |
138 (re-search-forward "[.?!][])}\"']*$" end t)) | |
139 (insert ? )))) | |
140 | |
141 ;; XEmacs -- added DONT-SKIP-FIRST. Port of older code changes by Stig. | |
142 ;; #### probably this junk is broken -- do-auto-fill doesn't actually use | |
143 ;; it. If so, it should be removed. | |
144 (defun fill-context-prefix (from to &optional first-line-regexp | |
145 dont-skip-first) | |
146 "Compute a fill prefix from the text between FROM and TO. | |
147 This uses the variables `adapive-fill-prefix' and `adaptive-fill-function'. | |
148 If FIRST-LINE-REGEXP is non-nil, then when taking a prefix from the | |
149 first line, insist it must match FIRST-LINE-REGEXP." | |
150 (save-excursion | |
151 (goto-char from) | |
152 (if (eolp) (forward-line 1)) | |
153 ;; Move to the second line unless there is just one. | |
154 (let ((firstline (point)) | |
155 ;; Non-nil if we are on the second line. | |
156 at-second | |
157 result) | |
158 (if (not dont-skip-first) | |
159 (forward-line 1)) | |
160 (if (>= (point) to) | |
161 (goto-char firstline) | |
162 (setq at-second t)) | |
163 (move-to-left-margin) | |
164 (let ((start (point)) | |
165 (eol (save-excursion (end-of-line) (point)))) | |
166 (setq result | |
167 (if (not (looking-at paragraph-start)) | |
168 (cond ((and adaptive-fill-regexp (looking-at adaptive-fill-regexp)) | |
169 (buffer-substring-no-properties start (match-end 0))) | |
170 (adaptive-fill-function (funcall adaptive-fill-function))))) | |
171 (and result | |
172 (or at-second | |
173 (null first-line-regexp) | |
174 (string-match first-line-regexp result)) | |
175 result))))) | |
176 | |
177 ;; XEmacs (stig) - this is pulled out of fill-region-as-paragraph so that it | |
178 ;; can also be called from do-auto-fill | |
179 ;; #### But it's not used there. Chuck pulled it out because it broke things. | |
180 (defun maybe-adapt-fill-prefix (&optional from to dont-skip-first) | |
181 (if (and adaptive-fill-mode | |
182 (or (null fill-prefix) (string= fill-prefix ""))) | |
183 (setq fill-prefix (fill-context-prefix from to nil dont-skip-first)))) | |
184 | |
185 (defun fill-region-as-paragraph (from to &optional justify nosqueeze) | |
186 "Fill the region as one paragraph. | |
187 It removes any paragraph breaks in the region and extra newlines at the end, | |
188 indents and fills lines between the margins given by the | |
189 `current-left-margin' and `current-fill-column' functions. | |
190 It leaves point at the beginning of the line following the paragraph. | |
191 | |
192 Normally performs justification according to the `current-justification' | |
193 function, but with a prefix arg, does full justification instead. | |
194 | |
195 From a program, optional third arg JUSTIFY can specify any type of | |
196 justification, and fourth arg NOSQUEEZE non-nil means not to make spaces | |
197 between words canonical before filling. | |
198 | |
199 If `sentence-end-double-space' is non-nil, then period followed by one | |
200 space does not end a sentence, so don't break a line there." | |
201 (interactive | |
202 (progn | |
203 ;; XEmacs addition: | |
204 (barf-if-buffer-read-only nil (region-beginning) (region-end)) | |
205 (list (region-beginning) (region-end) | |
206 (if current-prefix-arg 'full)))) | |
207 ;; Arrange for undoing the fill to restore point. | |
208 (if (and buffer-undo-list (not (eq buffer-undo-list t))) | |
209 (setq buffer-undo-list (cons (point) buffer-undo-list))) | |
210 | |
211 ;; Make sure "to" is the endpoint. | |
212 (goto-char (min from to)) | |
213 (setq to (max from to)) | |
214 ;; Ignore blank lines at beginning of region. | |
215 (skip-chars-forward " \t\n") | |
216 | |
217 (let ((from-plus-indent (point)) | |
218 (oneleft nil)) | |
219 | |
220 (beginning-of-line) | |
221 (setq from (point)) | |
222 | |
223 ;; Delete all but one soft newline at end of region. | |
224 (goto-char to) | |
225 (while (and (> (point) from) (eq ?\n (char-after (1- (point))))) | |
226 (if (and oneleft | |
227 (not (and use-hard-newlines | |
228 (get-text-property (1- (point)) 'hard)))) | |
229 (delete-backward-char 1) | |
230 (backward-char 1) | |
231 (setq oneleft t))) | |
232 (setq to (point)) | |
233 | |
234 ;; If there was no newline, and there is text in the paragraph, then | |
235 ;; create a newline. | |
236 (if (and (not oneleft) (> to from-plus-indent)) | |
237 (newline)) | |
238 (goto-char from-plus-indent)) | |
239 | |
240 (if (not (> to (point))) | |
241 nil ; There is no paragraph, only whitespace: exit now. | |
242 | |
243 (or justify (setq justify (current-justification))) | |
244 | |
245 ;; Don't let Adaptive Fill mode alter the fill prefix permanently. | |
246 (let ((fill-prefix fill-prefix)) | |
247 ;; Figure out how this paragraph is indented, if desired. | |
248 ;; XEmacs: move some code here to a separate function. | |
249 (maybe-adapt-fill-prefix from to t) | |
250 | |
251 (save-restriction | |
252 (goto-char from) | |
253 (beginning-of-line) | |
254 (narrow-to-region (point) to) | |
255 | |
256 (if (not justify) ; filling disabled: just check indentation | |
257 (progn | |
258 (goto-char from) | |
259 (while (not (eobp)) | |
260 (if (and (not (eolp)) | |
261 (< (current-indentation) (current-left-margin))) | |
262 (indent-to-left-margin)) | |
263 (forward-line 1))) | |
264 | |
265 (if use-hard-newlines | |
266 (remove-text-properties from (point-max) '(hard nil))) | |
267 ;; Make sure first line is indented (at least) to left margin... | |
268 (if (or (memq justify '(right center)) | |
269 (< (current-indentation) (current-left-margin))) | |
270 (indent-to-left-margin)) | |
271 ;; Delete the fill prefix from every line except the first. | |
272 ;; The first line may not even have a fill prefix. | |
273 (goto-char from) | |
274 (let ((fpre (and fill-prefix (not (equal fill-prefix "")) | |
275 (concat "[ \t]*" | |
276 (regexp-quote fill-prefix) | |
277 "[ \t]*")))) | |
278 (and fpre | |
279 (progn | |
280 (if (>= (+ (current-left-margin) (length fill-prefix)) | |
281 (current-fill-column)) | |
282 (error "fill-prefix too long for specified width")) | |
283 (goto-char from) | |
284 (forward-line 1) | |
285 (while (not (eobp)) | |
286 (if (looking-at fpre) | |
287 (delete-region (point) (match-end 0))) | |
288 (forward-line 1)) | |
289 (goto-char from) | |
290 (and (looking-at fpre) (goto-char (match-end 0))) | |
291 (setq from (point))))) | |
292 ;; Remove indentation from lines other than the first. | |
293 (beginning-of-line 2) | |
294 (indent-region (point) (point-max) 0) | |
295 (goto-char from) | |
296 | |
297 ;; FROM, and point, are now before the text to fill, | |
298 ;; but after any fill prefix on the first line. | |
299 | |
300 ;; Make sure sentences ending at end of line get an extra space. | |
301 ;; loses on split abbrevs ("Mr.\nSmith") | |
302 (while (re-search-forward "[.?!][])}\"']*$" nil t) | |
303 (or (eobp) (insert ?\ ))) | |
304 (goto-char from) | |
305 (skip-chars-forward " \t") | |
306 ;; Then change all newlines to spaces. | |
307 (subst-char-in-region from (point-max) ?\n ?\ ) | |
308 (if (and nosqueeze (not (eq justify 'full))) | |
309 nil | |
310 (canonically-space-region (point) (point-max)) | |
311 (goto-char (point-max)) | |
312 (delete-horizontal-space) | |
313 (insert " ")) | |
314 (goto-char (point-min)) | |
315 | |
316 ;; This is the actual filling loop. | |
317 (let ((prefixcol 0) linebeg) | |
318 (while (not (eobp)) | |
319 (setq linebeg (point)) | |
320 (move-to-column (1+ (current-fill-column))) | |
321 (if (eobp) | |
322 (or nosqueeze (delete-horizontal-space)) | |
323 ;; Move back to start of word. | |
324 (skip-chars-backward "^ \n" linebeg) | |
325 ;; Don't break after a period followed by just one space. | |
326 ;; Move back to the previous place to break. | |
327 ;; The reason is that if a period ends up at the end of a line, | |
328 ;; further fills will assume it ends a sentence. | |
329 ;; If we now know it does not end a sentence, | |
330 ;; avoid putting it at the end of the line. | |
331 (if sentence-end-double-space | |
332 (while (and (> (point) (+ linebeg 2)) | |
333 (eq (preceding-char) ?\ ) | |
334 (not (eq (following-char) ?\ )) | |
335 (eq (char-after (- (point) 2)) ?\.)) | |
336 (forward-char -2) | |
337 (skip-chars-backward "^ \n" linebeg))) | |
338 ;; If the left margin and fill prefix by themselves | |
339 ;; pass the fill-column, keep at least one word. | |
340 ;; This handles ALL BUT the first line of the paragraph. | |
341 (if (if (zerop prefixcol) | |
342 (save-excursion | |
343 (skip-chars-backward " \t" linebeg) | |
344 (bolp)) | |
345 (>= prefixcol (current-column))) | |
346 ;; Ok, skip at least one word. | |
347 ;; Meanwhile, don't stop at a period followed by one space. | |
348 (let ((first t)) | |
349 (move-to-column prefixcol) | |
350 (while (and (not (eobp)) | |
351 (or first | |
352 (and (not (bobp)) | |
353 sentence-end-double-space | |
354 (save-excursion (forward-char -1) | |
355 (and (looking-at "\\. ") | |
356 (not (looking-at "\\. "))))))) | |
357 (skip-chars-forward " \t") | |
358 (skip-chars-forward "^ \n\t") | |
359 (setq first nil))) | |
360 ;; Normally, move back over the single space between the words. | |
361 (forward-char -1)) | |
362 ;; If the left margin and fill prefix by themselves | |
363 ;; pass the fill-column, keep at least one word. | |
364 ;; This handles the first line of the paragraph. | |
365 (if (and (zerop prefixcol) | |
366 (let ((fill-point (point)) nchars) | |
367 (save-excursion | |
368 (move-to-left-margin) | |
369 (setq nchars (- fill-point (point))) | |
370 (or (< nchars 0) | |
371 (and fill-prefix | |
372 (< nchars (length fill-prefix)) | |
373 (string= (buffer-substring (point) fill-point) | |
374 (substring fill-prefix 0 nchars))))))) | |
375 ;; Ok, skip at least one word. But | |
376 ;; don't stop at a period followed by just one space. | |
377 (let ((first t)) | |
378 (while (and (not (eobp)) | |
379 (or first | |
380 (and (not (bobp)) | |
381 sentence-end-double-space | |
382 (save-excursion (forward-char -1) | |
383 (and (looking-at "\\. ") | |
384 (not (looking-at "\\. "))))))) | |
385 (skip-chars-forward " \t") | |
386 (skip-chars-forward "^ \t\n") | |
387 (setq first nil)))) | |
388 ;; Replace whitespace here with one newline, then indent to left | |
389 ;; margin. | |
390 (skip-chars-backward " \t") | |
391 (insert ?\n) | |
392 ;; Give newline the properties of the space(s) it replaces | |
393 (set-text-properties (1- (point)) (point) | |
394 (text-properties-at (point))) | |
395 (indent-to-left-margin) | |
396 ;; Insert the fill prefix after indentation. | |
397 ;; Set prefixcol so whitespace in the prefix won't get lost. | |
398 (and fill-prefix (not (equal fill-prefix "")) | |
399 (progn | |
400 (insert fill-prefix) | |
401 (setq prefixcol (current-column))))) | |
402 ;; Justify the line just ended, if desired. | |
403 (if justify | |
404 (if (eobp) | |
405 (justify-current-line justify t t) | |
406 (forward-line -1) | |
407 (justify-current-line justify nil t) | |
408 (forward-line 1)))))) | |
409 ;; Leave point after final newline. | |
410 (goto-char (point-max))) | |
411 (forward-char 1)))) | |
412 | |
413 (defun fill-paragraph (arg) | |
414 "Fill paragraph at or after point. Prefix arg means justify as well. | |
415 If `sentence-end-double-space' is non-nil, then period followed by one | |
416 space does not end a sentence, so don't break a line there. | |
417 | |
418 If `fill-paragraph-function' is non-nil, we call it (passing our | |
419 argument to it), and if it returns non-nil, we simply return its value." | |
420 (interactive (list (if current-prefix-arg 'full))) | |
421 (or (and fill-paragraph-function | |
422 (let ((function fill-paragraph-function) | |
423 fill-paragraph-function) | |
424 (funcall function arg))) | |
425 (let ((before (point))) | |
426 (save-excursion | |
427 (forward-paragraph) | |
428 (or (bolp) (newline 1)) | |
429 (let ((end (point)) | |
430 (beg (progn (backward-paragraph) (point)))) | |
431 (goto-char before) | |
432 (if use-hard-newlines | |
433 ;; Can't use fill-region-as-paragraph, since this paragraph may | |
434 ;; still contain hard newlines. See fill-region. | |
435 (fill-region beg end arg) | |
436 (fill-region-as-paragraph beg end arg))))))) | |
437 | |
438 (defun fill-region (from to &optional justify nosqueeze to-eop) | |
439 "Fill each of the paragraphs in the region. | |
440 Prefix arg (non-nil third arg, if called from program) means justify as well. | |
441 | |
442 Noninteractively, fourth arg NOSQUEEZE non-nil means to leave | |
443 whitespace other than line breaks untouched, and fifth arg TO-EOP | |
444 non-nil means to keep filling to the end of the paragraph (or next | |
445 hard newline, if `use-hard-newlines' is on). | |
446 | |
447 If `sentence-end-double-space' is non-nil, then period followed by one | |
448 space does not end a sentence, so don't break a line there." | |
449 (interactive | |
450 (progn | |
451 ;; XEmacs addition: | |
452 (barf-if-buffer-read-only nil (region-beginning) (region-end)) | |
453 (list (region-beginning) (region-end) | |
454 (if current-prefix-arg 'full)))) | |
455 (let (end beg) | |
456 (save-restriction | |
457 (goto-char (max from to)) | |
458 (if to-eop | |
459 (progn (skip-chars-backward "\n") | |
460 (forward-paragraph))) | |
461 (setq end (point)) | |
462 (goto-char (setq beg (min from to))) | |
463 (beginning-of-line) | |
464 (narrow-to-region (point) end) | |
465 (while (not (eobp)) | |
466 (let ((initial (point)) | |
467 end) | |
468 ;; If using hard newlines, break at every one for filling | |
469 ;; purposes rather than using paragraph breaks. | |
470 (if use-hard-newlines | |
471 (progn | |
472 (while (and (setq end (text-property-any (point) (point-max) | |
473 'hard t)) | |
474 (not (= ?\n (char-after end))) | |
475 (not (= end (point-max)))) | |
476 (goto-char (1+ end))) | |
477 (setq end (if end (min (point-max) (1+ end)) (point-max))) | |
478 (goto-char initial)) | |
479 (forward-paragraph 1) | |
480 (setq end (point)) | |
481 (forward-paragraph -1)) | |
482 (if (< (point) beg) | |
483 (goto-char beg)) | |
484 (if (>= (point) initial) | |
485 (fill-region-as-paragraph (point) end justify nosqueeze) | |
486 (goto-char end))))))) | |
487 | |
488 ;; XEmacs addition: from Tim Bradshaw <tfb@edinburgh.ac.uk> | |
489 (defun fill-paragraph-or-region (arg) | |
490 "Fill the current region, if it's active; otherwise, fill the paragraph. | |
491 See `fill-paragraph' and `fill-region' for more information." | |
492 (interactive "*P") | |
493 (if (region-active-p) | |
494 (fill-region (point) (mark) arg) | |
495 (fill-paragraph arg))) | |
496 | |
497 | |
498 (defconst default-justification 'left | |
499 "*Method of justifying text not otherwise specified. | |
500 Possible values are `left', `right', `full', `center', or `none'. | |
501 The requested kind of justification is done whenever lines are filled. | |
502 The `justification' text-property can locally override this variable. | |
503 This variable automatically becomes buffer-local when set in any fashion.") | |
504 (make-variable-buffer-local 'default-justification) | |
505 | |
506 (defun current-justification () | |
507 "How should we justify this line? | |
508 This returns the value of the text-property `justification', | |
509 or the variable `default-justification' if there is no text-property. | |
510 However, it returns nil rather than `none' to mean \"don't justify\"." | |
511 (let ((j (or (get-text-property | |
512 ;; Make sure we're looking at paragraph body. | |
513 (save-excursion (skip-chars-forward " \t") | |
514 (if (and (eobp) (not (bobp))) | |
515 (1- (point)) (point))) | |
516 'justification) | |
517 default-justification))) | |
518 (if (eq 'none j) | |
519 nil | |
520 j))) | |
521 | |
522 (defun set-justification (begin end value &optional whole-par) | |
523 "Set the region's justification style. | |
524 The kind of justification to use is prompted for. | |
525 If the mark is not active, this command operates on the current paragraph. | |
526 If the mark is active, the region is used. However, if the beginning and end | |
527 of the region are not at paragraph breaks, they are moved to the beginning and | |
528 end of the paragraphs they are in. | |
529 If `use-hard-newlines' is true, all hard newlines are taken to be paragraph | |
530 breaks. | |
531 | |
532 When calling from a program, operates just on region between BEGIN and END, | |
533 unless optional fourth arg WHOLE-PAR is non-nil. In that case bounds are | |
534 extended to include entire paragraphs as in the interactive command." | |
535 (interactive (list (if (region-active-p) (region-beginning) (point)) | |
536 (if (region-active-p) (region-end) (point)) | |
537 (let ((s (completing-read | |
538 "Set justification to: " | |
539 '(("left") ("right") ("full") | |
540 ("center") ("none")) | |
541 nil t))) | |
542 (if (equal s "") (error "")) | |
543 (intern s)) | |
544 t)) | |
545 (save-excursion | |
546 (save-restriction | |
547 (if whole-par | |
548 (let ((paragraph-start (if use-hard-newlines "." paragraph-start)) | |
549 (paragraph-ignore-fill-prefix (if use-hard-newlines t | |
550 paragraph-ignore-fill-prefix))) | |
551 (goto-char begin) | |
552 (while (and (bolp) (not (eobp))) (forward-char 1)) | |
553 (backward-paragraph) | |
554 (setq begin (point)) | |
555 (goto-char end) | |
556 (skip-chars-backward " \t\n" begin) | |
557 (forward-paragraph) | |
558 (setq end (point)))) | |
559 | |
560 (narrow-to-region (point-min) end) | |
561 (unjustify-region begin (point-max)) | |
562 (put-text-property begin (point-max) 'justification value) | |
563 (fill-region begin (point-max) nil t)))) | |
564 | |
565 (defun set-justification-none (b e) | |
566 "Disable automatic filling for paragraphs in the region. | |
567 If the mark is not active, this applies to the current paragraph." | |
568 (interactive (list (if (region-active-p) (region-beginning) (point)) | |
569 (if (region-active-p) (region-end) (point)))) | |
570 (set-justification b e 'none t)) | |
571 | |
572 (defun set-justification-left (b e) | |
573 "Make paragraphs in the region left-justified. | |
574 This is usually the default, but see the variable `default-justification'. | |
575 If the mark is not active, this applies to the current paragraph." | |
576 (interactive (list (if (region-active-p) (region-beginning) (point)) | |
577 (if (region-active-p) (region-end) (point)))) | |
578 (set-justification b e 'left t)) | |
579 | |
580 (defun set-justification-right (b e) | |
581 "Make paragraphs in the region right-justified: | |
582 Flush at the right margin and ragged on the left. | |
583 If the mark is not active, this applies to the current paragraph." | |
584 (interactive (list (if (region-active-p) (region-beginning) (point)) | |
585 (if (region-active-p) (region-end) (point)))) | |
586 (set-justification b e 'right t)) | |
587 | |
588 (defun set-justification-full (b e) | |
589 "Make paragraphs in the region fully justified: | |
590 This makes lines flush on both margins by inserting spaces between words. | |
591 If the mark is not active, this applies to the current paragraph." | |
592 (interactive (list (if (region-active-p) (region-beginning) (point)) | |
593 (if (region-active-p) (region-end) (point)))) | |
594 (set-justification b e 'full t)) | |
595 | |
596 (defun set-justification-center (b e) | |
597 "Make paragraphs in the region centered. | |
598 If the mark is not active, this applies to the current paragraph." | |
599 (interactive (list (if (region-active-p) (region-beginning) (point)) | |
600 (if (region-active-p) (region-end) (point)))) | |
601 (set-justification b e 'center t)) | |
602 | |
603 ;; A line has up to six parts: | |
604 ;; | |
605 ;; >>> hello. | |
606 ;; [Indent-1][FP][ Indent-2 ][text][trailing whitespace][newline] | |
607 ;; | |
608 ;; "Indent-1" is the left-margin indentation; normally it ends at column | |
609 ;; given by the `current-left-margin' function. | |
610 ;; "FP" is the fill-prefix. It can be any string, including whitespace. | |
611 ;; "Indent-2" is added to justify a line if the `current-justification' is | |
612 ;; `center' or `right'. In `left' and `full' justification regions, any | |
613 ;; whitespace there is part of the line's text, and should not be changed. | |
614 ;; Trailing whitespace is not counted as part of the line length when | |
615 ;; center- or right-justifying. | |
616 ;; | |
617 ;; All parts of the line are optional, although the final newline can | |
618 ;; only be missing on the last line of the buffer. | |
619 | |
620 (defun justify-current-line (&optional how eop nosqueeze) | |
621 "Do some kind of justification on this line. | |
622 Normally does full justification: adds spaces to the line to make it end at | |
623 the column given by `current-fill-column'. | |
624 Optional first argument HOW specifies alternate type of justification: | |
625 it can be `left', `right', `full', `center', or `none'. | |
626 If HOW is t, will justify however the `current-justification' function says to. | |
627 If HOW is nil or missing, full justification is done by default. | |
628 Second arg EOP non-nil means that this is the last line of the paragraph, so | |
629 it will not be stretched by full justification. | |
630 Third arg NOSQUEEZE non-nil means to leave interior whitespace unchanged, | |
631 otherwise it is made canonical." | |
632 (interactive) | |
633 (if (eq t how) (setq how (or (current-justification) 'none)) | |
634 (if (null how) (setq how 'full) | |
635 (or (memq how '(none left right center)) | |
636 (setq how 'full)))) | |
637 (or (memq how '(none left)) ; No action required for these. | |
638 (let ((fc (current-fill-column)) | |
639 (pos (point-marker)) | |
640 fp-end ; point at end of fill prefix | |
641 beg ; point at beginning of line's text | |
642 end ; point at end of line's text | |
643 indent ; column of `beg' | |
644 endcol ; column of `end' | |
645 ncols) ; new indent point or offset | |
646 (end-of-line) | |
647 ;; Check if this is the last line of the paragraph. | |
648 (if (and use-hard-newlines (null eop) | |
649 (get-text-property (point) 'hard)) | |
650 (setq eop t)) | |
651 (skip-chars-backward " \t") | |
652 ;; Quick exit if it appears to be properly justified already | |
653 ;; or there is no text. | |
654 (if (or (bolp) | |
655 (and (memq how '(full right)) | |
656 (= (current-column) fc))) | |
657 nil | |
658 (setq end (point)) | |
659 (beginning-of-line) | |
660 (skip-chars-forward " \t") | |
661 ;; Skip over fill-prefix. | |
662 (if (and fill-prefix | |
663 (not (string-equal fill-prefix "")) | |
664 (equal fill-prefix | |
665 (buffer-substring | |
666 (point) (min (point-max) (+ (length fill-prefix) | |
667 (point)))))) | |
668 (forward-char (length fill-prefix)) | |
669 (if (and adaptive-fill-mode | |
670 (looking-at adaptive-fill-regexp)) | |
671 (goto-char (match-end 0)))) | |
672 (setq fp-end (point)) | |
673 (skip-chars-forward " \t") | |
674 ;; This is beginning of the line's text. | |
675 (setq indent (current-column)) | |
676 (setq beg (point)) | |
677 (goto-char end) | |
678 (setq endcol (current-column)) | |
679 | |
680 ;; HOW can't be null or left--we would have exited already | |
681 (cond ((eq 'right how) | |
682 (setq ncols (- fc endcol)) | |
683 (if (< ncols 0) | |
684 ;; Need to remove some indentation | |
685 (delete-region | |
686 (progn (goto-char fp-end) | |
687 (if (< (current-column) (+ indent ncols)) | |
688 (move-to-column (+ indent ncols) t)) | |
689 (point)) | |
690 (progn (move-to-column indent) (point))) | |
691 ;; Need to add some | |
692 (goto-char beg) | |
693 (indent-to (+ indent ncols)) | |
694 ;; If point was at beginning of text, keep it there. | |
695 (if (= beg pos) | |
696 (move-marker pos (point))))) | |
697 | |
698 ((eq 'center how) | |
699 ;; Figure out how much indentation is needed | |
700 (setq ncols (+ (current-left-margin) | |
701 (/ (- fc (current-left-margin) ;avail. space | |
702 (- endcol indent)) ;text width | |
703 2))) | |
704 (if (< ncols indent) | |
705 ;; Have too much indentation - remove some | |
706 (delete-region | |
707 (progn (goto-char fp-end) | |
708 (if (< (current-column) ncols) | |
709 (move-to-column ncols t)) | |
710 (point)) | |
711 (progn (move-to-column indent) (point))) | |
712 ;; Have too little - add some | |
713 (goto-char beg) | |
714 (indent-to ncols) | |
715 ;; If point was at beginning of text, keep it there. | |
716 (if (= beg pos) | |
717 (move-marker pos (point))))) | |
718 | |
719 ((eq 'full how) | |
720 ;; Insert extra spaces between words to justify line | |
721 (save-restriction | |
722 (narrow-to-region beg end) | |
723 (or nosqueeze | |
724 (canonically-space-region beg end)) | |
725 (goto-char (point-max)) | |
726 (setq ncols (- fc endcol)) | |
727 ;; Ncols is number of additional spaces needed | |
728 (if (> ncols 0) | |
729 (if (and (not eop) | |
730 (search-backward " " nil t)) | |
731 (while (> ncols 0) | |
732 (let ((nmove (+ 3 (random 3)))) | |
733 (while (> nmove 0) | |
734 (or (search-backward " " nil t) | |
735 (progn | |
736 (goto-char (point-max)) | |
737 (search-backward " "))) | |
738 (skip-chars-backward " ") | |
739 (setq nmove (1- nmove)))) | |
740 (insert " ") | |
741 (skip-chars-backward " ") | |
742 (setq ncols (1- ncols))))))) | |
743 (t (error "Unknown justification value")))) | |
744 (goto-char pos) | |
745 (move-marker pos nil))) | |
746 nil) | |
747 | |
748 (defun unjustify-current-line () | |
749 "Remove justification whitespace from current line. | |
750 If the line is centered or right-justified, this function removes any | |
751 indentation past the left margin. If the line is full-jusitified, it removes | |
752 extra spaces between words. It does nothing in other justification modes." | |
753 (let ((justify (current-justification))) | |
754 (cond ((eq 'left justify) nil) | |
755 ((eq nil justify) nil) | |
756 ((eq 'full justify) ; full justify: remove extra spaces | |
757 (beginning-of-line-text) | |
758 (canonically-space-region | |
759 (point) (save-excursion (end-of-line) (point)))) | |
760 ((memq justify '(center right)) | |
761 (save-excursion | |
762 (move-to-left-margin nil t) | |
763 ;; Position ourselves after any fill-prefix. | |
764 (if (and fill-prefix | |
765 (not (string-equal fill-prefix "")) | |
766 (equal fill-prefix | |
767 (buffer-substring | |
768 (point) (min (point-max) (+ (length fill-prefix) | |
769 (point)))))) | |
770 (forward-char (length fill-prefix))) | |
771 (delete-region (point) (progn (skip-chars-forward " \t") | |
772 (point)))))))) | |
773 | |
774 (defun unjustify-region (&optional begin end) | |
775 "Remove justification whitespace from region. | |
776 For centered or right-justified regions, this function removes any indentation | |
777 past the left margin from each line. For full-jusitified lines, it removes | |
778 extra spaces between words. It does nothing in other justification modes. | |
779 Arguments BEGIN and END are optional; default is the whole buffer." | |
780 (save-excursion | |
781 (save-restriction | |
782 (if end (narrow-to-region (point-min) end)) | |
783 (goto-char (or begin (point-min))) | |
784 (while (not (eobp)) | |
785 (unjustify-current-line) | |
786 (forward-line 1))))) | |
787 | |
788 | |
789 (defun fill-nonuniform-paragraphs (min max &optional justifyp mailp) | |
790 "Fill paragraphs within the region, allowing varying indentation within each. | |
791 This command divides the region into \"paragraphs\", | |
792 only at paragraph-separator lines, then fills each paragraph | |
793 using as the fill prefix the smallest indentation of any line | |
794 in the paragraph. | |
795 | |
796 When calling from a program, pass range to fill as first two arguments. | |
797 | |
798 Optional third and fourth arguments JUSTIFY and MAIL-FLAG: | |
799 JUSTIFY to justify paragraphs (prefix arg), | |
800 MAIL-FLAG for a mail message, i. e. don't fill header lines." | |
801 (interactive (list (region-beginning) (region-end) | |
802 (if current-prefix-arg 'full))) | |
803 (let ((fill-individual-varying-indent t)) | |
804 (fill-individual-paragraphs min max justifyp mailp))) | |
805 | |
806 (defun fill-individual-paragraphs (min max &optional justify mailp) | |
807 "Fill paragraphs of uniform indentation within the region. | |
808 This command divides the region into \"paragraphs\", | |
809 treating every change in indentation level as a paragraph boundary, | |
810 then fills each paragraph using its indentation level as the fill prefix. | |
811 | |
812 When calling from a program, pass range to fill as first two arguments. | |
813 | |
814 Optional third and fourth arguments JUSTIFY and MAIL-FLAG: | |
815 JUSTIFY to justify paragraphs (prefix arg), | |
816 MAIL-FLAG for a mail message, i. e. don't fill header lines." | |
817 (interactive (list (region-beginning) (region-end) | |
818 (if current-prefix-arg 'full))) | |
819 (save-restriction | |
820 (save-excursion | |
821 (goto-char min) | |
822 (beginning-of-line) | |
823 (narrow-to-region (point) max) | |
824 (if mailp | |
825 (while (and (not (eobp)) | |
826 (or (looking-at "[ \t]*[^ \t\n]+:") | |
827 (looking-at "[ \t]*$"))) | |
828 (if (looking-at "[ \t]*[^ \t\n]+:") | |
829 (search-forward "\n\n" nil 'move) | |
830 (forward-line 1)))) | |
831 (narrow-to-region (point) max) | |
832 ;; Loop over paragraphs. | |
833 (while (progn (skip-chars-forward " \t\n") (not (eobp))) | |
834 (move-to-left-margin) | |
835 (let ((start (point)) | |
836 fill-prefix fill-prefix-regexp) | |
837 ;; Find end of paragraph, and compute the smallest fill-prefix | |
838 ;; that fits all the lines in this paragraph. | |
839 (while (progn | |
840 ;; Update the fill-prefix on the first line | |
841 ;; and whenever the prefix good so far is too long. | |
842 (if (not (and fill-prefix | |
843 (looking-at fill-prefix-regexp))) | |
844 (setq fill-prefix | |
845 (if (and adaptive-fill-mode adaptive-fill-regexp | |
846 (looking-at adaptive-fill-regexp)) | |
847 (match-string 0) | |
848 (buffer-substring | |
849 (point) | |
850 (save-excursion (skip-chars-forward " \t") | |
851 (point)))) | |
852 fill-prefix-regexp (regexp-quote fill-prefix))) | |
853 (forward-line 1) | |
854 (move-to-left-margin) | |
855 ;; Now stop the loop if end of paragraph. | |
856 (and (not (eobp)) | |
857 (if fill-individual-varying-indent | |
858 ;; If this line is a separator line, with or | |
859 ;; without prefix, end the paragraph. | |
860 (and | |
861 (not (looking-at paragraph-separate)) | |
862 (save-excursion | |
863 (not (and (looking-at fill-prefix-regexp) | |
864 (progn | |
865 (forward-char (length fill-prefix)) | |
866 (looking-at paragraph-separate)))))) | |
867 ;; If this line has more or less indent | |
868 ;; than the fill prefix wants, end the paragraph. | |
869 (and (looking-at fill-prefix-regexp) | |
870 (save-excursion | |
871 (not | |
872 (progn | |
873 (forward-char (length fill-prefix)) | |
874 (or (looking-at paragraph-separate) | |
875 (looking-at paragraph-start)))))))))) | |
876 ;; Fill this paragraph, but don't add a newline at the end. | |
877 (let ((had-newline (bolp))) | |
878 (fill-region-as-paragraph start (point) justify) | |
879 (or had-newline (delete-char -1)))))))) | |
880 | |
881 ;;; fill.el ends here |