paragraphs.el 8.13 KB
Newer Older
Eric S. Raymond's avatar
Eric S. Raymond committed
1 2
;;; paragraphs.el --- paragraph and sentence parsing.

Eric S. Raymond's avatar
Eric S. Raymond committed
3 4
;; Copyright (C) 1985, 86, 87, 1991 Free Software Foundation, Inc.

Eric S. Raymond's avatar
Eric S. Raymond committed
5
;; Maintainer: FSF
Eric S. Raymond's avatar
Eric S. Raymond committed
6
;; Keywords: wp
Eric S. Raymond's avatar
Eric S. Raymond committed
7

Joseph Arceneaux's avatar
Joseph Arceneaux committed
8 9 10 11
;; This file is part of GNU Emacs.

;; GNU Emacs is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
Roland McGrath's avatar
Roland McGrath committed
12
;; the Free Software Foundation; either version 2, or (at your option)
Joseph Arceneaux's avatar
Joseph Arceneaux committed
13 14 15 16 17 18 19 20 21 22 23
;; any later version.

;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING.  If not, write to
;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.

24 25 26 27 28
;;; Commentary:

;; This package provides the paragraph-oriented commands documented in the
;; Emacs manual.

Eric S. Raymond's avatar
Eric S. Raymond committed
29
;;; Code:
Joseph Arceneaux's avatar
Joseph Arceneaux committed
30

Jim Blandy's avatar
Jim Blandy committed
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
(defconst paragraph-start "^[ \t\n\f]" "\
*Regexp for beginning of a line that starts OR separates paragraphs.")

