branch: main commit 510d82b3b356dbbd007fd085662afea99e947fb7 Author: Paul Nelson <ultr...@gmail.com> Commit: Ikumi Keita <ik...@ikumi.que.jp>
Add folding support for TeX quotes * tex-fold.el (TeX-fold--verb-data): (TeX-fold-verbs): Move, unchanged, to a new part of the file consisting of functions used for TeX-fold-region-functions. (TeX-fold--make-misc-overlay): Deleted; now subsumed by TeX-fold-make-overlay. (TeX-fold-make-overlay): New optional argument display-string, used to subsume TeX-fold--make-misc-overlay. (TeX-fold-open-quote): (TeX-fold-close-quote): (TeX-fold-quotes-on-insert): New user options. (TeX-fold-quotes): New function, using the new user options. (TeX-fold-region-functions): Add TeX-fold-quotes. * tex.el (TeX-get-quote-characters): New helper function, extracted from TeX-insert-quote. (TeX-insert-quote): Use the new helper function, as well as the new user option, TeX-fold-quotes-on-insert. * auctex.texi (Folding Macros and Environments): Document the new user options. --- doc/auctex.texi | 33 +++++++--- tex-fold.el | 184 +++++++++++++++++++++++++++++++++++--------------------- tex.el | 55 +++++++++++++---- 3 files changed, 181 insertions(+), 91 deletions(-) diff --git a/doc/auctex.texi b/doc/auctex.texi index 4c4a900c..718d4c2a 100644 --- a/doc/auctex.texi +++ b/doc/auctex.texi @@ -2651,7 +2651,8 @@ around the mark will be kept unfolded. @defopt TeX-fold-region-functions This variable is a list of functions which allow the user, or external packages, to fold additional @LaTeX{} constructs beyond those supported by -default. +default. By default, it is configured to support folding for verbatim +environments and quotes. @end defopt @deffn Command TeX-fold-region @@ -2957,13 +2958,29 @@ specifications for @samp{begin} and @samp{end} from @defopt TeX-fold-bib-file The default folding behavior for @samp{\cite@{...@}} macros that point to -a BibTeX entry is to replace them with a string of the form [XYZ99], -formed using the authors' last names and the publication year. If -@AUCTeX{} cannot find the required BibTeX entries in any bib files -included in the current document, then, as a backup, it searches the files -specified in @code{TeX-fold-bib-file}. This may be useful when using -@samp{\thebibliography@{...@}} rather than BibTeX, or when working in -non-file buffers. +a Bib@TeX{} entry is to replace them with a string of the form +@samp{[XYZ99]}, formed using the authors' last names and the publication +year. If @AUCTeX{} cannot find the required Bib@TeX{} entries in any bib +files included in the current document, then, as a backup, it searches the +files specified in @code{TeX-fold-bib-file}. This may be useful when +using @samp{\thebibliography@{...@}} rather than Bib@TeX{}, or when +working in non-file buffers. +@end defopt + +@defopt TeX-fold-open-quote +Folded version of opening quote. This string is used to replace opening +quotes when folding @LaTeX{} quotes. +@end defopt + +@defopt TeX-fold-close-quote +Folded version of closing quote. This string is used to replace closing +quotes when folding @LaTeX{} quotes. +@end defopt + +@defopt TeX-fold-quotes-on-insert +If non-@code{nil}, automatically fold @LaTeX{} quotes when they are +inserted. This option is consulted by @code{TeX-insert-quote} when +determining whether to fold newly inserted quotes. @end defopt @node Outline diff --git a/tex-fold.el b/tex-fold.el index b213602e..2c10cc27 100644 --- a/tex-fold.el +++ b/tex-fold.el @@ -56,6 +56,8 @@ (declare-function LaTeX-verbatim-macro-boundaries "latex") (declare-function LaTeX-verbatim-macros-with-braces "latex") (declare-function LaTeX-verbatim-macros-with-delims "latex") +(declare-function bibtex-parse-entry "bibtex") +(declare-function bibtex-text-in-field "bibtex") (defgroup TeX-fold nil "Fold TeX macros." @@ -361,53 +363,12 @@ and `TeX-fold-math-spec-list', and environments in `TeX-fold-env-spec-list'." (TeX-fold-clearout-region start end) (TeX-fold-region start end)))) -(defcustom TeX-fold-region-functions '(TeX-fold-verbs) +(defcustom TeX-fold-region-functions '(TeX-fold-verbs TeX-fold-quotes) "List of additional functions to call when folding a region. Each function is called with two arguments, the start and end positions of the region to fold." :type '(repeat function) - :package-version '(auctex . "14.0.7")) - -(defun TeX-fold--verb-data (&rest _args) - "Return data describing verbatim macro at point. -Returns list of the form (START END CONTENT). This should be called -only in LaTeX modes." - (when-let* ((boundaries (LaTeX-verbatim-macro-boundaries)) - (bound-start (car boundaries)) - (bound-end (cdr boundaries)) - (end-delim-char (char-before bound-end)) - (start-delim-char (if (= end-delim-char ?\}) - ?\{ - end-delim-char)) - (start-delim (char-to-string start-delim-char)) - (verb-arg-start - (1+ (progn - (goto-char bound-end) - (if (string= start-delim TeX-grop) - (progn (backward-sexp) (point)) - (forward-char -1) - (search-backward start-delim bound-start t))))) - (verb-arg-end (1- bound-end))) - (list bound-start - bound-end - (buffer-substring verb-arg-start verb-arg-end)))) - -(defun TeX-fold-verbs (start end) - "In LaTeX modes, fold verbatim macros between START and END." - (when (derived-mode-p 'LaTeX-mode) - (save-excursion - (goto-char start) - (let ((re (concat (regexp-quote TeX-esc) - (regexp-opt - (append - (LaTeX-verbatim-macros-with-braces) - (LaTeX-verbatim-macros-with-delims)))))) - (while (let ((case-fold-search nil)) - (re-search-forward re end t)) - (when-let* ((data (TeX-fold--verb-data)) - (spec (lambda (&rest _args) - (nth 2 (TeX-fold--verb-data))))) - (apply #'TeX-fold--make-misc-overlay (append data (list spec))))))))) + :package-version '(auctex . "14.0.8")) (defun TeX-fold-region (start end) "Fold all items in region from START to END." @@ -822,8 +783,6 @@ with some additional non-alphabetical characters such as braces." Return string of the form \"XYZ99\", formed using authors' last names and publication year, or nil if author/year not found." (require 'bibtex) - (declare-function bibtex-parse-entry "bibtex") - (declare-function bibtex-text-in-field "bibtex") (when-let* ((case-fold-search t) (entry (bibtex-parse-entry)) (author (bibtex-text-in-field "author" entry)) @@ -898,14 +857,17 @@ using authors' last names and the the publication year." ;;; Utilities -(defun TeX-fold-make-overlay (ov-start ov-end type display-string-spec) +(defun TeX-fold-make-overlay (ov-start ov-end type display-string-spec + &optional display-string) "Make a TeX-fold overlay extending from OV-START to OV-END. -TYPE is a symbol which is used to describe the content to hide -and may be `macro' for macros, `math' for math macro and `env' for -environments. +TYPE is a symbol which is used to describe the content to hide and may +be `macro' for macros, `math' for math macro, `env' for environments, or +`misc' for miscellaneous constructs like quotes and dashes. DISPLAY-STRING-SPEC is the original specification of the display string in the variables `TeX-fold-macro-spec-list' and alikes. -See its doc string for detail." +See its doc string for detail. +If DISPLAY-STRING is provided, it will be used directly as the overlay's +display property." ;; Calculate priority before the overlay is instantiated. We don't ;; want `TeX-overlay-prioritize' to pick up a non-prioritized one. (let ((priority (TeX-overlay-prioritize ov-start ov-end)) @@ -913,27 +875,11 @@ See its doc string for detail." (overlay-put ov 'category 'TeX-fold) (overlay-put ov 'priority priority) (overlay-put ov 'evaporate t) - (overlay-put ov 'TeX-fold-type type) - (overlay-put ov 'TeX-fold-display-string-spec display-string-spec) - ov)) - -(defun TeX-fold--make-misc-overlay (start end display-string display-string-spec) - "Create a miscellaneous overlay between START and END. -DISPLAY-STRING is the display string, while DISPLAY-STRING-SPEC is as in -`TeX-fold-make-overlay'. - -This function is intended to be used with verbatim environments and -other miscellaneous folding constructs. By contrast, the function -`TeX-fold-make-overlay' is used in the implementation of -`TeX-fold-hide-item', which applies to typical macros, environments and -math." - (let ((priority (TeX-overlay-prioritize start end)) - (ov (make-overlay start end))) - (overlay-put ov 'category 'TeX-fold) - (overlay-put ov 'priority priority) - (overlay-put ov 'evaporate t) - (overlay-put ov 'display display-string) + (when type + (overlay-put ov 'TeX-fold-type type)) (overlay-put ov 'TeX-fold-display-string-spec display-string-spec) + (when display-string + (overlay-put ov 'display display-string)) ov)) (defun TeX-fold-item-end (start type) @@ -1397,6 +1343,104 @@ With zero or negative ARG turn mode off." ;;;###autoload (defalias 'tex-fold-mode #'TeX-fold-mode) +;;; Miscellaneous folding + +;; This section provides functions for use in +;; `TeX-fold-region-functions'. + +;;;; Verbatim constructs + +(defun TeX-fold--verb-data (&rest _args) + "Return data describing verbatim macro at point. +Returns list of the form (START END CONTENT). This should be called +only in LaTeX modes." + (when-let* ((boundaries (LaTeX-verbatim-macro-boundaries)) + (bound-start (car boundaries)) + (bound-end (cdr boundaries)) + (end-delim-char (char-before bound-end)) + (start-delim-char (if (= end-delim-char ?\}) + ?\{ + end-delim-char)) + (start-delim (char-to-string start-delim-char)) + (verb-arg-start + (1+ (progn + (goto-char bound-end) + (if (string= start-delim TeX-grop) + (progn (backward-sexp) (point)) + (forward-char -1) + (search-backward start-delim bound-start t))))) + (verb-arg-end (1- bound-end))) + (list bound-start + bound-end + (buffer-substring verb-arg-start verb-arg-end)))) + +(defun TeX-fold-verbs (start end) + "In LaTeX modes, fold verbatim macros between START and END. +Replaces the verbatim content with its own text." + (when (derived-mode-p 'LaTeX-mode) + (save-excursion + (goto-char start) + (let ((re (concat (regexp-quote TeX-esc) + (regexp-opt + (append + (LaTeX-verbatim-macros-with-braces) + (LaTeX-verbatim-macros-with-delims)))))) + (while (let ((case-fold-search nil)) + (re-search-forward re end t)) + (when-let* ((data (TeX-fold--verb-data)) + (verb-start (nth 0 data)) + (verb-end (nth 1 data)) + (verb-content (nth 2 data))) + (TeX-fold-make-overlay + verb-start verb-end + 'misc + (lambda (&rest _args) + (nth 2 (TeX-fold--verb-data))) + verb-content))))))) + +;;;; Quotes + +(defcustom TeX-fold-open-quote "“" + "Folded version of opening quote." + :type 'string + :package-version '(auctex . "14.0.8")) + +(defcustom TeX-fold-close-quote "”" + "Folded verison of closing quote." + :type 'string + :package-version '(auctex . "14.0.8")) + +(defcustom TeX-fold-quotes-on-insert nil + "Non-nil means to automatically fold LaTeX quotes when they are inserted. +Consulted by `TeX-insert-quote'." + :type 'boolean + :package-version '(auctex . "14.0.8")) + +(defun TeX-fold-quotes (start end) + "Fold LaTeX quotes between START and END. +Replaces opening and closing quotes with `TeX-fold-open-quote' and +`TeX-fold-close-quote', respectively, except in math environments, +verbatim contexts and comments." + (pcase-let ((`(,open-quote ,close-quote _) (TeX-get-quote-characters))) + (save-excursion + (goto-char start) + (let ((regexp (regexp-opt (list open-quote close-quote)))) + (while (re-search-forward regexp end t) + (let ((str (if (string= (match-string-no-properties 0) open-quote) + TeX-fold-open-quote + TeX-fold-close-quote)) + (quote-start (match-beginning 0)) + (quote-end (match-end 0))) + (unless (or (and (fboundp 'font-latex-faces-present-p) + (font-latex-faces-present-p + '(tex-math + font-latex-verbatim-face + font-latex-math-face + font-lock-comment-face) + quote-start)) + (texmathp)) + (TeX-fold-make-overlay quote-start quote-end 'misc str str)))))))) + (provide 'tex-fold) ;;; tex-fold.el ends here diff --git a/tex.el b/tex.el index 94d72afa..498464e0 100644 --- a/tex.el +++ b/tex.el @@ -6386,6 +6386,24 @@ the settings of style files. Style files should therefore check if this symbol is present and not alter `TeX-quote-language' if it is.") +(defun TeX-get-quote-characters () + "Get appropriate open and close quote strings. +Return list consisting of three elements as in +`TeX-quote-language-alist'." + (let* ((lang-override (if (eq (car TeX-quote-language) 'override) + TeX-quote-language + (assoc (car TeX-quote-language) + TeX-quote-language-alist))) + (lang (or lang-override TeX-quote-language)) + (open-quote (if lang (nth 1 lang) TeX-open-quote)) + (close-quote (if lang (nth 2 lang) TeX-close-quote)) + (q-after-q (if lang (nth 3 lang) TeX-quote-after-quote))) + (when (functionp open-quote) + (setq open-quote (funcall open-quote))) + (when (functionp close-quote) + (setq close-quote (funcall close-quote))) + (list open-quote close-quote q-after-q))) + ;; TODO: rework according to the slogan from ;; `TeX--put-electric-delete-selection'. That entails splitting off the ;; «electric» part that tries to do smart things and the plain part that @@ -6411,18 +6429,8 @@ With prefix argument FORCE, always inserts \" characters." (and (TeX-in-comment) (not (eq major-mode 'docTeX-mode)))) (self-insert-command (prefix-numeric-value force)) (TeX-update-style) - (let* ((lang-override (if (eq (car TeX-quote-language) 'override) - TeX-quote-language - (assoc (car TeX-quote-language) - TeX-quote-language-alist))) - (lang (or lang-override TeX-quote-language)) - (open-quote (if lang (nth 1 lang) TeX-open-quote)) - (close-quote (if lang (nth 2 lang) TeX-close-quote)) - (q-after-q (if lang (nth 3 lang) TeX-quote-after-quote))) - (when (functionp open-quote) - (setq open-quote (funcall open-quote))) - (when (functionp close-quote) - (setq close-quote (funcall close-quote))) + (pcase-let ((`(,open-quote ,close-quote ,q-after-q) + (TeX-get-quote-characters))) (if q-after-q (insert (cond ((bobp) ?\") @@ -6473,7 +6481,28 @@ With prefix argument FORCE, always inserts \" characters." (looking-at "[ \t\n]\\|\\s(")) open-quote) (t - close-quote))))))) + close-quote)))) + ;; Fold quotes if TeX-fold-quotes-on-insert is t + (when (and (boundp 'TeX-fold-mode) + (boundp 'TeX-fold-quotes-on-insert) + (fboundp 'TeX-fold-quotes) + TeX-fold-mode + TeX-fold-quotes-on-insert + (not (eq (char-before) ?\"))) ; Don't fold single quotes + (save-excursion + (let* ((end (point)) + (start (- end + (length + (if (string= (buffer-substring-no-properties + (max (point-min) + (- end (length open-quote))) + end) + open-quote) + open-quote + close-quote))))) + (when start + (TeX-fold-quotes start end)))))))) + (put 'TeX-insert-quote 'delete-selection t)