diff options
| author | Boris Goldowsky | 1995-02-23 18:22:04 +0000 |
|---|---|---|
| committer | Boris Goldowsky | 1995-02-23 18:22:04 +0000 |
| commit | 1095bc3caa984f840eea3d025e877813892b9892 (patch) | |
| tree | f7a7da4ee5ce8e44711765ac0e2574c51714d147 | |
| parent | 0bc395d481b8b3cb3c8bf6b9a9374982b9d44517 (diff) | |
| download | emacs-1095bc3caa984f840eea3d025e877813892b9892.tar.gz emacs-1095bc3caa984f840eea3d025e877813892b9892.zip | |
(set-fill-prefix): start from left-margin.
(fill-region-as-paragraph): don't delete hard newlines. ignore whitespace
at beginning of region. Remove justification indentation.
(fill-region): Don't use paragraph-movement commands when use-hard-newlines
is true, just search for hard newlines.
(current-justification): take care at EOB.
(set-justification): new argWHOLE-PAR. Callers changed.
(justify-current-line): Error if JUSTIFY arg is not reasonable.
Better interaction if there is a fill-prefix.
"Line too long" warning removed.
(unjustify-current-line, unjustify-region): New functions.
| -rw-r--r-- | lisp/textmodes/fill.el | 738 |
1 files changed, 448 insertions, 290 deletions
diff --git a/lisp/textmodes/fill.el b/lisp/textmodes/fill.el index dc70406a326..0e9f62feb3b 100644 --- a/lisp/textmodes/fill.el +++ b/lisp/textmodes/fill.el | |||
| @@ -46,7 +46,7 @@ Filling expects lines to start with the fill prefix and | |||
| 46 | reinserts the fill prefix in each resulting line." | 46 | reinserts the fill prefix in each resulting line." |
| 47 | (interactive) | 47 | (interactive) |
| 48 | (setq fill-prefix (buffer-substring | 48 | (setq fill-prefix (buffer-substring |
| 49 | (save-excursion (beginning-of-line) (point)) | 49 | (save-excursion (move-to-left-margin) (point)) |
| 50 | (point))) | 50 | (point))) |
| 51 | (if (equal fill-prefix "") | 51 | (if (equal fill-prefix "") |
| 52 | (setq fill-prefix nil)) | 52 | (setq fill-prefix nil)) |
| @@ -120,13 +120,17 @@ Remove indenation from each line." | |||
| 120 | (insert-and-inherit ? )))) | 120 | (insert-and-inherit ? )))) |
| 121 | 121 | ||
| 122 | (defun fill-region-as-paragraph (from to &optional justify nosqueeze) | 122 | (defun fill-region-as-paragraph (from to &optional justify nosqueeze) |
| 123 | "Fill region as one paragraph: break lines to fit `fill-column'. | 123 | "Fill the region as one paragraph. |
| 124 | This removes any paragraph breaks in the region. | 124 | Removes any paragraph breaks in the region and extra newlines at the end, |
| 125 | It performs justification according to the `justification' text-property, | 125 | indents and fills lines between the margins given by the |
| 126 | but a prefix arg can be used to override this and request full justification. | 126 | `current-left-margin' and `current-fill-column' functions. |
| 127 | 127 | ||
| 128 | Optional fourth arg NOSQUEEZE non-nil means to leave whitespace other than line | 128 | Normally performs justification according to the `current-justification' |
| 129 | breaks untouched. Normally it is made canonical before filling. | 129 | function, but with a prefix arg, does full justification instead. |
| 130 | |||
| 131 | From a program, optional third arg JUSTIFY can specify any type of | ||
| 132 | justification, and fourth arg NOSQUEEZE non-nil means not to make spaces | ||
| 133 | between words canonical before filling. | ||
| 130 | 134 | ||
| 131 | If `sentence-end-double-space' is non-nil, then period followed by one | 135 | If `sentence-end-double-space' is non-nil, then period followed by one |
| 132 | space does not end a sentence, so don't break a line there." | 136 | space does not end a sentence, so don't break a line there." |
| @@ -134,188 +138,208 @@ space does not end a sentence, so don't break a line there." | |||
| 134 | ;; Arrange for undoing the fill to restore point. | 138 | ;; Arrange for undoing the fill to restore point. |
| 135 | (if (and buffer-undo-list (not (eq buffer-undo-list t))) | 139 | (if (and buffer-undo-list (not (eq buffer-undo-list t))) |
| 136 | (setq buffer-undo-list (cons (point) buffer-undo-list))) | 140 | (setq buffer-undo-list (cons (point) buffer-undo-list))) |
| 137 | (or justify (setq justify (current-justification))) | 141 | |
| 138 | 142 | ;; Make sure "to" is the endpoint. Make sure that we end up there. | |
| 139 | ;; Don't let Adaptive Fill mode alter the fill prefix permanently. | 143 | (goto-char (min from to)) |
| 140 | (let ((fill-prefix fill-prefix) | 144 | (setq to (max from to)) |
| 141 | (skip-after 0)) | 145 | (setq from (point)) |
| 142 | ;; Figure out how this paragraph is indented, if desired. | 146 | |
| 143 | (if (and adaptive-fill-mode | 147 | ;; Delete all but one soft newline at end of region. |
| 144 | (or (null fill-prefix) (string= fill-prefix ""))) | 148 | (goto-char to) |
| 145 | (save-excursion | 149 | (let ((oneleft nil)) |
| 146 | (goto-char (min from to)) | 150 | (while (and (> (point) from) (eq ?\n (char-after (1- (point))))) |
| 147 | (if (eolp) (forward-line 1)) | 151 | (if (and oneleft |
| 148 | (forward-line 1) | 152 | (not (and use-hard-newlines |
| 149 | (move-to-left-margin) | 153 | (get-text-property (1- (point)) 'hard)))) |
| 150 | (if (< (point) (max from to)) | 154 | (delete-backward-char 1) |
| 151 | (let ((start (point))) | 155 | (backward-char 1) |
| 152 | (re-search-forward adaptive-fill-regexp) | 156 | (setq oneleft t))) |
| 153 | (setq fill-prefix (buffer-substring start (point))) | 157 | ;; If there was no newline, create one. |
| 154 | (set-text-properties 0 (length fill-prefix) nil fill-prefix)) | 158 | (if (and (not oneleft) (> (point) from)) |
| 155 | (goto-char (min from to)) | 159 | (save-excursion (newline)))) |
| 160 | (setq to (point)) | ||
| 161 | |||
| 162 | ;; Ignore blank lines at beginning of region. | ||
| 163 | (goto-char from) | ||
| 164 | (skip-chars-forward " \t\n") | ||
| 165 | (beginning-of-line) | ||
| 166 | (setq from (point)) | ||
| 167 | |||
| 168 | (if (>= from to) | ||
| 169 | nil ; There is no paragraph at all. | ||
| 170 | |||
| 171 | (or justify (setq justify (current-justification))) | ||
| 172 | |||
| 173 | ;; Don't let Adaptive Fill mode alter the fill prefix permanently. | ||
| 174 | (let ((fill-prefix fill-prefix)) | ||
| 175 | ;; Figure out how this paragraph is indented, if desired. | ||
| 176 | (if (and adaptive-fill-mode | ||
| 177 | (or (null fill-prefix) (string= fill-prefix ""))) | ||
| 178 | (save-excursion | ||
| 179 | (goto-char from) | ||
| 156 | (if (eolp) (forward-line 1)) | 180 | (if (eolp) (forward-line 1)) |
| 181 | (forward-line 1) | ||
| 182 | (move-to-left-margin) | ||
| 183 | (if (< (point) to) | ||
| 184 | (let ((start (point))) | ||
| 185 | (re-search-forward adaptive-fill-regexp) | ||
| 186 | (setq fill-prefix (buffer-substring start (point))) | ||
| 187 | (set-text-properties 0 (length fill-prefix) nil | ||
| 188 | fill-prefix))) | ||
| 157 | ;; If paragraph has only one line, don't assume in general | 189 | ;; If paragraph has only one line, don't assume in general |
| 158 | ;; that additional lines would have the same starting | 190 | ;; that additional lines would have the same starting |
| 159 | ;; decoration. Assume no indentation. | 191 | ;; decoration. Assume no indentation. |
| 160 | ))) | 192 | )) |
| 161 | |||
| 162 | (if (not justify) ; filling disabled: just check indentation | ||
| 163 | (progn | ||
| 164 | (goto-char (min from to)) | ||
| 165 | (setq to (max from to)) | ||
| 166 | (while (< (point) to) | ||
| 167 | (if (not (eolp)) | ||
| 168 | (if (< (current-indentation) (current-left-margin)) | ||
| 169 | (indent-to-left-margin))) | ||
| 170 | (forward-line 1))) | ||
| 171 | 193 | ||
| 172 | (save-restriction | 194 | (save-restriction |
| 173 | (let (beg) | ||
| 174 | (goto-char (min from to)) | ||
| 175 | (skip-chars-forward "\n") | ||
| 176 | (setq beg (point)) | ||
| 177 | (goto-char (max from to)) | ||
| 178 | (skip-chars-backward "\n") | ||
| 179 | (setq skip-after (- to (point))) | ||
| 180 | ;; If we omit some final newlines from the end of the narrowing, | ||
| 181 | ;; arrange to advance past them at the end. | ||
| 182 | (setq to (point) | ||
| 183 | from beg) | ||
| 184 | (goto-char from) | ||
| 185 | (beginning-of-line) | ||
| 186 | (narrow-to-region (point) to)) | ||
| 187 | (if use-hard-newlines | ||
| 188 | (remove-text-properties from to '(hard nil))) | ||
| 189 | ;; Make sure first line is indented (at least) to left margin... | ||
| 190 | (if (or (memq justify '(right center)) | ||
| 191 | (< (current-indentation) (current-left-margin))) | ||
| 192 | (indent-to-left-margin)) | ||
| 193 | ;; and remove indentation from other lines. | ||
| 194 | (beginning-of-line 2) | ||
| 195 | (indent-region (point) (point-max) 0) | ||
| 196 | ;; Delete the fill prefix from every line except the first. | ||
| 197 | ;; The first line may not even have a fill prefix. | ||
| 198 | (goto-char from) | ||
| 199 | (let ((fpre (and fill-prefix (not (equal fill-prefix "")) | ||
| 200 | (concat "[ \t]*" | ||
| 201 | (regexp-quote fill-prefix))))) | ||
| 202 | (and fpre | ||
| 203 | (progn | ||
| 204 | (if (>= (+ (current-left-margin) (length fill-prefix)) | ||
| 205 | (current-fill-column)) | ||
| 206 | (error "fill-prefix too long for specified width")) | ||
| 207 | (goto-char from) | ||
| 208 | (forward-line 1) | ||
| 209 | (while (not (eobp)) | ||
| 210 | (if (looking-at fpre) | ||
| 211 | (delete-region (point) (match-end 0))) | ||
| 212 | (forward-line 1)) | ||
| 213 | (goto-char from) | ||
| 214 | (and (looking-at fpre) (goto-char (match-end 0))) | ||
| 215 | (setq from (point))))) | ||
| 216 | ;; "from" is now before the text to fill, | ||
| 217 | ;; but after any fill prefix on the first line. | ||
| 218 | |||
| 219 | ;; Make sure sentences ending at end of line get an extra space. | ||
| 220 | ;; loses on split abbrevs ("Mr.\nSmith") | ||
| 221 | (while (re-search-forward "[.?!][])}\"']*$" nil t) | ||
| 222 | (insert-and-inherit ? )) | ||
| 223 | (goto-char from) | 195 | (goto-char from) |
| 224 | (skip-chars-forward " \t") | 196 | (beginning-of-line) |
| 225 | ;; Then change all newlines to spaces. | 197 | (narrow-to-region (point) to) |
| 226 | (subst-char-in-region from (point-max) ?\n ?\ ) | 198 | |
| 227 | (if (and nosqueeze (not (eq justify 'full))) | 199 | (if (not justify) ; filling disabled: just check indentation |
| 228 | nil | 200 | (progn |
| 229 | (canonically-space-region (point) (point-max)) | 201 | (goto-char from) |
| 230 | (goto-char (point-max)) | 202 | (while (not (eobp)) |
| 231 | (delete-horizontal-space) | 203 | (if (and (not (eolp)) |
| 232 | (insert-and-inherit " ")) | 204 | (< (current-indentation) (current-left-margin))) |
| 233 | (goto-char (point-min)) | 205 | (indent-to-left-margin)) |
| 234 | 206 | (forward-line 1))) | |
| 235 | ;; This is the actual filling loop. | 207 | |
| 236 | (let ((prefixcol 0) linebeg) | 208 | (if use-hard-newlines |
| 237 | (while (not (eobp)) | 209 | (remove-text-properties from (point-max) '(hard nil))) |
| 238 | (setq linebeg (point)) | 210 | ;; Make sure first line is indented (at least) to left margin... |
| 239 | (move-to-column (1+ (current-fill-column))) | 211 | (if (or (memq justify '(right center)) |
| 240 | (if (eobp) | 212 | (< (current-indentation) (current-left-margin))) |
| 241 | (or nosqueeze (delete-horizontal-space)) | 213 | (indent-to-left-margin)) |
| 242 | ;; Move back to start of word. | 214 | ;; and remove indentation from other lines. |
| 243 | (skip-chars-backward "^ \n" linebeg) | 215 | (beginning-of-line 2) |
| 244 | ;; Don't break after a period followed by just one space. | 216 | (indent-region (point) (point-max) 0) |
| 245 | ;; Move back to the previous place to break. | 217 | ;; Delete the fill prefix from every line except the first. |
| 246 | ;; The reason is that if a period ends up at the end of a line, | 218 | ;; The first line may not even have a fill prefix. |
| 247 | ;; further fills will assume it ends a sentence. | 219 | (goto-char from) |
| 248 | ;; If we now know it does not end a sentence, | 220 | (let ((fpre (and fill-prefix (not (equal fill-prefix "")) |
| 249 | ;; avoid putting it at the end of the line. | 221 | (concat "[ \t]*" |
| 250 | (if sentence-end-double-space | 222 | (regexp-quote fill-prefix) |
| 251 | (while (and (> (point) (+ linebeg 2)) | 223 | "[ \t]*")))) |
| 252 | (eq (preceding-char) ?\ ) | 224 | (and fpre |
| 253 | (not (eq (following-char) ?\ )) | 225 | (progn |
| 254 | (eq (char-after (- (point) 2)) ?\.)) | 226 | (if (>= (+ (current-left-margin) (length fill-prefix)) |
| 255 | (forward-char -2) | 227 | (current-fill-column)) |
| 256 | (skip-chars-backward "^ \n" linebeg))) | 228 | (error "fill-prefix too long for specified width")) |
| 257 | (if (if (zerop prefixcol) | 229 | (goto-char from) |
| 258 | (save-excursion | 230 | (forward-line 1) |
| 259 | (skip-chars-backward " " linebeg) | 231 | (while (not (eobp)) |
| 260 | (bolp)) | 232 | (if (looking-at fpre) |
| 261 | (>= prefixcol (current-column))) | 233 | (delete-region (point) (match-end 0))) |
| 262 | ;; Keep at least one word even if fill prefix exceeds margin. | 234 | (forward-line 1)) |
| 263 | ;; This handles all but the first line of the paragraph. | 235 | (goto-char from) |
| 264 | ;; Meanwhile, don't stop at a period followed by one space. | 236 | (and (looking-at fpre) (goto-char (match-end 0))) |
| 265 | (let ((first t)) | 237 | (setq from (point))))) |
| 266 | (move-to-column prefixcol) | 238 | ;; "from" is now before the text to fill, |
| 267 | (while (and (not (eobp)) | 239 | ;; but after any fill prefix on the first line. |
| 268 | (or first | 240 | |
| 269 | (and (not (bobp)) | 241 | ;; Make sure sentences ending at end of line get an extra space. |
| 270 | sentence-end-double-space | 242 | ;; loses on split abbrevs ("Mr.\nSmith") |
| 271 | (save-excursion (forward-char -1) | 243 | (while (re-search-forward "[.?!][])}\"']*$" nil t) |
| 272 | (and (looking-at "\\. ") | 244 | (insert-and-inherit ? )) |
| 273 | (not (looking-at "\\. "))))))) | 245 | (goto-char from) |
| 274 | (skip-chars-forward " ") | 246 | (skip-chars-forward " \t") |
| 275 | (skip-chars-forward "^ \n") | 247 | ;; Then change all newlines to spaces. |
| 276 | (setq first nil))) | 248 | (subst-char-in-region from (point-max) ?\n ?\ ) |
| 277 | ;; Normally, move back over the single space between the words. | 249 | (if (and nosqueeze (not (eq justify 'full))) |
| 278 | (forward-char -1)) | 250 | nil |
| 279 | (if (and fill-prefix (zerop prefixcol) | 251 | (canonically-space-region (point) (point-max)) |
| 280 | (< (- (point) (point-min)) (length fill-prefix)) | 252 | (goto-char (point-max)) |
| 281 | (string= (buffer-substring (point-min) (point)) | 253 | (delete-horizontal-space) |
| 282 | (substring fill-prefix 0 (- (point) (point-min))))) | 254 | (insert-and-inherit " ")) |
| 283 | ;; Keep at least one word even if fill prefix exceeds margin. | 255 | (goto-char (point-min)) |
| 284 | ;; This handles the first line of the paragraph. | 256 | |
| 285 | ;; Don't stop at a period followed by just one space. | 257 | ;; This is the actual filling loop. |
| 286 | (let ((first t)) | 258 | (let ((prefixcol 0) linebeg) |
| 287 | (while (and (not (eobp)) | 259 | (while (not (eobp)) |
| 288 | (or first | 260 | (setq linebeg (point)) |
| 289 | (and (not (bobp)) | 261 | (move-to-column (1+ (current-fill-column))) |
| 290 | sentence-end-double-space | 262 | (if (eobp) |
| 291 | (save-excursion (forward-char -1) | 263 | (or nosqueeze (delete-horizontal-space)) |
| 292 | (and (looking-at "\\. ") | 264 | ;; Move back to start of word. |
| 293 | (not (looking-at "\\. "))))))) | 265 | (skip-chars-backward "^ \n" linebeg) |
| 294 | (skip-chars-forward " ") | 266 | ;; Don't break after a period followed by just one space. |
| 295 | (skip-chars-forward "^ \n") | 267 | ;; Move back to the previous place to break. |
| 296 | (setq first nil)))) | 268 | ;; The reason is that if a period ends up at the end of a line, |
| 297 | ;; Replace whitespace here with one newline, then indent to left | 269 | ;; further fills will assume it ends a sentence. |
| 298 | ;; margin. | 270 | ;; If we now know it does not end a sentence, |
| 299 | (skip-chars-backward " ") | 271 | ;; avoid putting it at the end of the line. |
| 300 | (insert ?\n) | 272 | (if sentence-end-double-space |
| 301 | ;; Give newline the properties of the space(s) it replaces | 273 | (while (and (> (point) (+ linebeg 2)) |
| 302 | (set-text-properties (1- (point)) (point) | 274 | (eq (preceding-char) ?\ ) |
| 303 | (text-properties-at (point))) | 275 | (not (eq (following-char) ?\ )) |
| 304 | (indent-to-left-margin) | 276 | (eq (char-after (- (point) 2)) ?\.)) |
| 305 | ;; Insert the fill prefix after indentation. | 277 | (forward-char -2) |
| 306 | ;; Set prefixcol so whitespace in the prefix won't get lost. | 278 | (skip-chars-backward "^ \n" linebeg))) |
| 307 | (and fill-prefix (not (equal fill-prefix "")) | 279 | (if (if (zerop prefixcol) |
| 308 | (progn | 280 | (save-excursion |
| 309 | (insert-and-inherit fill-prefix) | 281 | (skip-chars-backward " " linebeg) |
| 310 | (setq prefixcol (current-column))))) | 282 | (bolp)) |
| 311 | ;; Justify the line just ended, if desired. | 283 | (>= prefixcol (current-column))) |
| 312 | (if justify | 284 | ;; Keep at least one word even if fill prefix exceeds margin. |
| 313 | (if (eobp) | 285 | ;; This handles all but the first line of the paragraph. |
| 314 | (justify-current-line justify t t) | 286 | ;; Meanwhile, don't stop at a period followed by one space. |
| 315 | (forward-line -1) | 287 | (let ((first t)) |
| 316 | (justify-current-line justify nil t) | 288 | (move-to-column prefixcol) |
| 317 | (forward-line 1)))))) | 289 | (while (and (not (eobp)) |
| 318 | (forward-char skip-after)))) | 290 | (or first |
| 291 | (and (not (bobp)) | ||
| 292 | sentence-end-double-space | ||
| 293 | (save-excursion (forward-char -1) | ||
| 294 | (and (looking-at "\\. ") | ||
| 295 | (not (looking-at "\\. "))))))) | ||
| 296 | (skip-chars-forward " ") | ||
| 297 | (skip-chars-forward "^ \n") | ||
| 298 | (setq first nil))) | ||
| 299 | ;; Normally, move back over the single space between the words. | ||
| 300 | (forward-char -1)) | ||
| 301 | (if (and fill-prefix (zerop prefixcol) | ||
| 302 | (< (- (point) (point-min)) (length fill-prefix)) | ||
| 303 | (string= (buffer-substring (point-min) (point)) | ||
| 304 | (substring fill-prefix 0 (- (point) (point-min))))) | ||
| 305 | ;; Keep at least one word even if fill prefix exceeds margin. | ||
| 306 | ;; This handles the first line of the paragraph. | ||
| 307 | ;; Don't stop at a period followed by just one space. | ||
| 308 | (let ((first t)) | ||
| 309 | (while (and (not (eobp)) | ||
| 310 | (or first | ||
| 311 | (and (not (bobp)) | ||
| 312 | sentence-end-double-space | ||
| 313 | (save-excursion (forward-char -1) | ||
| 314 | (and (looking-at "\\. ") | ||
| 315 | (not (looking-at "\\. "))))))) | ||
| 316 | (skip-chars-forward " ") | ||
| 317 | (skip-chars-forward "^ \n") | ||
| 318 | (setq first nil)))) | ||
| 319 | ;; Replace whitespace here with one newline, then indent to left | ||
| 320 | ;; margin. | ||
| 321 | (skip-chars-backward " ") | ||
| 322 | (insert ?\n) | ||
| 323 | ;; Give newline the properties of the space(s) it replaces | ||
| 324 | (set-text-properties (1- (point)) (point) | ||
| 325 | (text-properties-at (point))) | ||
| 326 | (indent-to-left-margin) | ||
| 327 | ;; Insert the fill prefix after indentation. | ||
| 328 | ;; Set prefixcol so whitespace in the prefix won't get lost. | ||
| 329 | (and fill-prefix (not (equal fill-prefix "")) | ||
| 330 | (progn | ||
| 331 | (insert-and-inherit fill-prefix) | ||
| 332 | (setq prefixcol (current-column))))) | ||
| 333 | ;; Justify the line just ended, if desired. | ||
| 334 | (if justify | ||
| 335 | (if (eobp) | ||
| 336 | (justify-current-line justify t t) | ||
| 337 | (forward-line -1) | ||
| 338 | (justify-current-line justify nil t) | ||
| 339 | (forward-line 1)))))) | ||
| 340 | ;; Leave point after final newline. | ||
| 341 | (goto-char (point-max))) | ||
| 342 | (forward-char 1)))) | ||
| 319 | 343 | ||
| 320 | (defun fill-paragraph (arg) | 344 | (defun fill-paragraph (arg) |
| 321 | "Fill paragraph at or after point. Prefix arg means justify as well. | 345 | "Fill paragraph at or after point. Prefix arg means justify as well. |
| @@ -354,10 +378,7 @@ hard newline, if `use-hard-newlines' is on). | |||
| 354 | If `sentence-end-double-space' is non-nil, then period followed by one | 378 | If `sentence-end-double-space' is non-nil, then period followed by one |
| 355 | space does not end a sentence, so don't break a line there." | 379 | space does not end a sentence, so don't break a line there." |
| 356 | (interactive "r\nP") | 380 | (interactive "r\nP") |
| 357 | ;; If using hard newlines, break at every one for filling purposes rather | 381 | (let (end beg) |
| 358 | ;; than breaking at normal paragraph breaks. | ||
| 359 | (let ((paragraph-start (if use-hard-newlines "^" paragraph-start)) | ||
| 360 | end beg) | ||
| 361 | (save-restriction | 382 | (save-restriction |
| 362 | (goto-char (max from to)) | 383 | (goto-char (max from to)) |
| 363 | (if to-eop | 384 | (if to-eop |
| @@ -369,9 +390,21 @@ space does not end a sentence, so don't break a line there." | |||
| 369 | (narrow-to-region (point) end) | 390 | (narrow-to-region (point) end) |
| 370 | (while (not (eobp)) | 391 | (while (not (eobp)) |
| 371 | (let ((initial (point)) | 392 | (let ((initial (point)) |
| 372 | (end (progn | 393 | end) |
| 373 | (forward-paragraph 1) (point)))) | 394 | ;; If using hard newlines, break at every one for filling |
| 374 | (forward-paragraph -1) | 395 | ;; purposes rather than using paragraph breaks. |
| 396 | (if use-hard-newlines | ||
| 397 | (progn | ||
| 398 | (while (and (setq end (text-property-any (point) (point-max) | ||
| 399 | 'hard t)) | ||
| 400 | (not (= ?\n (char-after end))) | ||
| 401 | (not (= end (point-max)))) | ||
| 402 | (goto-char (1+ end))) | ||
| 403 | (setq end (min (point-max) (1+ end))) | ||
| 404 | (goto-char initial)) | ||
| 405 | (forward-paragraph 1) | ||
| 406 | (setq end (point)) | ||
| 407 | (forward-paragraph -1)) | ||
| 375 | (if (< (point) beg) | 408 | (if (< (point) beg) |
| 376 | (goto-char beg)) | 409 | (goto-char beg)) |
| 377 | (if (>= (point) initial) | 410 | (if (>= (point) initial) |
| @@ -394,154 +427,279 @@ or the variable `default-justification' if there is no text-property. | |||
| 394 | However, it returns nil rather than `none' to mean \"don't justify\"." | 427 | However, it returns nil rather than `none' to mean \"don't justify\"." |
| 395 | (let ((j (or (get-text-property | 428 | (let ((j (or (get-text-property |
| 396 | ;; Make sure we're looking at paragraph body. | 429 | ;; Make sure we're looking at paragraph body. |
| 397 | (save-excursion (skip-chars-forward " \t") (point)) | 430 | (save-excursion (skip-chars-forward " \t") |
| 431 | (if (and (eobp) (not (bobp))) | ||
| 432 | (1- (point)) (point))) | ||
| 398 | 'justification) | 433 | 'justification) |
| 399 | default-justification))) | 434 | default-justification))) |
| 400 | (if (eq 'none j) | 435 | (if (eq 'none j) |
| 401 | nil | 436 | nil |
| 402 | j))) | 437 | j))) |
| 403 | 438 | ||
| 404 | (defun set-justification (begin end value) | 439 | (defun set-justification (begin end value &optional whole-par) |
| 405 | "Set the region's justification style. | 440 | "Set the region's justification style. |
| 406 | If the mark is not active, this operates on the current line. | 441 | The kind of justification to use is prompted for. |
| 407 | In interactive use, if the BEGIN and END points are | 442 | If the mark is not active, this command operates on the current paragraph. |
| 408 | not at line breaks, they are moved outward to the next line break. | 443 | If the mark is active, the region is used. However, if the beginning and end |
| 409 | If `use-hard-newlines' is true, they are moved to the next hard line breaks. | 444 | of the region are not at paragraph breaks, they are moved to the beginning and |
| 410 | Noninteractively, the values of BEGIN, END and VALUE are not modified." | 445 | end of the paragraphs they are in. |
| 446 | If `use-hard-newlines' is true, all hard newlines are taken to be paragraph | ||
| 447 | breaks. | ||
| 448 | |||
| 449 | When calling from a program, operates just on region between BEGIN and END, | ||
| 450 | unless optional fourth arg WHOLE-PAR is non-nil. In that case bounds are | ||
| 451 | extended to include entire paragraphs as in the interactive command." | ||
| 411 | (interactive (list (if mark-active (region-beginning) (point)) | 452 | (interactive (list (if mark-active (region-beginning) (point)) |
| 412 | (if mark-active (region-end) (point)) | 453 | (if mark-active (region-end) (point)) |
| 413 | (let ((s (completing-read | 454 | (let ((s (completing-read |
| 414 | "Set justification to: " | 455 | "Set justification to: " |
| 415 | '(("left") ("right") ("full") ("center") | 456 | '(("left") ("right") ("full") |
| 416 | ("none")) | 457 | ("center") ("none")) |
| 417 | nil t))) | 458 | nil t))) |
| 418 | (if (equal s "") | 459 | (if (equal s "") (error "")) |
| 419 | (error "") | 460 | (intern s)) |
| 420 | (intern s))))) | 461 | t)) |
| 421 | (let* ((paragraph-start (if use-hard-newlines "^" paragraph-start))) | 462 | (save-excursion |
| 422 | (save-excursion | 463 | (save-restriction |
| 423 | (goto-char begin) | 464 | (if whole-par |
| 424 | (while (bolp) (forward-char 1)) | 465 | (let ((paragraph-start (if use-hard-newlines "." paragraph-start)) |
| 425 | (backward-paragraph) | 466 | (paragraph-ignore-fill-prefix (if use-hard-newlines t |
| 426 | (setq begin (point)) | 467 | paragraph-ignore-fill-prefix))) |
| 427 | 468 | (goto-char begin) | |
| 428 | (goto-char end) | 469 | (while (and (bolp) (not (eobp))) (forward-char 1)) |
| 429 | (skip-chars-backward " \t\n" begin) | 470 | (backward-paragraph) |
| 430 | (forward-paragraph) | 471 | (setq begin (point)) |
| 431 | (setq end (point)) | 472 | (goto-char end) |
| 432 | (set-mark begin) | 473 | (skip-chars-backward " \t\n" begin) |
| 433 | (goto-char end) | 474 | (forward-paragraph) |
| 434 | (y-or-n-p "set-just"))) | 475 | (setq end (point)))) |
| 435 | (put-text-property begin end 'justification value) | 476 | |
| 436 | (fill-region begin end nil t)) | 477 | (narrow-to-region (point-min) end) |
| 478 | (unjustify-region begin (point-max)) | ||
| 479 | (put-text-property begin (point-max) 'justification value) | ||
| 480 | (fill-region begin (point-max) nil t)))) | ||
| 437 | 481 | ||
| 438 | (defun set-justification-none (b e) | 482 | (defun set-justification-none (b e) |
| 439 | "Disable automatic filling for paragraphs in the region. | 483 | "Disable automatic filling for paragraphs in the region. |
| 440 | If the mark is not active, this applies to the current paragraph." | 484 | If the mark is not active, this applies to the current paragraph." |
| 441 | (interactive "r") | 485 | (interactive (list (if mark-active (region-beginning) (point)) |
| 442 | (set-justification b e 'none)) | 486 | (if mark-active (region-end) (point)))) |
| 487 | (set-justification b e 'none t)) | ||
| 443 | 488 | ||
| 444 | (defun set-justification-left (b e) | 489 | (defun set-justification-left (b e) |
| 445 | "Make paragraphs in the region left-justified. | 490 | "Make paragraphs in the region left-justified. |
| 446 | This is usually the default, but see `enriched-default-justification'. | 491 | This is usually the default, but see the variable `default-justification'. |
| 447 | If the mark is not active, this applies to the current paragraph." | 492 | If the mark is not active, this applies to the current paragraph." |
| 448 | (interactive "r") | 493 | (interactive (list (if mark-active (region-beginning) (point)) |
| 449 | (set-justification b e 'left)) | 494 | (if mark-active (region-end) (point)))) |
| 495 | (set-justification b e 'left t)) | ||
| 450 | 496 | ||
| 451 | (defun set-justification-right (b e) | 497 | (defun set-justification-right (b e) |
| 452 | "Make paragraphs in the region right-justified: | 498 | "Make paragraphs in the region right-justified: |
| 453 | Flush at the right margin and ragged on the left. | 499 | Flush at the right margin and ragged on the left. |
| 454 | If the mark is not active, this applies to the current paragraph." | 500 | If the mark is not active, this applies to the current paragraph." |
| 455 | (interactive "r") | 501 | (interactive (list (if mark-active (region-beginning) (point)) |
| 456 | (set-justification b e 'right)) | 502 | (if mark-active (region-end) (point)))) |
| 503 | (set-justification b e 'right t)) | ||
| 457 | 504 | ||
| 458 | (defun set-justification-full (b e) | 505 | (defun set-justification-full (b e) |
| 459 | "Make paragraphs in the region fully justified: | 506 | "Make paragraphs in the region fully justified: |
| 460 | Flush on both margins. | 507 | This makes lines flush on both margins by inserting spaces between words. |
| 461 | If the mark is not active, this applies to the current paragraph." | 508 | If the mark is not active, this applies to the current paragraph." |
| 462 | (interactive "r") | 509 | (interactive (list (if mark-active (region-beginning) (point)) |
| 463 | (set-justification b e 'both)) | 510 | (if mark-active (region-end) (point)))) |
| 511 | (set-justification b e 'full t)) | ||
| 464 | 512 | ||
| 465 | (defun set-justification-center (b e) | 513 | (defun set-justification-center (b e) |
| 466 | "Make paragraphs in the region centered. | 514 | "Make paragraphs in the region centered. |
| 467 | If the mark is not active, this applies to the current paragraph." | 515 | If the mark is not active, this applies to the current paragraph." |
| 468 | (interactive "r") | 516 | (interactive (list (if mark-active (region-beginning) (point)) |
| 469 | (set-justification b e 'center)) | 517 | (if mark-active (region-end) (point)))) |
| 518 | (set-justification b e 'center t)) | ||
| 519 | |||
| 520 | ;; A line has up to six parts: | ||
| 521 | ;; | ||
| 522 | ;; >>> hello. | ||
| 523 | ;; [Indent-1][FP][ Indent-2 ][text][trailing whitespace][newline] | ||
| 524 | ;; | ||
| 525 | ;; "Indent-1" is the left-margin indentation; normally it ends at column | ||
| 526 | ;; given by the `current-left-margin' function. | ||
| 527 | ;; "FP" is the fill-prefix. It can be any string, including whitespace. | ||
| 528 | ;; "Indent-2" is added to justify a line if the `current-justification' is | ||
| 529 | ;; `center' or `right'. In `left' and `full' justification regions, any | ||
| 530 | ;; whitespace there is part of the line's text, and should not be changed. | ||
| 531 | ;; Trailing whitespace is not counted as part of the line length when | ||
| 532 | ;; center- or right-justifying. | ||
| 533 | ;; | ||
| 534 | ;; All parts of the line are optional, although the final newline can | ||
| 535 | ;; only be missing on the last line of the buffer. | ||
| 470 | 536 | ||
| 471 | (defun justify-current-line (&optional how eop nosqueeze) | 537 | (defun justify-current-line (&optional how eop nosqueeze) |
| 472 | "Add spaces to line point is in, so it ends at `fill-column'. | 538 | "Do some kind of justification on this line. |
| 539 | Normally does full justification: adds spaces to the line to make it end at | ||
| 540 | the column given by `current-fill-column'. | ||
| 473 | Optional first argument HOW specifies alternate type of justification: | 541 | Optional first argument HOW specifies alternate type of justification: |
| 474 | it can be `left', `right', `full', `center', or `none'. | 542 | it can be `left', `right', `full', `center', or `none'. |
| 475 | If HOW is t, will justify however the `justification' function says. | 543 | If HOW is t, will justify however the `current-justification' function says to. |
| 476 | Any other value, including nil, is taken to mean `full'. | 544 | If HOW is nil or missing, full justification is done by default. |
| 477 | Second arg EOP non-nil means that this is the last line of the paragraph, so | 545 | Second arg EOP non-nil means that this is the last line of the paragraph, so |
| 478 | it will not be stretched by full justification. | 546 | it will not be stretched by full justification. |
| 479 | Third arg NOSQUEEZE non-nil means to leave interior whitespace unchanged, | 547 | Third arg NOSQUEEZE non-nil means to leave interior whitespace unchanged, |
| 480 | otherwise it is made canonical." | 548 | otherwise it is made canonical." |
| 481 | (interactive (list 'full nil nil)) | 549 | (interactive) |
| 482 | (if (eq t how) (setq how (or (current-justification) 'none))) | 550 | (if (eq t how) (setq how (or (current-justification) 'none))) |
| 483 | (or (memq how '(none left)) | 551 | (if (null how) (setq how 'full)) |
| 484 | (save-excursion | 552 | (or (memq how '(none left)) ; No action required for these. |
| 485 | (save-restriction | 553 | (let ((fc (current-fill-column)) |
| 486 | (let ((fc (current-fill-column)) | 554 | (pos (point-marker)) |
| 487 | ncols beg indent end) | 555 | fp-end ; point at end of fill prefix |
| 488 | (end-of-line) | 556 | beg ; point at beginning of line's text |
| 489 | (if (and use-hard-newlines (null eop) | 557 | end ; point at end of line's text |
| 490 | (get-text-property (point) 'hard)) | 558 | indent ; column of `beg' |
| 491 | (setq eop t)) | 559 | endcol ; column of `end' |
| 492 | (skip-chars-backward " \t") | 560 | ncols) ; new indent point or offset |
| 493 | (if (= (current-column) fc) | 561 | (end-of-line) |
| 494 | nil ;; Quick exit if it appears to be properly justified already. | 562 | ;; Check if this is the last line of the paragraph. |
| 495 | (setq end (point)) | 563 | (if (and use-hard-newlines (null eop) |
| 496 | (beginning-of-line) | 564 | (get-text-property (point) 'hard)) |
| 497 | (skip-chars-forward " \t") | 565 | (setq eop t)) |
| 498 | (if (and fill-prefix | 566 | (skip-chars-backward " \t") |
| 499 | (equal fill-prefix | 567 | ;; Quick exit if it appears to be properly justified already |
| 500 | (buffer-substring (point) | 568 | ;; or there is no text. |
| 501 | (min (point-max) | 569 | (if (or (bolp) |
| 502 | (+ (point) (length fill-prefix)))))) | 570 | (and (memq how '(full right)) |
| 503 | (forward-char (length fill-prefix))) | 571 | (= (current-column) fc))) |
| 504 | (setq indent (current-column)) | 572 | nil |
| 505 | (setq beg (point)) | 573 | (setq end (point)) |
| 506 | (goto-char end) | 574 | (beginning-of-line) |
| 507 | (cond ((or (eq 'none how) (eq 'left how)) | 575 | (skip-chars-forward " \t") |
| 508 | nil) | 576 | ;; Skip over fill-prefix. |
| 509 | ((eq 'right how) | 577 | (if (and fill-prefix |
| 510 | (setq ncols (- (+ indent (current-fill-column)) | 578 | (not (string-equal fill-prefix "")) |
| 511 | (current-column))) | 579 | (equal fill-prefix |
| 512 | (if (> ncols 0) | 580 | (buffer-substring |
| 513 | (indent-line-to ncols))) | 581 | (point) (min (point-max) (+ (length fill-prefix) |
| 514 | ((eq 'center how) | 582 | (point)))))) |
| 515 | (setq ncols | 583 | (forward-char (length fill-prefix)) |
| 516 | (/ (- (+ indent (current-fill-column)) (current-column)) | 584 | (if (and adaptive-fill-mode |
| 517 | 2)) | 585 | (looking-at adaptive-fill-regexp)) |
| 518 | (if (>= ncols 0) | 586 | (goto-char (match-end 0)))) |
| 519 | (indent-line-to ncols) | 587 | (setq fp-end (point)) |
| 520 | (message "Line to long to center"))) | 588 | (skip-chars-forward " \t") |
| 521 | (t ;; full | 589 | ;; This is beginning of the line's text. |
| 590 | (setq indent (current-column)) | ||
| 591 | (setq beg (point)) | ||
| 592 | (goto-char end) | ||
| 593 | (setq endcol (current-column)) | ||
| 594 | |||
| 595 | ;; HOW can't be null or left--we would have exited already | ||
| 596 | (cond ((eq 'right how) | ||
| 597 | (setq ncols (- fc endcol)) | ||
| 598 | (if (< ncols 0) | ||
| 599 | ;; Need to remove some indentation | ||
| 600 | (delete-region | ||
| 601 | (progn (goto-char fp-end) | ||
| 602 | (if (< (current-column) (+ indent ncols)) | ||
| 603 | (move-to-column (+ indent ncols) t)) | ||
| 604 | (point)) | ||
| 605 | (progn (move-to-column indent) (point))) | ||
| 606 | ;; Need to add some | ||
| 607 | (goto-char beg) | ||
| 608 | (indent-to (+ indent ncols)) | ||
| 609 | ;; If point was at beginning of text, keep it there. | ||
| 610 | (if (= beg pos) | ||
| 611 | (move-marker pos (point))))) | ||
| 612 | |||
| 613 | ((eq 'center how) | ||
| 614 | ;; Figure out how much indentation is needed | ||
| 615 | (setq ncols (+ (current-left-margin) | ||
| 616 | (/ (- fc (current-left-margin) ;avail. space | ||
| 617 | (- endcol indent)) ;text width | ||
| 618 | 2))) | ||
| 619 | (if (< ncols indent) | ||
| 620 | ;; Have too much indentation - remove some | ||
| 621 | (delete-region | ||
| 622 | (progn (goto-char fp-end) | ||
| 623 | (if (< (current-column) ncols) | ||
| 624 | (move-to-column ncols t)) | ||
| 625 | (point)) | ||
| 626 | (progn (move-to-column indent) (point))) | ||
| 627 | ;; Have too little - add some | ||
| 628 | (goto-char beg) | ||
| 629 | (indent-to ncols) | ||
| 630 | ;; If point was at beginning of text, keep it there. | ||
| 631 | (if (= beg pos) | ||
| 632 | (move-marker pos (point))))) | ||
| 633 | |||
| 634 | ((eq 'full how) | ||
| 635 | ;; Insert extra spaces between words to justify line | ||
| 636 | (save-restriction | ||
| 522 | (narrow-to-region beg end) | 637 | (narrow-to-region beg end) |
| 523 | (or nosqueeze | 638 | (or nosqueeze |
| 524 | (canonically-space-region beg end)) | 639 | (canonically-space-region beg end)) |
| 525 | (goto-char (point-max)) | 640 | (goto-char (point-max)) |
| 526 | (setq ncols (- (current-fill-column) indent (current-column))) | 641 | (setq ncols (- fc endcol)) |
| 527 | (if (< ncols 0) | 642 | ;; Ncols is number of additional spaces needed |
| 528 | (message "Line to long to justify") | 643 | (if (> ncols 0) |
| 529 | (if (and (not eop) | 644 | (if (and (not eop) |
| 530 | (search-backward " " nil t)) | 645 | (search-backward " " nil t)) |
| 531 | (while (> ncols 0) | 646 | (while (> ncols 0) |
| 532 | (let ((nmove (+ 3 (random 3)))) | 647 | (let ((nmove (+ 3 (random 3)))) |
| 533 | (while (> nmove 0) | 648 | (while (> nmove 0) |
| 534 | (or (search-backward " " nil t) | 649 | (or (search-backward " " nil t) |
| 535 | (progn | 650 | (progn |
| 536 | (goto-char (point-max)) | 651 | (goto-char (point-max)) |
| 537 | (search-backward " "))) | 652 | (search-backward " "))) |
| 538 | (skip-chars-backward " ") | 653 | (skip-chars-backward " ") |
| 539 | (setq nmove (1- nmove)))) | 654 | (setq nmove (1- nmove)))) |
| 540 | (insert-and-inherit " ") | 655 | (insert-and-inherit " ") |
| 541 | (skip-chars-backward " ") | 656 | (skip-chars-backward " ") |
| 542 | (setq ncols (1- ncols)))))))))))) | 657 | (setq ncols (1- ncols))))))) |
| 658 | (t (error "Unknown justification value")))) | ||
| 659 | (goto-char pos) | ||
| 660 | (move-marker pos nil))) | ||
| 543 | nil) | 661 | nil) |
| 544 | 662 | ||
| 663 | (defun unjustify-current-line () | ||
| 664 | "Remove justification whitespace from current line. | ||
| 665 | If the line is centered or right-justified, this function removes any | ||
| 666 | indentation past the left margin. If the line is full-jusitified, it removes | ||
| 667 | extra spaces between words. It does nothing in other justification modes." | ||
| 668 | (let ((justify (current-justification))) | ||
| 669 | (cond ((eq 'left justify) nil) | ||
| 670 | ((eq nil justify) nil) | ||
| 671 | ((eq 'full justify) ; full justify: remove extra spaces | ||
| 672 | (beginning-of-line-text) | ||
| 673 | (canonically-space-region | ||
| 674 | (point) (save-excursion (end-of-line) (point)))) | ||
| 675 | ((memq justify '(center right)) | ||
| 676 | (save-excursion | ||
| 677 | (move-to-left-margin nil t) | ||
| 678 | ;; Position ourselves after any fill-prefix. | ||
| 679 | (if (and fill-prefix | ||
| 680 | (not (string-equal fill-prefix "")) | ||
| 681 | (equal fill-prefix | ||
| 682 | (buffer-substring | ||
| 683 | (point) (min (point-max) (+ (length fill-prefix) | ||
| 684 | (point)))))) | ||
| 685 | (forward-char (length fill-prefix))) | ||
| 686 | (delete-region (point) (progn (skip-chars-forward " \t") | ||
| 687 | (point)))))))) | ||
| 688 | |||
| 689 | (defun unjustify-region (&optional begin end) | ||
| 690 | "Remove justification whitespace from region. | ||
| 691 | For centered or right-justified regions, this function removes any indentation | ||
| 692 | past the left margin from each line. For full-jusitified lines, it removes | ||
| 693 | extra spaces between words. It does nothing in other justification modes. | ||
| 694 | Arguments BEGIN and END are optional; default is the whole buffer." | ||
| 695 | (save-excursion | ||
| 696 | (save-restriction | ||
| 697 | (if end (narrow-to-region (point-min) end)) | ||
| 698 | (goto-char (or begin (point-min))) | ||
| 699 | (while (not (eobp)) | ||
| 700 | (unjustify-current-line) | ||
| 701 | (forward-line 1))))) | ||
| 702 | |||
| 545 | 703 | ||
| 546 | (defun fill-nonuniform-paragraphs (min max &optional justifyp mailp) | 704 | (defun fill-nonuniform-paragraphs (min max &optional justifyp mailp) |
| 547 | "Fill paragraphs within the region, allowing varying indentation within each. | 705 | "Fill paragraphs within the region, allowing varying indentation within each. |