(defconst paragraph-separate "^[ \t\f]*$" "\
*Regexp for beginning of a line that separates paragraphs.
If you change this, you may have to change paragraph-start also.")

(defconst sentence-end (purecopy "[.?!][]\"')}]*\\($\\| $\\|\t\\|  \\)[ \t\n]*") "\
*Regexp describing the end of a sentence.
All paragraph boundaries also end sentences, regardless.")

(defconst page-delimiter "^\014" "\
*Regexp describing line-beginnings that separate pages.")

(defvar paragraph-ignore-fill-prefix nil "\
Non-nil means the paragraph commands are not affected by `fill-prefix'.
This is desirable in modes where blank lines are the paragraph delimiters.")
Roland McGrath's avatar
Roland McGrath committed
48

Joseph Arceneaux's avatar
Joseph Arceneaux committed
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116

(defun forward-paragraph (&optional arg)
  "Move forward to end of paragraph.
With arg N, do it N times; negative arg -N means move forward N paragraphs.

A line which `paragraph-start' matches either separates paragraphs
\(if `paragraph-separate' matches it also) or is the first line of a paragraph.
A paragraph end is the beginning of a line which is not part of the paragraph
to which the end of the previous line belongs, or the end of the buffer."
  (interactive "p")
  (or arg (setq arg 1))
  (let* ((fill-prefix-regexp
	  (and fill-prefix (not (equal fill-prefix ""))
	       (not paragraph-ignore-fill-prefix)
	       (regexp-quote fill-prefix)))
	 (paragraph-separate
	  (if fill-prefix-regexp
	      (concat paragraph-separate "\\|^"
		      fill-prefix-regexp "[ \t]*$")
	    paragraph-separate)))
    (while (< arg 0)
      (if (and (not (looking-at paragraph-separate))
	       (re-search-backward "^\n" (max (1- (point)) (point-min)) t))
	  nil
	(forward-char -1) (beginning-of-line)
	(while (and (not (bobp)) (looking-at paragraph-separate))
	  (forward-line -1))
	(end-of-line)
	;; Search back for line that starts or separates paragraphs.
	(if (if fill-prefix-regexp
		;; There is a fill prefix; it overrides paragraph-start.
		(progn
		 (while (progn (beginning-of-line)
			       (and (not (bobp))
				    (not (looking-at paragraph-separate))
				    (looking-at fill-prefix-regexp)))
		   (forward-line -1))
		 (not (bobp)))
	      (re-search-backward paragraph-start nil t))
	    ;; Found one.
	    (progn
	      (while (and (not (eobp)) (looking-at paragraph-separate))
		(forward-line 1))
	      (if (eq (char-after (- (point) 2)) ?\n)
		  (forward-line -1)))
	  ;; No starter or separator line => use buffer beg.
	  (goto-char (point-min))))
      (setq arg (1+ arg)))
    (while (> arg 0)
      (beginning-of-line)
      (while (prog1 (and (not (eobp))
			 (looking-at paragraph-separate))
		    (forward-line 1)))
      (if fill-prefix-regexp
	  ;; There is a fill prefix; it overrides paragraph-start.
	  (while (and (not (eobp))
		      (not (looking-at paragraph-separate))
		      (looking-at fill-prefix-regexp))
	    (forward-line 1))
	(if (re-search-forward paragraph-start nil t)
	    (goto-char (match-beginning 0))
	  (goto-char (point-max))))
      (setq arg (1- arg)))))

(defun backward-paragraph (&optional arg)
  "Move backward to start of paragraph.
With arg N, do it N times; negative arg -N means move forward N paragraphs.

Brian Preble's avatar
Brian Preble committed
117 118 119 120 121 122 123
A paragraph start is the beginning of a line which is a
`first-line-of-paragraph' or which is ordinary text and follows a
paragraph-separating line; except: if the first real line of a
paragraph is preceded by a blank line, the paragraph starts at that
blank line.

See `forward-paragraph' for more information."
Joseph Arceneaux's avatar
Joseph Arceneaux committed
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
  (interactive "p")
  (or arg (setq arg 1))
  (forward-paragraph (- arg)))

(defun mark-paragraph ()
  "Put point at beginning of this paragraph, mark at end.
The paragraph marked is the one that contains point or follows point."
  (interactive)
  (forward-paragraph 1)
  (push-mark nil t)
  (backward-paragraph 1))

(defun kill-paragraph (arg)
  "Kill forward to end of paragraph.
With arg N, kill forward to Nth end of paragraph;
negative arg -N means kill backward to Nth start of paragraph."
Brian Preble's avatar
Brian Preble committed
140
  (interactive "p")
141
  (kill-region (point) (save-excursion (forward-paragraph arg) (point))))
Joseph Arceneaux's avatar
Joseph Arceneaux committed
142 143 144 145 146

(defun backward-kill-paragraph (arg)
  "Kill back to start of paragraph.
With arg N, kill back to Nth start of paragraph;
negative arg -N means kill forward to Nth end of paragraph."
Brian Preble's avatar
Brian Preble committed
147
  (interactive "p")
148
  (kill-region (point) (save-excursion (backward-paragraph arg) (point))))
Joseph Arceneaux's avatar
Joseph Arceneaux committed
149 150 151 152 153 154 155 156 157 158 159

(defun transpose-paragraphs (arg)
  "Interchange this (or next) paragraph with previous one."
  (interactive "*p")
  (transpose-subr 'forward-paragraph arg))

(defun start-of-paragraph-text ()
  (let ((opoint (point)) npoint)
    (forward-paragraph -1)
    (setq npoint (point))
    (skip-chars-forward " \t\n")
160 161 162 163 164
    ;; If the range of blank lines found spans the original start point,
    ;; try again from the beginning of it.
    ;; Must be careful to avoid infinite loop
    ;; when following a single return at start of buffer.
    (if (and (>= (point) opoint) (< npoint opoint))
Joseph Arceneaux's avatar
Joseph Arceneaux committed
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
	(progn
	  (goto-char npoint)
	  (if (> npoint (point-min))
	      (start-of-paragraph-text))))))

(defun end-of-paragraph-text ()
  (let ((opoint (point)))
    (forward-paragraph 1)
    (if (eq (preceding-char) ?\n) (forward-char -1))
    (if (<= (point) opoint)
	(progn
	  (forward-char 1)
	  (if (< (point) (point-max))
	      (end-of-paragraph-text))))))

(defun forward-sentence (&optional arg)
Brian Preble's avatar
Brian Preble committed
181 182
  "Move forward to next`sentence-end'.  With argument, repeat.
With negative argument, move backward repeatedly to `sentence-beginning'.
Joseph Arceneaux's avatar
Joseph Arceneaux committed
183

Brian Preble's avatar
Brian Preble committed
184 185
The variable `sentence-end' is a regular expression that matches ends of
sentences.  Also, every paragraph boundary terminates sentences as well."
Joseph Arceneaux's avatar
Joseph Arceneaux committed
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
  (interactive "p")
  (or arg (setq arg 1))
  (while (< arg 0)
    (let ((par-beg (save-excursion (start-of-paragraph-text) (point))))
      (if (re-search-backward (concat sentence-end "[^ \t\n]") par-beg t)
	  (goto-char (1- (match-end 0)))
	(goto-char par-beg)))
    (setq arg (1+ arg)))
  (while (> arg 0)
    (let ((par-end (save-excursion (end-of-paragraph-text) (point))))
      (if (re-search-forward sentence-end par-end t)
	  (skip-chars-backward " \t\n")
	(goto-char par-end)))
    (setq arg (1- arg))))

(defun backward-sentence (&optional arg)
  "Move backward to start of sentence.  With arg, do it arg times.
Brian Preble's avatar
Brian Preble committed
203
See `forward-sentence' for more information."
Joseph Arceneaux's avatar
Joseph Arceneaux committed
204 205 206 207 208 209 210 211
  (interactive "p")
  (or arg (setq arg 1))
  (forward-sentence (- arg)))

(defun kill-sentence (&optional arg)
  "Kill from point to end of sentence.
With arg, repeat; negative arg -N means kill back to Nth start of sentence."
  (interactive "*p")
212
  (kill-region (point) (save-excursion (forward-sentence arg) (point))))
Joseph Arceneaux's avatar
Joseph Arceneaux committed
213 214 215 216 217

(defun backward-kill-sentence (&optional arg)
  "Kill back from point to start of sentence.
With arg, repeat, or kill forward to Nth end of sentence if negative arg -N."
  (interactive "*p")
218
  (kill-region (point) (save-excursion (backward-sentence arg) (point))))
Joseph Arceneaux's avatar
Joseph Arceneaux committed
219 220

(defun mark-end-of-sentence (arg)
Brian Preble's avatar
Brian Preble committed
221
  "Put mark at end of sentence.  Arg works as in `forward-sentence'."
Joseph Arceneaux's avatar
Joseph Arceneaux committed
222 223 224 225 226 227 228 229 230 231
  (interactive "p")
  (push-mark
    (save-excursion
      (forward-sentence arg)
      (point))))

(defun transpose-sentences (arg)
  "Interchange this (next) and previous sentence."
  (interactive "*p")
  (transpose-subr 'forward-sentence arg))
Eric S. Raymond's avatar
Eric S. Raymond committed
232 233

;;; paragraphs.el ends here