diff options
| author | Richard M. Stallman | 1995-01-19 04:20:52 +0000 |
|---|---|---|
| committer | Richard M. Stallman | 1995-01-19 04:20:52 +0000 |
| commit | 0cb08f98380da55714e253028eaf57c5b6afa217 (patch) | |
| tree | 9e7038a4be754fabcc0308103896b1f07f65a612 | |
| parent | 106b6d0e36341b7b6a438c8a1df546205bb59726 (diff) | |
| download | emacs-0cb08f98380da55714e253028eaf57c5b6afa217.tar.gz emacs-0cb08f98380da55714e253028eaf57c5b6afa217.zip | |
(set-justification): New function.
(set-justification-{none,left,right,full,center}): New functions.
(fill-region-as-paragraph, fill-region, justify-current-line): New
arg NOSQUEEZE defeats normal removal of extra whitespace.
(fill-region-as-paragraph, fill-region)
(fill-nonuniform-paragraphs, fill-individual-paragraphs):
Arg JUSTIFY-FLAG (JUSTIFYP) renamed to JUSTIFY.
(fill-region-as-paragraph): Obey left-margin; fill-prefix starts
after left-margin. Disable filling if JUSTIFY == none, but indent to
margin anyway.
Adaptive-fill removes text-props from fill-prefixes it finds.
Adaptive-fill no longer has to notice left-margin: std fill does that.
Use fill-column and canonically-space-region functions.
(canonically-space-region): New fn split from fill-region-as-paragraph.
(fill-region): New args NOSQUEEZE (as above) and TO-EOP.
(default-justification): New variable.
(current-left-margin, fill-column, justification): New functions.
(fill-paragraph): Use fill-region-as-paragraph when possible.
(justify-current-line): New arguments; different kinds of
justification handled. Uses left-margin and fill-column functions.
| -rw-r--r-- | lisp/textmodes/fill.el | 602 |
1 files changed, 393 insertions, 209 deletions
diff --git a/lisp/textmodes/fill.el b/lisp/textmodes/fill.el index 9880e8c5fca..336236d8822 100644 --- a/lisp/textmodes/fill.el +++ b/lisp/textmodes/fill.el | |||
| @@ -60,17 +60,79 @@ If Adaptive Fill mode is enabled, whatever text matches this pattern | |||
| 60 | on the second line of a paragraph is used as the standard indentation | 60 | on the second line of a paragraph is used as the standard indentation |
| 61 | for the paragraph.") | 61 | for the paragraph.") |
| 62 | 62 | ||
| 63 | (defun fill-region-as-paragraph (from to &optional justify-flag) | 63 | (defun current-fill-column () |
| 64 | "Return the fill-column to use for this line. | ||
| 65 | The fill-column to use for a buffer is stored in the variable `fill-column', | ||
| 66 | but can be locally modified by the `right-margin' text property, which is | ||
| 67 | subtracted from `fill-column'. | ||
| 68 | |||
| 69 | The fill column to use for a line is the first column at which the column | ||
| 70 | number equals or exceeds the local fill-column - right-margin difference." | ||
| 71 | (save-excursion | ||
| 72 | (let* ((here (progn (beginning-of-line) (point))) | ||
| 73 | (here-col 0) | ||
| 74 | (eol (progn (end-of-line) (point))) | ||
| 75 | margin fill-col change col) | ||
| 76 | ;; Look separately at each region of line with a different right-margin | ||
| 77 | (while (and (setq margin (get-text-property here 'right-margin) | ||
| 78 | fill-col (- fill-column (or margin 0)) | ||
| 79 | change (text-property-not-all here eol | ||
| 80 | 'right-margin margin)) | ||
| 81 | (progn (goto-char (1- change)) | ||
| 82 | (setq col (current-column)) | ||
| 83 | (< col fill-col))) | ||
| 84 | (setq here change | ||
| 85 | here-col col)) | ||
| 86 | (max here-col fill-col)))) | ||
| 87 | |||
| 88 | (defun canonically-space-region (beg end) | ||
| 89 | "Remove extra spaces between words in region. | ||
| 90 | Puts one space between words in region; two between sentences. | ||
| 91 | Remove indenation from each line." | ||
| 92 | (interactive "r") | ||
| 93 | (save-excursion | ||
| 94 | (goto-char beg) | ||
| 95 | ;; Nuke tabs; they get screwed up in a fill. | ||
| 96 | ;; This is quick, but loses when a tab follows the end of a sentence. | ||
| 97 | ;; Actually, it is difficult to tell that from "Mr.\tSmith". | ||
| 98 | ;; Blame the typist. | ||
| 99 | (subst-char-in-region beg end ?\t ?\ ) | ||
| 100 | (while (and (< (point) end) | ||
| 101 | (re-search-forward " *" end t)) | ||
| 102 | (delete-region | ||
| 103 | (+ (match-beginning 0) | ||
| 104 | ;; Determine number of spaces to leave: | ||
| 105 | (save-excursion | ||
| 106 | (skip-chars-backward " ]})\"'") | ||
| 107 | (cond ((and sentence-end-double-space | ||
| 108 | (memq (preceding-char) '(?. ?? ?!))) 2) | ||
| 109 | ((char-equal (preceding-char) ?\n) 0) | ||
| 110 | (t 1)))) | ||
| 111 | (match-end 0))) | ||
| 112 | ;; Make sure sentences ending at end of line get an extra space. | ||
| 113 | ;; loses on split abbrevs ("Mr.\nSmith") | ||
| 114 | (goto-char beg) | ||
| 115 | (while (and (< (point) end) | ||
| 116 | (re-search-forward "[.?!][])}\"']*$" end t)) | ||
| 117 | (insert-and-inherit ? )))) | ||
| 118 | |||
| 119 | (defun fill-region-as-paragraph (from to &optional justify nosqueeze) | ||
| 64 | "Fill region as one paragraph: break lines to fit `fill-column'. | 120 | "Fill region as one paragraph: break lines to fit `fill-column'. |
| 65 | Any paragraph breaks in the region will be removed. | 121 | This removes any paragraph breaks in the region. |
| 66 | Prefix arg means justify too. | 122 | It performs justification according to the `justification' text-property, |
| 123 | but a prefix arg can be used to override this and request full justification. | ||
| 124 | |||
| 125 | Optional fourth arg NOSQUEEZE non-nil means to leave whitespace other than line | ||
| 126 | breaks untouched. Normally it is made canonical before filling. | ||
| 127 | |||
| 67 | If `sentence-end-double-space' is non-nil, then period followed by one | 128 | If `sentence-end-double-space' is non-nil, then period followed by one |
| 68 | space does not end a sentence, so don't break a line there. | 129 | space does not end a sentence, so don't break a line there." |
| 69 | From program, pass args FROM, TO and JUSTIFY-FLAG." | ||
| 70 | (interactive "r\nP") | 130 | (interactive "r\nP") |
| 71 | ;; Arrange for undoing the fill to restore point. | 131 | ;; Arrange for undoing the fill to restore point. |
| 72 | (if (and buffer-undo-list (not (eq buffer-undo-list t))) | 132 | (if (and buffer-undo-list (not (eq buffer-undo-list t))) |
| 73 | (setq buffer-undo-list (cons (point) buffer-undo-list))) | 133 | (setq buffer-undo-list (cons (point) buffer-undo-list))) |
| 134 | (or justify (setq justify (justification))) | ||
| 135 | |||
| 74 | ;; Don't let Adaptive Fill mode alter the fill prefix permanently. | 136 | ;; Don't let Adaptive Fill mode alter the fill prefix permanently. |
| 75 | (let ((fill-prefix fill-prefix)) | 137 | (let ((fill-prefix fill-prefix)) |
| 76 | ;; Figure out how this paragraph is indented, if desired. | 138 | ;; Figure out how this paragraph is indented, if desired. |
| @@ -80,173 +142,172 @@ From program, pass args FROM, TO and JUSTIFY-FLAG." | |||
| 80 | (goto-char (min from to)) | 142 | (goto-char (min from to)) |
| 81 | (if (eolp) (forward-line 1)) | 143 | (if (eolp) (forward-line 1)) |
| 82 | (forward-line 1) | 144 | (forward-line 1) |
| 145 | (move-to-left-margin) | ||
| 83 | (if (< (point) (max from to)) | 146 | (if (< (point) (max from to)) |
| 84 | (let ((start (point))) | 147 | (let ((start (point))) |
| 85 | (re-search-forward adaptive-fill-regexp) | 148 | (re-search-forward adaptive-fill-regexp) |
| 86 | (setq fill-prefix (buffer-substring start (point)))) | 149 | (setq fill-prefix (buffer-substring start (point))) |
| 150 | (set-text-properties 0 (length fill-prefix) nil fill-prefix)) | ||
| 87 | (goto-char (min from to)) | 151 | (goto-char (min from to)) |
| 88 | (if (eolp) (forward-line 1)) | 152 | (if (eolp) (forward-line 1)) |
| 89 | ;; If paragraph has only one line, don't assume in general | 153 | ;; If paragraph has only one line, don't assume in general |
| 90 | ;; that additional lines would have the same starting | 154 | ;; that additional lines would have the same starting |
| 91 | ;; decoration. Assume no indentation. | 155 | ;; decoration. Assume no indentation. |
| 92 | ;; But if left-margin is nonzero, we can assume ordinary | ||
| 93 | ;; lines do have indentation. | ||
| 94 | (if (> left-margin 0) | ||
| 95 | (progn | ||
| 96 | (re-search-forward adaptive-fill-regexp) | ||
| 97 | (setq fill-prefix (make-string (current-column) ?\ )))) | ||
| 98 | ))) | 156 | ))) |
| 99 | 157 | ||
| 100 | (save-restriction | 158 | (if (not justify) ; filling disabled: just check indentation |
| 101 | (let (beg) | 159 | (progn |
| 102 | (goto-char (min from to)) | 160 | (goto-char (min from to)) |
| 103 | (skip-chars-forward "\n") | 161 | (setq to (max from to)) |
| 104 | (setq beg (point)) | 162 | (while (< (point) to) |
| 105 | (goto-char (max from to)) | 163 | (if (not (eolp)) |
| 106 | (skip-chars-backward "\n") | 164 | (if (< (current-indentation) (left-margin)) |
| 107 | (setq to (point) | 165 | (indent-to-left-margin))) |
| 108 | from beg) | 166 | (forward-line 1))) |
| 109 | (goto-char from) | 167 | |
| 110 | (beginning-of-line) | 168 | (save-restriction |
| 111 | (narrow-to-region (point) to)) | 169 | (let (beg) |
| 112 | (if use-hard-newlines | 170 | (goto-char (min from to)) |
| 113 | (remove-text-properties from to '(hard nil))) | 171 | (skip-chars-forward "\n") |
| 114 | (if (> from (point)) | 172 | (setq beg (point)) |
| 115 | (goto-char from)) | 173 | (goto-char (max from to)) |
| 116 | (let ((fpre (and fill-prefix (not (equal fill-prefix "")) | 174 | (skip-chars-backward "\n") |
| 117 | (regexp-quote fill-prefix)))) | 175 | (setq to (point) |
| 176 | from beg) | ||
| 177 | (goto-char from) | ||
| 178 | (beginning-of-line) | ||
| 179 | (narrow-to-region (point) to)) | ||
| 180 | (if use-hard-newlines | ||
| 181 | (remove-text-properties from to '(hard nil))) | ||
| 182 | ;; Make sure first line is indented (at least) to left margin... | ||
| 183 | (if (or (memq justify '(right center)) | ||
| 184 | (< (current-indentation) (left-margin))) | ||
| 185 | (indent-to-left-margin)) | ||
| 186 | ;; and remove indentation from other lines. | ||
| 187 | (beginning-of-line 2) | ||
| 188 | (indent-region (point) (point-max) 0) | ||
| 118 | ;; Delete the fill prefix from every line except the first. | 189 | ;; Delete the fill prefix from every line except the first. |
| 119 | ;; The first line may not even have a fill prefix. | 190 | ;; The first line may not even have a fill prefix. |
| 120 | (and fpre | 191 | (goto-char from) |
| 121 | (progn | 192 | (let ((fpre (and fill-prefix (not (equal fill-prefix "")) |
| 122 | (if (>= (length fill-prefix) fill-column) | 193 | (concat "[ \t]*" |
| 123 | (error "fill-prefix too long for specified width")) | 194 | (regexp-quote fill-prefix))))) |
| 124 | (goto-char from) | 195 | (and fpre |
| 125 | (forward-line 1) | ||
| 126 | (while (not (eobp)) | ||
| 127 | (if (looking-at fpre) | ||
| 128 | (delete-region (point) (match-end 0))) | ||
| 129 | (forward-line 1)) | ||
| 130 | (goto-char from) | ||
| 131 | (and (looking-at fpre) (forward-char (length fill-prefix))) | ||
| 132 | (setq from (point))))) | ||
| 133 | ;; from is now before the text to fill, | ||
| 134 | ;; but after any fill prefix on the first line. | ||
| 135 | |||
| 136 | ;; Make sure sentences ending at end of line get an extra space. | ||
| 137 | ;; loses on split abbrevs ("Mr.\nSmith") | ||
| 138 | (goto-char from) | ||
| 139 | (while (re-search-forward "[.?!][])}\"']*$" nil t) | ||
| 140 | (insert-and-inherit ? )) | ||
| 141 | |||
| 142 | ;; Then change all newlines to spaces. | ||
| 143 | (subst-char-in-region from (point-max) ?\n ?\ ) | ||
| 144 | |||
| 145 | ;; Flush excess spaces, except in the paragraph indentation. | ||
| 146 | (goto-char from) | ||
| 147 | (skip-chars-forward " \t") | ||
| 148 | ;; Nuke tabs while we're at it; they get screwed up in a fill. | ||
| 149 | ;; This is quick, but loses when a tab follows the end of a sentence. | ||
| 150 | ;; Actually, it is difficult to tell that from "Mr.\tSmith". | ||
| 151 | ;; Blame the typist. | ||
| 152 | (subst-char-in-region (point) (point-max) ?\t ?\ ) | ||
| 153 | (while (re-search-forward " *" nil t) | ||
| 154 | (delete-region | ||
| 155 | (+ (match-beginning 0) | ||
| 156 | (if (and sentence-end-double-space | ||
| 157 | (save-excursion | ||
| 158 | (skip-chars-backward " ]})\"'") | ||
| 159 | (memq (preceding-char) '(?. ?? ?!)))) | ||
| 160 | 2 1)) | ||
| 161 | (match-end 0))) | ||
| 162 | (goto-char (point-max)) | ||
| 163 | (delete-horizontal-space) | ||
| 164 | (insert-and-inherit " ") | ||
| 165 | (goto-char (point-min)) | ||
| 166 | |||
| 167 | ;; This is the actual filling loop. | ||
| 168 | (let ((prefixcol 0) linebeg) | ||
| 169 | (while (not (eobp)) | ||
| 170 | (setq linebeg (point)) | ||
| 171 | (move-to-column (1+ fill-column)) | ||
| 172 | (if (eobp) | ||
| 173 | (delete-horizontal-space) | ||
| 174 | ;; Move back to start of word. | ||
| 175 | (skip-chars-backward "^ \n" linebeg) | ||
| 176 | ;; Don't break after a period followed by just one space. | ||
| 177 | ;; Move back to the previous place to break. | ||
| 178 | ;; The reason is that if a period ends up at the end of a line, | ||
| 179 | ;; further fills will assume it ends a sentence. | ||
| 180 | ;; If we now know it does not end a sentence, | ||
| 181 | ;; avoid putting it at the end of the line. | ||
| 182 | (if sentence-end-double-space | ||
| 183 | (while (and (> (point) (+ linebeg 2)) | ||
| 184 | (eq (preceding-char) ?\ ) | ||
| 185 | (not (eq (following-char) ?\ )) | ||
| 186 | (eq (char-after (- (point) 2)) ?\.)) | ||
| 187 | (forward-char -2) | ||
| 188 | (skip-chars-backward "^ \n" linebeg))) | ||
| 189 | (if (if (zerop prefixcol) | ||
| 190 | (save-excursion | ||
| 191 | (skip-chars-backward " " linebeg) | ||
| 192 | (bolp)) | ||
| 193 | (>= prefixcol (current-column))) | ||
| 194 | ;; Keep at least one word even if fill prefix exceeds margin. | ||
| 195 | ;; This handles all but the first line of the paragraph. | ||
| 196 | ;; Meanwhile, don't stop at a period followed by one space. | ||
| 197 | (let ((first t)) | ||
| 198 | (move-to-column prefixcol) | ||
| 199 | (while (and (not (eobp)) | ||
| 200 | (or first | ||
| 201 | (and (not (bobp)) | ||
| 202 | sentence-end-double-space | ||
| 203 | (save-excursion (forward-char -1) | ||
| 204 | (and (looking-at "\\. ") | ||
| 205 | (not (looking-at "\\. "))))))) | ||
| 206 | (skip-chars-forward " ") | ||
| 207 | (skip-chars-forward "^ \n") | ||
| 208 | (setq first nil))) | ||
| 209 | ;; Normally, move back over the single space between the words. | ||
| 210 | (forward-char -1)) | ||
| 211 | (if (and fill-prefix (zerop prefixcol) | ||
| 212 | (< (- (point) (point-min)) (length fill-prefix)) | ||
| 213 | (string= (buffer-substring (point-min) (point)) | ||
| 214 | (substring fill-prefix 0 (- (point) (point-min))))) | ||
| 215 | ;; Keep at least one word even if fill prefix exceeds margin. | ||
| 216 | ;; This handles the first line of the paragraph. | ||
| 217 | ;; Don't stop at a period followed by just one space. | ||
| 218 | (let ((first t)) | ||
| 219 | (while (and (not (eobp)) | ||
| 220 | (or first | ||
| 221 | (and (not (bobp)) | ||
| 222 | sentence-end-double-space | ||
| 223 | (save-excursion (forward-char -1) | ||
| 224 | (and (looking-at "\\. ") | ||
| 225 | (not (looking-at "\\. "))))))) | ||
| 226 | (skip-chars-forward " ") | ||
| 227 | (skip-chars-forward "^ \n") | ||
| 228 | (setq first nil)))) | ||
| 229 | ;; Replace all whitespace here with one newline. | ||
| 230 | ;; Insert before deleting, so we don't forget which side of | ||
| 231 | ;; the whitespace point or markers used to be on. | ||
| 232 | (skip-chars-backward " ") | ||
| 233 | (insert ?\n) | ||
| 234 | ;; Give newline the properties of the space(s) it replaces | ||
| 235 | (set-text-properties (1- (point)) (point) | ||
| 236 | (text-properties-at (point))) | ||
| 237 | (delete-horizontal-space) | ||
| 238 | ;; Insert the fill prefix at start of each line. | ||
| 239 | ;; Set prefixcol so whitespace in the prefix won't get lost. | ||
| 240 | (and fill-prefix (not (equal fill-prefix "")) | ||
| 241 | (progn | ||
| 242 | (insert-and-inherit fill-prefix) | ||
| 243 | (setq prefixcol (current-column))))) | ||
| 244 | ;; Justify the line just ended, if desired. | ||
| 245 | (and justify-flag (not (eobp)) | ||
| 246 | (progn | 196 | (progn |
| 247 | (forward-line -1) | 197 | (if (>= (+ (left-margin) (length fill-prefix)) |
| 248 | (justify-current-line) | 198 | (current-fill-column)) |
| 249 | (forward-line 1)))))))) | 199 | (error "fill-prefix too long for specified width")) |
| 200 | (goto-char from) | ||
| 201 | (forward-line 1) | ||
| 202 | (while (not (eobp)) | ||
| 203 | (if (looking-at fpre) | ||
| 204 | (delete-region (point) (match-end 0))) | ||
| 205 | (forward-line 1)) | ||
| 206 | (goto-char from) | ||
| 207 | (and (looking-at fpre) (goto-char (match-end 0))) | ||
| 208 | (setq from (point))))) | ||
| 209 | ;; "from" is now before the text to fill, | ||
| 210 | ;; but after any fill prefix on the first line. | ||
| 211 | |||
| 212 | ;; Make sure sentences ending at end of line get an extra space. | ||
| 213 | ;; loses on split abbrevs ("Mr.\nSmith") | ||
| 214 | (while (re-search-forward "[.?!][])}\"']*$" nil t) | ||
| 215 | (insert-and-inherit ? )) | ||
| 216 | (goto-char from) | ||
| 217 | (skip-chars-forward " \t") | ||
| 218 | ;; Then change all newlines to spaces. | ||
| 219 | (subst-char-in-region from (point-max) ?\n ?\ ) | ||
| 220 | (if (and nosqueeze (not (eq justify 'full))) | ||
| 221 | nil | ||
| 222 | (canonically-space-region (point) (point-max)) | ||
| 223 | (goto-char (point-max)) | ||
| 224 | (delete-horizontal-space) | ||
| 225 | (insert-and-inherit " ")) | ||
| 226 | (goto-char (point-min)) | ||
| 227 | |||
| 228 | ;; This is the actual filling loop. | ||
| 229 | (let ((prefixcol 0) linebeg) | ||
| 230 | (while (not (eobp)) | ||
| 231 | (setq linebeg (point)) | ||
| 232 | (move-to-column (1+ (current-fill-column))) | ||
| 233 | (if (eobp) | ||
| 234 | (or nosqueeze (delete-horizontal-space)) | ||
| 235 | ;; Move back to start of word. | ||
| 236 | (skip-chars-backward "^ \n" linebeg) | ||
| 237 | ;; Don't break after a period followed by just one space. | ||
| 238 | ;; Move back to the previous place to break. | ||
| 239 | ;; The reason is that if a period ends up at the end of a line, | ||
| 240 | ;; further fills will assume it ends a sentence. | ||
| 241 | ;; If we now know it does not end a sentence, | ||
| 242 | ;; avoid putting it at the end of the line. | ||
| 243 | (if sentence-end-double-space | ||
| 244 | (while (and (> (point) (+ linebeg 2)) | ||
| 245 | (eq (preceding-char) ?\ ) | ||
| 246 | (not (eq (following-char) ?\ )) | ||
| 247 | (eq (char-after (- (point) 2)) ?\.)) | ||
| 248 | (forward-char -2) | ||
| 249 | (skip-chars-backward "^ \n" linebeg))) | ||
| 250 | (if (if (zerop prefixcol) | ||
| 251 | (save-excursion | ||
| 252 | (skip-chars-backward " " linebeg) | ||
| 253 | (bolp)) | ||
| 254 | (>= prefixcol (current-column))) | ||
| 255 | ;; Keep at least one word even if fill prefix exceeds margin. | ||
| 256 | ;; This handles all but the first line of the paragraph. | ||
| 257 | ;; Meanwhile, don't stop at a period followed by one space. | ||
| 258 | (let ((first t)) | ||
| 259 | (move-to-column prefixcol) | ||
| 260 | (while (and (not (eobp)) | ||
| 261 | (or first | ||
| 262 | (and (not (bobp)) | ||
| 263 | sentence-end-double-space | ||
| 264 | (save-excursion (forward-char -1) | ||
| 265 | (and (looking-at "\\. ") | ||
| 266 | (not (looking-at "\\. "))))))) | ||
| 267 | (skip-chars-forward " ") | ||
| 268 | (skip-chars-forward "^ \n") | ||
| 269 | (setq first nil))) | ||
| 270 | ;; Normally, move back over the single space between the words. | ||
| 271 | (forward-char -1)) | ||
| 272 | (if (and fill-prefix (zerop prefixcol) | ||
| 273 | (< (- (point) (point-min)) (length fill-prefix)) | ||
| 274 | (string= (buffer-substring (point-min) (point)) | ||
| 275 | (substring fill-prefix 0 (- (point) (point-min))))) | ||
| 276 | ;; Keep at least one word even if fill prefix exceeds margin. | ||
| 277 | ;; This handles the first line of the paragraph. | ||
| 278 | ;; Don't stop at a period followed by just one space. | ||
| 279 | (let ((first t)) | ||
| 280 | (while (and (not (eobp)) | ||
| 281 | (or first | ||
| 282 | (and (not (bobp)) | ||
| 283 | sentence-end-double-space | ||
| 284 | (save-excursion (forward-char -1) | ||
| 285 | (and (looking-at "\\. ") | ||
| 286 | (not (looking-at "\\. "))))))) | ||
| 287 | (skip-chars-forward " ") | ||
| 288 | (skip-chars-forward "^ \n") | ||
| 289 | (setq first nil)))) | ||
| 290 | ;; Replace whitespace here with one newline, then indent to left | ||
| 291 | ;; margin. | ||
| 292 | (skip-chars-backward " ") | ||
| 293 | (insert ?\n) | ||
| 294 | ;; Give newline the properties of the space(s) it replaces | ||
| 295 | (set-text-properties (1- (point)) (point) | ||
| 296 | (text-properties-at (point))) | ||
| 297 | (indent-to-left-margin) | ||
| 298 | ;; Insert the fill prefix after indentation. | ||
| 299 | ;; Set prefixcol so whitespace in the prefix won't get lost. | ||
| 300 | (and fill-prefix (not (equal fill-prefix "")) | ||
| 301 | (progn | ||
| 302 | (insert-and-inherit fill-prefix) | ||
| 303 | (setq prefixcol (current-column))))) | ||
| 304 | ;; Justify the line just ended, if desired. | ||
| 305 | (if justify | ||
| 306 | (if (eobp) | ||
| 307 | (justify-current-line justify t t) | ||
| 308 | (forward-line -1) | ||
| 309 | (justify-current-line justify nil t) | ||
| 310 | (forward-line 1))))))))) | ||
| 250 | 311 | ||
| 251 | (defun fill-paragraph (arg) | 312 | (defun fill-paragraph (arg) |
| 252 | "Fill paragraph at or after point. Prefix arg means justify as well. | 313 | "Fill paragraph at or after point. Prefix arg means justify as well. |
| @@ -266,9 +327,15 @@ space does not end a sentence, so don't break a line there." | |||
| 266 | (fill-region beg end arg) | 327 | (fill-region beg end arg) |
| 267 | (fill-region-as-paragraph beg end arg)))))) | 328 | (fill-region-as-paragraph beg end arg)))))) |
| 268 | 329 | ||
| 269 | (defun fill-region (from to &optional justify-flag) | 330 | (defun fill-region (from to &optional justify nosqueeze to-eop) |
| 270 | "Fill each of the paragraphs in the region. | 331 | "Fill each of the paragraphs in the region. |
| 271 | Prefix arg (non-nil third arg, if called from program) means justify as well. | 332 | Prefix arg (non-nil third arg, if called from program) means justify as well. |
| 333 | |||
| 334 | Noninteractively, fourth arg NOSQUEEZE non-nil means to leave | ||
| 335 | whitespace other than line breaks untouched, and fifth arg TO-EOP | ||
| 336 | non-nil means to keep filling to the end of the paragraph (or next | ||
| 337 | hard newline, if `use-hard-newlines' is on). | ||
| 338 | |||
| 272 | If `sentence-end-double-space' is non-nil, then period followed by one | 339 | If `sentence-end-double-space' is non-nil, then period followed by one |
| 273 | space does not end a sentence, so don't break a line there." | 340 | space does not end a sentence, so don't break a line there." |
| 274 | (interactive "r\nP") | 341 | (interactive "r\nP") |
| @@ -278,6 +345,9 @@ space does not end a sentence, so don't break a line there." | |||
| 278 | end beg) | 345 | end beg) |
| 279 | (save-restriction | 346 | (save-restriction |
| 280 | (goto-char (max from to)) | 347 | (goto-char (max from to)) |
| 348 | (if to-eop | ||
| 349 | (progn (skip-chars-backward "\n") | ||
| 350 | (forward-paragraph))) | ||
| 281 | (setq end (point)) | 351 | (setq end (point)) |
| 282 | (goto-char (setq beg (min from to))) | 352 | (goto-char (setq beg (min from to))) |
| 283 | (beginning-of-line) | 353 | (beginning-of-line) |
| @@ -290,55 +360,169 @@ space does not end a sentence, so don't break a line there." | |||
| 290 | (if (< (point) beg) | 360 | (if (< (point) beg) |
| 291 | (goto-char beg)) | 361 | (goto-char beg)) |
| 292 | (if (>= (point) initial) | 362 | (if (>= (point) initial) |
| 293 | (fill-region-as-paragraph (point) end justify-flag) | 363 | (fill-region-as-paragraph (point) end justify nosqueeze) |
| 294 | (goto-char end))))))) | 364 | (goto-char end))))))) |
| 295 | 365 | ||
| 296 | (defun justify-current-line () | 366 | |
| 297 | "Add spaces to line point is in, so it ends at `fill-column'." | 367 | (defconst default-justification 'left |
| 298 | (interactive) | 368 | "*Method of justifying text not otherwise specified. |
| 369 | Possible values are `left', `right', `full', `center', or `none'. | ||
| 370 | The requested kind of justification is done whenever lines are filled. | ||
| 371 | The `justification' text-property can locally override this variable. | ||
| 372 | This variable automatically becomes buffer-local when set in any fashion.") | ||
| 373 | (make-variable-buffer-local 'default-justification) | ||
| 374 | |||
| 375 | (defun justification () | ||
| 376 | "How should we justify this line? | ||
| 377 | This returns the value of the text-property `justification', | ||
| 378 | or the variable `default-justification' if there is no text-property. | ||
| 379 | However, it returns nil rather than `none' to mean \"don't justify\"." | ||
| 380 | (let ((j (or (get-text-property | ||
| 381 | ;; Make sure we're looking at paragraph body. | ||
| 382 | (save-excursion (skip-chars-forward " \t") (point)) | ||
| 383 | 'justification) | ||
| 384 | default-justification))) | ||
| 385 | (if (eq 'none j) | ||
| 386 | nil | ||
| 387 | j))) | ||
| 388 | |||
| 389 | (defun set-justification (begin end value) | ||
| 390 | "Set the region's justification style. | ||
| 391 | If the mark is not active, this operates on the current line. | ||
| 392 | In interactive use, if the BEGIN and END points are | ||
| 393 | not at line breaks, they are moved outward to the next line break. | ||
| 394 | If `use-hard-newlines' is true, they are moved to the next hard line breaks. | ||
| 395 | Noninteractively, the values of BEGIN, END and VALUE are not modified." | ||
| 396 | (interactive (list (if mark-active (region-beginning) (point)) | ||
| 397 | (if mark-active (region-end) (point)) | ||
| 398 | (let ((s (completing-read | ||
| 399 | "Set justification to: " | ||
| 400 | '(("left") ("right") ("full") ("center") | ||
| 401 | ("none")) | ||
| 402 | nil t))) | ||
| 403 | (if (equal s "") | ||
| 404 | (error "") | ||
| 405 | (intern s))))) | ||
| 406 | (let* ((paragraph-start (if use-hard-newlines "^" paragraph-start))) | ||
| 407 | (save-excursion | ||
| 408 | (goto-char begin) | ||
| 409 | (while (bolp) (forward-char 1)) | ||
| 410 | (backward-paragraph) | ||
| 411 | (setq begin (point)) | ||
| 412 | |||
| 413 | (goto-char end) | ||
| 414 | (skip-chars-backward " \t\n" begin) | ||
| 415 | (forward-paragraph) | ||
| 416 | (setq end (point)) | ||
| 417 | (set-mark begin) | ||
| 418 | (goto-char end) | ||
| 419 | (y-or-n-p "set-just"))) | ||
| 420 | (put-text-property begin end 'justification value) | ||
| 421 | (fill-region begin end nil t)) | ||
| 422 | |||
| 423 | (defun set-justification-none (b e) | ||
| 424 | "Disable automatic filling for paragraphs in the region. | ||
| 425 | If the mark is not active, this applies to the current paragraph." | ||
| 426 | (interactive "r") | ||
| 427 | (set-justification b e 'none)) | ||
| 428 | |||
| 429 | (defun set-justification-left (b e) | ||
| 430 | "Make paragraphs in the region left-justified. | ||
| 431 | This is usually the default, but see `enriched-default-justification'. | ||
| 432 | If the mark is not active, this applies to the current paragraph." | ||
| 433 | (interactive "r") | ||
| 434 | (set-justification b e 'left)) | ||
| 435 | |||
| 436 | (defun set-justification-right (b e) | ||
| 437 | "Make paragraphs in the region right-justified: | ||
| 438 | Flush at the right margin and ragged on the left. | ||
| 439 | If the mark is not active, this applies to the current paragraph." | ||
| 440 | (interactive "r") | ||
| 441 | (set-justification b e 'right)) | ||
| 442 | |||
| 443 | (defun set-justification-full (b e) | ||
| 444 | "Make paragraphs in the region fully justified: | ||
| 445 | Flush on both margins. | ||
| 446 | If the mark is not active, this applies to the current paragraph." | ||
| 447 | (interactive "r") | ||
| 448 | (set-justification b e 'both)) | ||
| 449 | |||
| 450 | (defun set-justification-center (b e) | ||
| 451 | "Make paragraphs in the region centered. | ||
| 452 | If the mark is not active, this applies to the current paragraph." | ||
| 453 | (interactive "r") | ||
| 454 | (set-justification b e 'center)) | ||
| 455 | |||
| 456 | (defun justify-current-line (&optional how eop nosqueeze) | ||
| 457 | "Add spaces to line point is in, so it ends at `fill-column'. | ||
| 458 | Optional first argument HOW specifies alternate type of justification: | ||
| 459 | it can be `left', `right', `full', `center', or `none'. | ||
| 460 | If HOW is t, will justify however the `justification' function says. | ||
| 461 | Any other value, including nil, is taken to mean `full'. | ||
| 462 | Second arg EOP non-nil means that this is the last line of the paragraph, so | ||
| 463 | it will not be stretched by full justification. | ||
| 464 | Third arg NOSQUEEZE non-nil means to leave interior whitespace unchanged, | ||
| 465 | otherwise it is made canonical." | ||
| 466 | (interactive (list 'full nil nil)) | ||
| 467 | (if (eq t how) (setq how (or (justification) 'none))) | ||
| 299 | (save-excursion | 468 | (save-excursion |
| 300 | (save-restriction | 469 | (save-restriction |
| 301 | (let (ncols beg indent end) | 470 | (let ((fc (current-fill-column)) |
| 302 | (beginning-of-line) | 471 | ncols beg indent end) |
| 303 | (forward-char (length fill-prefix)) | ||
| 304 | (skip-chars-forward " \t") | ||
| 305 | (setq indent (current-column)) | ||
| 306 | (setq beg (point)) | ||
| 307 | (end-of-line) | 472 | (end-of-line) |
| 308 | (narrow-to-region beg (point)) | 473 | (if (and use-hard-newlines (null eop) |
| 309 | (setq end (point)) | 474 | (get-text-property (point) 'hard)) |
| 475 | (setq eop t)) | ||
| 310 | (skip-chars-backward " \t") | 476 | (skip-chars-backward " \t") |
| 311 | (delete-char (- end (point))) | 477 | (if (= (current-column) fc) |
| 312 | (goto-char beg) | 478 | nil ;; Quick exit if it appears to be properly justified already. |
| 313 | (while (re-search-forward " *" nil t) | 479 | (setq end (point)) |
| 314 | (delete-region | 480 | (beginning-of-line) |
| 315 | (+ (match-beginning 0) | 481 | (skip-chars-forward " \t") |
| 316 | (if (save-excursion | 482 | (if (and fill-prefix |
| 317 | (skip-chars-backward " ])\"'") | 483 | (equal fill-prefix |
| 318 | (memq (preceding-char) '(?. ?? ?!))) | 484 | (buffer-substring (point) |
| 319 | 2 1)) | 485 | (+ (point) (length fill-prefix))))) |
| 320 | (match-end 0))) | 486 | (forward-char (length fill-prefix))) |
| 321 | (goto-char beg) | 487 | (setq indent (current-column)) |
| 322 | (while (re-search-forward "[.?!][])\"']*\n" nil t) | 488 | (setq beg (point)) |
| 323 | (forward-char -1) | 489 | (goto-char end) |
| 324 | (insert-and-inherit ? )) | 490 | (cond ((or (eq 'none how) (eq 'left how)) |
| 325 | (goto-char (point-max)) | 491 | nil) |
| 326 | ;; Note that the buffer bounds start after the indentation, | 492 | ((eq 'right how) |
| 327 | ;; so the columns counted by INDENT don't appear in (current-column). | 493 | (setq ncols (- (+ indent (current-fill-column)) |
| 328 | (setq ncols (- fill-column (current-column) indent)) | 494 | (current-column))) |
| 329 | (if (search-backward " " nil t) | 495 | (if (> ncols 0) |
| 330 | (while (> ncols 0) | 496 | (indent-line-to ncols))) |
| 331 | (let ((nmove (+ 3 (random 3)))) | 497 | ((eq 'center how) |
| 332 | (while (> nmove 0) | 498 | (setq ncols |
| 333 | (or (search-backward " " nil t) | 499 | (/ (- (+ indent (current-fill-column)) (current-column)) |
| 334 | (progn | 500 | 2)) |
| 335 | (goto-char (point-max)) | 501 | (if (>= ncols 0) |
| 336 | (search-backward " "))) | 502 | (indent-line-to ncols) |
| 337 | (skip-chars-backward " ") | 503 | (message "Line to long to center"))) |
| 338 | (setq nmove (1- nmove)))) | 504 | (t ;; full |
| 339 | (insert-and-inherit " ") | 505 | (narrow-to-region beg end) |
| 340 | (skip-chars-backward " ") | 506 | (or nosqueeze |
| 341 | (setq ncols (1- ncols))))))) | 507 | (canonically-space-region beg end)) |
| 508 | (goto-char (point-max)) | ||
| 509 | (setq ncols (- (current-fill-column) indent (current-column))) | ||
| 510 | (if (< ncols 0) | ||
| 511 | (message "Line to long to justify") | ||
| 512 | (if (and (not eop) | ||
| 513 | (search-backward " " nil t)) | ||
| 514 | (while (> ncols 0) | ||
| 515 | (let ((nmove (+ 3 (random 3)))) | ||
| 516 | (while (> nmove 0) | ||
| 517 | (or (search-backward " " nil t) | ||
| 518 | (progn | ||
| 519 | (goto-char (point-max)) | ||
| 520 | (search-backward " "))) | ||
| 521 | (skip-chars-backward " ") | ||
| 522 | (setq nmove (1- nmove)))) | ||
| 523 | (insert-and-inherit " ") | ||
| 524 | (skip-chars-backward " ") | ||
| 525 | (setq ncols (1- ncols))))))))))) | ||
| 342 | nil) | 526 | nil) |
| 343 | 527 | ||
| 344 | 528 | ||
| @@ -351,14 +535,14 @@ in the paragraph. | |||
| 351 | 535 | ||
| 352 | When calling from a program, pass range to fill as first two arguments. | 536 | When calling from a program, pass range to fill as first two arguments. |
| 353 | 537 | ||
| 354 | Optional third and fourth arguments JUSTIFY-FLAG and MAIL-FLAG: | 538 | Optional third and fourth arguments JUSTIFY and MAIL-FLAG: |
| 355 | JUSTIFY-FLAG to justify paragraphs (prefix arg), | 539 | JUSTIFY to justify paragraphs (prefix arg), |
| 356 | MAIL-FLAG for a mail message, i. e. don't fill header lines." | 540 | MAIL-FLAG for a mail message, i. e. don't fill header lines." |
| 357 | (interactive "r\nP") | 541 | (interactive "r\nP") |
| 358 | (let ((fill-individual-varying-indent t)) | 542 | (let ((fill-individual-varying-indent t)) |
| 359 | (fill-individual-paragraphs min max justifyp mailp))) | 543 | (fill-individual-paragraphs min max justifyp mailp))) |
| 360 | 544 | ||
| 361 | (defun fill-individual-paragraphs (min max &optional justifyp mailp) | 545 | (defun fill-individual-paragraphs (min max &optional justify mailp) |
| 362 | "Fill paragraphs of uniform indentation within the region. | 546 | "Fill paragraphs of uniform indentation within the region. |
| 363 | This command divides the region into \"paragraphs\", | 547 | This command divides the region into \"paragraphs\", |
| 364 | treating every change in indentation level as a paragraph boundary, | 548 | treating every change in indentation level as a paragraph boundary, |
| @@ -366,8 +550,8 @@ then fills each paragraph using its indentation level as the fill prefix. | |||
| 366 | 550 | ||
| 367 | When calling from a program, pass range to fill as first two arguments. | 551 | When calling from a program, pass range to fill as first two arguments. |
| 368 | 552 | ||
| 369 | Optional third and fourth arguments JUSTIFY-FLAG and MAIL-FLAG: | 553 | Optional third and fourth arguments JUSTIFY and MAIL-FLAG: |
| 370 | JUSTIFY-FLAG to justify paragraphs (prefix arg), | 554 | JUSTIFY to justify paragraphs (prefix arg), |
| 371 | MAIL-FLAG for a mail message, i. e. don't fill header lines." | 555 | MAIL-FLAG for a mail message, i. e. don't fill header lines." |
| 372 | (interactive "r\nP") | 556 | (interactive "r\nP") |
| 373 | (save-restriction | 557 | (save-restriction |
| @@ -421,7 +605,7 @@ MAIL-FLAG for a mail message, i. e. don't fill header lines." | |||
| 421 | (looking-at paragraph-start)))))))))) | 605 | (looking-at paragraph-start)))))))))) |
| 422 | ;; Fill this paragraph, but don't add a newline at the end. | 606 | ;; Fill this paragraph, but don't add a newline at the end. |
| 423 | (let ((had-newline (bolp))) | 607 | (let ((had-newline (bolp))) |
| 424 | (fill-region-as-paragraph start (point) justifyp) | 608 | (fill-region-as-paragraph start (point) justify) |
| 425 | (or had-newline (delete-char -1)))))))) | 609 | (or had-newline (delete-char -1)))))))) |
| 426 | 610 | ||
| 427 | ;;; fill.el ends here | 611 | ;;; fill.el ends here |