Mercurial > hg > xemacs-beta
comparison lisp/prim/paragraphs.el @ 0:376386a54a3c r19-14
Import from CVS: tag r19-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:45:50 +0200 |
parents | |
children | b82b59fe008d |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:376386a54a3c |
---|---|
1 ;;; paragraphs.el --- paragraph and sentence parsing. | |
2 | |
3 ;; Copyright (C) 1985, 1986, 1987, 1991, 1993, 1994, 1995 | |
4 ;; Free Software Foundation, Inc. | |
5 | |
6 ;; Maintainer: FSF | |
7 ;; Keywords: wp | |
8 | |
9 ;; This file is part of XEmacs. | |
10 | |
11 ;; XEmacs is free software; you can redistribute it and/or modify it | |
12 ;; under the terms of the GNU General Public License as published by | |
13 ;; the Free Software Foundation; either version 2, or (at your option) | |
14 ;; any later version. | |
15 | |
16 ;; XEmacs is distributed in the hope that it will be useful, but | |
17 ;; WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 ;; General Public License for more details. | |
20 | |
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 | |
23 ;; Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | |
24 | |
25 ;;; Synched up with: FSF 19.30. | |
26 | |
27 ;;; Commentary: | |
28 | |
29 ;; This package provides the paragraph-oriented commands documented in the | |
30 ;; XEmacs Reference Manual. | |
31 | |
32 ;;; Code: | |
33 | |
34 (defvar use-hard-newlines nil | |
35 "Non-nil means to distinguish hard and soft newlines. | |
36 When this is non-nil, the functions `newline' and `open-line' add the | |
37 text-property `hard' to newlines that they insert. Also, a line is | |
38 only considered as a candidate to match `paragraph-start' or | |
39 `paragraph-separate' if it follows a hard newline. Newlines not | |
40 marked hard are called \"soft\", and are always internal to | |
41 paragraphs. The fill functions always insert soft newlines. | |
42 | |
43 Each buffer has its own value of this variable.") | |
44 (make-variable-buffer-local 'use-hard-newlines) | |
45 | |
46 (defconst paragraph-start (purecopy "[ \t\n\f]") "\ | |
47 *Regexp for beginning of a line that starts OR separates paragraphs. | |
48 This regexp should match lines that separate paragraphs | |
49 and should also match lines that start a paragraph | |
50 \(and are part of that paragraph). | |
51 | |
52 This is matched against the text at the left margin, which is not necessarily | |
53 the beginning of the line, so it should never use \"^\" as an anchor. This | |
54 ensures that the paragraph functions will work equally well within a region | |
55 of text indented by a margin setting. | |
56 | |
57 The variable `paragraph-separate' specifies how to distinguish | |
58 lines that start paragraphs from lines that separate them. | |
59 | |
60 If the variable `use-hard-newlines' is nonnil, then only lines following a | |
61 hard newline are considered to match.") | |
62 | |
63 ;; paragraph-start requires a hard newline, but paragraph-separate does not: | |
64 ;; It is assumed that paragraph-separate is distinctive enough to be believed | |
65 ;; whenever it occurs, while it is reasonable to set paragraph-start to | |
66 ;; something very minimal, even including "." (which makes every hard newline | |
67 ;; start a new paragraph). | |
68 | |
69 (defconst paragraph-separate (purecopy "[ \t\f]*$") "\ | |
70 *Regexp for beginning of a line that separates paragraphs. | |
71 If you change this, you may have to change paragraph-start also. | |
72 | |
73 This is matched against the text at the left margin, which is not necessarily | |
74 the beginning of the line, so it should not use \"^\" as an anchor. This | |
75 ensures that the paragraph functions will work equally within a region of | |
76 text indented by a margin setting.") | |
77 | |
78 (defconst sentence-end (purecopy "[.?!][]\"')}]*\\($\\| $\\|\t\\| \\)[ \t\n]*") "\ | |
79 *Regexp describing the end of a sentence. | |
80 All paragraph boundaries also end sentences, regardless. | |
81 | |
82 In order to be recognized as the end of a sentence, the ending period, | |
83 question mark, or exclamation point must be followed by two spaces, | |
84 unless it's inside some sort of quotes or parenthesis.") | |
85 | |
86 (defconst page-delimiter (purecopy "^\014") "\ | |
87 *Regexp describing line-beginnings that separate pages.") | |
88 | |
89 (defvar paragraph-ignore-fill-prefix nil "\ | |
90 Non-nil means the paragraph commands are not affected by `fill-prefix'. | |
91 This is desirable in modes where blank lines are the paragraph delimiters.") | |
92 | |
93 (defun forward-paragraph (&optional arg) | |
94 "Move forward to end of paragraph. | |
95 With arg N, do it N times; negative arg -N means move backward N paragraphs. | |
96 | |
97 A line which `paragraph-start' matches either separates paragraphs | |
98 \(if `paragraph-separate' matches it also) or is the first line of a paragraph. | |
99 A paragraph end is the beginning of a line which is not part of the paragraph | |
100 to which the end of the previous line belongs, or the end of the buffer." | |
101 (interactive "_p") | |
102 (or arg (setq arg 1)) | |
103 (let* ((fill-prefix-regexp | |
104 (and fill-prefix (not (equal fill-prefix "")) | |
105 (not paragraph-ignore-fill-prefix) | |
106 (regexp-quote fill-prefix))) | |
107 ;; Remove ^ from paragraph-start and paragraph-sep if they are there. | |
108 ;; These regexps shouldn't be anchored, because we look for them | |
109 ;; starting at the left-margin. This allows paragraph commands to | |
110 ;; work normally with indented text. | |
111 ;; This hack will not find problem cases like "whatever\\|^something". | |
112 (paragraph-start (if (and (not (equal "" paragraph-start)) | |
113 (equal ?^ (aref paragraph-start 0))) | |
114 (substring paragraph-start 1) | |
115 paragraph-start)) | |
116 (paragraph-separate (if (and (not (equal "" paragraph-start)) | |
117 (equal ?^ (aref paragraph-separate 0))) | |
118 (substring paragraph-separate 1) | |
119 paragraph-separate)) | |
120 (paragraph-separate | |
121 (if fill-prefix-regexp | |
122 (concat paragraph-separate "\\|" | |
123 fill-prefix-regexp "[ \t]*$") | |
124 paragraph-separate)) | |
125 ;; This is used for searching. | |
126 (sp-paragraph-start (concat "^[ \t]*\\(" paragraph-start "\\)")) | |
127 start) | |
128 (while (and (< arg 0) (not (bobp))) | |
129 (if (and (not (looking-at paragraph-separate)) | |
130 (re-search-backward "^\n" (max (1- (point)) (point-min)) t) | |
131 (looking-at paragraph-separate)) | |
132 nil | |
133 (setq start (point)) | |
134 ;; Move back over paragraph-separating lines. | |
135 (forward-char -1) (beginning-of-line) | |
136 (while (and (not (bobp)) | |
137 (progn (move-to-left-margin) | |
138 (looking-at paragraph-separate))) | |
139 (forward-line -1)) | |
140 (if (bobp) | |
141 nil | |
142 (progn | |
143 ;; Go to end of the previous (non-separating) line. | |
144 (end-of-line) | |
145 ;; Search back for line that starts or separates paragraphs. | |
146 (if (if fill-prefix-regexp | |
147 ;; There is a fill prefix; it overrides paragraph-start. | |
148 (let (multiple-lines) | |
149 (while (and (progn (beginning-of-line) (not (bobp))) | |
150 (progn (move-to-left-margin) | |
151 (not (looking-at paragraph-separate))) | |
152 (looking-at fill-prefix-regexp)) | |
153 (if (not (= (point) start)) | |
154 (setq multiple-lines t)) | |
155 (forward-line -1)) | |
156 (move-to-left-margin) | |
157 ;; Don't move back over a line before the paragraph | |
158 ;; which doesn't start with fill-prefix | |
159 ;; unless that is the only line we've moved over. | |
160 (and (not (looking-at fill-prefix-regexp)) | |
161 multiple-lines | |
162 (forward-line 1)) | |
163 (not (bobp))) | |
164 (while (and (re-search-backward sp-paragraph-start nil 1) | |
165 ;; Found a candidate, but need to check if it is a | |
166 ;; REAL paragraph-start. | |
167 (not (bobp)) | |
168 (progn (setq start (point)) | |
169 (move-to-left-margin) | |
170 (not (looking-at paragraph-separate))) | |
171 (or (not (looking-at paragraph-start)) | |
172 (and use-hard-newlines | |
173 (not (get-text-property (1- start) | |
174 'hard))))) | |
175 (goto-char start)) | |
176 (> (point) (point-min))) | |
177 ;; Found one. | |
178 (progn | |
179 ;; Move forward over paragraph separators. | |
180 ;; We know this cannot reach the place we started | |
181 ;; because we know we moved back over a non-separator. | |
182 (while (and (not (eobp)) | |
183 (progn (move-to-left-margin) | |
184 (looking-at paragraph-separate))) | |
185 (forward-line 1)) | |
186 ;; If line before paragraph is just margin, back up to there. | |
187 (end-of-line 0) | |
188 (if (> (current-column) (current-left-margin)) | |
189 (forward-char 1) | |
190 (skip-chars-backward " \t") | |
191 (if (not (bolp)) | |
192 (forward-line 1)))) | |
193 ;; No starter or separator line => use buffer beg. | |
194 (goto-char (point-min)))))) | |
195 (setq arg (1+ arg))) | |
196 (while (and (> arg 0) (not (eobp))) | |
197 (while (prog1 (and (not (eobp)) | |
198 (progn (move-to-left-margin) (not (eobp))) | |
199 (looking-at paragraph-separate)) | |
200 (forward-line 1))) | |
201 (if fill-prefix-regexp | |
202 ;; There is a fill prefix; it overrides paragraph-start. | |
203 (while (and (not (eobp)) | |
204 (progn (move-to-left-margin) (not (eobp))) | |
205 (not (looking-at paragraph-separate)) | |
206 (looking-at fill-prefix-regexp)) | |
207 (forward-line 1)) | |
208 (while (and (re-search-forward sp-paragraph-start nil 1) | |
209 (progn (setq start (match-beginning 0)) | |
210 (goto-char start) | |
211 (not (eobp))) | |
212 (progn (move-to-left-margin) | |
213 (not (looking-at paragraph-separate))) | |
214 (or (not (looking-at paragraph-start)) | |
215 (and use-hard-newlines | |
216 (not (get-text-property (1- start) 'hard))))) | |
217 (forward-char 1)) | |
218 (if (< (point) (point-max)) | |
219 (goto-char start))) | |
220 (setq arg (1- arg))))) | |
221 | |
222 (defun backward-paragraph (&optional arg) | |
223 "Move backward to start of paragraph. | |
224 With arg N, do it N times; negative arg -N means move forward N paragraphs. | |
225 | |
226 A paragraph start is the beginning of a line which is a | |
227 `first-line-of-paragraph' or which is ordinary text and follows a | |
228 paragraph-separating line; except: if the first real line of a | |
229 paragraph is preceded by a blank line, the paragraph starts at that | |
230 blank line. | |
231 | |
232 See `forward-paragraph' for more information." | |
233 (interactive "_p") | |
234 (or arg (setq arg 1)) | |
235 (forward-paragraph (- arg))) | |
236 | |
237 (defun mark-paragraph () | |
238 "Put point at beginning of this paragraph, mark at end. | |
239 The paragraph marked is the one that contains point or follows point." | |
240 (interactive) | |
241 (forward-paragraph 1) | |
242 (push-mark nil t t) | |
243 (backward-paragraph 1)) | |
244 | |
245 (defun kill-paragraph (arg) | |
246 "Kill forward to end of paragraph. | |
247 With arg N, kill forward to Nth end of paragraph; | |
248 negative arg -N means kill backward to Nth start of paragraph." | |
249 (interactive "*p") | |
250 (kill-region (point) (progn (forward-paragraph arg) (point)))) | |
251 | |
252 (defun backward-kill-paragraph (arg) | |
253 "Kill back to start of paragraph. | |
254 With arg N, kill back to Nth start of paragraph; | |
255 negative arg -N means kill forward to Nth end of paragraph." | |
256 (interactive "*p") | |
257 (kill-region (point) (progn (backward-paragraph arg) (point)))) | |
258 | |
259 (defun transpose-paragraphs (arg) | |
260 "Interchange this (or next) paragraph with previous one." | |
261 (interactive "*p") | |
262 (transpose-subr 'forward-paragraph arg)) | |
263 | |
264 (defun start-of-paragraph-text () | |
265 (let ((opoint (point)) npoint) | |
266 (forward-paragraph -1) | |
267 (setq npoint (point)) | |
268 (skip-chars-forward " \t\n") | |
269 ;; If the range of blank lines found spans the original start point, | |
270 ;; try again from the beginning of it. | |
271 ;; Must be careful to avoid infinite loop | |
272 ;; when following a single return at start of buffer. | |
273 (if (and (>= (point) opoint) (< npoint opoint)) | |
274 (progn | |
275 (goto-char npoint) | |
276 (if (> npoint (point-min)) | |
277 (start-of-paragraph-text)))))) | |
278 | |
279 (defun end-of-paragraph-text () | |
280 (let ((opoint (point))) | |
281 (forward-paragraph 1) | |
282 (if (eq (preceding-char) ?\n) (forward-char -1)) | |
283 (if (<= (point) opoint) | |
284 (progn | |
285 (forward-char 1) | |
286 (if (< (point) (point-max)) | |
287 (end-of-paragraph-text)))))) | |
288 | |
289 (defun forward-sentence (&optional arg) | |
290 "Move forward to next `sentence-end'. With argument, repeat. | |
291 With negative argument, move backward repeatedly to `sentence-beginning'. | |
292 | |
293 The variable `sentence-end' is a regular expression that matches ends | |
294 of sentences. Also, every paragraph boundary terminates sentences as | |
295 well." | |
296 (interactive "_p") | |
297 (or arg (setq arg 1)) | |
298 (while (< arg 0) | |
299 (let ((par-beg (save-excursion (start-of-paragraph-text) (point)))) | |
300 (if (re-search-backward (concat sentence-end "[^ \t\n]") par-beg t) | |
301 (goto-char (1- (match-end 0))) | |
302 (goto-char par-beg))) | |
303 (setq arg (1+ arg))) | |
304 (while (> arg 0) | |
305 (let ((par-end (save-excursion (end-of-paragraph-text) (point)))) | |
306 (if (re-search-forward sentence-end par-end t) | |
307 (skip-chars-backward " \t\n") | |
308 (goto-char par-end))) | |
309 (setq arg (1- arg)))) | |
310 | |
311 (defun backward-sentence (&optional arg) | |
312 "Move backward to start of sentence. With arg, do it arg times. | |
313 See `forward-sentence' for more information." | |
314 (interactive "_p") | |
315 (or arg (setq arg 1)) | |
316 (forward-sentence (- arg))) | |
317 | |
318 (defun kill-sentence (&optional arg) | |
319 "Kill from point to end of sentence. | |
320 With arg, repeat; negative arg -N means kill back to Nth start of sentence." | |
321 (interactive "p") | |
322 (kill-region (point) (progn (forward-sentence arg) (point)))) | |
323 | |
324 (defun backward-kill-sentence (&optional arg) | |
325 "Kill back from point to start of sentence. | |
326 With arg, repeat, or kill forward to Nth end of sentence if negative arg -N." | |
327 (interactive "p") | |
328 (kill-region (point) (progn (backward-sentence arg) (point)))) | |
329 | |
330 (defun mark-end-of-sentence (arg) | |
331 "Put mark at end of sentence. Arg works as in `forward-sentence'." | |
332 (interactive "p") | |
333 (mark-something 'mark-end-of-sentence 'forward-sentence arg)) | |
334 | |
335 (defun transpose-sentences (arg) | |
336 "Interchange this (next) and previous sentence." | |
337 (interactive "*p") | |
338 (transpose-subr 'forward-sentence arg)) | |
339 | |
340 ;;; paragraphs.el ends here | |
341 |