summaryrefslogtreecommitdiff
path: root/lisp/textmodes
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/textmodes')
-rw-r--r--lisp/textmodes/artist.el15
-rw-r--r--lisp/textmodes/bibtex.el80
-rw-r--r--lisp/textmodes/css-mode.el109
-rw-r--r--lisp/textmodes/emacs-news-mode.el224
-rw-r--r--lisp/textmodes/enriched.el24
-rw-r--r--lisp/textmodes/etc-authors-mode.el10
-rw-r--r--lisp/textmodes/fill.el146
-rw-r--r--lisp/textmodes/flyspell.el17
-rw-r--r--lisp/textmodes/glyphless-mode.el68
-rw-r--r--lisp/textmodes/ispell.el140
-rw-r--r--lisp/textmodes/page.el17
-rw-r--r--lisp/textmodes/paragraphs.el40
-rw-r--r--lisp/textmodes/pixel-fill.el240
-rw-r--r--lisp/textmodes/reftex-cite.el6
-rw-r--r--lisp/textmodes/reftex-global.el10
-rw-r--r--lisp/textmodes/reftex-index.el2
-rw-r--r--lisp/textmodes/reftex-parse.el29
-rw-r--r--lisp/textmodes/reftex-toc.el2
-rw-r--r--lisp/textmodes/reftex-vars.el39
-rw-r--r--lisp/textmodes/reftex.el3
-rw-r--r--lisp/textmodes/remember.el2
-rw-r--r--lisp/textmodes/rst.el2
-rw-r--r--lisp/textmodes/sgml-mode.el52
-rw-r--r--lisp/textmodes/string-edit.el136
-rw-r--r--lisp/textmodes/table.el119
-rw-r--r--lisp/textmodes/tex-mode.el147
-rw-r--r--lisp/textmodes/texinfo.el139
-rw-r--r--lisp/textmodes/word-wrap-mode.el80
28 files changed, 1529 insertions, 369 deletions
diff --git a/lisp/textmodes/artist.el b/lisp/textmodes/artist.el
index 18e03b49049..686d5f494c9 100644
--- a/lisp/textmodes/artist.el
+++ b/lisp/textmodes/artist.el
@@ -338,7 +338,8 @@ Example:
(defvar artist-pointer-shape (if (eq window-system 'x) x-pointer-crosshair nil)
"If in X Windows, use this pointer shape while drawing with the mouse.")
-(defvaralias 'artist-text-renderer 'artist-text-renderer-function)
+(define-obsolete-variable-alias 'artist-text-renderer
+ 'artist-text-renderer-function "29.1")
(defcustom artist-text-renderer-function 'artist-figlet
"Function for doing text rendering."
@@ -1370,8 +1371,11 @@ Keymap summary
(t
;; Turn mode on
(artist-mode-init)
- (let ((font (face-attribute 'default :font)))
- (when (and (fontp font) (not (font-get font :spacing)))
+ (let* ((font (face-attribute 'default :font))
+ (spacing-prop (if (fontp font)
+ (font-get font :spacing)
+ t)))
+ (when (or (null spacing-prop) (eq spacing-prop 0))
(message "The default font isn't monospaced, so the drawings in this buffer may look odd"))))))
;; Init and exit
@@ -2840,9 +2844,8 @@ Returns a list of strings."
(if (memq system-type '(windows-nt ms-dos))
(artist-figlet-get-font-list-windows)
(artist-figlet-get-font-list)))
- (font (completing-read (concat "Select font (default "
- artist-figlet-default-font
- "): ")
+ (font (completing-read (format-prompt "Select font"
+ artist-figlet-default-font)
(mapcar
(lambda (font) (cons font font))
avail-fonts))))
diff --git a/lisp/textmodes/bibtex.el b/lisp/textmodes/bibtex.el
index e4df28d03de..544e0da8276 100644
--- a/lisp/textmodes/bibtex.el
+++ b/lisp/textmodes/bibtex.el
@@ -764,6 +764,20 @@ for a new entry."
("eprint") ("eprintclass" nil nil 4) ("primaryclass" nil nil -4)
("eprinttype" nil nil 5) ("archiveprefix" nil nil -5)
("url") ("urldate")))
+ ("Conference" "Article in Conference Proceedings" ; same as InProceedings
+ (("author")
+ ("title" "Title of the article in proceedings (BibTeX converts it to lowercase)"))
+ (("booktitle" "Name of the conference proceedings")
+ ("year"))
+ (("editor")
+ ("volume" "Volume of the conference proceedings in the series")
+ ("number" "Number of the conference proceedings in a small series (overwritten by volume)")
+ ("series" "Series in which the conference proceedings appeared")
+ ("pages" "Pages in the conference proceedings")
+ ("month") ("address")
+ ("organization" "Sponsoring organization of the conference")
+ ("publisher" "Publishing company, its location")
+ ("note")))
("Reference" "Single-Volume Work of Reference" ; same as @collection
(("editor") ("title") ("date" nil nil 1) ("year" nil nil -1))
nil
@@ -839,6 +853,33 @@ for a new entry."
("eprint") ("eprintclass" nil nil 4) ("primaryclass" nil nil -4)
("eprinttype" nil nil 5) ("archiveprefix" nil nil -5)
("url") ("urldate")))
+ ("PhdThesis" "PhD Thesis"
+ (("author")
+ ("title" "Title of the PhD thesis")
+ ("school" "School where the PhD thesis was written")
+ ("year"))
+ nil
+ (("type" "Type of the PhD thesis")
+ ("address" "Address of the school (if not part of field \"school\") or country")
+ ("month") ("note")))
+ ("MastersThesis" "Master's Thesis"
+ (("author")
+ ("title" "Title of the master's thesis (BibTeX converts it to lowercase)")
+ ("school" "School where the master's thesis was written")
+ ("year"))
+ nil
+ (("type" "Type of the master's thesis (if other than \"Master's thesis\")")
+ ("address" "Address of the school (if not part of field \"school\") or country")
+ ("month") ("note")))
+ ("TechReport" "Technical Report"
+ (("author")
+ ("title" "Title of the technical report (BibTeX converts it to lowercase)")
+ ("institution" "Sponsoring institution of the report")
+ ("year"))
+ nil
+ (("type" "Type of the report (if other than \"technical report\")")
+ ("number" "Number of the technical report")
+ ("address") ("month") ("note")))
("Unpublished" "Unpublished"
(("author") ("title") ("date" nil nil 1) ("year" nil nil -1))
nil
@@ -1193,8 +1234,8 @@ See `bibtex-generate-autokey' for details."
:type '(repeat (cons (regexp :tag "Old")
(string :tag "New"))))
-(defvaralias 'bibtex-autokey-name-case-convert
- 'bibtex-autokey-name-case-convert-function)
+(define-obsolete-variable-alias 'bibtex-autokey-name-case-convert
+ 'bibtex-autokey-name-case-convert-function "29.1")
(defcustom bibtex-autokey-name-case-convert-function #'downcase
"Function called for each name to perform case conversion.
@@ -1268,8 +1309,8 @@ Case is significant. See `bibtex-generate-autokey' for details."
:group 'bibtex-autokey
:type '(repeat regexp))
-(defvaralias 'bibtex-autokey-titleword-case-convert
- 'bibtex-autokey-titleword-case-convert-function)
+(define-obsolete-variable-alias 'bibtex-autokey-titleword-case-convert
+ 'bibtex-autokey-titleword-case-convert-function "29.1")
(defcustom bibtex-autokey-titleword-case-convert-function #'downcase
"Function called for each titleword to perform case conversion.
@@ -2257,11 +2298,17 @@ is non-nil, FUN is not called for @String entries."
(set-marker-insertion-type end-marker t)
(save-excursion
(goto-char (point-min))
- (while (setq found (bibtex-skip-to-valid-entry))
- (set-marker end-marker (cdr found))
- (looking-at bibtex-any-entry-maybe-empty-head)
- (funcall fun (bibtex-key-in-head "") (car found) end-marker)
- (goto-char end-marker)))))
+ (let ((prev nil))
+ (while (setq found (bibtex-skip-to-valid-entry))
+ ;; If we have invalid entries, ensure that we have forward
+ ;; progress so that we don't infloop.
+ (if (equal (point) prev)
+ (forward-line 1)
+ (setq prev (point))
+ (set-marker end-marker (cdr found))
+ (looking-at bibtex-any-entry-maybe-empty-head)
+ (funcall fun (bibtex-key-in-head "") (car found) end-marker)
+ (goto-char end-marker)))))))
(defun bibtex-progress-message (&optional flag interval)
"Echo a message about progress of current buffer.
@@ -4101,11 +4148,11 @@ Optional arg POS is the position of the BibTeX entry to use."
(goto-char pnt)))))
(defun bibtex-mark-entry ()
- "Put mark at beginning, point at end of current BibTeX entry.
+ "Put mark at end, point at beginning of current BibTeX entry.
Activate mark in Transient Mark mode."
(interactive)
- (push-mark (bibtex-beginning-of-entry) t t)
- (bibtex-end-of-entry))
+ (push-mark (bibtex-end-of-entry) t t)
+ (bibtex-beginning-of-entry))
(defun bibtex-count-entries (&optional count-string-entries)
"Count number of entries in current buffer or region.
@@ -4317,8 +4364,6 @@ for a crossref key, t otherwise."
(eqb (goto-char pos))
(t (set-buffer buffer) (goto-char pos)))
pos))
-;; backward compatibility
-(defalias 'bibtex-find-crossref 'bibtex-search-crossref)
(defun bibtex-dist (pos beg end)
"Return distance between POS and region delimited by BEG and END."
@@ -4381,8 +4426,6 @@ A prefix arg negates the value of `bibtex-search-entry-globally'."
(if display (bibtex-reposition-window)))
(display (message "Key `%s' not found" key)))
pnt)))
-;; backward compatibility
-(defalias 'bibtex-find-entry 'bibtex-search-entry)
(defun bibtex-prepare-new-entry (index)
"Prepare a new BibTeX entry with index INDEX.
@@ -4996,7 +5039,7 @@ on the value of `bibtex-entry-format'.
If the reference key of the entry is empty or a prefix argument is given,
calculate a new reference key. (Note: this works only if fields in entry
begin on separate lines prior to calling `bibtex-clean-entry' or if
-'realign is contained in `bibtex-entry-format'.)
+`realign' is contained in `bibtex-entry-format'.)
Don't call `bibtex-clean-entry' on @Preamble entries.
At end of the cleaning process, the functions in
`bibtex-clean-entry-hook' are called with region narrowed to entry."
@@ -5608,5 +5651,8 @@ If APPEND is non-nil, append ENTRIES to those already displayed."
(setq buffer-read-only t)
(goto-char (point-min)))
+(define-obsolete-function-alias 'bibtex-find-crossref #'bibtex-search-crossref "29.1")
+(define-obsolete-function-alias 'bibtex-find-entry #'bibtex-search-entry "29.1")
+
(provide 'bibtex)
;;; bibtex.el ends here
diff --git a/lisp/textmodes/css-mode.el b/lisp/textmodes/css-mode.el
index 1139fd1976e..a2a7774aba7 100644
--- a/lisp/textmodes/css-mode.el
+++ b/lisp/textmodes/css-mode.el
@@ -269,6 +269,10 @@
("resize" "none" "both" "horizontal" "vertical")
("text-overflow" "clip" "ellipsis" string)
+ ;; CSS Cascading and Inheritance Level 3
+ ;; (https://www.w3.org/TR/css-cascade-3/#property-index)
+ ("all")
+
;; CSS Color Module Level 3
;; (https://www.w3.org/TR/css3-color/#property)
("color" color)
@@ -304,27 +308,27 @@
;; CSS Box Alignment Module Level 3
;; (https://www.w3.org/TR/css-align-3/#property-index)
- ("align-content"
- baseline-position content-distribution overflow-position content-position)
- ("align-items"
- "normal" "stretch" baseline-position overflow-position self-position)
- ("align-self"
- "auto" "normal" "stretch"
- baseline-position overflow-position self-position)
- ("justify-content" "normal"
- content-distribution overflow-position content-position "left" "right")
- ("justify-items"
- "normal" "stretch" baseline-position overflow-position self-position
- "left" "right" "legacy")
- ("justify-self"
- "auto" "normal" "stretch" baseline-position overflow-position self-position
- "left" "right")
+ ("align-content" baseline-position content-distribution
+ overflow-position content-position)
+ ("align-items" "normal" "stretch" baseline-position
+ overflow-position self-position)
+ ("align-self" "auto" "normal" "stretch" baseline-position
+ overflow-position self-position)
+ ("column-gap" "normal" length-percentage)
+ ("gap" row-gap column-gap)
+ ("justify-content" "normal" content-distribution overflow-position
+ content-position "left" "right")
+ ("justify-items" "normal" "stretch" baseline-position
+ overflow-position self-position "left" "right" "legacy" "center")
+ ("justify-self" "auto" "normal" "stretch" baseline-position
+ overflow-position self-position "left" "right")
("place-content" align-content justify-content)
("place-items" align-items justify-items)
("place-self" justify-self align-self)
+ ("row-gap" "normal" length-percentage)
- ;; CSS Flexible Box Layout Module Level 2
- ;; (https://www.w3.org/TR/css-flexbox-2/#property-index)
+ ;; CSS Flexible Box Layout Module Level 1
+ ;; (https://www.w3.org/TR/css-flexbox-1/#property-index)
("flex" "none" flex-grow flex-shrink flex-basis)
("flex-basis" "auto" "content" width)
("flex-direction" "row" "row-reverse" "column" "column-reverse")
@@ -413,21 +417,20 @@
("mask-type" "luminance" "alpha")
("clip" "rect()" "auto")
- ;; CSS Multi-column Layout Module
+ ;; CSS Multi-column Layout Module Level 1
;; (https://www.w3.org/TR/css3-multicol/#property-index)
;; "break-after", "break-before", and "break-inside" are left out
;; below, because they're already included in CSS Fragmentation
;; Module Level 3.
- ("column-count" integer "auto")
- ("column-fill" "auto" "balance")
- ("column-gap" length "normal")
+ ("column-count" "auto" integer)
+ ("column-fill" "auto" "balance" "balance-all")
("column-rule" column-rule-width column-rule-style
- column-rule-color "transparent")
+ column-rule-color)
("column-rule-color" color)
- ("column-rule-style" border-style)
- ("column-rule-width" border-width)
+ ("column-rule-style" line-style)
+ ("column-rule-width" line-width)
("column-span" "none" "all")
- ("column-width" length "auto")
+ ("column-width" "auto" length)
("columns" column-width column-count)
;; CSS Overflow Module Level 3
@@ -925,6 +928,32 @@ cannot be completed sensibly: `custom-ident',
(defface css-proprietary-property '((t :inherit (css-property italic)))
"Face to use for vendor-specific properties.")
+(defun css--selector-regexp (sassy)
+ (concat
+ "\\(?:"
+ (if (not sassy)
+ "[-_%*#.>[:alnum:]]+"
+ ;; Same as for non-sassy except we do want to allow { and }
+ ;; chars in selectors in the case of #{$foo}
+ ;; variable interpolation!
+ (concat "\\(?:[-_%*#.>&+~[:alnum:]]*" scss--hash-re
+ "\\|[-_%*#.>&+~[:alnum:]]+\\)"))
+ ;; Even though pseudo-elements should be prefixed by ::, a
+ ;; single colon is accepted for backward compatibility.
+ "\\(?:\\(:" (regexp-opt (append css-pseudo-class-ids
+ css-pseudo-element-ids)
+ t)
+ "\\|::" (regexp-opt css-pseudo-element-ids t) "\\)\\)?"
+ ;; Braces after selectors.
+ "\\(?:\\[[^]\n]+\\]\\)?"
+ ;; Parentheses after selectors.
+ "\\(?:([^)]+)\\)?"
+ ;; Main bit over. But perhaps just [target]?
+ "\\|\\[[^]\n]+\\]"
+ ;; :root, ::marker and the like.
+ "\\|::?[[:alnum:]]+\\(?:([^)]+)\\)?"
+ "\\)"))
+
(defun css--font-lock-keywords (&optional sassy)
`((,(concat "!\\s-*" (regexp-opt css--bang-ids))
(0 font-lock-builtin-face))
@@ -945,28 +974,16 @@ cannot be completed sensibly: `custom-ident',
;; selector between [...] should simply not be highlighted.
(,(concat
"^[ \t]*\\("
- (if (not sassy)
- ;; We don't allow / as first char, so as not to
- ;; take a comment as the beginning of a selector.
- "[^@/:{}() \t\n][^:{}()]*"
- ;; Same as for non-sassy except we do want to allow { and }
- ;; chars in selectors in the case of #{$foo}
- ;; variable interpolation!
- (concat "\\(?:" scss--hash-re
- "\\|[^@/:{}() \t\n#]\\)"
- "[^:{}()#]*\\(?:" scss--hash-re "[^:{}()#]*\\)*"))
- ;; Even though pseudo-elements should be prefixed by ::, a
- ;; single colon is accepted for backward compatibility.
- "\\(?:\\(:" (regexp-opt (append css-pseudo-class-ids
- css-pseudo-element-ids)
- t)
- "\\|::" (regexp-opt css-pseudo-element-ids t) "\\)"
- "\\(?:([^)]+)\\)?"
- (if (not sassy)
- "[^:{}()\n]*"
- (concat "[^:{}()\n#]*\\(?:" scss--hash-re "[^:{}()\n#]*\\)*"))
+ ;; We have at least one selector.
+ (css--selector-regexp sassy)
+ ;; And then possibly more.
+ "\\(?:"
+ ;; Separators between selectors.
+ "[ \n\t,+~>]+"
+ (css--selector-regexp sassy)
"\\)*"
- "\\)\\(?:\n[ \t]*\\)*{")
+ ;; And then a brace.
+ "\\)[ \n\t]*{")
(1 'css-selector keep))
;; In the above rule, we allow the open-brace to be on some subsequent
;; line. This will only work if we properly mark the intervening text
diff --git a/lisp/textmodes/emacs-news-mode.el b/lisp/textmodes/emacs-news-mode.el
new file mode 100644
index 00000000000..fdb3cb86284
--- /dev/null
+++ b/lisp/textmodes/emacs-news-mode.el
@@ -0,0 +1,224 @@
+;;; emacs-news-mode.el --- major mode to edit and view the NEWS file -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2022 Free Software Foundation, Inc.
+
+;; Keywords: tools
+
+;; 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
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) 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. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile (require 'cl-lib))
+
+(defgroup emacs-news-mode nil
+ "Major mode for editing and viewing the Emacs NEWS file."
+ :group 'lisp)
+
+(defface emacs-news-is-documented
+ '((t :inherit font-lock-type-face))
+ "Face used for displaying the \"is documented\" tag."
+ :version "29.1")
+
+(defface emacs-news-does-not-need-documentation
+ '((t :inherit font-lock-preprocessor-face))
+ "Face used for displaying the \"does not need documentation\" tag."
+ :version "29.1")
+
+(defvar-keymap emacs-news-mode-map
+ "C-c C-s" #'emacs-news-next-untagged-entry
+ "C-c C-r" #'emacs-news-previous-untagged-entry
+ "C-c C-g" #'emacs-news-goto-section
+ "C-c C-f" #'emacs-news-find-heading
+ "C-c C-n" #'emacs-news-count-untagged-entries)
+
+(defvar emacs-news-mode-font-lock-keywords
+ `(("^---$" 0 'emacs-news-does-not-need-documentation)
+ ("^\\+\\+\\+$" 0 'emacs-news-is-documented)))
+
+(defun emacs-news--mode-common ()
+ (setq-local font-lock-defaults '(emacs-news-mode-font-lock-keywords t))
+ (setq-local outline-regexp "\\*+ "
+ outline-minor-mode-cycle t
+ ;; We subtract one from the level, because we have a
+ ;; space after the asterisks.
+ outline-level (lambda () (1- (length (match-string 0))))
+ outline-minor-mode-highlight 'append)
+ (outline-minor-mode))
+
+;;;###autoload
+(define-derived-mode emacs-news-mode text-mode "NEWS"
+ "Major mode for editing the Emacs NEWS file."
+ (setq-local fill-paragraph-function #'emacs-news--fill-paragraph)
+ (emacs-news--mode-common))
+
+;;;###autoload
+(define-derived-mode emacs-news-view-mode special-mode "NEWS"
+ "Major mode for viewing the Emacs NEWS file."
+ (setq buffer-read-only t)
+ (emacs-news--buttonize)
+ (button-mode)
+ (emacs-news--mode-common))
+
+(defun emacs-news--fill-paragraph (&optional justify)
+ (cond
+ ;; We're in a heading -- do nothing.
+ ((save-excursion
+ (beginning-of-line)
+ (looking-at "\\*+ "))
+ )
+ ;; We're in a news item -- exclude the heading before filling.
+ ((and (save-excursion
+ (re-search-backward (concat "^\\(?:" paragraph-start "\\|\\*+ \\)")
+ nil t))
+ (= (char-after (match-beginning 0)) ?*))
+ (save-restriction
+ (narrow-to-region (save-excursion
+ (goto-char (match-beginning 0))
+ (forward-line 1)
+ (point))
+ (point-max))
+ (fill-paragraph justify)))
+ ;; Fill normally.
+ (t
+ (fill-paragraph justify))))
+
+(defun emacs-news-next-untagged-entry (&optional reverse)
+ "Go to the next untagged NEWS entry.
+If REVERSE (interactively, the prefix), go to the previous
+untagged NEWS entry."
+ (interactive "P" emacs-news-mode)
+ (let ((start (point))
+ (found nil))
+ ;; Don't consider the current line, because that would stop
+ ;; progress if calling this command repeatedly.
+ (unless reverse
+ (forward-line 1))
+ (while (and (not found)
+ (funcall (if reverse #'re-search-backward
+ #'re-search-forward)
+ "^\\(\\*+\\) " nil t))
+ (when (and (not (save-excursion
+ (forward-line -1)
+ (looking-at "---$\\|\\+\\+\\+$")))
+ ;; We have an entry without a tag before it, but
+ ;; check whether it's a heading (which we can
+ ;; determine if the next entry has more asterisks).
+ (not (emacs-news--heading-p)))
+ ;; It wasn't a sub-heading, so we've found one.
+ (setq found t)))
+ (if found
+ (progn
+ (push-mark start)
+ (message "Untagged entry")
+ (beginning-of-line)
+ t)
+ (message "No further untagged entries")
+ (goto-char start)
+ nil)))
+
+(defun emacs-news--heading-p ()
+ (save-excursion
+ (beginning-of-line)
+ ;; A heading starts with * characters, and then a blank line, and
+ ;; then paragraphs with more * characters than in the heading.
+ (and (looking-at "\\(\\*+\\) ")
+ (let ((level (length (match-string 1))))
+ (forward-line 1)
+ (and (looking-at "$")
+ (re-search-forward "^\\(\\*+\\) " nil t)
+ (> (length (match-string 1)) level))))))
+
+(defun emacs-news-previous-untagged-entry ()
+ "Go to the previous untagged NEWS entry."
+ (interactive nil emacs-news-mode)
+ (emacs-news-next-untagged-entry t))
+
+(defun emacs-news-count-untagged-entries ()
+ "Say how many untagged entries there are in the current NEWS buffer."
+ (interactive nil emacs-news-mode)
+ (save-excursion
+ (goto-char (point-min))
+ (let ((i 0))
+ (while (emacs-news-next-untagged-entry)
+ (setq i (1+ i)))
+ (message (if (= i 1)
+ "There's 1 untagged entry"
+ (format "There are %s untagged entries" i))))))
+
+(defun emacs-news--buttonize ()
+ "Make manual and symbol references into buttons."
+ (save-excursion
+ (with-silent-modifications
+ (let ((inhibit-read-only t))
+ ;; Do functions and variables.
+ (goto-char (point-min))
+ (search-forward "\f" nil t)
+ (while (re-search-forward "'\\([^-][^ \t\n]+\\)'" nil t)
+ ;; Filter out references to key sequences.
+ (let ((string (match-string 1)))
+ (when-let ((symbol (intern-soft string)))
+ (when (or (boundp symbol)
+ (fboundp symbol))
+ (buttonize-region (match-beginning 1) (match-end 1)
+ (lambda (symbol)
+ (describe-symbol symbol))
+ symbol)))))
+ ;; Do manual references.
+ (goto-char (point-min))
+ (search-forward "\f" nil t)
+ (while (re-search-forward "\"\\(([a-z0-9]+)[ \n][^\"]\\{1,80\\}\\)\""
+ nil t)
+ (buttonize-region (match-beginning 1) (match-end 1)
+ (lambda (node) (info node))
+ (match-string 1)))))))
+
+(defun emacs-news--sections (regexp)
+ (let ((sections nil))
+ (save-excursion
+ (goto-char (point-min))
+ (while (re-search-forward (concat "^" regexp "\\(.*\\)") nil t)
+ (when (save-match-data (emacs-news--heading-p))
+ (push (buffer-substring-no-properties
+ (match-beginning 1) (match-end 1))
+ sections))))
+ (nreverse sections)))
+
+(defun emacs-news-goto-section (section)
+ "Go to SECTION in the Emacs NEWS file."
+ (interactive (list
+ (completing-read "Goto section: " (emacs-news--sections "\\* ")
+ nil t))
+ emacs-news-mode)
+ (goto-char (point-min))
+ (when (search-forward (concat "\n* " section) nil t)
+ (beginning-of-line)))
+
+(defun emacs-news-find-heading (heading)
+ "Go to HEADING in the Emacs NEWS file."
+ (interactive (list
+ (completing-read "Goto heading: "
+ (emacs-news--sections "\\*\\*\\*? ")
+ nil t))
+ emacs-news-mode)
+ (goto-char (point-min))
+ (when (re-search-forward (concat "^*+ " (regexp-quote heading)) nil t)
+ (beginning-of-line)))
+
+(provide 'emacs-news-mode)
+
+;;; emacs-news-mode.el ends here
diff --git a/lisp/textmodes/enriched.el b/lisp/textmodes/enriched.el
index 50ff668a9ff..935be06812f 100644
--- a/lisp/textmodes/enriched.el
+++ b/lisp/textmodes/enriched.el
@@ -539,6 +539,30 @@ the range of text to assign text property SYMBOL with value VALUE."
(list start end 'display prop)
(list start end 'display (list 'disable-eval prop)))))
+(defvar enriched--markup-shown)
+(defun enriched-toggle-markup ()
+ "Toggle whether to see markup in the current buffer."
+ (interactive)
+ (save-excursion
+ (save-restriction
+ (widen)
+ (with-silent-modifications
+ (if (bound-and-true-p enriched--markup-shown)
+ (progn
+ (setq-local enriched--markup-shown nil)
+ ;; Remove any faces, because they will be decoded, too.
+ (goto-char (point-min))
+ (let (match)
+ (while (setq match (text-property-search-forward 'face))
+ (put-text-property (prop-match-beginning match)
+ (prop-match-end match)
+ 'face nil)))
+ (enriched-decode (point-min) (point-max))
+ (enriched-mode 1))
+ (setq-local enriched--markup-shown t)
+ (enriched-encode (point-min) (point-max) (current-buffer))
+ (enriched-mode -1))))))
+
(provide 'enriched)
;;; enriched.el ends here
diff --git a/lisp/textmodes/etc-authors-mode.el b/lisp/textmodes/etc-authors-mode.el
index 3912b829d20..7eabdd4c2b8 100644
--- a/lisp/textmodes/etc-authors-mode.el
+++ b/lisp/textmodes/etc-authors-mode.el
@@ -115,12 +115,10 @@ With a prefix arg ARG, move point that many authors backward."
(interactive "p" etc-authors-mode)
(etc-authors-next-author (- arg)))
-(defvar etc-authors-mode-map
- (let ((map (make-sparse-keymap)))
- (define-key map "n" #'etc-authors-next-author)
- (define-key map "p" #'etc-authors-prev-author)
- map)
- "Keymap for `etc-authors-mode'.")
+(defvar-keymap etc-authors-mode-map
+ :doc "Keymap for `etc-authors-mode'."
+ "n" #'etc-authors-next-author
+ "p" #'etc-authors-prev-author)
;;;###autoload
(define-derived-mode etc-authors-mode special-mode "Authors View"
diff --git a/lisp/textmodes/fill.el b/lisp/textmodes/fill.el
index ff84c353aa8..88a8395c88a 100644
--- a/lisp/textmodes/fill.el
+++ b/lisp/textmodes/fill.el
@@ -29,6 +29,8 @@
;;; Code:
+(eval-when-compile (require 'subr-x))
+
(defgroup fill nil
"Indenting and filling text."
:link '(custom-manual "(emacs)Filling")
@@ -396,12 +398,8 @@ and `fill-nobreak-invisible'."
(save-excursion
(skip-chars-backward " ")
(and (eq (preceding-char) ?.)
- (looking-at " \\([^ ]\\|$\\)"))))
- ;; Another approach to the same problem.
- (save-excursion
- (skip-chars-backward " ")
- (and (eq (preceding-char) ?.)
- (not (progn (forward-char -1) (looking-at (sentence-end))))))
+ ;; There's something more after the space.
+ (looking-at " [^ \n]"))))
;; Don't split a line if the rest would look like a new paragraph.
(unless use-hard-newlines
(save-excursion
@@ -716,7 +714,10 @@ space does not end a sentence, so don't break a line there."
(goto-char from-plus-indent))
(if (not (> to (point)))
- nil ;; There is no paragraph, only whitespace: exit now.
+ ;; There is no paragraph, only whitespace: exit now.
+ (progn
+ (set-marker to nil)
+ nil)
(or justify (setq justify (current-justification)))
@@ -792,6 +793,7 @@ space does not end a sentence, so don't break a line there."
;; Leave point after final newline.
(goto-char to)
(unless (eobp) (forward-char 1))
+ (set-marker to nil)
;; Return the fill-prefix we used
fill-prefix)))
@@ -839,75 +841,67 @@ region, instead of just filling the current paragraph."
(interactive (progn
(barf-if-buffer-read-only)
(list (if current-prefix-arg 'full) t)))
- (let ((hash (and (not (buffer-modified-p))
- (buffer-hash))))
- (prog1
- (or
- ;; 1. Fill the region if it is active when called interactively.
- (and region transient-mark-mode mark-active
- (not (eq (region-beginning) (region-end)))
- (or (fill-region (region-beginning) (region-end) justify) t))
- ;; 2. Try fill-paragraph-function.
- (and (not (eq fill-paragraph-function t))
- (or fill-paragraph-function
- (and (minibufferp (current-buffer))
- (= 1 (point-min))))
- (let ((function (or fill-paragraph-function
- ;; In the minibuffer, don't count
- ;; the width of the prompt.
- 'fill-minibuffer-function))
- ;; If fill-paragraph-function is set, it probably
- ;; takes care of comments and stuff. If not, it
- ;; will have to set fill-paragraph-handle-comment
- ;; back to t explicitly or return nil.
- (fill-paragraph-handle-comment nil)
- (fill-paragraph-function t))
- (funcall function justify)))
- ;; 3. Try our syntax-aware filling code.
- (and fill-paragraph-handle-comment
- ;; Our code only handles \n-terminated comments right now.
- comment-start (equal comment-end "")
- (let ((fill-paragraph-handle-comment nil))
- (fill-comment-paragraph justify)))
- ;; 4. If it all fails, default to the good ol' text paragraph filling.
- (let ((before (point))
- (paragraph-start paragraph-start)
- ;; Fill prefix used for filling the paragraph.
- fill-pfx)
- ;; Try to prevent code sections and comment sections from being
- ;; filled together.
- (when (and fill-paragraph-handle-comment comment-start-skip)
- (setq paragraph-start
- (concat paragraph-start "\\|[ \t]*\\(?:"
- comment-start-skip "\\)")))
- (save-excursion
- ;; To make sure the return value of forward-paragraph is
- ;; meaningful, we have to start from the beginning of
- ;; line, otherwise skipping past the last few chars of a
- ;; paragraph-separator would count as a paragraph (and
- ;; not skipping any chars at EOB would not count as a
- ;; paragraph even if it is).
- (move-to-left-margin)
- (if (not (zerop (fill-forward-paragraph 1)))
- ;; There's no paragraph at or after point: give up.
- (setq fill-pfx "")
- (let ((end (point))
- (beg (progn (fill-forward-paragraph -1) (point))))
- (goto-char before)
- (setq fill-pfx
- (if use-hard-newlines
- ;; Can't use fill-region-as-paragraph, since this
- ;; paragraph may still contain hard newlines. See
- ;; fill-region.
- (fill-region beg end justify)
- (fill-region-as-paragraph beg end justify))))))
- fill-pfx))
- ;; If we didn't change anything in the buffer (and the buffer
- ;; was previously unmodified), then flip the modification status
- ;; back to "unchanged".
- (when (and hash
- (equal hash (buffer-hash)))
- (set-buffer-modified-p nil)))))
+ (with-buffer-unmodified-if-unchanged
+ (or
+ ;; 1. Fill the region if it is active when called interactively.
+ (and region transient-mark-mode mark-active
+ (not (eq (region-beginning) (region-end)))
+ (or (fill-region (region-beginning) (region-end) justify) t))
+ ;; 2. Try fill-paragraph-function.
+ (and (not (eq fill-paragraph-function t))
+ (or fill-paragraph-function
+ (and (minibufferp (current-buffer))
+ (= 1 (point-min))))
+ (let ((function (or fill-paragraph-function
+ ;; In the minibuffer, don't count
+ ;; the width of the prompt.
+ 'fill-minibuffer-function))
+ ;; If fill-paragraph-function is set, it probably
+ ;; takes care of comments and stuff. If not, it
+ ;; will have to set fill-paragraph-handle-comment
+ ;; back to t explicitly or return nil.
+ (fill-paragraph-handle-comment nil)
+ (fill-paragraph-function t))
+ (funcall function justify)))
+ ;; 3. Try our syntax-aware filling code.
+ (and fill-paragraph-handle-comment
+ ;; Our code only handles \n-terminated comments right now.
+ comment-start (equal comment-end "")
+ (let ((fill-paragraph-handle-comment nil))
+ (fill-comment-paragraph justify)))
+ ;; 4. If it all fails, default to the good ol' text paragraph filling.
+ (let ((before (point))
+ (paragraph-start paragraph-start)
+ ;; Fill prefix used for filling the paragraph.
+ fill-pfx)
+ ;; Try to prevent code sections and comment sections from being
+ ;; filled together.
+ (when (and fill-paragraph-handle-comment comment-start-skip)
+ (setq paragraph-start
+ (concat paragraph-start "\\|[ \t]*\\(?:"
+ comment-start-skip "\\)")))
+ (save-excursion
+ ;; To make sure the return value of forward-paragraph is
+ ;; meaningful, we have to start from the beginning of
+ ;; line, otherwise skipping past the last few chars of a
+ ;; paragraph-separator would count as a paragraph (and
+ ;; not skipping any chars at EOB would not count as a
+ ;; paragraph even if it is).
+ (move-to-left-margin)
+ (if (not (zerop (fill-forward-paragraph 1)))
+ ;; There's no paragraph at or after point: give up.
+ (setq fill-pfx "")
+ (let ((end (point))
+ (beg (progn (fill-forward-paragraph -1) (point))))
+ (goto-char before)
+ (setq fill-pfx
+ (if use-hard-newlines
+ ;; Can't use fill-region-as-paragraph, since this
+ ;; paragraph may still contain hard newlines. See
+ ;; fill-region.
+ (fill-region beg end justify)
+ (fill-region-as-paragraph beg end justify))))))
+ fill-pfx))))
(declare-function comment-search-forward "newcomment" (limit &optional noerror))
(declare-function comment-string-strip "newcomment" (str beforep afterp))
diff --git a/lisp/textmodes/flyspell.el b/lisp/textmodes/flyspell.el
index 21612cd5e38..2c5e30fecd8 100644
--- a/lisp/textmodes/flyspell.el
+++ b/lisp/textmodes/flyspell.el
@@ -1942,9 +1942,7 @@ before point that's highlighted as misspelled."
'face 'flyspell-incorrect
string))
(setq pos (cdr pos)))
- (if (fboundp 'display-message)
- (display-message 'no-log string)
- (message "%s" string))))
+ (message "%s" string)))
;;*---------------------------------------------------------------------*/
;;* flyspell-abbrev-table ... */
@@ -2273,17 +2271,8 @@ If OPOINT is non-nil, restore point there after adjusting it for replacement."
;;*---------------------------------------------------------------------*/
(defun flyspell-emacs-popup (event poss word)
"The Emacs popup menu."
- (if (and (not event)
- (display-mouse-p))
- (let* ((mouse-pos (mouse-position))
- (mouse-pos (if (nth 1 mouse-pos)
- mouse-pos
- (set-mouse-position (car mouse-pos)
- (/ (frame-width) 2) 2)
- (mouse-position))))
- (setq event (list (list (car (cdr mouse-pos))
- (1+ (cdr (cdr mouse-pos))))
- (car mouse-pos)))))
+ (unless event
+ (setq event (popup-menu-normalize-position (point))))
(let* ((corrects (flyspell-sort (car (cdr (cdr poss))) word))
(cor-menu (if (consp corrects)
(mapcar (lambda (correct)
diff --git a/lisp/textmodes/glyphless-mode.el b/lisp/textmodes/glyphless-mode.el
new file mode 100644
index 00000000000..4d48d90b562
--- /dev/null
+++ b/lisp/textmodes/glyphless-mode.el
@@ -0,0 +1,68 @@
+;;; glyphless-mode.el --- minor mode for displaying glyphless characters -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2021-2022 Free Software Foundation, Inc.
+
+;; Maintainer: emacs-devel@gnu.org
+
+;; 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
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) 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. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(defcustom glyphless-mode-types '(all)
+ "Which glyphless characters to display.
+The value can be any of the groups supported by
+`glyphless-char-display-control' (which see), and in addition
+`all', for all glyphless characters."
+ :version "29.1"
+ :type '(repeat (choice (const :tag "All" all)
+ (const :tag "No font" no-font)
+ (const :tag "C0 Control" c0-control)
+ (const :tag "C1 Control" c1-control)
+ (const :tag "Format Control" format-control)
+ (const :tag "Bidirectional Control" bidi-control)
+ (const :tag "Variation Selectors" variation-selectors)
+ (const :tag "No Font" no-font)))
+ :group 'display)
+
+;;;###autoload
+(define-minor-mode glyphless-display-mode
+ "Minor mode for displaying glyphless characters in the current buffer.
+If enabled, all glyphless characters will be displayed as boxes
+that display their acronyms."
+ :lighter " Glyphless"
+ (if glyphless-display-mode
+ (progn
+ (setq-local glyphless-char-display
+ (let ((table (make-display-table)))
+ (set-char-table-parent table glyphless-char-display)
+ table))
+ (glyphless-mode--setup))
+ (kill-local-variable 'glyphless-char-display)))
+
+(defun glyphless-mode--setup ()
+ (let ((types (if (memq 'all glyphless-mode-types)
+ '(c0-control c1-control format-control
+ variation-selectors no-font)
+ glyphless-mode-types)))
+ (when types
+ (update-glyphless-char-display
+ nil (mapcar (lambda (e) (cons e 'acronym)) types)))))
+
+(provide 'glyphless-mode)
+
+;;; glyphless-mode.el ends here
diff --git a/lisp/textmodes/ispell.el b/lisp/textmodes/ispell.el
index a4bf454fdcb..1810d7bcaeb 100644
--- a/lisp/textmodes/ispell.el
+++ b/lisp/textmodes/ispell.el
@@ -296,7 +296,8 @@ The following values are supported:
"Non-nil means suppress messages in `ispell-word'."
:type 'boolean)
-(defvaralias 'ispell-format-word 'ispell-format-word-function)
+(define-obsolete-variable-alias 'ispell-format-word
+ 'ispell-format-word-function "29.1")
(defcustom ispell-format-word-function (function upcase)
"Formatting function for displaying word being spell checked.
@@ -796,6 +797,9 @@ See `ispell-buffer-with-debug' for an example of use."
"An alist of parsed Aspell dicts and associated parameters.
Internal use.")
+(defvar ispell--aspell-found-dictionaries nil
+ "An alist of identified aspell dictionaries.")
+
(defun ispell-find-aspell-dictionaries ()
"Find Aspell's dictionaries, and record in `ispell-aspell-dictionary-alist'."
(let* ((dictionaries
@@ -809,7 +813,8 @@ Internal use.")
(mapcar #'ispell-aspell-find-dictionary dictionaries))))
;; Ensure aspell's alias dictionary will override standard
;; definitions.
- (setq found (ispell-aspell-add-aliases found))
+ (setq found (ispell-aspell-add-aliases found)
+ ispell--aspell-found-dictionaries (copy-sequence found))
;; Merge into FOUND any elements from the standard ispell-dictionary-base-alist
;; which have no element in FOUND at all.
(dolist (dict ispell-dictionary-base-alist)
@@ -1377,9 +1382,11 @@ The variable `ispell-library-directory' defines their location."
(if (and name
(or
;; Include all for Aspell (we already know existing dicts)
- ispell-really-aspell
+ (and ispell-really-aspell
+ (assoc name ispell--aspell-found-dictionaries))
;; Include all if `ispell-library-directory' is nil (Hunspell)
- (not ispell-library-directory)
+ (and (not ispell-really-aspell)
+ (not ispell-library-directory))
;; If explicit (-d with an absolute path) and existing dict.
(and dict-explt
(file-name-absolute-p dict-explt)
@@ -1672,14 +1679,13 @@ Valid forms include:
("\\\\bibliographystyle" ispell-tex-arg-end)
("\\\\makebox" ispell-tex-arg-end 0)
("\\\\e?psfig" ispell-tex-arg-end)
- ("\\\\document\\(class\\|style\\)" .
- "\\\\begin[ \t\n]*{[ \t\n]*document[ \t\n]*}"))
+ ("\\\\document\\(class\\|style\\)" . "\\\\begin[ \t\n]*{document}"))
(;; delimited with \begin. In ispell: displaymath, eqnarray, eqnarray*,
;; equation, minipage, picture, tabular, tabular* (ispell)
("\\(figure\\|table\\)\\*?" ispell-tex-arg-end 0)
("list" ispell-tex-arg-end 2)
- ("program" . "\\\\end[ \t\n]*{[ \t\n]*program[ \t\n]*}")
- ("verbatim\\*?" . "\\\\end[ \t\n]*{[ \t\n]*verbatim\\*?[ \t\n]*}"))))
+ ("program" . "\\\\end[ \t]*{program}")
+ ("verbatim\\*?" . "\\\\end[ \t]*{verbatim\\*?}"))))
"Lists of regions to be skipped in TeX mode.
First list is used raw.
Second list has key placed inside \\begin{}.
@@ -2398,24 +2404,24 @@ Global `ispell-quit' set to start location to continue spell session."
Selections are:
-DIGIT: Replace the word with a digit offered in the *Choices* buffer.
-SPC: Accept word this time.
-`i': Accept word and insert into private dictionary.
-`a': Accept word for this session.
-`A': Accept word and place in `buffer-local dictionary'.
-`r': Replace word with typed-in value. Rechecked.
-`R': Replace word with typed-in value. Query-replaced in buffer. Rechecked.
-`?': Show these commands.
-`x': Exit spelling buffer. Move cursor to original point.
-`X': Exit spelling buffer. Leaves cursor at the current point, and permits
+\\`0'..\\`9' Replace the word with a digit offered in the *Choices* buffer.
+\\`SPC' Accept word this time.
+\\`i' Accept word and insert into private dictionary.
+\\`a' Accept word for this session.
+\\`A' Accept word and place in `buffer-local dictionary'.
+\\`r' Replace word with typed-in value. Rechecked.
+\\`R' Replace word with typed-in value. Query-replaced in buffer. Rechecked.
+\\`?' Show these commands.
+\\`x' Exit spelling buffer. Move cursor to original point.
+\\`X' Exit spelling buffer. Leaves cursor at the current point, and permits
the aborted check to be completed later.
-`q': Quit spelling session (Kills ispell process).
-`l': Look up typed-in replacement in alternate dictionary. Wildcards okay.
-`u': Like `i', but the word is lower-cased first.
-`m': Place typed-in value in personal dictionary, then recheck current word.
-`C-l': Redraw screen.
-`C-r': Recursive edit.
-`C-z': Suspend Emacs or iconify frame."
+\\`q' Quit spelling session (Kills ispell process).
+\\`l' Look up typed-in replacement in alternate dictionary. Wildcards okay.
+\\`u' Like \\`i', but the word is lower-cased first.
+\\`m' Place typed-in value in personal dictionary, then recheck current word.
+\\`C-l' Redraw screen.
+\\`C-r' Recursive edit.
+\\`C-z' Suspend Emacs or iconify frame."
(if (equal ispell-help-in-bufferp 'electric)
(progn
@@ -2428,26 +2434,28 @@ SPC: Accept word this time.
;;(if (< (window-height) 15)
;; (enlarge-window
;; (- 15 (ispell-adjusted-window-height))))
- (princ "Selections are:
-
-DIGIT: Replace the word with a digit offered in the *Choices* buffer.
-SPC: Accept word this time.
-`i': Accept word and insert into private dictionary.
-`a': Accept word for this session.
-`A': Accept word and place in `buffer-local dictionary'.
-`r': Replace word with typed-in value. Rechecked.
-`R': Replace word with typed-in value. Query-replaced in buffer. Rechecked.
-`?': Show these commands.
-`x': Exit spelling buffer. Move cursor to original point.
-`X': Exit spelling buffer. Leaves cursor at the current point, and permits
- the aborted check to be completed later.
-`q': Quit spelling session (Kills ispell process).
-`l': Look up typed-in replacement in alternate dictionary. Wildcards okay.
-`u': Like `i', but the word is lower-cased first.
-`m': Place typed-in value in personal dictionary, then recheck current word.
-`C-l': Redraw screen.
-`C-r': Recursive edit.
-`C-z': Suspend Emacs or iconify frame.")
+ (princ
+ (substitute-command-keys
+ "Selections are:
+
+\\`0'..\\`9' Replace the word with a digit offered in the *Choices* buffer.
+\\`SPC' Accept word this time.
+\\`i' Accept word and insert into private dictionary.
+\\`a' Accept word for this session.
+\\`A' Accept word and place in `buffer-local dictionary'.
+\\`r' Replace word with typed-in value. Rechecked.
+\\`R' Replace word with typed-in value. Query-replaced in buffer. Rechecked.
+\\`?' Show these commands.
+\\`x' Exit spelling buffer. Move cursor to original point.
+\\`X' Exit spelling buffer. Leaves cursor at the current point, and permits
+ the aborted check to be completed later.
+\\`q' Quit spelling session (Kills ispell process).
+\\`l' Look up typed-in replacement in alternate dictionary. Wildcards okay.
+\\`u' Like \\`i', but the word is lower-cased first.
+\\`m' Place typed-in value in personal dictionary, then recheck current word.
+\\`C-l' Redraw screen.
+\\`C-r' Recursive edit.
+\\`C-z' Suspend Emacs or iconify frame."))
nil)))
@@ -2984,8 +2992,7 @@ By just answering RET you can find out what the current dictionary is."
(interactive
(list (completing-read
"Use new dictionary (RET for current, SPC to complete): "
- (and (fboundp 'ispell-valid-dictionary-list)
- (mapcar #'list (ispell-valid-dictionary-list)))
+ (mapcar #'list (ispell-valid-dictionary-list))
nil t)
current-prefix-arg))
(ispell-set-spellchecker-params) ; Initialize variables and dicts alists
@@ -3045,6 +3052,8 @@ when needed."
;;;###autoload
(defun ispell-region (reg-start reg-end &optional recheckp shift)
"Interactively check a region for spelling errors.
+Leave the mark at the last misspelled word that the user was queried about.
+
Return nil if spell session was terminated, otherwise returns shift offset
amount for last line processed."
(interactive "r") ; Don't flag errors on read-only bufs.
@@ -3056,7 +3065,8 @@ amount for last line processed."
(region-type (if (and (= reg-start (point-min)) (= reg-end (point-max)))
(buffer-name) "region"))
(program-basename (file-name-nondirectory ispell-program-name))
- (dictionary (or ispell-current-dictionary "default")))
+ (dictionary (or ispell-current-dictionary "default"))
+ max-word)
(unwind-protect
(save-excursion
(message "Spell-checking %s using %s with %s dictionary..."
@@ -3152,10 +3162,14 @@ ispell-region: Search for first region to skip after (ispell-begin-skip-region-r
;; Reset `in-comment' (and indirectly `add-comment') for new line
in-comment nil))
(setq ispell-end (point)) ; "end" tracks region retrieved.
- (if string ; there is something to spell check!
- ;; (special start end)
- (setq shift (ispell-process-line string
- (and recheckp shift))))
+ ;; There is something to spell check!
+ (when string
+ ;; (special start end)
+ (let ((res (ispell-process-line string
+ (and recheckp shift))))
+ (setq shift (car res))
+ (when (cdr res)
+ (setq max-word (cdr res)))))
(goto-char ispell-end)))))
(if ispell-quit
nil
@@ -3166,6 +3180,9 @@ ispell-region: Search for first region to skip after (ispell-begin-skip-region-r
(kill-buffer ispell-choices-buffer))
(set-marker skip-region-start nil)
(set-marker rstart nil)
+ ;; Allow the user to pop back to the last position.
+ (when max-word
+ (push-mark max-word t))
(if ispell-quit
(progn
;; preserve or clear the region for ispell-continue.
@@ -3400,9 +3417,12 @@ Returns a string with the line data."
This will modify the buffer for spelling errors.
Requires variables ISPELL-START and ISPELL-END to be defined in its
dynamic scope.
-Returns the sum SHIFT due to changes in word replacements."
+
+Returns a cons cell where the `car' is sum SHIFT due to changes
+in word replacements, and the `cdr' is the location of the final
+word that was queried about."
;;(declare special ispell-start ispell-end)
- (let (poss accept-list)
+ (let (poss accept-list max-word)
(if (not (numberp shift))
(setq shift 0))
;; send string to spell process and get input.
@@ -3456,6 +3476,7 @@ Returns the sum SHIFT due to changes in word replacements."
(error (concat "Ispell misalignment: word "
"`%s' point %d; probably incompatible versions")
ispell-pipe-word actual-point)))
+ (setq max-word (marker-position word-start))
;; ispell-cmd-loop can go recursive & change buffer
(if ispell-keep-choices-win
(setq replace (ispell-command-loop
@@ -3552,7 +3573,7 @@ Returns the sum SHIFT due to changes in word replacements."
(set-marker line-end nil)))
;; Finished with misspelling!
(setq ispell-filter (cdr ispell-filter)))
- shift))
+ (cons shift max-word)))
;;;###autoload
@@ -3593,7 +3614,8 @@ to limit the check."
;;;###autoload
(defun ispell-buffer ()
- "Check the current buffer for spelling errors interactively."
+ "Check the current buffer for spelling errors interactively.
+Leave the mark at the last misspelled word that the user was queried about."
(interactive)
(ispell-region (point-min) (point-max)))
@@ -3883,8 +3905,8 @@ Don't check spelling of message headers except the Subject field.
Don't check included messages.
To abort spell checking of a message region and send the message anyway,
-use the `x' command. (Any subsequent regions will be checked.)
-The `X' command aborts sending the message so that you can edit the buffer.
+use the \\`x' command. (Any subsequent regions will be checked.)
+The \\`X' command aborts sending the message so that you can edit the buffer.
To spell-check whenever a message is sent, include the appropriate lines
in your init file:
@@ -3975,7 +3997,7 @@ You can bind this to the key C-c i in GNUS or mail by adding to
(if (re-search-forward "^Subject: *" end-of-headers t)
(progn
(goto-char (match-end 0))
- (if (and (not (looking-at ".*Re\\>"))
+ (if (and (not (looking-at ".*\\<Re\\>"))
(not (looking-at "\\[")))
(progn
(setq case-fold-search old-case-fold-search)
diff --git a/lisp/textmodes/page.el b/lisp/textmodes/page.el
index 3fc18323349..5d6f017eb99 100644
--- a/lisp/textmodes/page.el
+++ b/lisp/textmodes/page.el
@@ -35,11 +35,18 @@ A page boundary is any line whose beginning matches the regexp
(interactive "p")
(or count (setq count 1))
(while (and (> count 0) (not (eobp)))
- ;; In case the page-delimiter matches the null string,
- ;; don't find a match without moving.
- (if (bolp) (forward-char 1))
- (unless (re-search-forward page-delimiter nil t)
- (goto-char (point-max)))
+ (if (and (looking-at page-delimiter)
+ (> (match-end 0) (point)))
+ ;; If we're standing at the page delimiter, then just skip to
+ ;; the end of it. (But only if it's not a zero-length
+ ;; delimiter, because then we wouldn't have forward progress.)
+ (goto-char (match-end 0))
+ ;; In case the page-delimiter matches the null string,
+ ;; don't find a match without moving.
+ (when (bolp)
+ (forward-char 1))
+ (unless (re-search-forward page-delimiter nil t)
+ (goto-char (point-max))))
(setq count (1- count)))
(while (and (< count 0) (not (bobp)))
;; In case the page-delimiter matches the null string,
diff --git a/lisp/textmodes/paragraphs.el b/lisp/textmodes/paragraphs.el
index 29804c3bfd2..7daf71e990e 100644
--- a/lisp/textmodes/paragraphs.el
+++ b/lisp/textmodes/paragraphs.el
@@ -479,18 +479,42 @@ sentences. Also, every paragraph boundary terminates sentences as well."
(setq arg (1- arg)))
(constrain-to-field nil opoint t)))
-(defun repunctuate-sentences (&optional no-query)
+(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)
diff --git a/lisp/textmodes/pixel-fill.el b/lisp/textmodes/pixel-fill.el
new file mode 100644
index 00000000000..e47653e734a
--- /dev/null
+++ b/lisp/textmodes/pixel-fill.el
@@ -0,0 +1,240 @@
+;;; pixel-fill.el --- variable pitch filling functions -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2021-2022 Free Software Foundation, Inc.
+
+;; Maintainer: emacs-devel@gnu.org
+;; Keywords: filling
+
+;; 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
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) 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. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; The main entry point is `pixel-fill-region', but
+;; `pixel-fill-find-fill-point' can also be useful by itself.
+
+;;; Code:
+
+(require 'kinsoku)
+
+(defgroup pixel-fill nil
+ "Filling based on pixel widths."
+ :group 'fill
+ :version "29.1")
+
+(defcustom pixel-fill-respect-kinsoku t
+ "If nil, fill even if we can't find a good kinsoku point.
+Kinsoku is a Japanese word meaning a rule that should not be violated.
+In Emacs, it is a term used for characters, e.g. punctuation marks,
+parentheses, and so on, that should not be placed in the beginning
+of a line or the end of a line."
+ :type 'boolean
+ :version "29.1")
+
+(defun pixel-fill-width (&optional columns window)
+ "Return the pixel width corresponding to COLUMNS in WINDOW.
+If COLUMNS is nil or omitted, use the entire window width.
+
+If WINDOW is nil or omitted, this defaults to the selected window."
+ (unless window
+ (setq window (selected-window)))
+ (let ((frame (window-frame window)))
+ (if columns
+ (* (frame-char-width frame) columns)
+ (- (window-body-width nil t)
+ (* 2 (frame-char-width frame))
+ ;; We need to adjust the available width for when the user
+ ;; disables the fringes, which will cause the display
+ ;; engine usurp one column for the continuation glyph.
+ (if (and (fboundp 'fringe-columns)
+ (or (not (zerop (fringe-columns 'right)))
+ (not (zerop (fringe-columns 'left)))))
+ 0
+ (* (frame-char-width frame) 2))
+ 1))))
+
+(defun pixel-fill-region (start end pixel-width)
+ "Fill the region between START and END.
+This will attempt to reformat the text in the region to have no
+lines that are visually wider than PIXEL-WIDTH.
+
+If START isn't at the start of a line, the horizontal position of
+START, converted to pixel units, will be used as the indentation
+prefix on subsequent lines."
+ (save-excursion
+ (goto-char start)
+ (let ((indentation
+ (car (window-text-pixel-size nil (line-beginning-position)
+ (point))))
+ (newline-end nil))
+ (when (> indentation pixel-width)
+ (error "The indentation (%s) is wider than the fill width (%s)"
+ indentation pixel-width))
+ (save-restriction
+ (narrow-to-region start end)
+ (goto-char (point-max))
+ (when (looking-back "\n[ \t]*" (point-min))
+ (setq newline-end t))
+ (goto-char (point-min))
+ ;; First replace all whitespace with space.
+ (while (re-search-forward "[ \t\n]+" nil t)
+ (cond
+ ((or (= (match-beginning 0) start)
+ (= (match-end 0) end))
+ (delete-region (match-beginning 0) (match-end 0)))
+ ;; If there's just a single space here, don't replace.
+ ((not (and (= (- (match-end 0) (match-beginning 0)) 1)
+ (= (char-after (match-beginning 0)) ?\s)))
+ (replace-match
+ ;; We need to use a space that has an appropriate width.
+ (propertize " " 'face
+ (get-text-property (match-beginning 0) 'face))))))
+ (goto-char start)
+ (pixel-fill--fill-line pixel-width indentation)
+ (goto-char (point-max))
+ (when newline-end
+ (insert "\n"))))))
+
+(defun pixel-fill--goto-pixel (width)
+ (vertical-motion (cons (/ width (frame-char-width)) 0)))
+
+(defun pixel-fill--fill-line (width &optional indentation)
+ (let ((start (point)))
+ (pixel-fill--goto-pixel width)
+ (while (not (eolp))
+ ;; We have to do some folding. First find the first previous
+ ;; point suitable for folding.
+ (when (or (not (pixel-fill-find-fill-point (line-beginning-position)))
+ (= (point) start))
+ ;; We had unbreakable text (for this width), so just go to
+ ;; the first space and carry on.
+ (beginning-of-line)
+ (skip-chars-forward " ")
+ (search-forward " " (line-end-position) 'move))
+ (when (= (preceding-char) ?\s)
+ (delete-char -1))
+ (unless (eobp)
+ (insert ?\n)
+ (when (> indentation 0)
+ (insert (propertize " " 'display
+ (list 'space :align-to (list indentation))))))
+ (setq start (point))
+ (unless (eobp)
+ (pixel-fill--goto-pixel width)))))
+
+(define-inline pixel-fill--char-breakable-p (char)
+ "Return non-nil if a line can be broken before and after CHAR."
+ (inline-quote (aref fill-find-break-point-function-table ,char)))
+
+(define-inline pixel-fill--char-nospace-p (char)
+ "Return non-nil if no space is required before and after CHAR."
+ (inline-quote (aref fill-nospace-between-words-table ,char)))
+
+(define-inline pixel-fill--char-kinsoku-bol-p (char)
+ "Return non-nil if a line ought not to begin with CHAR."
+ (inline-letevals (char)
+ (inline-quote (and (not (eq ,char ?'))
+ (aref (char-category-set ,char) ?>)))))
+
+(define-inline pixel-fill--char-kinsoku-eol-p (char)
+ "Return non-nil if a line ought not to end with CHAR."
+ (inline-quote (aref (char-category-set ,char) ?<)))
+
+(defun pixel-fill-find-fill-point (start)
+ "Find a place suitable for breaking the current line.
+START should be the earliest buffer position that should be considered
+(typically the start of the line), and this function will search
+backward in the current buffer from the current position."
+ (let ((bp (point))
+ (end (point))
+ failed)
+ (while (not
+ (or (setq failed (<= (point) start))
+ (eq (preceding-char) ?\s)
+ (eq (following-char) ?\s)
+ (pixel-fill--char-breakable-p (preceding-char))
+ (pixel-fill--char-breakable-p (following-char))
+ (and (pixel-fill--char-kinsoku-bol-p (preceding-char))
+ (pixel-fill--char-breakable-p (following-char))
+ (not (pixel-fill--char-kinsoku-bol-p (following-char))))
+ (pixel-fill--char-kinsoku-eol-p (following-char))
+ (bolp)))
+ (backward-char 1))
+ (if failed
+ ;; There's no breakable point, so we give it up.
+ (let (found)
+ (goto-char bp)
+ ;; Don't overflow the window edge, even if
+ ;; `pixel-fill-respect-kinsoku' is t.
+ (when pixel-fill-respect-kinsoku
+ (while (setq found (re-search-forward
+ "\\(\\c>\\)\\| \\|\\c<\\|\\c|"
+ (line-end-position) 'move)))
+ (if (and found
+ (not (match-beginning 1)))
+ (goto-char (match-beginning 0)))))
+ (or
+ (eolp)
+ ;; Don't put kinsoku-bol characters at the beginning of a line,
+ ;; or kinsoku-eol characters at the end of a line.
+ (cond
+ ;; Don't overflow the window edge, even if `pixel-fill-respect-kinsoku'
+ ;; is t.
+ ((not pixel-fill-respect-kinsoku)
+ (while (and (not (eq (preceding-char) ?\s))
+ (or (pixel-fill--char-kinsoku-eol-p (preceding-char))
+ (pixel-fill--char-kinsoku-bol-p (following-char))))
+ (backward-char 1))
+ (when (setq failed (<= (point) start))
+ ;; There's no breakable point that doesn't violate kinsoku,
+ ;; so we look for the second best position.
+ (while (and (progn
+ (forward-char 1)
+ (<= (point) end))
+ (progn
+ (setq bp (point))
+ (pixel-fill--char-kinsoku-eol-p (following-char)))))
+ (goto-char bp)))
+ ((pixel-fill--char-kinsoku-eol-p (preceding-char))
+ ;; Find backward the point where kinsoku-eol characters begin.
+ (let ((count 4))
+ (while
+ (progn
+ (backward-char 1)
+ (and (> (setq count (1- count)) 0)
+ (not (eq (preceding-char) ?\s))
+ (or (pixel-fill--char-kinsoku-eol-p (preceding-char))
+ (pixel-fill--char-kinsoku-bol-p (following-char)))))))
+ (when (setq failed (<= (point) start))
+ ;; There's no breakable point that doesn't violate kinsoku,
+ ;; so we go to the second best position.
+ (if (looking-at "\\(\\c<+\\)\\c<")
+ (goto-char (match-end 1))
+ (forward-char 1))))
+ ((pixel-fill--char-kinsoku-bol-p (following-char))
+ ;; Find forward the point where kinsoku-bol characters end.
+ (let ((count 4))
+ (while (progn
+ (forward-char 1)
+ (and (>= (setq count (1- count)) 0)
+ (pixel-fill--char-kinsoku-bol-p (following-char))
+ (pixel-fill--char-breakable-p (following-char))))))))
+ (when (eq (following-char) ?\s)
+ (forward-char 1))))
+ (not failed)))
+
+(provide 'pixel-fill)
+
+;;; pixel-fill.el ends here
diff --git a/lisp/textmodes/reftex-cite.el b/lisp/textmodes/reftex-cite.el
index 4e487d745c2..26b14ebc79e 100644
--- a/lisp/textmodes/reftex-cite.el
+++ b/lisp/textmodes/reftex-cite.el
@@ -360,7 +360,7 @@ The name of the first different author/editor is used."
;; Parse the bibliography environment
(defun reftex-extract-bib-entries-from-thebibliography (files)
- "Extract bib-entries from the \begin{thebibliography} environment.
+ "Extract bib-entries from the \\begin{thebibliography} environment.
Parsing is not as good as for the BibTeX database stuff.
The environment should be located in FILES."
(let* (start end buf entries re re-list file default)
@@ -580,7 +580,7 @@ If FORMAT is non-nil `format' entry accordingly."
(concat key "\n " authors " " year " " extra "\n " title "\n\n")))
(defun reftex-parse-bibitem (item)
- "Parse a \bibitem entry in ITEM."
+ "Parse a \\bibitem entry in ITEM."
(let ((key "") (text ""))
(when (string-match "\\`{\\([^}]+\\)}\\([^\000]*\\)" item)
(setq key (match-string 1 item)
@@ -596,7 +596,7 @@ If FORMAT is non-nil `format' entry accordingly."
(cons "&entry" (concat key " " text)))))
(defun reftex-format-bibitem (item)
- "Format a \bibitem entry in ITEM so that it is (relatively) nice to look at."
+ "Format a \\bibitem entry in ITEM so that it is (relatively) nice to look at."
(let ((text (reftex-get-bib-field "&text" item))
(key (reftex-get-bib-field "&key" item))
(lines nil))
diff --git a/lisp/textmodes/reftex-global.el b/lisp/textmodes/reftex-global.el
index c7e34b4b90a..062cea9c505 100644
--- a/lisp/textmodes/reftex-global.el
+++ b/lisp/textmodes/reftex-global.el
@@ -154,8 +154,10 @@ No active TAGS table is required."
(erase-buffer)
(insert " MULTIPLE LABELS IN CURRENT DOCUMENT:\n")
(insert
- " Move point to label and type `r' to run a query-replace on the label\n"
- " and its references. Type `q' to exit this buffer.\n\n")
+ (substitute-command-keys
+ " Move point to label and type \\`r' to run a query-replace on the label\n")
+ (substitute-command-keys
+ " and its references. Type \\`q' to exit this buffer.\n\n"))
(insert " LABEL FILE\n")
(insert " -------------------------------------------------------------\n")
(use-local-map (make-sparse-keymap))
@@ -188,8 +190,8 @@ No active TAGS table is required."
default))))
(if (string= from "") (setq from default))
(unless to
- (setq to (read-string (format "Replace label %s with: "
- from))))
+ (setq to (read-string (format "Replace label %s with: " from)
+ nil nil from)))
(reftex-query-replace-document
(concat "{" (regexp-quote from) "}")
(format "{%s}" to))))
diff --git a/lisp/textmodes/reftex-index.el b/lisp/textmodes/reftex-index.el
index c28f31d5647..734f82aba3f 100644
--- a/lisp/textmodes/reftex-index.el
+++ b/lisp/textmodes/reftex-index.el
@@ -29,9 +29,7 @@
(require 'reftex)
-;; START remove for XEmacs release
(defvar TeX-master)
-;; END remove for XEmacs release
;;;###autoload
(defun reftex-index-selection-or-word (&optional arg phrase)
diff --git a/lisp/textmodes/reftex-parse.el b/lisp/textmodes/reftex-parse.el
index e34c45178b4..49cef297882 100644
--- a/lisp/textmodes/reftex-parse.el
+++ b/lisp/textmodes/reftex-parse.el
@@ -345,7 +345,17 @@ of master file."
;; Find external document specifications
(goto-char 1)
- (while (re-search-forward "[\n\r][ \t]*\\\\externaldocument\\(\\[\\([^]]*\\)\\]\\)?{\\([^}]+\\)}" nil t)
+ (while (re-search-forward
+ (concat "[\n\r][ \t]*"
+ ;; Support \externalcitedocument macro
+ "\\\\external\\(?:cite\\)?document"
+ ;; The optional prefix
+ "\\(\\[\\([^]]*\\)\\]\\)?"
+ ;; The 2nd opt. arg can only be nocite
+ "\\(?:\\[nocite\\]\\)?"
+ ;; Mandatory file argument
+ "{\\([^}]+\\)}")
+ nil t)
(push (list 'xr-doc (reftex-match-string 2)
(reftex-match-string 3))
docstruct))
@@ -360,13 +370,18 @@ of master file."
docstruct))
(defun reftex-using-biblatex-p ()
- "Return non-nil if we are using biblatex rather than bibtex."
+ "Return non-nil if we are using biblatex or other specific cite package.
+biblatex and other similar packages like multibib allow multiple macro
+calls to load a bibliography file. This function should be able to
+detect those packages."
(if (boundp 'TeX-active-styles)
;; the sophisticated AUCTeX way
- (member "biblatex" TeX-active-styles)
+ (or (member "biblatex" TeX-active-styles)
+ (member "multibib" TeX-active-styles))
;; poor-man's check...
(save-excursion
- (re-search-forward "^[^%\n]*?\\\\usepackage.*{biblatex}" nil t))))
+ (re-search-forward
+ "^[^%\n]*?\\\\usepackage\\(\\[[^]]*\\]\\)?{biblatex\\|multibib}" nil t))))
;;;###autoload
(defun reftex-locate-bibliography-files (master-dir &optional files)
@@ -374,7 +389,7 @@ of master file."
(unless files
(save-excursion
(goto-char (point-min))
- ;; when biblatex is used, multiple \bibliography or
+ ;; when biblatex or multibib are used, multiple \bibliography or
;; \addbibresource macros are allowed. With plain bibtex, only
;; the first is used.
(let ((using-biblatex (reftex-using-biblatex-p))
@@ -382,7 +397,7 @@ of master file."
(while (and again
(re-search-forward
(concat
- ;; "\\(\\`\\|[\n\r]\\)[^%]*\\\\\\("
+ ;; "\\(\\`\\|[\n\r]\\)[^%]*\\\\\\("
"\\(^\\)[^%\n\r]*\\\\\\("
(mapconcat #'identity reftex-bibliography-commands "\\|")
"\\)\\(\\[.+?\\]\\)?{[ \t]*\\([^}]+\\)")
@@ -405,7 +420,7 @@ of master file."
;; find the file
(reftex-locate-file x "bib" master-dir)))
files))
- (delq nil files)))
+ (delq nil (delete-dups files))))
(defun reftex-replace-label-list-segment (old insert &optional entirely)
"Replace the segment in OLD which corresponds to INSERT.
diff --git a/lisp/textmodes/reftex-toc.el b/lisp/textmodes/reftex-toc.el
index 4ba3c2193ee..f6f72cec4f8 100644
--- a/lisp/textmodes/reftex-toc.el
+++ b/lisp/textmodes/reftex-toc.el
@@ -381,7 +381,7 @@ SPC=view TAB=goto RET=goto+hide [q]uit [r]escan [l]abels [f]ollow [x]r [?]Help
(- (or reftex-last-window-height (window-height))
(window-height)))))
(when (> count 0)
- (with-demoted-errors ;E.g. the window might be the root window!
+ (with-demoted-errors "Enlarge window error: %S"
(enlarge-window count reftex-toc-split-windows-horizontally)))))
(defun reftex-toc-dframe-p (&optional frame error)
diff --git a/lisp/textmodes/reftex-vars.el b/lisp/textmodes/reftex-vars.el
index 36dd36c95ea..f9f09825fa0 100644
--- a/lisp/textmodes/reftex-vars.el
+++ b/lisp/textmodes/reftex-vars.el
@@ -70,12 +70,16 @@
("tabwindow" ?f nil nil 1)))
(rotating "Sidewaysfigure and table"
- (("sidewaysfigure" ?f nil nil caption)
- ("sidewaystable" ?t nil nil caption)))
+ (("sidewaysfigure" ?f nil nil caption)
+ ("sidewaysfigure*" ?f nil nil caption)
+ ("sidewaystable" ?t nil nil caption)
+ ("sidewaystable*" ?t nil nil caption)))
- (sidecap "CSfigure and SCtable"
- (("SCfigure" ?f nil nil caption)
- ("SCtable" ?t nil nil caption)))
+ (sidecap "SCfigure and SCtable"
+ (("SCfigure" ?f nil nil caption)
+ ("SCfigure*" ?f nil nil caption)
+ ("SCtable" ?t nil nil caption)
+ ("SCtable*" ?t nil nil caption)))
(subfigure "Subfigure environments/macro"
(("subfigure" ?f nil nil caption)
@@ -392,19 +396,19 @@ that the *toc* window fills half the frame."
(defcustom reftex-toc-include-file-boundaries nil
"Non-nil means, include file boundaries in *toc* buffer.
-This flag can be toggled from within the *toc* buffer with the `F' key."
+This flag can be toggled from within the *toc* buffer with the \\`F' key."
:group 'reftex-table-of-contents-browser
:type 'boolean)
(defcustom reftex-toc-include-labels nil
"Non-nil means, include labels in *toc* buffer.
-This flag can be toggled from within the *toc* buffer with the `l' key."
+This flag can be toggled from within the *toc* buffer with the \\`l' key."
:group 'reftex-table-of-contents-browser
:type 'boolean)
(defcustom reftex-toc-include-index-entries nil
"Non-nil means, include index entries in *toc* buffer.
-This flag can be toggled from within the *toc* buffer with the `i' key."
+This flag can be toggled from within the *toc* buffer with the \\`i' key."
:group 'reftex-table-of-contents-browser
:type 'boolean)
@@ -422,14 +426,14 @@ changed."
(defcustom reftex-toc-include-context nil
"Non-nil means, include context with labels in the *toc* buffer.
Context will only be shown when labels are visible as well.
-This flag can be toggled from within the *toc* buffer with the `c' key."
+This flag can be toggled from within the *toc* buffer with the \\`c' key."
:group 'reftex-table-of-contents-browser
:type 'boolean)
(defcustom reftex-toc-follow-mode nil
"Non-nil means, point in *toc* buffer will cause other window to follow.
The other window will show the corresponding part of the document.
-This flag can be toggled from within the *toc* buffer with the `f' key."
+This flag can be toggled from within the *toc* buffer with the \\`f' key."
:group 'reftex-table-of-contents-browser
:type 'boolean)
@@ -1314,7 +1318,7 @@ macro before insertion. For example, it will change
\\cite[][]{Jones} -> \\cite{Jones}
\\cite[][Chapter 1]{Jones} -> \\cite[Chapter 1]{Jones}
\\cite[see][]{Jones} -> \\cite[see][]{Jones}
- \\cite[see][Chapter 1]{Jones} -> \\cite{Jones}
+ \\cite[see][Chapter 1]{Jones} -> \\cite[see][Chapter 1]{Jones}
It is possible that other packages have other conventions about which
optional argument is interpreted how - that is why this cleaning up
can be turned off."
@@ -1627,14 +1631,14 @@ to that section."
(defcustom reftex-index-include-context nil
"Non-nil means, display the index definition context in the index buffer.
-This flag may also be toggled from the index buffer with the `c' key."
+This flag may also be toggled from the index buffer with the \\`c' key."
:group 'reftex-index-support
:type 'boolean)
(defcustom reftex-index-follow-mode nil
"Non-nil means, point in *Index* buffer will cause other window to follow.
The other window will show the corresponding part of the document.
-This flag can be toggled from within the *Index* buffer with the `f' key."
+This flag can be toggled from within the *Index* buffer with the \\`f' key."
:group 'reftex-table-of-contents-browser
:type 'boolean)
@@ -1863,10 +1867,11 @@ of the regular expressions in this list, that file is not parsed by RefTeX."
(defcustom reftex-enable-partial-scans nil
"Non-nil means, re-parse only 1 file when asked to re-parse.
Re-parsing is normally requested with a \\[universal-argument] prefix to many RefTeX commands,
-or with the `r' key in menus. When this option is t in a multifile document,
+or with the \\`r' key in menus. When this option is t in a multifile document,
we will only parse the current buffer, or the file associated with the label
or section heading near point in a menu. Requesting re-parsing of an entire
-multifile document then requires a \\[universal-argument] \\[universal-argument] prefix or the capital `R' key
+multifile document then requires a \\[universal-argument] \
+\\[universal-argument] prefix or the capital \\`R' key
in menus."
:group 'reftex-optimizations-for-large-documents
:type 'boolean)
@@ -1912,7 +1917,7 @@ when new labels in its category are added. See the variable
When a new label is defined with `reftex-label', all selection buffers
associated with that label category are emptied, in order to force an
update upon next use. When nil, the buffers are left alone and have to be
-updated by hand, with the `g' key from the label selection process.
+updated by hand, with the \\`g' key from the label selection process.
The value of this variable will only have any effect when
`reftex-use-multiple-selection-buffers' is non-nil."
:group 'reftex-optimizations-for-large-documents
@@ -1964,7 +1969,7 @@ instead or as well. The variable may have one of these values:
both Both cursor and mouse trigger highlighting.
Changing this variable requires rebuilding the selection and *toc* buffers
-to become effective (keys `g' or `r')."
+to become effective (keys \\`g' or \\`r')."
:group 'reftex-fontification-configurations
:type '(choice
(const :tag "Never" nil)
diff --git a/lisp/textmodes/reftex.el b/lisp/textmodes/reftex.el
index 907d50889a1..e72576cdc74 100644
--- a/lisp/textmodes/reftex.el
+++ b/lisp/textmodes/reftex.el
@@ -2257,8 +2257,7 @@ IGNORE-WORDS List of words which should be removed from the string."
("Customize"
["Browse RefTeX Group" reftex-customize t]
"--"
- ["Build Full Customize Menu" reftex-create-customize-menu
- (fboundp 'customize-menu-create)])
+ ["Build Full Customize Menu" reftex-create-customize-menu])
("Documentation"
["Info" reftex-info t]
["Commentary" reftex-show-commentary t])))
diff --git a/lisp/textmodes/remember.el b/lisp/textmodes/remember.el
index d65aea62862..e72f86f7db6 100644
--- a/lisp/textmodes/remember.el
+++ b/lisp/textmodes/remember.el
@@ -653,7 +653,7 @@ to turn the *scratch* buffer into your notes buffer."
(remember-notes-mode 1)
(current-buffer)))))
(when switch-to
- (switch-to-buffer buf))
+ (pop-to-buffer-same-window buf))
buf))
(defun remember-notes--kill-buffer-query ()
diff --git a/lisp/textmodes/rst.el b/lisp/textmodes/rst.el
index 9d3e9effe6e..6a91cef1d94 100644
--- a/lisp/textmodes/rst.el
+++ b/lisp/textmodes/rst.el
@@ -2351,7 +2351,7 @@ If user selects bullets or #, it's just added with position arranged by
`rst-insert-list-new-tag'.
If user selects enumerations, a further prompt is given. User need to
-input a starting item, for example 'e' for 'A)' style. The position is
+input a starting item, for example `e' for `A)' style. The position is
also arranged by `rst-insert-list-new-tag'."
(let* ((itemstyle (completing-read
(format-prompt "Select preferred item style" "#.")
diff --git a/lisp/textmodes/sgml-mode.el b/lisp/textmodes/sgml-mode.el
index efebee0521b..b49541f47d4 100644
--- a/lisp/textmodes/sgml-mode.el
+++ b/lisp/textmodes/sgml-mode.el
@@ -75,7 +75,8 @@ a DOCTYPE or an XML declaration."
:type 'boolean
:version "22.1")
-(defvaralias 'sgml-transformation 'sgml-transformation-function)
+(define-obsolete-variable-alias 'sgml-transformation
+ 'sgml-transformation-function "29.1")
(defcustom sgml-transformation-function 'identity
"Default value for `skeleton-transformation-function' in SGML mode."
@@ -418,11 +419,11 @@ These have to be run via `sgml-syntax-propertize'"))
(defun sgml-syntax-propertize (start end &optional rules-function)
"Syntactic keywords for `sgml-mode'."
(setq sgml--syntax-propertize-ppss (cons start (syntax-ppss start)))
- (cl-assert (>= (cadr sgml--syntax-propertize-ppss) 0))
- (sgml-syntax-propertize-inside end)
- (funcall (or rules-function sgml--syntax-propertize) (point) end)
- ;; Catch any '>' after the last quote.
- (sgml--syntax-propertize-ppss end))
+ (when (>= (cadr sgml--syntax-propertize-ppss) 0)
+ (sgml-syntax-propertize-inside end)
+ (funcall (or rules-function sgml--syntax-propertize) (point) end)
+ ;; Catch any '>' after the last quote.
+ (sgml--syntax-propertize-ppss end)))
(defun sgml-syntax-propertize-inside (end)
(let ((ppss (syntax-ppss)))
@@ -440,7 +441,8 @@ These have to be run via `sgml-syntax-propertize'"))
;; internal
(defvar sgml-face-tag-alist ()
- "Alist of face and tag name for facemenu.")
+ "Alist of face and tag name for facemenu.
+The tag name can be a string or a list of strings.")
(defvar sgml-tag-face-alist ()
"Tag names and face or list of faces to fontify with when invisible.
@@ -528,11 +530,13 @@ an optional alist of possible values."
(comment-indent-new-line soft)))
(defun sgml-mode-facemenu-add-face-function (face _end)
- (let ((tag-face (cdr (assq face sgml-face-tag-alist))))
+ "Add \"face\" tags with `facemenu-keymap' commands."
+ (let ((tag-face (ensure-list (cdr (assq face sgml-face-tag-alist)))))
(cond (tag-face
(setq tag-face (funcall skeleton-transformation-function tag-face))
- (setq facemenu-end-add-face (concat "</" tag-face ">"))
- (concat "<" tag-face ">"))
+ (setq facemenu-end-add-face
+ (mapconcat (lambda (f) (concat "</" f ">")) (reverse tag-face) ""))
+ (mapconcat (lambda (f) (concat "<" f ">")) tag-face ""))
((and (consp face)
(consp (car face))
(null (cdr face))
@@ -620,6 +624,7 @@ Do \\[describe-key] on the following bindings to discover what they do.
(setq-local comment-indent-function 'sgml-comment-indent)
(setq-local comment-line-break-function 'sgml-comment-indent-new-line)
(setq-local skeleton-further-elements '((completion-ignore-case t)))
+ (setq-local skeleton-end-newline nil)
(setq-local skeleton-end-hook
(lambda ()
(or (eolp)
@@ -1868,6 +1873,7 @@ This takes effect when first loading the library.")
(defvar html-face-tag-alist
'((bold . "strong")
(italic . "em")
+ (bold-italic . ("strong" "em"))
(underline . "u")
(mode-line . "rev"))
"Value of `sgml-face-tag-alist' for HTML mode.")
@@ -2411,6 +2417,8 @@ To work around that, do:
(setq-local css-id-list-function #'html-current-buffer-ids))
(setq imenu-create-index-function 'html-imenu-index)
+ (yank-media-handler 'text/html #'html-mode--html-yank-handler)
+ (yank-media-handler "image/.*" #'html-mode--image-yank-handler)
(setq-local sgml-empty-tags
;; From HTML-4.01's loose.dtd, parsed with
@@ -2426,6 +2434,30 @@ To work around that, do:
;; (setq imenu-sort-function nil) ; sorting the menu defeats the purpose
)
+(defun html-mode--html-yank-handler (_type html)
+ (save-restriction
+ (insert html)
+ (ignore-errors
+ (sgml-pretty-print (point-min) (point-max)))))
+
+(defun html-mode--image-yank-handler (type image)
+ (let ((file (read-file-name (format "Save %s image to: " type))))
+ (when (file-directory-p file)
+ (user-error "%s is a directory"))
+ (when (and (file-exists-p file)
+ (not (yes-or-no-p (format "%s exists; overwrite?" file))))
+ (user-error "%s exists"))
+ (with-temp-buffer
+ (set-buffer-multibyte nil)
+ (insert image)
+ (write-region (point-min) (point-max) file))
+ (insert (format "<img src=%S>\n" (file-relative-name file)))
+ (insert-image
+ (create-image file (mailcap-mime-type-to-extension type) nil
+ :max-width 200
+ :max-height 200)
+ " ")))
+
(defvar html-imenu-regexp
"\\s-*<h\\([1-9]\\)[^\n<>]*>\\(<[^\n<>]*>\\)*\\s-*\\([^\n<>]*\\)"
"A regular expression matching a head line to be added to the menu.
diff --git a/lisp/textmodes/string-edit.el b/lisp/textmodes/string-edit.el
new file mode 100644
index 00000000000..53850674ac0
--- /dev/null
+++ b/lisp/textmodes/string-edit.el
@@ -0,0 +1,136 @@
+;;; string-edit.el --- editing long strings -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2022 Free Software Foundation, Inc.
+
+;; Maintainer: emacs-devel@gnu.org
+
+;; 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
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) 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. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'cl-lib)
+
+(defface string-edit-prompt
+ '((t (:inherit font-lock-comment-face)))
+ "Face used on `string-edit' help text."
+ :group 'text
+ :version "29.1")
+
+(defvar string-edit--success-callback)
+(defvar string-edit--abort-callback)
+
+;;;###autoload
+(cl-defun string-edit (prompt string success-callback
+ &key abort-callback)
+ "Switch to a new buffer to edit STRING.
+When the user finishes editing (with \\<string-edit-mode-map>\\[string-edit-done]), SUCCESS-CALLBACK
+is called with the resulting string.
+
+If the user aborts (with \\<string-edit-mode-map>\\[string-edit-abort]), ABORT-CALLBACK (if any) is
+called with no parameters.
+
+PROMPT will be inserted at the start of the buffer, but won't be
+included in the resulting string. If PROMPT is nil, no help text
+will be inserted."
+ (with-current-buffer (generate-new-buffer "*edit string*")
+ (when prompt
+ (let ((inhibit-read-only t))
+ (insert prompt)
+ (ensure-empty-lines 0)
+ (add-text-properties (point-min) (point)
+ (list 'intangible t
+ 'face 'string-edit-prompt
+ 'read-only t))
+ (insert (propertize (make-separator-line) 'rear-nonsticky t))
+ (add-text-properties (point-min) (point)
+ (list 'string-edit--prompt t))))
+ (let ((start (point)))
+ (insert string)
+ (goto-char start))
+
+ ;; Use `fit-window-to-buffer' after the buffer is filled with text.
+ (pop-to-buffer (current-buffer)
+ '(display-buffer-below-selected
+ (window-height . (lambda (window)
+ (fit-window-to-buffer window nil 10)))))
+
+ (set-buffer-modified-p nil)
+ (setq buffer-undo-list nil)
+ (string-edit-mode)
+ (setq-local string-edit--success-callback success-callback)
+ (when abort-callback
+ (setq-local string-edit--abort-callback abort-callback))
+ (setq-local header-line-format
+ (substitute-command-keys
+ "Type \\<string-edit-mode-map>\\[string-edit-done] when you've finished editing or \\[string-edit-abort] to abort"))
+ (message "%s" (substitute-command-keys
+ "Type \\<string-edit-mode-map>\\[string-edit-done] when you've finished editing"))))
+
+;;;###autoload
+(defun read-string-from-buffer (prompt string)
+ "Switch to a new buffer to edit STRING in a recursive edit.
+The user finishes editing with \\<string-edit-mode-map>\\[string-edit-done], or aborts with \\<string-edit-mode-map>\\[string-edit-abort]).
+
+PROMPT will be inserted at the start of the buffer, but won't be
+included in the resulting string. If nil, no prompt will be
+inserted in the buffer."
+ (string-edit
+ prompt
+ string
+ (lambda (edited)
+ (setq string edited)
+ (exit-recursive-edit))
+ :abort-callback (lambda ()
+ (exit-recursive-edit)
+ (error "Aborted edit")))
+ (recursive-edit)
+ string)
+
+(defvar-keymap string-edit-mode-map
+ "C-c C-c" #'string-edit-done
+ "C-c C-k" #'string-edit-abort)
+
+(define-derived-mode string-edit-mode text-mode "String"
+ "Mode for editing strings."
+ :interactive nil)
+
+(defun string-edit-done ()
+ "Finish editing the string and call the callback function.
+This will kill the current buffer."
+ (interactive)
+ (goto-char (point-min))
+ ;; Skip past the help text.
+ (when-let ((match (text-property-search-forward
+ 'string-edit--prompt nil t)))
+ (goto-char (prop-match-beginning match)))
+ (let ((string (buffer-substring (point) (point-max)))
+ (callback string-edit--success-callback))
+ (quit-window 'kill)
+ (funcall callback string)))
+
+(defun string-edit-abort ()
+ "Abort editing the current string."
+ (interactive)
+ (let ((callback string-edit--abort-callback))
+ (quit-window 'kill)
+ (when callback
+ (funcall callback))))
+
+(provide 'string-edit)
+
+;;; string-edit.el ends here
diff --git a/lisp/textmodes/table.el b/lisp/textmodes/table.el
index 30a07cbefea..fc06c4c0da1 100644
--- a/lisp/textmodes/table.el
+++ b/lisp/textmodes/table.el
@@ -753,6 +753,18 @@ the cell contents dynamically."
:type 'string
:group 'table)
+(defcustom table-latex-environment "tabular"
+ "Tabular-compatible environment to use when generating latex.
+The value should be a string suitable for use as a LaTeX environment
+that's compatible with the \"tabular\" protocol, such as \"tabular\"
+and \"longtable\"."
+ :tag "Latex environment used to export tables"
+ :type '(choice
+ (const :tag "tabular" "tabular")
+ (const :tag "longtable" "longtable")
+ string)
+ :version "29.1")
+
(defcustom table-cals-thead-rows 1
"Number of top rows to become header rows in CALS table."
:tag "CALS Header Rows"
@@ -1195,6 +1207,21 @@ executing body forms.")
(easy-menu-add-item (current-global-map)
'("menu-bar" "tools") table-global-menu-map)
+;;;###autoload
+(define-minor-mode table-fixed-width-mode
+ "Cell width is fixed when this is non-nil.
+Normally it should be nil for allowing automatic cell width expansion
+that widens a cell when it is necessary. When non-nil, typing in a
+cell does not automatically expand the cell width. A word that is too
+long to fit in a cell is chopped into multiple lines. The chopped
+location is indicated by `table-word-continuation-char'. This
+variable's value can be toggled by \\[table-fixed-width-mode] at
+run-time."
+ :tag "Fix Cell Width"
+ :group 'table
+ (table--finish-delayed-tasks)
+ (table--update-cell-face))
+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Macros
@@ -1219,43 +1246,49 @@ original buffer's point is moved to the location that corresponds to
the last cache point coordinate."
(declare (debug (body)) (indent 0))
(let ((height-expansion (make-symbol "height-expansion-var-symbol"))
- (width-expansion (make-symbol "width-expansion-var-symbol")))
- `(let (,height-expansion ,width-expansion)
+ (width-expansion (make-symbol "width-expansion-var-symbol"))
+ (fixed-width (make-symbol "fixed-width")))
+ `(let ((,fixed-width table-fixed-width-mode)
+ ,height-expansion ,width-expansion)
;; make sure cache has valid data unless it is explicitly inhibited.
(unless table-inhibit-update
(table-recognize-cell))
(with-current-buffer (get-buffer-create table-cache-buffer-name)
- ;; goto the cell coordinate based on `table-cell-cache-point-coordinate'.
- (set-mark (table--goto-coordinate table-cell-cache-mark-coordinate))
- (table--goto-coordinate table-cell-cache-point-coordinate)
- (table--untabify-line)
- ;; always reset before executing body forms because auto-fill behavior is the default.
- (setq table-inhibit-auto-fill-paragraph nil)
- ;; do the body
- ,@body
- ;; fill paragraph unless the body does not want to by setting `table-inhibit-auto-fill-paragraph'.
- (unless table-inhibit-auto-fill-paragraph
- (if (and table-cell-info-justify
- (not (eq table-cell-info-justify 'left)))
- (table--fill-region (point-min) (point-max))
- (table--fill-region
- (save-excursion (forward-paragraph -1) (point))
- (save-excursion (forward-paragraph 1) (point)))))
- ;; keep the updated cell coordinate.
- (setq table-cell-cache-point-coordinate (table--get-coordinate))
- ;; determine the cell width expansion.
- (setq ,width-expansion (table--measure-max-width))
- (if (<= ,width-expansion table-cell-info-width) nil
- (table--fill-region (point-min) (point-max) ,width-expansion)
- ;; keep the updated cell coordinate.
- (setq table-cell-cache-point-coordinate (table--get-coordinate)))
- (setq ,width-expansion (- ,width-expansion table-cell-info-width))
- ;; determine the cell height expansion.
- (if (looking-at "\\s *\\'") nil
- (goto-char (point-min))
- (if (re-search-forward "\\(\\s *\\)\\'" nil t)
- (goto-char (match-beginning 1))))
- (setq ,height-expansion (- (cdr (table--get-coordinate)) (1- table-cell-info-height))))
+ (let ((table-fixed-width-mode ,fixed-width))
+ ;; Go to the cell coordinate based on
+ ;; `table-cell-cache-point-coordinate'.
+ (set-mark (table--goto-coordinate table-cell-cache-mark-coordinate))
+ (table--goto-coordinate table-cell-cache-point-coordinate)
+ (table--untabify-line)
+ ;; Always reset before executing body forms because
+ ;; auto-fill behavior is the default.
+ (setq table-inhibit-auto-fill-paragraph nil)
+ ;; Do the body
+ ,@body
+ ;; Fill paragraph unless the body does not want to by
+ ;; setting `table-inhibit-auto-fill-paragraph'.
+ (unless table-inhibit-auto-fill-paragraph
+ (if (and table-cell-info-justify
+ (not (eq table-cell-info-justify 'left)))
+ (table--fill-region (point-min) (point-max))
+ (table--fill-region
+ (save-excursion (forward-paragraph -1) (point))
+ (save-excursion (forward-paragraph 1) (point)))))
+ ;; Keep the updated cell coordinate.
+ (setq table-cell-cache-point-coordinate (table--get-coordinate))
+ ;; Determine the cell width expansion.
+ (setq ,width-expansion (table--measure-max-width))
+ (if (<= ,width-expansion table-cell-info-width) nil
+ (table--fill-region (point-min) (point-max) ,width-expansion)
+ ;; Keep the updated cell coordinate.
+ (setq table-cell-cache-point-coordinate (table--get-coordinate)))
+ (setq ,width-expansion (- ,width-expansion table-cell-info-width))
+ ;; Determine the cell height expansion.
+ (if (looking-at "\\s *\\'") nil
+ (goto-char (point-min))
+ (if (re-search-forward "\\(\\s *\\)\\'" nil t)
+ (goto-char (match-beginning 1))))
+ (setq ,height-expansion (- (cdr (table--get-coordinate)) (1- table-cell-info-height)))))
;; now back to the table buffer.
;; expand the cell width in the table buffer if necessary.
(if (> ,width-expansion 0)
@@ -2823,21 +2856,6 @@ or `top', `middle', `bottom' or `none' for vertical."
(table--justify-cell-contents justify))))))
;;;###autoload
-(define-minor-mode table-fixed-width-mode
- "Cell width is fixed when this is non-nil.
-Normally it should be nil for allowing automatic cell width expansion
-that widens a cell when it is necessary. When non-nil, typing in a
-cell does not automatically expand the cell width. A word that is too
-long to fit in a cell is chopped into multiple lines. The chopped
-location is indicated by `table-word-continuation-char'. This
-variable's value can be toggled by \\[table-fixed-width-mode] at
-run-time."
- :tag "Fix Cell Width"
- :group 'table
- (table--finish-delayed-tasks)
- (table--update-cell-face))
-
-;;;###autoload
(defun table-query-dimension (&optional where)
"Return the dimension of the current cell and the current table.
The result is a list (cw ch tw th c r cells) where cw is the cell
@@ -3019,7 +3037,8 @@ CALS (DocBook DTD):
"")))
((eq language 'latex)
(insert (format "%% This LaTeX table template is generated by emacs %s\n" emacs-version)
- "\\begin{tabular}{|" (apply #'concat (make-list (length col-list) "l|")) "}\n"
+ "\\begin{" table-latex-environment "}{|"
+ (apply #'concat (make-list (length col-list) "l|")) "}\n"
"\\hline\n"))
((eq language 'cals)
(insert (format "<!-- This CALS table template is generated by emacs %s -->\n" emacs-version)
@@ -3045,7 +3064,7 @@ CALS (DocBook DTD):
((eq language 'html)
(insert "</table>\n"))
((eq language 'latex)
- (insert "\\end{tabular}\n"))
+ (insert "\\end{" table-latex-environment "}\n"))
((eq language 'cals)
(set-marker-insertion-type (table-get-source-info 'colspec-marker) t) ;; insert before
(save-excursion
diff --git a/lisp/textmodes/tex-mode.el b/lisp/textmodes/tex-mode.el
index 64e38ad6973..da4d7cc442d 100644
--- a/lisp/textmodes/tex-mode.el
+++ b/lisp/textmodes/tex-mode.el
@@ -505,7 +505,9 @@ An alternative value is \" . \", if you use a font with a narrow period."
"documentstyle" "documentclass" "verbatiminput"
"includegraphics" "includegraphics*")
t))
- (verbish (regexp-opt '("url" "nolinkurl" "path") t))
+ (verbish (regexp-opt '("url" "nolinkurl" "path"
+ "href" "ProvidesFile")
+ t))
;; Miscellany.
(slash "\\\\")
(opt " *\\(\\[[^]]*\\] *\\)*")
@@ -2037,7 +2039,7 @@ In the tex shell buffer this command behaves like `comint-send-input'."
(defun tex-display-shell ()
"Make the TeX shell buffer visible in a window."
- (display-buffer (tex-shell-buf))
+ (display-buffer (tex-shell-buf) display-comint-buffer-action)
(tex-recenter-output-buffer nil))
(defun tex-shell-sentinel (proc _msg)
@@ -2441,7 +2443,7 @@ Only applies the FSPEC to the args part of FORMAT."
(if cmds (tex-format-cmd (caar cmds) fspec))))))
(defun tex-cmd-doc-view (file)
- (pop-to-buffer (find-file-noselect file)))
+ (pop-to-buffer (find-file-noselect file) display-comint-buffer-action))
(defun tex-compile (dir cmd)
"Run a command CMD on current TeX buffer's file in DIR."
@@ -2457,7 +2459,7 @@ Only applies the FSPEC to the args part of FORMAT."
(default (tex-compile-default fspec)))
(list default-directory
(completing-read
- (format "Command [%s]: " (tex-summarize-command default))
+ (format-prompt "Command" (tex-summarize-command default))
(mapcar (lambda (x)
(list (tex-format-cmd (eval (car x) t) fspec)))
tex-compile-commands)
@@ -2698,7 +2700,7 @@ line LINE of the window, or centered if LINE is nil."
(window))
(if (null tex-shell)
(message "No TeX output buffer")
- (setq window (display-buffer tex-shell))
+ (setq window (display-buffer tex-shell display-comint-buffer-action))
(with-selected-window window
(bury-buffer tex-shell)
(goto-char (point-max))
@@ -2987,13 +2989,7 @@ There might be text before point."
(put-text-property
(1- (match-beginning 1)) (match-beginning 1)
'syntax-table
- (if (= (1+ (line-beginning-position)) (match-beginning 1))
- ;; The `%' is a single-char comment, which Emacs
- ;; syntax-table can't deal with. We could turn it
- ;; into a non-comment, or use `\n%' or `%^' as the comment.
- ;; Instead, we include it in the ^^A comment.
- (string-to-syntax "< b")
- (string-to-syntax ">")))
+ (string-to-syntax ">"))
(let ((end (line-end-position)))
(if (< end (point-max))
(put-text-property
@@ -3016,8 +3012,9 @@ There might be text before point."
(defconst doctex-syntax-propertize-rules
(syntax-propertize-precompile-rules
latex-syntax-propertize-rules
- ;; For DocTeX comment-in-doc.
- ("\\(\\^\\)\\^A" (1 (doctex-font-lock-^^A))))))
+ ;; For DocTeX comment-in-doc (DocTeX ≥3 also allows ^^X).
+ ;; We make the comment start on the second char because of bug#35140.
+ ("\\^\\(\\^\\)[AX]" (1 (doctex-font-lock-^^A))))))
(defvar doctex-font-lock-keywords
(append tex-font-lock-keywords
@@ -3566,28 +3563,122 @@ There might be text before point."
("\\ordmasculine" . ?º)
("\\lambdabar" . ?ƛ)
("\\celsius" . ?℃)
+ ;; Text symbols formerly part of textcomp package:
+ ("\\textdollar" . ?$)
+ ("\\textborn" . ?*)
+ ("\\textless" . ?<)
+ ("\\textgreater" . ?>)
+ ("\\textbackslash" . ?\\)
+ ("\\textasciicircum" . ?^)
+ ("\\textunderscore" . ?_)
+ ("\\textbraceleft" . ?\{)
+ ("\\textbar" . ?|)
+ ("\\textbraceright" . ?\})
+ ("\\textasciitilde" . ?~)
+ ("\\textexclamdown" . ?¡)
+ ("\\textcent" . ?¢)
+ ("\\textsterling" . ?£)
+ ("\\textcurrency" . ?¤)
+ ("\\textyen" . ?¥)
+ ("\\textbrokenbar" . ?¦)
+ ("\\textsection" . ?§)
+ ("\\textasciidieresis" . ?¨)
+ ("\\textcopyright" . ?©)
+ ("\\textordfeminine" . ?ª)
+ ("\\guillemetleft" . ?«)
+ ("\\guillemotleft" . ?«)
+ ("\\textlnot" . ?¬)
+ ("\\textregistered" . ?®)
+ ("\\textasciimacron" . ?¯)
+ ("\\textdegree" . ?°)
+ ("\\textpm" . ?±)
+ ("\\texttwosuperior" . ?²)
+ ("\\textthreesuperior" . ?³)
+ ("\\textasciiacute" . ?´)
("\\textmu" . ?µ)
+ ("\\textparagraph" . ?¶)
+ ("\\textpilcrow" . ?¶)
+ ("\\textperiodcentered" . ?·)
+ ("\\textonesuperior" . ?¹)
+ ("\\textordmasculine" . ?º)
+ ("\\guillemetright" . ?»)
+ ("\\guillemotright" . ?»)
+ ("\\textonequarter" . ?¼)
+ ("\\textonehalf" . ?½)
+ ("\\textthreequarters" . ?¾)
+ ("\\textquestiondown" . ?¿)
+ ("\\texttimes" . ?×)
+ ("\\textdiv" . ?÷)
+ ("\\textflorin" . ?ƒ)
+ ("\\textasciicaron" . ?ˇ)
+ ("\\textasciibreve" . ?˘)
+ ("\\textacutedbl" . ?˝)
+ ("\\textgravedbl" . 757)
+ ("\\texttildelow" . 759)
+ ("\\textbaht" . ?฿)
+ ("\\textendash" . ?–)
+ ("\\textemdash" . ?—)
+ ("\\textbardbl" . ?‖)
+ ("\\textquoteleft" . 8216)
+ ("\\textquoteright" . 8217)
+ ("\\quotesinglbase" . 8218)
+ ("\\textquotedblleft" . 8220)
+ ("\\textquotedblright" . 8221)
+ ("\\quotedblbase" . 8222)
+ ;; \textdagger and \textdied are replaced with DAGGER (#x2020) and
+ ;; not with LATIN CROSS (#x271d)
+ ("\\textdagger" . ?†)
+ ("\\textdied" . ?†)
+ ("\\textdaggerdbl" . ?‡)
+ ("\\textbullet" . ?•)
+ ("\\textellipsis" . ?…)
+ ("\\textperthousand" . ?‰)
+ ("\\textpertenthousand" . ?‱)
+ ("\\guilsinglleft" . ?‹)
+ ("\\guilsinglright" . ?›)
+ ("\\textreferencemark" . ?※)
+ ("\\textinterrobang" . ?‽)
("\\textfractionsolidus" . ?⁄)
- ("\\textbigcircle" . ?⃝)
- ("\\textmusicalnote" . ?♪)
- ("\\textdied" . ?✝)
+ ("\\textlquill" . 8261) ; Literal ?⁅ breaks indentation
+ ("\\textrquill" . 8262) ; Literal ?⁆ breaks indentation
+ ("\\textdiscount" . ?⁒)
("\\textcolonmonetary" . ?₡)
- ("\\textwon" . ?₩)
+ ("\\textlira" . ?₤)
("\\textnaira" . ?₦)
+ ("\\textwon" . ?₩)
+ ("\\textdong" . ?₫)
+ ("\\texteuro" . ?€)
("\\textpeso" . ?₱)
- ("\\textlira" . ?₤)
- ("\\textrecipe" . ?℞)
- ("\\textinterrobang" . ?‽)
- ("\\textpertenthousand" . ?‱)
- ("\\textbaht" . ?฿)
+ ("\\textguarani" . ?₲)
+ ("\\textcelsius" . ?℃)
("\\textnumero" . ?№)
- ("\\textdiscount" . ?⁒)
+ ("\\textcircledP" . ?℗)
+ ("\\textrecipe" . ?℞)
+ ("\\textservicemark" . ?℠)
+ ("\\texttrademark" . ?™)
+ ("\\textohm" . ?Ω)
+ ("\\textmho" . ?℧)
("\\textestimated" . ?℮)
+ ("\\textleftarrow" . ?←)
+ ("\\textuparrow" . ?↑)
+ ("\\textrightarrow" . ?→)
+ ("\\textdownarrow" . ?↓)
+ ("\\textminus" . ?−)
+ ("\\textsurd" . ?√)
+ ("\\textlangle" . 9001) ; Literal ?〈 breaks indentation
+ ("\\textrangle" . 9002) ; Literal ?〉 breaks indentation
+ ("\\textblank" . ?␢)
+ ("\\textvisiblespace" . ?␣)
("\\textopenbullet" . ?◦)
- ("\\textlquill" . 8261) ; Literal ?⁅ breaks indentation.
- ("\\textrquill" . 8262) ; Literal ?⁆ breaks indentation.
- ("\\textcircledP" . ?℗)
- ("\\textreferencemark" . ?※))
+ ;; \textbigcircle is replaced with LARGE CIRCLE (#x25ef) and not
+ ;; with COMBINING ENCLOSING CIRCLE (#x20dd)
+ ("\\textbigcircle" . ?◯)
+ ("\\textmusicalnote" . ?♪)
+ ("\\textmarried" . ?⚭)
+ ("\\textdivorced" . ?⚮)
+ ("\\textlbrackdbl" . 10214) ; Literal ?⟦ breaks indentation
+ ("\\textrbrackdbl" . 10215) ; Literal ?⟧ breaks indentation
+ ("\\textinterrobangdown" . ?⸘))
"A `prettify-symbols-alist' usable for (La)TeX modes.")
(defun tex--prettify-symbols-compose-p (_start end _match)
diff --git a/lisp/textmodes/texinfo.el b/lisp/textmodes/texinfo.el
index 81ac45eb6c4..5d6f5deae1b 100644
--- a/lisp/textmodes/texinfo.el
+++ b/lisp/textmodes/texinfo.el
@@ -4,7 +4,6 @@
;; Foundation, Inc.
;; Author: Robert J. Chassell
-;; Date: [See date below for texinfo-version]
;; Maintainer: emacs-devel@gnu.org
;; Keywords: maint, tex, docs
@@ -32,6 +31,16 @@
;;; Code:
+(eval-when-compile (require 'cl-lib)
+ (require 'flymake)
+ (require 'rx))
+(declare-function flymake-diag-region "flymake"
+ (buffer line &optional col))
+(declare-function flymake-make-diagnostic "flymake"
+ ( locus beg end type text
+ &optional data overlay-properties))
+(declare-function flymake--log-1 "flymake" (level sublog msg &rest args))
+
(eval-when-compile (require 'tex-mode))
(declare-function tex-buffer "tex-mode" ())
(declare-function tex-region "tex-mode" (beg end))
@@ -336,6 +345,69 @@ Subexpression 1 is what goes into the corresponding `@end' statement.")
(if (re-search-backward "^@node[ \t]+\\([^,\n]+\\)" nil t)
(match-string-no-properties 1))))
+;;; Flymake support
+(defvar-local texinfo--flymake-proc nil)
+(defun texinfo-flymake (report-fn &rest _)
+ "Texinfo checking for Flymake.
+
+REPORT-FN is the callback function."
+ (let ((executable (or (executable-find "makeinfo")
+ (executable-find "texi2any")))
+ (source (current-buffer)))
+
+ (unless executable
+ (error "Flymake for Texinfo requires `makeinfo' or `texi2any'"))
+
+ (when (process-live-p texinfo--flymake-proc)
+ (kill-process texinfo--flymake-proc))
+
+ (save-restriction
+ (widen)
+ (setq texinfo--flymake-proc
+ (make-process
+ :name "texinfo-flymake"
+ :noquery t
+ :connection-type 'pipe
+ :buffer (generate-new-buffer " *texinfo-flymake*")
+ :command `(,executable "-o" ,null-device "-")
+ :sentinel
+ (lambda (proc _event)
+ (when (memq (process-status proc) '(exit signal))
+ (unwind-protect
+ (if (eq (buffer-local-value 'texinfo--flymake-proc
+ source)
+ proc)
+ (with-current-buffer (process-buffer proc)
+ (goto-char (point-min))
+ (cl-loop
+ while (search-forward-regexp
+ (rx line-start
+ "-:"
+ (group-n 1 (0+ digit)) ; Line
+ (optional ":" (group-n 2 (0+ digit))) ; col
+ ": "
+ (optional (group-n 3 "warning: ")) ; warn
+ (group-n 4 (0+ nonl)) ; Message
+ line-end)
+ nil t)
+ for msg = (match-string 4)
+ for (beg . end) = (flymake-diag-region
+ source
+ (string-to-number (match-string 1)))
+ for type = (if (match-string 3)
+ :warning
+ :error)
+ collect (flymake-make-diagnostic
+ source beg end type msg)
+ into diags
+ finally (funcall report-fn diags)))
+ (flymake-log :warning "Cancelling obsolete check %s"
+ proc))
+ (kill-buffer (process-buffer proc)))))))
+ (process-send-region texinfo--flymake-proc (point-min) (point-max))
+ (process-send-eof texinfo--flymake-proc))))
+
+
;;; Texinfo mode
;;;###autoload
@@ -411,13 +483,13 @@ value of `texinfo-mode-hook'."
"\\)\\>"))
(setq-local require-final-newline mode-require-final-newline)
(setq-local indent-tabs-mode nil)
- (setq-local paragraph-separate
- (concat "@[a-zA-Z]*[ \n]\\|"
- paragraph-separate))
(setq-local paragraph-start (concat "@[a-zA-Z]*[ \n]\\|"
paragraph-start))
+ (setq-local fill-paragraph-function 'texinfo--fill-paragraph)
(setq-local sentence-end-base "\\(@\\(end\\)?dots{}\\|[.?!]\\)[]\"'”)}]*")
(setq-local fill-column 70)
+ (setq-local beginning-of-defun-function #'texinfo--beginning-of-defun)
+ (setq-local end-of-defun-function #'texinfo--end-of-defun)
(setq-local comment-start "@c ")
(setq-local comment-start-skip "@c +\\|@comment +")
(setq-local words-include-escapes t)
@@ -455,8 +527,63 @@ value of `texinfo-mode-hook'."
(let ((prevent-filling "^@\\(def\\|multitable\\)"))
(if (null auto-fill-inhibit-regexp)
prevent-filling
- (concat auto-fill-inhibit-regexp "\\|" prevent-filling)))))
-
+ (concat auto-fill-inhibit-regexp "\\|" prevent-filling))))
+
+ ;; Set up Flymake support.
+ (add-hook 'flymake-diagnostic-functions #'texinfo-flymake nil t))
+
+(defvar texinfo-fillable-commands '("@noindent")
+ "A list of commands that can be filled.")
+
+(defun texinfo--fill-paragraph (justify)
+ "Function to fill a paragraph in `texinfo-mode'."
+ (let ((command-re "\\(@[a-zA-Z]+\\)[ \t\n]"))
+ (catch 'no-fill
+ (save-restriction
+ ;; First check whether we're on a command line that can be
+ ;; filled by itself.
+ (or
+ (save-excursion
+ (beginning-of-line)
+ (when (looking-at command-re)
+ (let ((command (match-string 1)))
+ (if (member command texinfo-fillable-commands)
+ (progn
+ (narrow-to-region (point) (progn (forward-line 1) (point)))
+ t)
+ (throw 'no-fill nil)))))
+ ;; We're not on such a line, so fill the region.
+ (save-excursion
+ (let ((regexp (concat command-re "\\|^[ \t]*$\\|\f")))
+ (narrow-to-region
+ (if (re-search-backward regexp nil t)
+ (progn
+ (forward-line 1)
+ (point))
+ (point-min))
+ (if (re-search-forward regexp nil t)
+ (match-beginning 0)
+ (point-max)))
+ (goto-char (point-min)))))
+ ;; We've now narrowed to the region we want to fill.
+ (let ((fill-paragraph-function nil)
+ (adaptive-fill-mode nil))
+ (fill-paragraph justify))))
+ t))
+
+(defun texinfo--beginning-of-defun (&optional arg)
+ "Go to the previous @node line."
+ (while (and (> arg 0)
+ (re-search-backward "^@node " nil t))
+ (setq arg (1- arg))))
+
+(defun texinfo--end-of-defun ()
+ "Go to the start of the next @node line."
+ (when (looking-at-p "@node")
+ (forward-line))
+ (if (re-search-forward "^@node " nil t)
+ (goto-char (match-beginning 0))
+ (goto-char (point-max))))
;;; Insert string commands
diff --git a/lisp/textmodes/word-wrap-mode.el b/lisp/textmodes/word-wrap-mode.el
new file mode 100644
index 00000000000..c354fc773a7
--- /dev/null
+++ b/lisp/textmodes/word-wrap-mode.el
@@ -0,0 +1,80 @@
+;;; word-wrap-mode.el --- minor mode for `word-wrap' tweaks -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2022 Free Software Foundation, Inc.
+
+;; Maintainer: emacs-devel@gnu.org
+
+;; 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
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) 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. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+;; The list below lists all characters that have a general-category of
+;; Zs, but with the ones we don't want to add here commented out.
+(defcustom word-wrap-whitespace-characters
+ '(;;?\N{SPACE}
+ ;;?\N{NO-BREAK SPACE}
+ ?\N{OGHAM SPACE MARK}
+ ?\N{EN QUAD}
+ ?\N{EM QUAD}
+ ?\N{EN SPACE}
+ ?\N{EM SPACE}
+ ?\N{THREE-PER-EM SPACE}
+ ?\N{FOUR-PER-EM SPACE}
+ ?\N{SIX-PER-EM SPACE}
+ ?\N{FIGURE SPACE}
+ ?\N{PUNCTUATION SPACE}
+ ?\N{THIN SPACE}
+ ?\N{HAIR SPACE}
+ ;;?\N{NARROW NO-BREAK SPACE}
+ ?\N{MEDIUM MATHEMATICAL SPACE}
+ ?\N{IDEOGRAPHIC SPACE}
+ ;; Not in the Zs category:
+ ?\N{ZERO WIDTH SPACE})
+ "Characters that `word-wrap-whitespace-mode' should add to `word-wrap'."
+ :version "29.1"
+ :type '(repeat character)
+ :group 'display)
+
+(defvar word-wrap-mode--previous-state)
+
+;;;###autoload
+(define-minor-mode word-wrap-whitespace-mode
+ "Allow `word-wrap' to fold on all breaking whitespace characters.
+The characters to break on are defined by `word-wrap-whitespace-characters'."
+ :group 'display
+ (if word-wrap-whitespace-mode
+ (progn
+ (setq-local word-wrap-mode--previous-state
+ (cons (category-table)
+ (buffer-local-set-state
+ word-wrap-by-category t
+ word-wrap t)))
+ (set-category-table (copy-category-table))
+ (dolist (char word-wrap-whitespace-characters)
+ (modify-category-entry char ?|)))
+ (set-category-table (car word-wrap-mode--previous-state))
+ (buffer-local-restore-state (cdr word-wrap-mode--previous-state))))
+
+;;;###autoload
+(define-globalized-minor-mode global-word-wrap-whitespace-mode
+ word-wrap-whitespace-mode word-wrap-whitespace-mode
+ :group 'display)
+
+(provide 'word-wrap-mode)
+
+;;; word-wrap-mode.el ends here