comparison lisp/paragraphs.el @ 2549:9ec13301bb30

[xemacs-hg @ 2005-02-03 07:15:56 by ben] behavior ws #5: paragraphs.el sync to 21.3 paragraphs.el: Sync to 21.3. Depends on easy-mmode in core.
author ben
date Thu, 03 Feb 2005 07:15:56 +0000
parents d8c768dcca7a
children b880fa9b5d8a
comparison
equal deleted inserted replaced
2548:c4c8a36043be 2549:9ec13301bb30
1 ;;; paragraphs.el --- paragraph and sentence parsing. 1 ;;; paragraphs.el --- paragraph and sentence parsing
2 2
3 ;; Copyright (C) 1985, 86, 87, 91, 94, 95, 97, 2001 3 ;; Copyright (C) 1985, 86, 87, 91, 94, 95, 96, 1997, 1999, 2000, 2001
4 ;; Free Software Foundation, Inc. 4 ;; Free Software Foundation, Inc.
5 5
6 ;; Maintainer: FSF 6 ;; Maintainer: FSF
7 ;; Keywords: wp, dumped 7 ;; Keywords: wp, dumped
8 8
9 ;; This file is part of XEmacs. 9 ;; This file is part of XEmacs.
21 ;; You should have received a copy of the GNU General Public License 21 ;; You should have received a copy of the GNU General Public License
22 ;; along with XEmacs; see the file COPYING. If not, write to the Free 22 ;; along with XEmacs; see the file COPYING. If not, write to the Free
23 ;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 23 ;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
24 ;; 02111-1307, USA. 24 ;; 02111-1307, USA.
25 25
26 ;;; Synched up with: FSF 19.34. 26 ;;; Synched up with: FSF 21.3.
27 27
28 ;;; Commentary: 28 ;;; Commentary:
29 29
30 ;; This file is dumped with XEmacs. 30 ;; This file is dumped with XEmacs.
31 31
35 ;; 06/11/1997 - Use char-(after|before) instead of 35 ;; 06/11/1997 - Use char-(after|before) instead of
36 ;; (following|preceding)-char. -slb 36 ;; (following|preceding)-char. -slb
37 37
38 ;;; Code: 38 ;;; Code:
39 39
40 (defvar use-hard-newlines nil 40 (defgroup paragraphs nil
41 "Non-nil means to distinguish hard and soft newlines. 41 "Paragraph and sentence parsing."
42 When this is non-nil, the functions `newline' and `open-line' add the 42 :group 'editing)
43 text-property `hard' to newlines that they insert. Also, a line is 43
44 only considered as a candidate to match `paragraph-start' or 44 (define-minor-mode use-hard-newlines
45 `paragraph-separate' if it follows a hard newline. Newlines not
46 marked hard are called \"soft\", and are always internal to
47 paragraphs. The fill functions always insert soft newlines.
48
49 Each buffer has its own value of this variable.")
50 (make-variable-buffer-local 'use-hard-newlines)
51
52 (defun use-hard-newlines (&optional arg insert)
53 "Minor mode to distinguish hard and soft newlines. 45 "Minor mode to distinguish hard and soft newlines.
54 When active, the functions `newline' and `open-line' add the 46 When active, the functions `newline' and `open-line' add the
55 text-property `hard' to newlines that they insert, and a line is 47 text-property `hard' to newlines that they insert, and a line is
56 only considered as a candidate to match `paragraph-start' or 48 only considered as a candidate to match `paragraph-start' or
57 `paragraph-separate' if it follows a hard newline. 49 `paragraph-separate' if it follows a hard newline.
58 50
59 Prefix argument says to turn mode on if positive, off if negative. 51 Prefix argument says to turn mode on if positive, off if negative.
60 When the mode is turned on, if there are newlines in the buffer but no hard 52 When the mode is turned on, if there are newlines in the buffer but no hard
61 newlines, ask the user whether to mark as hard any newlines preceding a 53 newlines, ask the user whether to mark as hard any newlines preceeding a
62 `paragraph-start' line. From a program, second arg INSERT specifies whether 54 `paragraph-start' line. From a program, second arg INSERT specifies whether
63 to do this; it can be `never' to change nothing, t or `always' to force 55 to do this; it can be `never' to change nothing, t or `always' to force
64 marking, `guess' to try to do the right thing with no questions, nil 56 marking, `guess' to try to do the right thing with no questions, nil
65 or anything else to ask the user. 57 or anything else to ask the user.
66 58
67 Newlines not marked hard are called \"soft\", and are always internal 59 Newlines not marked hard are called \"soft\", and are always internal
68 to paragraphs. The fill functions insert and delete only soft newlines." 60 to paragraphs. The fill functions insert and delete only soft newlines."
69 (interactive (list current-prefix-arg nil)) 61 :group 'paragraphs
70 (if (or (<= (prefix-numeric-value arg) 0) 62 :extra-args (insert)
71 (and use-hard-newlines (null arg))) 63 (when use-hard-newlines
72 ;; Turn mode off
73 (setq use-hard-newlines nil)
74 ;; Turn mode on 64 ;; Turn mode on
75 ;; Intuit hard newlines -- 65 ;; Intuit hard newlines --
76 ;; mark as hard any newlines preceding a paragraph-start line. 66 ;; mark as hard any newlines preceding a paragraph-start line.
77 (if (or (eq insert t) (eq insert 'always) 67 (if (or (eq insert t) (eq insert 'always)
78 (and (not (eq 'never insert)) 68 (and (not (eq 'never insert))
79 (not use-hard-newlines)
80 (not (text-property-any (point-min) (point-max) 'hard t)) 69 (not (text-property-any (point-min) (point-max) 'hard t))
81 (save-excursion 70 (save-excursion
82 (goto-char (point-min)) 71 (goto-char (point-min))
83 (search-forward "\n" nil t)) 72 (search-forward "\n" nil t))
84 (or (eq insert 'guess) 73 (or (eq insert 'guess)
86 (save-excursion 75 (save-excursion
87 (goto-char (point-min)) 76 (goto-char (point-min))
88 (while (search-forward "\n" nil t) 77 (while (search-forward "\n" nil t)
89 (let ((pos (point))) 78 (let ((pos (point)))
90 (move-to-left-margin) 79 (move-to-left-margin)
91 (if (looking-at paragraph-start) 80 (when (looking-at paragraph-start)
92 (progn 81 (set-hard-newline-properties (1- pos) pos))
93 (set-hard-newline-properties (1- pos) pos) 82 ;; If paragraph-separate, newline after it is hard too.
94 ;; If paragraph-separate, newline after it is hard too. 83 (when (looking-at paragraph-separate)
95 (if (looking-at paragraph-separate) 84 (set-hard-newline-properties (1- pos) pos)
96 (progn 85 (end-of-line)
97 (end-of-line) 86 (unless (eobp)
98 (if (not (eobp)) 87 (set-hard-newline-properties (point) (1+ (point)))))))))))
99 (set-hard-newline-properties 88
100 (point) (1+ (point)))))))))))) 89 (defcustom paragraph-start "\f\\|[ \t]*$" "\
101 (setq use-hard-newlines t)))
102
103 (defconst paragraph-start "[ \t\n\f]" "\
104 *Regexp for beginning of a line that starts OR separates paragraphs. 90 *Regexp for beginning of a line that starts OR separates paragraphs.
105 This regexp should match lines that separate paragraphs 91 This regexp should match lines that separate paragraphs
106 and should also match lines that start a paragraph 92 and should also match lines that start a paragraph
107 \(and are part of that paragraph). 93 \(and are part of that paragraph).
108 94
113 99
114 The variable `paragraph-separate' specifies how to distinguish 100 The variable `paragraph-separate' specifies how to distinguish
115 lines that start paragraphs from lines that separate them. 101 lines that start paragraphs from lines that separate them.
116 102
117 If the variable `use-hard-newlines' is non-nil, then only lines following a 103 If the variable `use-hard-newlines' is non-nil, then only lines following a
118 hard newline are considered to match.") 104 hard newline are considered to match."
105 :group 'paragraphs
106 :type 'regexp)
119 107
120 ;; paragraph-start requires a hard newline, but paragraph-separate does not: 108 ;; paragraph-start requires a hard newline, but paragraph-separate does not:
121 ;; It is assumed that paragraph-separate is distinctive enough to be believed 109 ;; It is assumed that paragraph-separate is distinctive enough to be believed
122 ;; whenever it occurs, while it is reasonable to set paragraph-start to 110 ;; whenever it occurs, while it is reasonable to set paragraph-start to
123 ;; something very minimal, even including "." (which makes every hard newline 111 ;; something very minimal, even including "." (which makes every hard newline
124 ;; start a new paragraph). 112 ;; start a new paragraph).
125 113
126 (defconst paragraph-separate "[ \t\f]*$" "\ 114 (defcustom paragraph-separate "[ \t\f]*$"
127 *Regexp for beginning of a line that separates paragraphs. 115 "*Regexp for beginning of a line that separates paragraphs.
128 If you change this, you may have to change `paragraph-start' also. 116 If you change this, you may have to change `paragraph-start' also.
129 117
130 A line matching this is not part of any paragraph. 118 A line matching this is not part of any paragraph.
131 119
132 This is matched against the text at the left margin, which is not necessarily 120 This is matched against the text at the left margin, which is not necessarily
133 the beginning of the line, so it should not use \"^\" as an anchor. This 121 the beginning of the line, so it should not use \"^\" as an anchor. This
134 ensures that the paragraph functions will work equally within a region of 122 ensures that the paragraph functions will work equally within a region of
135 text indented by a margin setting.") 123 text indented by a margin setting."
136 124 :group 'paragraphs
137 (defconst sentence-end "[.?!][]\"')}]*\\($\\| $\\|\t\\| \\)[ \t\n]*" "\ 125 :type 'regexp)
138 *Regexp describing the end of a sentence. 126
127 (defcustom sentence-end-double-space t
128 "*Non-nil means a single space does not end a sentence.
129 This is relevant for filling. See also `sentence-end-without-period'
130 and `colon-double-space'.
131
132 This variable applies only to filling, not motion commands. To
133 change the behavior of motion commands, see `sentence-end'.
134
135 If you change this, you should also change `sentence-end'. See Info
136 node `Sentences'."
137 :type 'boolean
138 :group 'fill)
139
140 (defcustom sentence-end-without-period nil
141 "*Non-nil means a sentence will end without a period.
142 For example, a sentence in Thai text ends with double space but
143 without a period."
144 :type 'boolean
145 :group 'fill)
146
147 (defcustom sentence-end
148 (purecopy
149 ;; This is a bit stupid since it's not auto-updated when the
150 ;; other variables are changes, but it's still useful info.
151 (concat (if sentence-end-without-period "\\w \\|")
152 "[.?!$B!#!%!)!*$A!##.#?#!$(0!$!%!)!*$(G!$!%!)!*(B][]\"')}]*"
153 (if sentence-end-double-space
154 "\\($\\| $\\|\t\\| \\)" "\\($\\|[\t ]\\)")
155 "[ \t\n]*"))
156 "*Regexp describing the end of a sentence.
157 The value includes the whitespace following the sentence.
139 All paragraph boundaries also end sentences, regardless. 158 All paragraph boundaries also end sentences, regardless.
140 159
141 In order to be recognized as the end of a sentence, the ending period, 160 The default value specifies that in order to be recognized as the end
142 question mark, or exclamation point must be followed by two spaces, 161 of a sentence, the ending period, question mark, or exclamation point
143 unless it's inside some sort of quotes or parenthesis.") 162 must be followed by two spaces, unless it's inside some sort of quotes
144 163 or parenthesis.
145 (defconst page-delimiter "^\014" "\ 164
146 *Regexp describing line-beginnings that separate pages.") 165 See also the variable `sentence-end-double-space', the variable
147 166 `sentence-end-without-period' and Info node `Sentences'."
148 (defvar paragraph-ignore-fill-prefix nil "\ 167 :group 'paragraphs
149 Non-nil means the paragraph commands are not affected by `fill-prefix'. 168 :type 'regexp)
150 This is desirable in modes where blank lines are the paragraph delimiters.") 169
170 (defcustom page-delimiter "^\014"
171 "*Regexp describing line-beginnings that separate pages."
172 :group 'paragraphs
173 :type 'regexp)
174
175 (defcustom paragraph-ignore-fill-prefix nil
176 "*Non-nil means the paragraph commands are not affected by `fill-prefix'.
177 This is desirable in modes where blank lines are the paragraph delimiters."
178 :group 'paragraphs
179 :type 'boolean)
151 180
152 (defun forward-paragraph (&optional arg) 181 (defun forward-paragraph (&optional arg)
153 "Move forward to end of paragraph. 182 "Move forward to end of paragraph.
154 With arg N, do it N times; negative arg -N means move backward N paragraphs. 183 With argument ARG, do it ARG times;
184 a negative argument ARG = -N means move backward N paragraphs.
155 185
156 A line which `paragraph-start' matches either separates paragraphs 186 A line which `paragraph-start' matches either separates paragraphs
157 \(if `paragraph-separate' matches it also) or is the first line of a paragraph. 187 \(if `paragraph-separate' matches it also) or is the first line of a paragraph.
158 A paragraph end is the beginning of a line which is not part of the paragraph 188 A paragraph end is the beginning of a line which is not part of the paragraph
159 to which the end of the previous line belongs, or the end of the buffer." 189 to which the end of the previous line belongs, or the end of the buffer.
190 Returns the count of paragraphs left to move."
160 (interactive "_p") ; XEmacs 191 (interactive "_p") ; XEmacs
161 (or arg (setq arg 1)) 192 (or arg (setq arg 1))
162 (let* ((fill-prefix-regexp 193 (let* ((opoint (point))
194 (fill-prefix-regexp
163 (and fill-prefix (not (equal fill-prefix "")) 195 (and fill-prefix (not (equal fill-prefix ""))
164 (not paragraph-ignore-fill-prefix) 196 (not paragraph-ignore-fill-prefix)
165 (regexp-quote fill-prefix))) 197 (regexp-quote fill-prefix)))
166 ;; Remove ^ from paragraph-start and paragraph-sep if they are there. 198 ;; Remove ^ from paragraph-start and paragraph-sep if they are there.
167 ;; These regexps shouldn't be anchored, because we look for them 199 ;; These regexps shouldn't be anchored, because we look for them
168 ;; starting at the left-margin. This allows paragraph commands to 200 ;; starting at the left-margin. This allows paragraph commands to
169 ;; work normally with indented text. 201 ;; work normally with indented text.
170 ;; This hack will not find problem cases like "whatever\\|^something". 202 ;; This hack will not find problem cases like "whatever\\|^something".
171 (paragraph-start (if (and (not (equal "" paragraph-start)) 203 (parstart (if (and (not (equal "" paragraph-start))
172 (equal ?^ (aref paragraph-start 0))) 204 (equal ?^ (aref paragraph-start 0)))
173 (substring paragraph-start 1) 205 (substring paragraph-start 1)
174 paragraph-start)) 206 paragraph-start))
175 (paragraph-separate (if (and (not (equal "" paragraph-start)) 207 (parsep (if (and (not (equal "" paragraph-separate))
176 (equal ?^ (aref paragraph-separate 0))) 208 (equal ?^ (aref paragraph-separate 0)))
177 (substring paragraph-separate 1) 209 (substring paragraph-separate 1)
178 paragraph-separate)) 210 paragraph-separate))
179 (paragraph-separate 211 (parsep
180 (if fill-prefix-regexp 212 (if fill-prefix-regexp
181 (concat paragraph-separate "\\|" 213 (concat parsep "\\|"
182 fill-prefix-regexp "[ \t]*$") 214 fill-prefix-regexp "[ \t]*$")
183 paragraph-separate)) 215 parsep))
184 ;; This is used for searching. 216 ;; This is used for searching.
185 (sp-paragraph-start (concat "^[ \t]*\\(" paragraph-start "\\)")) 217 (sp-parstart (concat "^[ \t]*\\(?:" parstart "\\|" parsep "\\)"))
186 start) 218 start found-start)
187 (while (and (< arg 0) (not (bobp))) 219 (while (and (< arg 0) (not (bobp)))
188 (if (and (not (looking-at paragraph-separate)) 220 (if (and (not (looking-at parsep))
189 (re-search-backward "^\n" (max (1- (point)) (point-min)) t) 221 (re-search-backward "^\n" (max (1- (point)) (point-min)) t)
190 (looking-at paragraph-separate)) 222 (looking-at parsep))
191 nil 223 (setq arg (1+ arg))
192 (setq start (point)) 224 (setq start (point))
193 ;; Move back over paragraph-separating lines. 225 ;; Move back over paragraph-separating lines.
194 (backward-char 1) (beginning-of-line) 226 (backward-char 1) (beginning-of-line)
195 (while (and (not (bobp)) 227 (while (and (not (bobp))
196 (progn (move-to-left-margin) 228 (progn (move-to-left-margin)
197 (looking-at paragraph-separate))) 229 (looking-at parsep)))
198 (forward-line -1)) 230 (forward-line -1))
199 (if (bobp) 231 (if (bobp)
200 nil 232 nil
233 (setq arg (1+ arg))
201 ;; Go to end of the previous (non-separating) line. 234 ;; Go to end of the previous (non-separating) line.
202 (end-of-line) 235 (end-of-line)
203 ;; Search back for line that starts or separates paragraphs. 236 ;; Search back for line that starts or separates paragraphs.
204 (if (if fill-prefix-regexp 237 (if (if fill-prefix-regexp
205 ;; There is a fill prefix; it overrides paragraph-start. 238 ;; There is a fill prefix; it overrides parstart.
206 (let (multiple-lines) 239 (let (multiple-lines)
207 (while (and (progn (beginning-of-line) (not (bobp))) 240 (while (and (progn (beginning-of-line) (not (bobp)))
208 (progn (move-to-left-margin) 241 (progn (move-to-left-margin)
209 (not (looking-at paragraph-separate))) 242 (not (looking-at parsep)))
210 (looking-at fill-prefix-regexp)) 243 (looking-at fill-prefix-regexp))
211 (if (not (= (point) start)) 244 (unless (= (point) start)
212 (setq multiple-lines t)) 245 (setq multiple-lines t))
213 (forward-line -1)) 246 (forward-line -1))
214 (move-to-left-margin) 247 (move-to-left-margin)
215 ;; Don't move back over a line before the paragraph 248 ;; This deleted code caused a long hanging-indent line
216 ;; which doesn't start with fill-prefix 249 ;; not to be filled together with the following lines.
217 ;; unless that is the only line we've moved over. 250 ;; ;; Don't move back over a line before the paragraph
218 (and (not (looking-at fill-prefix-regexp)) 251 ;; ;; which doesn't start with fill-prefix
219 multiple-lines 252 ;; ;; unless that is the only line we've moved over.
220 (forward-line 1)) 253 ;; (and (not (looking-at fill-prefix-regexp))
254 ;; multiple-lines
255 ;; (forward-line 1))
221 (not (bobp))) 256 (not (bobp)))
222 (while (and (re-search-backward sp-paragraph-start nil 1) 257 (while (and (re-search-backward sp-parstart nil 1)
258 (setq found-start t)
223 ;; Found a candidate, but need to check if it is a 259 ;; Found a candidate, but need to check if it is a
224 ;; REAL paragraph-start. 260 ;; REAL parstart.
225 (not (bobp))
226 (progn (setq start (point)) 261 (progn (setq start (point))
227 (move-to-left-margin) 262 (move-to-left-margin)
228 (not (looking-at paragraph-separate))) 263 (not (looking-at parsep)))
229 (or (not (looking-at paragraph-start)) 264 (not (and (looking-at parstart)
230 (and use-hard-newlines 265 (or (not use-hard-newlines)
231 (not (get-text-property (1- start) 266 (get-text-property (1- start) 'hard)
232 'hard))))) 267 (bobp)))))
268 (setq found-start nil)
233 (goto-char start)) 269 (goto-char start))
234 (> (point) (point-min))) 270 found-start)
235 ;; Found one. 271 ;; Found one.
236 (progn 272 (progn
237 ;; Move forward over paragraph separators. 273 ;; Move forward over paragraph separators.
238 ;; We know this cannot reach the place we started 274 ;; We know this cannot reach the place we started
239 ;; because we know we moved back over a non-separator. 275 ;; because we know we moved back over a non-separator.
240 (while (and (not (eobp)) 276 (while (and (not (eobp))
241 (progn (move-to-left-margin) 277 (progn (move-to-left-margin)
242 (looking-at paragraph-separate))) 278 (looking-at parsep)))
243 (forward-line 1)) 279 (forward-line 1))
244 ;; If line before paragraph is just margin, back up to there. 280 ;; If line before paragraph is just margin, back up to there.
245 (end-of-line 0) 281 (end-of-line 0)
246 (if (> (current-column) (current-left-margin)) 282 (if (> (current-column) (current-left-margin))
247 (forward-char 1) 283 (forward-char 1)
248 (skip-chars-backward " \t") 284 (skip-chars-backward " \t")
249 (if (not (bolp)) 285 (if (not (bolp))
250 (forward-line 1)))) 286 (forward-line 1))))
251 ;; No starter or separator line => use buffer beg. 287 ;; No starter or separator line => use buffer beg.
252 (goto-char (point-min))))) 288 (goto-char (point-min))))))
253 (setq arg (1+ arg))) 289
254 (while (and (> arg 0) (not (eobp))) 290 (while (and (> arg 0) (not (eobp)))
255 ;; Move forward over separator lines, and one more line. 291 ;; Move forward over separator lines...
256 (while (prog1 (and (not (eobp)) 292 (while (and (not (eobp))
257 (progn (move-to-left-margin) (not (eobp))) 293 (progn (move-to-left-margin) (not (eobp)))
258 (looking-at paragraph-separate)) 294 (looking-at parsep))
259 (forward-line 1))) 295 (forward-line 1))
296 (unless (eobp) (setq arg (1- arg)))
297 ;; ... and one more line.
298 (forward-line 1)
260 (if fill-prefix-regexp 299 (if fill-prefix-regexp
261 ;; There is a fill prefix; it overrides paragraph-start. 300 ;; There is a fill prefix; it overrides parstart.
262 (while (and (not (eobp)) 301 (while (and (not (eobp))
263 (progn (move-to-left-margin) (not (eobp))) 302 (progn (move-to-left-margin) (not (eobp)))
264 (not (looking-at paragraph-separate)) 303 (not (looking-at parsep))
265 (looking-at fill-prefix-regexp)) 304 (looking-at fill-prefix-regexp))
266 (forward-line 1)) 305 (forward-line 1))
267 (while (and (re-search-forward sp-paragraph-start nil 1) 306 (while (and (re-search-forward sp-parstart nil 1)
268 (progn (setq start (match-beginning 0)) 307 (progn (setq start (match-beginning 0))
269 (goto-char start) 308 (goto-char start)
270 (not (eobp))) 309 (not (eobp)))
271 (progn (move-to-left-margin) 310 (progn (move-to-left-margin)
272 (not (looking-at paragraph-separate))) 311 (not (looking-at parsep)))
273 (or (not (looking-at paragraph-start)) 312 (or (not (looking-at parstart))
274 (and use-hard-newlines 313 (and use-hard-newlines
275 (not (get-text-property (1- start) 'hard))))) 314 (not (get-text-property (1- start) 'hard)))))
276 (forward-char 1)) 315 (forward-char 1))
277 (if (< (point) (point-max)) 316 (if (< (point) (point-max))
278 (goto-char start))) 317 (goto-char start))))
279 (setq arg (1- arg))))) 318 (constrain-to-field nil opoint t)
319 ;; Return the number of steps that could not be done.
320 arg))
280 321
281 (defun backward-paragraph (&optional arg) 322 (defun backward-paragraph (&optional arg)
282 "Move backward to start of paragraph. 323 "Move backward to start of paragraph.
283 With arg N, do it N times; negative arg -N means move forward N paragraphs. 324 With argument ARG, do it ARG times;
325 a negative argument ARG = -N means move forward N paragraphs.
284 326
285 A paragraph start is the beginning of a line which is a 327 A paragraph start is the beginning of a line which is a
286 `first-line-of-paragraph' or which is ordinary text and follows a 328 `first-line-of-paragraph' or which is ordinary text and follows a
287 paragraph-separating line; except: if the first real line of a 329 paragraph-separating line; except: if the first real line of a
288 paragraph is preceded by a blank line, the paragraph starts at that 330 paragraph is preceded by a blank line, the paragraph starts at that
294 (forward-paragraph (- arg))) 336 (forward-paragraph (- arg)))
295 337
296 (defun mark-paragraph (&optional arg) 338 (defun mark-paragraph (&optional arg)
297 "Put point at beginning of this paragraph, mark at end. 339 "Put point at beginning of this paragraph, mark at end.
298 The paragraph marked is the one that contains point or follows point. 340 The paragraph marked is the one that contains point or follows point.
299 With arg N, puts mark at end of following N paragraphs; 341
300 negative arg -N means point is put at end of this paragraph, mark is put 342 With argument ARG, puts mark at end of a following paragraph, so that
301 at beginning of this or a previous paragraph." 343 the number of paragraphs marked equals ARG.
344
345 If ARG is negative, point is put at end of this paragraph, mark is put
346 at beginning of this or a previous paragraph.
347
348 If this command is repeated, it marks the next ARG paragraphs after (or
349 before, if arg is negative) the ones already marked."
302 (interactive "p") 350 (interactive "p")
303 (unless arg (setq arg 1)) 351 (unless arg (setq arg 1))
304 (when (zerop arg) 352 (when (zerop arg)
305 (error "Cannot mark zero paragraphs")) 353 (error "Cannot mark zero paragraphs"))
306 (forward-paragraph arg) 354 (cond ((and (eq last-command this-command) (mark t))
307 (push-mark nil t t) 355 (set-mark
308 (backward-paragraph arg)) 356 (save-excursion
357 (goto-char (mark))
358 (forward-paragraph arg)
359 (point))))
360 (t
361 (forward-paragraph arg)
362 (push-mark nil t t)
363 (backward-paragraph arg))))
309 364
310 (defun kill-paragraph (arg) 365 (defun kill-paragraph (arg)
311 "Kill forward to end of paragraph. 366 "Kill forward to end of paragraph.
312 With arg N, kill forward to Nth end of paragraph; 367 With arg N, kill forward to Nth end of paragraph;
313 negative arg -N means kill backward to Nth start of paragraph." 368 negative arg -N means kill backward to Nth start of paragraph."
357 412
358 The variable `sentence-end' is a regular expression that matches ends of 413 The variable `sentence-end' is a regular expression that matches ends of
359 sentences. A paragraph boundary also terminates a sentence." 414 sentences. A paragraph boundary also terminates a sentence."
360 (interactive "_p") ; XEmacs 415 (interactive "_p") ; XEmacs
361 (or arg (setq arg 1)) 416 (or arg (setq arg 1))
362 (while (< arg 0) 417 (let ((opoint (point)))
363 (let ((par-beg (save-excursion (start-of-paragraph-text) (point)))) 418 (while (< arg 0)
364 (if (re-search-backward (concat sentence-end "[^ \t\n]") par-beg t) 419 (let ((pos (point))
365 (goto-char (1- (match-end 0))) 420 (par-beg (save-excursion (start-of-paragraph-text) (point))))
366 (goto-char par-beg))) 421 (if (and (re-search-backward sentence-end par-beg t)
367 (setq arg (1+ arg))) 422 (or (< (match-end 0) pos)
368 (while (> arg 0) 423 (re-search-backward sentence-end par-beg t)))
369 (let ((par-end (save-excursion (end-of-paragraph-text) (point)))) 424 (goto-char (match-end 0))
370 (if (re-search-forward sentence-end par-end t) 425 (goto-char par-beg)))
371 (skip-chars-backward " \t\n") 426 (setq arg (1+ arg)))
372 (goto-char par-end))) 427 (while (> arg 0)
373 (setq arg (1- arg)))) 428 (let ((par-end (save-excursion (end-of-paragraph-text) (point))))
429 (if (re-search-forward sentence-end par-end t)
430 (skip-chars-backward " \t\n")
431 (goto-char par-end)))
432 (setq arg (1- arg)))
433 (constrain-to-field nil opoint t)))
374 434
375 (defun backward-sentence (&optional arg) 435 (defun backward-sentence (&optional arg)
376 "Move backward to start of sentence. With arg, do it arg times. 436 "Move backward to start of sentence. With arg, do it arg times.
377 See `forward-sentence' for more information." 437 See `forward-sentence' for more information."
378 (interactive "_p") ; XEmacs 438 (interactive "_p") ; XEmacs
390 With arg, repeat, or kill forward to Nth end of sentence if negative arg -N." 450 With arg, repeat, or kill forward to Nth end of sentence if negative arg -N."
391 (interactive "*p") ; XEmacs 451 (interactive "*p") ; XEmacs
392 (kill-region (point) (progn (backward-sentence arg) (point)))) 452 (kill-region (point) (progn (backward-sentence arg) (point))))
393 453
394 (defun mark-end-of-sentence (arg) 454 (defun mark-end-of-sentence (arg)
395 "Put mark at end of sentence. Arg works as in `forward-sentence'." 455 "Put mark at end of sentence. Arg works as in `forward-sentence'.
456 If this command is repeated, it marks the next ARG sentences after the
457 ones already marked."
396 (interactive "p") 458 (interactive "p")
397 ;; FSF Version: 459 ;; FSF Version:
398 ; (push-mark 460 ; (push-mark
399 ; (save-excursion 461 ; (save-excursion
400 ; (forward-sentence arg) 462 ; (if (and (eq last-command this-command) (mark t))
401 ; (point)) 463 ; (goto-char (mark)))
402 ; nil t)) 464 ; (forward-sentence arg)
465 ; (point))
466 ; nil t))
403 (mark-something 'mark-end-of-sentence 'forward-sentence arg)) 467 (mark-something 'mark-end-of-sentence 'forward-sentence arg))
404 468
405 (defun mark-end-of-line (arg) 469 (defun mark-end-of-line (arg)
406 "Put mark at end of line. Arg works as in `end-of-line'." 470 "Put mark at end of line. Arg works as in `end-of-line'."
407 (interactive "p") 471 (interactive "p")
408 (mark-something 'mark-end-of-line 'end-of-line arg)) 472 (mark-something 'mark-end-of-line 'end-of-line arg))
409 473
410
411 (defun transpose-sentences (arg) 474 (defun transpose-sentences (arg)
412 "Interchange this (next) and previous sentence." 475 "Interchange this (next) and previous sentence."
413 (interactive "*p") 476 (interactive "*p")
414 (transpose-subr 'forward-sentence arg)) 477 (transpose-subr 'forward-sentence arg))
415 478
479 ;;; Local Variables:
480 ;;; coding: iso-2022-7bit
481 ;;; End:
482
416 ;;; paragraphs.el ends here 483 ;;; paragraphs.el ends here