summaryrefslogtreecommitdiff
path: root/lisp/textmodes/paragraphs.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/textmodes/paragraphs.el')
-rw-r--r--lisp/textmodes/paragraphs.el90
1 files changed, 65 insertions, 25 deletions
diff --git a/lisp/textmodes/paragraphs.el b/lisp/textmodes/paragraphs.el
index 29804c3bfd2..cd726ad4776 100644
--- a/lisp/textmodes/paragraphs.el
+++ b/lisp/textmodes/paragraphs.el
@@ -96,8 +96,8 @@ lines that start paragraphs from lines that separate them.
If the variable `use-hard-newlines' is non-nil, then only lines following a
hard newline are considered to match."
- :type 'regexp)
-(put 'paragraph-start 'safe-local-variable #'stringp)
+ :type 'regexp
+ :safe #'stringp)
;; paragraph-start requires a hard newline, but paragraph-separate does not:
;; It is assumed that paragraph-separate is distinctive enough to be believed
@@ -113,8 +113,8 @@ This is matched against the text at the left margin, which is not necessarily
the beginning of the line, so it should not use \"^\" as an anchor. This
ensures that the paragraph functions will work equally within a region of
text indented by a margin setting."
- :type 'regexp)
-(put 'paragraph-separate 'safe-local-variable #'stringp)
+ :type 'regexp
+ :safe #'stringp)
(defcustom sentence-end-double-space t
"Non-nil means a single space does not end a sentence.
@@ -125,8 +125,8 @@ This value is used by the function `sentence-end' to construct the
regexp describing the end of a sentence, when the value of the variable
`sentence-end' is nil. See Info node `(elisp)Standard Regexps'."
:type 'boolean
+ :safe #'booleanp
:group 'fill)
-(put 'sentence-end-double-space 'safe-local-variable #'booleanp)
(defcustom sentence-end-without-period nil
"Non-nil means a sentence will end without a period.
@@ -137,8 +137,8 @@ This value is used by the function `sentence-end' to construct the
regexp describing the end of a sentence, when the value of the variable
`sentence-end' is nil. See Info node `(elisp)Standard Regexps'."
:type 'boolean
+ :safe #'booleanp
:group 'fill)
-(put 'sentence-end-without-period 'safe-local-variable #'booleanp)
(defcustom sentence-end-without-space
"。.?!"
@@ -147,8 +147,8 @@ regexp describing the end of a sentence, when the value of the variable
This value is used by the function `sentence-end' to construct the
regexp describing the end of a sentence, when the value of the variable
`sentence-end' is nil. See Info node `(elisp)Standard Regexps'."
- :type 'string)
-(put 'sentence-end-without-space 'safe-local-variable #'stringp)
+ :type 'string
+ :safe #'stringp)
(defcustom sentence-end nil
"Regexp describing the end of a sentence.
@@ -158,14 +158,14 @@ All paragraph boundaries also end sentences, regardless.
The value nil means to use the default value defined by the
function `sentence-end'. You should always use this function
to obtain the value of this variable."
- :type '(choice regexp (const :tag "Use default value" nil)))
-(put 'sentence-end 'safe-local-variable #'string-or-null-p)
+ :type '(choice regexp (const :tag "Use default value" nil))
+ :safe #'string-or-null-p)
(defcustom sentence-end-base "[.?!…‽][]\"'”’)}»›]*"
"Regexp matching the basic end of a sentence, not including following space."
:type 'regexp
+ :safe #'stringp
:version "25.1")
-(put 'sentence-end-base 'safe-local-variable #'stringp)
(defun sentence-end ()
"Return the regexp describing the end of a sentence.
@@ -192,14 +192,14 @@ in between. See Info node `(elisp)Standard Regexps'."
(defcustom page-delimiter "^\014"
"Regexp describing line-beginnings that separate pages."
- :type 'regexp)
-(put 'page-delimiter 'safe-local-variable #'stringp)
+ :type 'regexp
+ :safe #'stringp)
(defcustom 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."
- :type 'boolean)
-(put 'paragraph-ignore-fill-prefix 'safe-local-variable #'booleanp)
+ :type 'boolean
+ :safe #'booleanp)
;; Silence the compiler.
(defun forward-paragraph (&optional arg)
@@ -477,20 +477,60 @@ sentences. Also, every paragraph boundary terminates sentences as well."
(skip-chars-backward " \t\n")
(goto-char par-end)))
(setq arg (1- arg)))
- (constrain-to-field nil opoint t)))
-
-(defun repunctuate-sentences (&optional no-query)
+ (let ((npoint (constrain-to-field nil opoint t)))
+ (not (= npoint opoint)))))
+
+(defun count-sentences (start end)
+ "Count sentences in current buffer from START to END."
+ (let ((sentences 0)
+ (inhibit-field-text-motion t))
+ (save-excursion
+ (save-restriction
+ (narrow-to-region start end)
+ (goto-char (point-min))
+ (while (ignore-errors (forward-sentence))
+ (setq sentences (1+ sentences)))
+ ;; Remove last possibly empty sentence
+ (when (/= (skip-chars-backward " \t\n") 0)
+ (setq sentences (1- sentences)))
+ sentences))))
+
+(defun repunctuate-sentences-filter (_start _end)
+ "Search filter used by `repunctuate-sentences' to skip unneeded spaces.
+By default, it skips occurrences that already have two spaces."
+ (/= 2 (- (point) (save-excursion (skip-chars-backward " ") (point)))))
+
+(defvar repunctuate-sentences-filter #'repunctuate-sentences-filter
+ "The default filter used by `repunctuate-sentences'.
+It is advised to use `add-function' on this to add more filters,
+for example, `(looking-back (rx (or \"e.g.\" \"i.e.\") \" \") 5)'
+with a set of predefined abbreviations to skip from adding two spaces.")
+
+(defun repunctuate-sentences (&optional no-query start end)
"Put two spaces at the end of sentences from point to the end of buffer.
-It works using `query-replace-regexp'.
-If optional argument NO-QUERY is non-nil, make changes without
-asking for confirmation."
- (interactive)
+It works using `query-replace-regexp'. In Transient Mark mode,
+if the mark is active, operate on the contents of the region.
+Second and third arg START and END specify the region to operate on.
+If optional argument NO-QUERY is non-nil, make changes without asking
+for confirmation. You can use `repunctuate-sentences-filter' to add
+filters to skip occurrences of spaces that don't need to be replaced."
+ (interactive (list nil
+ (if (use-region-p) (region-beginning))
+ (if (use-region-p) (region-end))))
(let ((regexp "\\([]\"')]?\\)\\([.?!]\\)\\([]\"')]?\\) +")
(to-string "\\1\\2\\3 "))
(if no-query
- (while (re-search-forward regexp nil t)
- (replace-match to-string))
- (query-replace-regexp regexp to-string))))
+ (progn
+ (when start (goto-char start))
+ (while (re-search-forward regexp end t)
+ (replace-match to-string)))
+ (unwind-protect
+ (progn
+ (add-function :after-while isearch-filter-predicate
+ repunctuate-sentences-filter)
+ (query-replace-regexp regexp to-string nil start end))
+ (remove-function isearch-filter-predicate
+ repunctuate-sentences-filter)))))
(defun backward-sentence (&optional arg)