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