diff options
| author | David Fussner | 2024-06-10 14:16:04 +0100 |
|---|---|---|
| committer | Stefan Kangas | 2024-09-14 17:05:33 +0200 |
| commit | b44c00669ace7b9e6a90aecb5f4e9f4edf6ed25a (patch) | |
| tree | 7119d2ff1695271877a27a1a0cf0b0d648983d1c | |
| parent | 98e582e74a2bbc2c7fdef02b8cd90036fa217712 (diff) | |
| download | emacs-b44c00669ace7b9e6a90aecb5f4e9f4edf6ed25a.tar.gz emacs-b44c00669ace7b9e6a90aecb5f4e9f4edf6ed25a.zip | |
Provide a modified xref backend for TeX buffers
In addition to providing a new `xref' backend, the patch also improves
the general handling of expl3 syntax. Expl3 is the next-generation
LaTeX specification, and has for some time been available by default in
the LaTeX kernel. The new syntax co-exists in many files with the
standard LaTeX2e syntax, so we try at least minimally to separate the
way modes handle the two specifications, both to reduce
visually-disturbing interference between them and also to improve the
`xref' backend. (Bug#53749)
* lib-src/etags.c (TeX_commands): Improve parsing of commands in TeX
buffers.
(TEX_defenv): Expand list of commands to tag by default in TeX buffers.
(TeX_help):
* doc/emacs/maintaining.texi (Tag Syntax): Document new tagged commands.
(Identifier Search): Add note about semantic-symref-filepattern-alist,
auto-mode-alist, and xref-find-references.
* lisp/textmodes/tex-mode.el (tex-font-lock-suscript): Test for
underscore in expl3 files and regions, disable subscript face there.
(tex-common-initialization): Set up xref backend for in-tree TeX modes.
Detect expl3 files, and in others set up a list of expl3 regions.
(tex-expl-buffer-parse): New function called in previous.
(tex-expl-buffer-p): New variable to hold the result of previous.
(tex-expl-region-set): New function added to
'syntax-propertize-extend-region-functions' hook.
(tex-expl-region-list): New variable to hold the result of previous.
(tex--xref-backend): New function to identify the xref backend.
(tex--thing-at-point, tex-thingatpt--beginning-of-symbol)
(tex-thingatpt--end-of-symbol, tex--bounds-of-symbol-at-point):
New functions to return 'thing-at-point' for xref backend.
(tex-thingatpt-exclude-chars): New variable to do the same.
(xref-backend-identifier-at-point): New TeX backend method to provide
symbols for processing by xref.
(xref-backend-identifier-completion-table)
(xref-backend-identifier-completion-ignore-case)
(xref-backend-definitions, xref-backend-apropos): Placeholders to
call the standard 'etags' xref backend methods.
(xref-backend-references): Wrapper to call the default xref backend
method, finding as many relevant files as possible and using a bespoke
syntax-propertize-function when required.
(tex--collect-file-extensions, tex-xref-syntax-function): Helper
functions for previous.
(tex-find-references-syntax-table, tex--buffers-list)
(tex--xref-syntax-fun, tex--old-syntax-function): New variables for
the same.
| -rw-r--r-- | doc/emacs/maintaining.texi | 39 | ||||
| -rw-r--r-- | etc/NEWS | 9 | ||||
| -rw-r--r-- | lib-src/etags.c | 186 | ||||
| -rw-r--r-- | lisp/textmodes/tex-mode.el | 358 |
4 files changed, 572 insertions, 20 deletions
diff --git a/doc/emacs/maintaining.texi b/doc/emacs/maintaining.texi index 3c34afbaa20..0ec2385860b 100644 --- a/doc/emacs/maintaining.texi +++ b/doc/emacs/maintaining.texi | |||
| @@ -2549,6 +2549,15 @@ identifier, showing the file name and the line where the identifier is | |||
| 2549 | referenced. The XREF mode commands are available in this buffer, see | 2549 | referenced. The XREF mode commands are available in this buffer, see |
| 2550 | @ref{Xref Commands}. | 2550 | @ref{Xref Commands}. |
| 2551 | 2551 | ||
| 2552 | When invoked in a buffer whose major mode uses the @code{etags} backend, | ||
| 2553 | @kbd{M-?} searches files and buffers whose major mode matches that of | ||
| 2554 | the original buffer. It guesses that mode from file extensions, so if | ||
| 2555 | @kbd{M-?} seems to be skipping relevant buffers or files, try | ||
| 2556 | customizing either the variable @code{semantic-symref-filepattern-alist} | ||
| 2557 | (if your buffer's major mode already has an entry in it), or | ||
| 2558 | @code{auto-mode-alist} (if not), thereby informing @code{xref} of the | ||
| 2559 | missing extensions (@pxref{Choosing Modes}). | ||
| 2560 | |||
| 2552 | @vindex xref-auto-jump-to-first-xref | 2561 | @vindex xref-auto-jump-to-first-xref |
| 2553 | If the value of the variable @code{xref-auto-jump-to-first-xref} is | 2562 | If the value of the variable @code{xref-auto-jump-to-first-xref} is |
| 2554 | @code{t}, @code{xref-find-references} automatically jumps to the first | 2563 | @code{t}, @code{xref-find-references} automatically jumps to the first |
| @@ -2767,10 +2776,32 @@ Tags for variables and functions in classes are named | |||
| 2767 | @item | 2776 | @item |
| 2768 | In @LaTeX{} documents, the arguments for @code{\chapter}, | 2777 | In @LaTeX{} documents, the arguments for @code{\chapter}, |
| 2769 | @code{\section}, @code{\subsection}, @code{\subsubsection}, | 2778 | @code{\section}, @code{\subsection}, @code{\subsubsection}, |
| 2770 | @code{\eqno}, @code{\label}, @code{\ref}, @code{\cite}, | 2779 | @code{\eqno}, @code{\label}, @code{\ref}, @code{\Ref}, @code{\footref}, |
| 2771 | @code{\bibitem}, @code{\part}, @code{\appendix}, @code{\entry}, | 2780 | @code{\cite}, @code{\bibitem}, @code{\part}, @code{\appendix}, |
| 2772 | @code{\index}, @code{\def}, @code{\newcommand}, @code{\renewcommand}, | 2781 | @code{\entry}, @code{\index}, @code{\def}, @code{\edef}, @code{\gdef}, |
| 2773 | @code{\newenvironment} and @code{\renewenvironment} are tags. | 2782 | @code{\xdef}, @code{\newcommand}, @code{\renewcommand}, |
| 2783 | @code{\newenvironment}, @code{\renewenvironment}, | ||
| 2784 | @code{\DeclareRobustCommand}, @code{\newrobustcmd}, | ||
| 2785 | @code{\renewrobustcmd}, @code{\providecommand}, | ||
| 2786 | @code{\providerobustcmd}, @code{\NewDocumentCommand}, | ||
| 2787 | @code{\RenewDocumentCommand}, @code{\ProvideDocumentCommand}, | ||
| 2788 | @code{\DeclareDocumentCommand}, @code{\NewExpandableDocumentCommand}, | ||
| 2789 | @code{\RenewExpandableDocumentCommand}, | ||
| 2790 | @code{\ProvideExpandableDocumentCommand}, | ||
| 2791 | @code{\DeclareExpandableDocumentCommand}, | ||
| 2792 | @code{\NewDocumentEnvironment}, @code{\RenewDocumentEnvironment}, | ||
| 2793 | @code{\ProvideDocumentEnvironment}, @code{\DeclareDocumentEnvironment}, | ||
| 2794 | @code{\csdef}, @code{\csedef}, @code{\csgdef}, @code{\csxdef}, | ||
| 2795 | @code{\csletcs}, @code{\cslet}, @code{\letcs}, @code{\let}, | ||
| 2796 | @code{\cs_new_protected_nopar}, @code{\cs_new_protected}, | ||
| 2797 | @code{\cs_new_nopar}, @code{\cs_new_eq}, @code{\cs_new}, | ||
| 2798 | @code{\cs_set_protected_nopar}, @code{\cs_set_protected}, | ||
| 2799 | @code{\cs_set_nopar}, @code{\cs_set_eq}, @code{\cs_set}, | ||
| 2800 | @code{\cs_gset_protected_nopar}, @code{\cs_gset_protected}, | ||
| 2801 | @code{\cs_gset_nopar}, @code{\cs_gset_eq}, @code{\cs_gset}, | ||
| 2802 | @code{\cs_generate_from_arg_count}, and @code{\cs_generate_variant} are | ||
| 2803 | tags. So too are the arguments of any starred variants of these | ||
| 2804 | commands. | ||
| 2774 | 2805 | ||
| 2775 | Other commands can make tags as well, if you specify them in the | 2806 | Other commands can make tags as well, if you specify them in the |
| 2776 | environment variable @env{TEXTAGS} before invoking @command{etags}. The | 2807 | environment variable @env{TEXTAGS} before invoking @command{etags}. The |
| @@ -343,6 +343,15 @@ the 'grep' results editable. The edits will be reflected in the buffer | |||
| 343 | visiting the originating file. Typing 'C-c C-c' will leave the Grep | 343 | visiting the originating file. Typing 'C-c C-c' will leave the Grep |
| 344 | Edit mode. | 344 | Edit mode. |
| 345 | 345 | ||
| 346 | ** TeX modes | ||
| 347 | |||
| 348 | +++ | ||
| 349 | *** New xref backend for TeX modes. | ||
| 350 | The new backend ('tex-etags') is on by default, and improves the | ||
| 351 | functionality of the standard 'xref' commands in TeX buffers. You can | ||
| 352 | restore the standard 'etags' backend with the 'M-x xref-etags-mode' | ||
| 353 | toggle. | ||
| 354 | |||
| 346 | 355 | ||
| 347 | * New Modes and Packages in Emacs 31.1 | 356 | * New Modes and Packages in Emacs 31.1 |
| 348 | 357 | ||
diff --git a/lib-src/etags.c b/lib-src/etags.c index 556b7d701fc..7f652790261 100644 --- a/lib-src/etags.c +++ b/lib-src/etags.c | |||
| @@ -793,11 +793,27 @@ variables set with 'set!' at top level in the file."; | |||
| 793 | static const char *TeX_suffixes [] = | 793 | static const char *TeX_suffixes [] = |
| 794 | { "bib", "clo", "cls", "ltx", "sty", "TeX", "tex", NULL }; | 794 | { "bib", "clo", "cls", "ltx", "sty", "TeX", "tex", NULL }; |
| 795 | static const char TeX_help [] = | 795 | static const char TeX_help [] = |
| 796 | "In LaTeX text, the argument of any of the commands '\\chapter',\n\ | 796 | "In LaTeX text, the argument of the commands '\\chapter', '\\section',\n\ |
| 797 | '\\section', '\\subsection', '\\subsubsection', '\\eqno', '\\label',\n\ | 797 | '\\subsection', '\\subsubsection', '\\eqno', '\\label', '\\ref',\n\ |
| 798 | '\\ref', '\\cite', '\\bibitem', '\\part', '\\appendix', '\\entry',\n\ | 798 | '\\Ref', '\\footref', '\\cite', '\\bibitem', '\\part', '\\appendix',\n\ |
| 799 | '\\index', '\\def', '\\newcommand', '\\renewcommand',\n\ | 799 | '\\entry', '\\index', '\\def', '\\edef', '\\gdef', '\\xdef',\n\ |
| 800 | '\\newenvironment' or '\\renewenvironment' is a tag.\n\ | 800 | '\\newcommand', '\\renewcommand', '\\newrobustcmd', '\\renewrobustcmd',\n\ |
| 801 | '\\newenvironment', '\\renewenvironment', '\\DeclareRobustCommand',\n\ | ||
| 802 | '\\providecommand', '\\providerobustcmd', '\\NewDocumentCommand',\n\ | ||
| 803 | '\\RenewDocumentCommand', '\\ProvideDocumentCommand',\n\ | ||
| 804 | '\\DeclareDocumentCommand', '\\NewExpandableDocumentCommand',\n\ | ||
| 805 | '\\RenewExpandableDocumentCommand', '\\ProvideExpandableDocumentCommand',\n\ | ||
| 806 | '\\DeclareExpandableDocumentCommand', '\\NewDocumentEnvironment',\n\ | ||
| 807 | '\\RenewDocumentEnvironment', '\\ProvideDocumentEnvironment',\n\ | ||
| 808 | '\\DeclareDocumentEnvironment','\\csdef', '\\csedef', '\\csgdef',\n\ | ||
| 809 | '\\csxdef', '\\csletcs', '\\cslet', '\\letcs', '\\let',\n\ | ||
| 810 | '\\cs_new_protected_nopar', '\\cs_new_protected', '\\cs_new_nopar',\n\ | ||
| 811 | '\\cs_new_eq', '\\cs_new', '\\cs_set_protected_nopar',\n\ | ||
| 812 | '\\cs_set_protected', '\\cs_set_nopar', '\\cs_set_eq', '\\cs_set',\n\ | ||
| 813 | '\\cs_gset_protected_nopar', '\\cs_gset_protected', '\\cs_gset_nopar',\n\ | ||
| 814 | '\\cs_gset_eq', '\\cs_gset', '\\cs_generate_from_arg_count', or\n\ | ||
| 815 | '\\cs_generate_variant' is a tag. So is the argument of any starred\n\ | ||
| 816 | variant of these commands.\n\ | ||
| 801 | \n\ | 817 | \n\ |
| 802 | Other commands can be specified by setting the environment variable\n\ | 818 | Other commands can be specified by setting the environment variable\n\ |
| 803 | 'TEXTAGS' to a colon-separated list like, for example,\n\ | 819 | 'TEXTAGS' to a colon-separated list like, for example,\n\ |
| @@ -5746,9 +5762,20 @@ static linebuffer *TEX_toktab = NULL; /* Table with tag tokens */ | |||
| 5746 | /* Default set of control sequences to put into TEX_toktab. | 5762 | /* Default set of control sequences to put into TEX_toktab. |
| 5747 | The value of environment var TEXTAGS is prepended to this. */ | 5763 | The value of environment var TEXTAGS is prepended to this. */ |
| 5748 | static const char *TEX_defenv = "\ | 5764 | static const char *TEX_defenv = "\ |
| 5749 | :chapter:section:subsection:subsubsection:eqno:label:ref:cite:bibitem\ | 5765 | :label:ref:Ref:footref:chapter:section:subsection:subsubsection:eqno:cite\ |
| 5750 | :part:appendix:entry:index:def\ | 5766 | :bibitem:part:appendix:entry:index:def:edef:gdef:xdef:newcommand:renewcommand\ |
| 5751 | :newcommand:renewcommand:newenvironment:renewenvironment"; | 5767 | :newenvironment:renewenvironment:DeclareRobustCommand:renewrobustcmd\ |
| 5768 | :newrobustcmd:providecommand:providerobustcmd:NewDocumentCommand\ | ||
| 5769 | :RenewDocumentCommand:ProvideDocumentCommand:DeclareDocumentCommand\ | ||
| 5770 | :NewExpandableDocumentCommand:RenewExpandableDocumentCommand\ | ||
| 5771 | :ProvideExpandableDocumentCommand:DeclareExpandableDocumentCommand\ | ||
| 5772 | :NewDocumentEnvironment:RenewDocumentEnvironment\ | ||
| 5773 | :ProvideDocumentEnvironment:DeclareDocumentEnvironment:csdef\ | ||
| 5774 | :csedef:csgdef:csxdef:csletcs:cslet:letcs:let:cs_new_protected_nopar\ | ||
| 5775 | :cs_new_protected:cs_new_nopar:cs_new_eq:cs_new:cs_set_protected_nopar\ | ||
| 5776 | :cs_set_protected:cs_set_nopar:cs_set_eq:cs_set:cs_gset_protected_nopar\ | ||
| 5777 | :cs_gset_protected:cs_gset_nopar:cs_gset_eq:cs_gset\ | ||
| 5778 | :cs_generate_from_arg_count:cs_generate_variant"; | ||
| 5752 | 5779 | ||
| 5753 | static void TEX_decode_env (const char *, const char *); | 5780 | static void TEX_decode_env (const char *, const char *); |
| 5754 | 5781 | ||
| @@ -5807,19 +5834,139 @@ TeX_commands (FILE *inf) | |||
| 5807 | { | 5834 | { |
| 5808 | char *p; | 5835 | char *p; |
| 5809 | ptrdiff_t namelen, linelen; | 5836 | ptrdiff_t namelen, linelen; |
| 5810 | bool opgrp = false; | 5837 | bool opgrp = false, one_esc = false, is_explthree = false; |
| 5811 | 5838 | ||
| 5812 | cp = skip_spaces (cp + key->len); | 5839 | cp = skip_spaces (cp + key->len); |
| 5840 | |||
| 5841 | /* 1. The canonical expl3 syntax looks something like this: | ||
| 5842 | \cs_new:Npn \__hook_tl_gput:Nn { \ERROR }. First, if we | ||
| 5843 | want to tag any such commands, we include only the part | ||
| 5844 | before the colon (cs_new) in TEX_defenv or TEXTAGS. Second, | ||
| 5845 | etags skips the argument specifier (including the colon) | ||
| 5846 | after the tag token, so that it doesn't become the tag name. | ||
| 5847 | Third, we set the boolean 'is_explthree' to true so that we | ||
| 5848 | can remove the argument specifier from the actual tag name | ||
| 5849 | (__hook_tl_gput). This all allows us to include expl3 | ||
| 5850 | constructs in TEX_defenv or in the environment variable | ||
| 5851 | TEXTAGS without requiring a change of separator, and it also | ||
| 5852 | allows us to find the definition of variant commands (with | ||
| 5853 | different argument specifiers) defined using, for example, | ||
| 5854 | \cs_generate_variant:Nn. Please note that the expl3 spec | ||
| 5855 | requires etags to pay more attention to whitespace in the | ||
| 5856 | code. | ||
| 5857 | |||
| 5858 | 2. We also automatically remove the asterisk from starred | ||
| 5859 | variants of all commands, without the need to include the | ||
| 5860 | starred commands explicitly in TEX_defenv or TEXTAGS. */ | ||
| 5861 | if (*cp == ':') | ||
| 5862 | { | ||
| 5863 | while (!c_isspace (*cp) && *cp != TEX_opgrp) | ||
| 5864 | cp++; | ||
| 5865 | cp = skip_spaces (cp); | ||
| 5866 | is_explthree = true; | ||
| 5867 | } | ||
| 5868 | else if (*cp == '*') | ||
| 5869 | cp++; | ||
| 5870 | |||
| 5871 | /* Skip the optional arguments to commands in the tags list so | ||
| 5872 | that these arguments don't end up as the name of the tag. | ||
| 5873 | The name will instead come from the argument in curly braces | ||
| 5874 | that follows the optional ones. The '\let' command gets | ||
| 5875 | special treatment. */ | ||
| 5876 | while (*cp != '\0' && *cp != '%' | ||
| 5877 | && !streq (key->buffer, "let")) | ||
| 5878 | { | ||
| 5879 | if (*cp == '[') | ||
| 5880 | { | ||
| 5881 | while (*cp != ']' && *cp != '\0' && *cp != '%') | ||
| 5882 | cp++; | ||
| 5883 | } | ||
| 5884 | else if (*cp == '(') | ||
| 5885 | { | ||
| 5886 | while (*cp != ')' && *cp != '\0' && *cp != '%') | ||
| 5887 | cp++; | ||
| 5888 | } | ||
| 5889 | else if (*cp == ']' || *cp == ')') | ||
| 5890 | cp++; | ||
| 5891 | else | ||
| 5892 | break; | ||
| 5893 | } | ||
| 5813 | if (*cp == TEX_opgrp) | 5894 | if (*cp == TEX_opgrp) |
| 5814 | { | 5895 | { |
| 5815 | opgrp = true; | 5896 | opgrp = true; |
| 5816 | cp++; | 5897 | cp++; |
| 5898 | cp = skip_spaces (cp); /* For expl3 code. */ | ||
| 5817 | } | 5899 | } |
| 5900 | |||
| 5901 | /* Removing the TeX escape character from tag names simplifies | ||
| 5902 | things for editors finding tagged commands in TeX buffers. | ||
| 5903 | This applies to Emacs but also to the tag-finding behavior | ||
| 5904 | of at least some of the editors that use ctags, though in | ||
| 5905 | the latter case this will remain suboptimal. The | ||
| 5906 | undocumented ctags option '--no-duplicates' may help. */ | ||
| 5907 | if (*cp == TEX_esc) | ||
| 5908 | { | ||
| 5909 | cp++; | ||
| 5910 | one_esc = true; | ||
| 5911 | } | ||
| 5912 | |||
| 5913 | /* Testing !c_isspace && !c_ispunct is simpler, but halts | ||
| 5914 | processing at too many places. The list as it stands tries | ||
| 5915 | both to ensure that tag names will derive from macro names | ||
| 5916 | rather than from optional parameters to those macros, and | ||
| 5917 | also to return findable names while still allowing for | ||
| 5918 | unorthodox constructs. */ | ||
| 5818 | for (p = cp; | 5919 | for (p = cp; |
| 5819 | (!c_isspace (*p) && *p != '#' && | 5920 | (!c_isspace (*p) && *p != '#' && *p != '=' && |
| 5820 | *p != TEX_opgrp && *p != TEX_clgrp); | 5921 | *p != '[' && *p != '(' && *p != TEX_opgrp && |
| 5922 | *p != TEX_clgrp && *p != '"' && *p != '\'' && | ||
| 5923 | *p != '%' && *p != ',' && *p != '|' && *p != '$'); | ||
| 5821 | p++) | 5924 | p++) |
| 5822 | continue; | 5925 | /* In expl3 code we remove the argument specification from |
| 5926 | the tag name. More generally we allow only one (deleted) | ||
| 5927 | escape char in a tag name, which (primarily) enables | ||
| 5928 | tagging a TeX command's different, possibly temporary, | ||
| 5929 | '\let' bindings. */ | ||
| 5930 | if (is_explthree && *p == ':') | ||
| 5931 | break; | ||
| 5932 | else if (*p == TEX_esc) | ||
| 5933 | { /* Second part of test is for, e.g., \cslet. */ | ||
| 5934 | if (!one_esc && !opgrp) | ||
| 5935 | { | ||
| 5936 | one_esc = true; | ||
| 5937 | continue; | ||
| 5938 | } | ||
| 5939 | else | ||
| 5940 | break; | ||
| 5941 | } | ||
| 5942 | else | ||
| 5943 | continue; | ||
| 5944 | /* For TeX files, tags without a name are basically cruft, and | ||
| 5945 | in some situations they can produce spurious and confusing | ||
| 5946 | matches. Try to catch as many cases as possible where a | ||
| 5947 | command name is of the form '\(', but avoid, as far as | ||
| 5948 | possible, the spurious matches. */ | ||
| 5949 | if (p == cp) | ||
| 5950 | { | ||
| 5951 | switch (*p) | ||
| 5952 | { /* Include =? */ | ||
| 5953 | case '(': case '[': case '"': case '\'': | ||
| 5954 | case '\\': case '!': case '=': case ',': | ||
| 5955 | case '|': case '$': | ||
| 5956 | p++; | ||
| 5957 | break; | ||
| 5958 | case '{': case '}': case '<': case '>': | ||
| 5959 | if (!opgrp) | ||
| 5960 | { | ||
| 5961 | p++; | ||
| 5962 | if (*p == '\0' || *p == '%') | ||
| 5963 | goto tex_next_line; | ||
| 5964 | } | ||
| 5965 | break; | ||
| 5966 | default: | ||
| 5967 | break; | ||
| 5968 | } | ||
| 5969 | } | ||
| 5823 | namelen = p - cp; | 5970 | namelen = p - cp; |
| 5824 | linelen = lb.len; | 5971 | linelen = lb.len; |
| 5825 | if (!opgrp || *p == TEX_clgrp) | 5972 | if (!opgrp || *p == TEX_clgrp) |
| @@ -5828,9 +5975,18 @@ TeX_commands (FILE *inf) | |||
| 5828 | p++; | 5975 | p++; |
| 5829 | linelen = p - lb.buffer + 1; | 5976 | linelen = p - lb.buffer + 1; |
| 5830 | } | 5977 | } |
| 5831 | make_tag (cp, namelen, true, | 5978 | if (namelen) |
| 5832 | lb.buffer, linelen, lineno, linecharno); | 5979 | make_tag (cp, namelen, true, |
| 5833 | goto tex_next_line; /* We only tag a line once */ | 5980 | lb.buffer, linelen, lineno, linecharno); |
| 5981 | /* Lines with more than one \def or \let are surprisingly | ||
| 5982 | common in TeX files, especially in the system files that | ||
| 5983 | form the basis of the various TeX formats. This tags them | ||
| 5984 | all. */ | ||
| 5985 | /* goto tex_next_line; /\* We only tag a line once *\/ */ | ||
| 5986 | while (*cp != '\0' && *cp != '%' && *cp != TEX_esc) | ||
| 5987 | cp++; | ||
| 5988 | if (*cp != TEX_esc) | ||
| 5989 | goto tex_next_line; | ||
| 5834 | } | 5990 | } |
| 5835 | } | 5991 | } |
| 5836 | tex_next_line: | 5992 | tex_next_line: |
diff --git a/lisp/textmodes/tex-mode.el b/lisp/textmodes/tex-mode.el index 4bc2c840cdb..ec0c0c47a2d 100644 --- a/lisp/textmodes/tex-mode.el +++ b/lisp/textmodes/tex-mode.el | |||
| @@ -637,6 +637,14 @@ An alternative value is \" . \", if you use a font with a narrow period." | |||
| 637 | 3 '(tex-font-lock-append-prop 'bold) 'append))))) | 637 | 3 '(tex-font-lock-append-prop 'bold) 'append))))) |
| 638 | "Gaudy expressions to highlight in TeX modes.") | 638 | "Gaudy expressions to highlight in TeX modes.") |
| 639 | 639 | ||
| 640 | (defvar-local tex-expl-region-list nil | ||
| 641 | "List of region boundaries where expl3 syntax is active. | ||
| 642 | It will be nil in buffers visiting files which use expl3 syntax | ||
| 643 | throughout, for example, expl3 classes or packages.") | ||
| 644 | |||
| 645 | (defvar-local tex-expl-buffer-p nil | ||
| 646 | "Non-nil in buffers using expl3 syntax throughout.") | ||
| 647 | |||
| 640 | (defun tex-font-lock-suscript (pos) | 648 | (defun tex-font-lock-suscript (pos) |
| 641 | (unless (or (memq (get-text-property pos 'face) | 649 | (unless (or (memq (get-text-property pos 'face) |
| 642 | '(font-lock-constant-face font-lock-builtin-face | 650 | '(font-lock-constant-face font-lock-builtin-face |
| @@ -646,7 +654,17 @@ An alternative value is \" . \", if you use a font with a narrow period." | |||
| 646 | (pos pos)) | 654 | (pos pos)) |
| 647 | (while (eq (char-before pos) ?\\) | 655 | (while (eq (char-before pos) ?\\) |
| 648 | (setq pos (1- pos) odd (not odd))) | 656 | (setq pos (1- pos) odd (not odd))) |
| 649 | odd)) | 657 | odd) |
| 658 | ;; Check if POS is in an expl3 syntax region or an expl3 buffer | ||
| 659 | (when (eq (char-after pos) ?_) | ||
| 660 | (or tex-expl-buffer-p | ||
| 661 | (and | ||
| 662 | tex-expl-region-list | ||
| 663 | (catch 'result | ||
| 664 | (dolist (range tex-expl-region-list) | ||
| 665 | (and (> pos (car range)) | ||
| 666 | (< pos (cdr range)) | ||
| 667 | (throw 'result t)))))))) | ||
| 650 | (if (eq (char-after pos) ?_) | 668 | (if (eq (char-after pos) ?_) |
| 651 | `(face subscript display (raise ,(car tex-font-script-display))) | 669 | `(face subscript display (raise ,(car tex-font-script-display))) |
| 652 | `(face superscript display (raise ,(cadr tex-font-script-display)))))) | 670 | `(face superscript display (raise ,(cadr tex-font-script-display)))))) |
| @@ -1290,8 +1308,16 @@ Entering SliTeX mode runs the hook `text-mode-hook', then the hook | |||
| 1290 | #'tex--prettify-symbols-compose-p) | 1308 | #'tex--prettify-symbols-compose-p) |
| 1291 | (setq-local syntax-propertize-function | 1309 | (setq-local syntax-propertize-function |
| 1292 | (syntax-propertize-rules latex-syntax-propertize-rules)) | 1310 | (syntax-propertize-rules latex-syntax-propertize-rules)) |
| 1311 | ;; Don't add extra processing to `syntax-propertize' in files where | ||
| 1312 | ;; expl3 syntax is always active. | ||
| 1313 | :after-hook (progn (tex-expl-buffer-parse) | ||
| 1314 | (unless tex-expl-buffer-p | ||
| 1315 | (add-hook 'syntax-propertize-extend-region-functions | ||
| 1316 | #'tex-expl-region-set nil t))) | ||
| 1293 | ;; TABs in verbatim environments don't do what you think. | 1317 | ;; TABs in verbatim environments don't do what you think. |
| 1294 | (setq-local indent-tabs-mode nil) | 1318 | (setq-local indent-tabs-mode nil) |
| 1319 | ;; Set up xref backend in TeX buffers. | ||
| 1320 | (add-hook 'xref-backend-functions #'tex--xref-backend nil t) | ||
| 1295 | ;; Other vars that should be buffer-local. | 1321 | ;; Other vars that should be buffer-local. |
| 1296 | (make-local-variable 'tex-command) | 1322 | (make-local-variable 'tex-command) |
| 1297 | (make-local-variable 'tex-start-of-header) | 1323 | (make-local-variable 'tex-start-of-header) |
| @@ -1937,6 +1963,36 @@ Mark is left at original location." | |||
| 1937 | (forward-sexp 1)))))) | 1963 | (forward-sexp 1)))))) |
| 1938 | (message "%s words" count)))) | 1964 | (message "%s words" count)))) |
| 1939 | 1965 | ||
| 1966 | (defun tex-expl-buffer-parse () | ||
| 1967 | "Identify buffers using expl3 syntax throughout." | ||
| 1968 | (save-excursion | ||
| 1969 | (goto-char (point-min)) | ||
| 1970 | (when (tex-search-noncomment | ||
| 1971 | (re-search-forward | ||
| 1972 | "\\\\\\(?:ExplFile\\|ProvidesExpl\\|__xparse_file\\)" | ||
| 1973 | nil t)) | ||
| 1974 | (setq tex-expl-buffer-p t)))) | ||
| 1975 | |||
| 1976 | (defun tex-expl-region-set (_beg _end) | ||
| 1977 | "Create a list of regions where expl3 syntax is active. | ||
| 1978 | This function updates the list whenever `syntax-propertize' runs, and | ||
| 1979 | stores it in the buffer-local variable `tex-expl-region-list'. The list | ||
| 1980 | will always be nil when the buffer visits an expl3 file, for example, an | ||
| 1981 | expl3 class or package, where the entire file uses expl3 syntax." | ||
| 1982 | (unless syntax-ppss--updated-cache;; Stop forward search running twice. | ||
| 1983 | (setq tex-expl-region-list nil) | ||
| 1984 | ;; Leaving this test here allows users to set `tex-expl-buffer-p' | ||
| 1985 | ;; independently of the mode's automatic detection of an expl3 file. | ||
| 1986 | (unless tex-expl-buffer-p | ||
| 1987 | (goto-char (point-min)) | ||
| 1988 | (let ((case-fold-search nil)) | ||
| 1989 | (while (tex-search-noncomment | ||
| 1990 | (search-forward "\\ExplSyntaxOn" nil t)) | ||
| 1991 | (let ((new-beg (point)) | ||
| 1992 | (new-end (or (tex-search-noncomment | ||
| 1993 | (search-forward "\\ExplSyntaxOff" nil t)) | ||
| 1994 | (point-max)))) | ||
| 1995 | (push (cons new-beg new-end) tex-expl-region-list))))))) | ||
| 1940 | 1996 | ||
| 1941 | 1997 | ||
| 1942 | ;;; Invoking TeX in an inferior shell. | 1998 | ;;; Invoking TeX in an inferior shell. |
| @@ -3743,6 +3799,306 @@ There might be text before point." | |||
| 3743 | (process-send-region tex-chktex--process (point-min) (point-max)) | 3799 | (process-send-region tex-chktex--process (point-min) (point-max)) |
| 3744 | (process-send-eof tex-chktex--process)))) | 3800 | (process-send-eof tex-chktex--process)))) |
| 3745 | 3801 | ||
| 3802 | |||
| 3803 | ;;; Xref backend | ||
| 3804 | |||
| 3805 | ;; Here we lightly adapt the default etags backend for xref so that | ||
| 3806 | ;; the main xref user commands (including `xref-find-definitions', | ||
| 3807 | ;; `xref-find-apropos', and `xref-find-references' [on M-., C-M-., and | ||
| 3808 | ;; M-?, respectively]) work in TeX buffers. The only methods we | ||
| 3809 | ;; actually modify are `xref-backend-identifier-at-point' and | ||
| 3810 | ;; `xref-backend-references'. Many of the complications here, and in | ||
| 3811 | ;; `etags' itself, are due to the necessity of parsing both the old | ||
| 3812 | ;; TeX syntax and the new expl3 syntax, which will continue to appear | ||
| 3813 | ;; together in documents for the foreseeable future. Synchronizing | ||
| 3814 | ;; Emacs and `etags' this way aims to improve the user experience "out | ||
| 3815 | ;; of the box." | ||
| 3816 | |||
| 3817 | (defvar tex-thingatpt-exclude-chars '(?\\ ?\{ ?\}) | ||
| 3818 | "Exclude these chars by default from TeX thing-at-point. | ||
| 3819 | |||
| 3820 | The TeX `xref-backend-identifier-at-point' method uses the characters | ||
| 3821 | listed in this variable to decide on the default search string to | ||
| 3822 | present to the user who calls an `xref' command. These characters | ||
| 3823 | become part of a regexp which always excludes them from that default | ||
| 3824 | string. For the `xref' commands to function properly in TeX buffers, at | ||
| 3825 | least the TeX escape and the two TeX grouping characters should be | ||
| 3826 | listed here. Should your TeX documents contain other characters which | ||
| 3827 | you want to exclude by default, then you can add them to the list, | ||
| 3828 | though you may wish to consult the functions | ||
| 3829 | `tex-thingatpt--beginning-of-symbol' and `tex-thingatpt--end-of-symbol' | ||
| 3830 | to see what the regexp already contains. If your documents contain | ||
| 3831 | non-standard escape and grouping characters, then you can replace the | ||
| 3832 | three listed here with your own, thereby allowing the three standard | ||
| 3833 | characters to appear by default in search strings. Please be aware, | ||
| 3834 | however, that the `etags' program only recognizes `\\' (92) and `!' (33) | ||
| 3835 | as escape characters in TeX documents, and if it detects the latter it | ||
| 3836 | also uses `<>' as the TeX grouping construct rather than `{}'. Setting | ||
| 3837 | the escape and grouping chars to anything other than `\\=\\{}' or `!<>' | ||
| 3838 | will not be useful without changes to `etags', at least for commands | ||
| 3839 | that search tags tables, such as \\[xref-find-definitions] and \ | ||
| 3840 | \\[xref-find-apropos]. | ||
| 3841 | |||
| 3842 | Should you wish to change the defaults, please also be aware that, | ||
| 3843 | without further modifications to tex-mode.el, the usual text-parsing | ||
| 3844 | routines for `font-lock' and the like won't work correctly, as the | ||
| 3845 | default escape and grouping characters are currently hard coded in many | ||
| 3846 | places.") | ||
| 3847 | |||
| 3848 | ;; Populate `semantic-symref-filepattern-alist' for the in-tree modes; | ||
| 3849 | ;; AUCTeX is doing the same for its modes. | ||
| 3850 | (with-eval-after-load 'semantic/symref/grep | ||
| 3851 | (defvar semantic-symref-filepattern-alist) | ||
| 3852 | (push '(latex-mode "*.[tT]e[xX]" "*.ltx" "*.sty" "*.cl[so]" | ||
| 3853 | "*.bbl" "*.drv" "*.hva") | ||
| 3854 | semantic-symref-filepattern-alist) | ||
| 3855 | (push '(plain-tex-mode "*.[tT]e[xX]" "*.ins") | ||
| 3856 | semantic-symref-filepattern-alist) | ||
| 3857 | (push '(doctex-mode "*.dtx") semantic-symref-filepattern-alist)) | ||
| 3858 | |||
| 3859 | (defun tex--xref-backend () 'tex-etags) | ||
| 3860 | |||
| 3861 | (cl-defmethod xref-backend-identifier-at-point ((_backend (eql 'tex-etags))) | ||
| 3862 | (require 'etags) | ||
| 3863 | (tex--thing-at-point)) | ||
| 3864 | |||
| 3865 | ;; The detection of `_' and `:' is a primitive method for determining | ||
| 3866 | ;; whether point is on an expl3 construct. It may fail in some | ||
| 3867 | ;; instances. | ||
| 3868 | (defun tex--thing-at-point () | ||
| 3869 | "Demarcate `thing-at-point' for the TeX `xref' backend." | ||
| 3870 | (let ((bounds (tex--bounds-of-symbol-at-point))) | ||
| 3871 | (when bounds | ||
| 3872 | (let ((texsym (buffer-substring-no-properties (car bounds) (cdr bounds)))) | ||
| 3873 | (if (and (not (string-match-p "reference" (symbol-name this-command))) | ||
| 3874 | (seq-contains-p texsym ?_) | ||
| 3875 | (seq-contains-p texsym ?:)) | ||
| 3876 | (seq-take texsym (seq-position texsym ?:)) | ||
| 3877 | texsym))))) | ||
| 3878 | |||
| 3879 | (defun tex-thingatpt--beginning-of-symbol () | ||
| 3880 | (and | ||
| 3881 | (re-search-backward (concat "[][" | ||
| 3882 | (mapconcat #'regexp-quote | ||
| 3883 | (mapcar #'char-to-string | ||
| 3884 | tex-thingatpt-exclude-chars)) | ||
| 3885 | "\"*`'#=&()%,|$[:cntrl:][:blank:]]")) | ||
| 3886 | (forward-char))) | ||
| 3887 | |||
| 3888 | (defun tex-thingatpt--end-of-symbol () | ||
| 3889 | (and | ||
| 3890 | (re-search-forward (concat "[][" | ||
| 3891 | (mapconcat #'regexp-quote | ||
| 3892 | (mapcar #'char-to-string | ||
| 3893 | tex-thingatpt-exclude-chars)) | ||
| 3894 | "\"*`'#=&()%,|$[:cntrl:][:blank:]]")) | ||
| 3895 | (backward-char))) | ||
| 3896 | |||
| 3897 | (defun tex--bounds-of-symbol-at-point () | ||
| 3898 | "Simplify `bounds-of-thing-at-point' for TeX `xref' backend." | ||
| 3899 | (let ((orig (point))) | ||
| 3900 | (ignore-errors | ||
| 3901 | (save-excursion | ||
| 3902 | (tex-thingatpt--end-of-symbol) | ||
| 3903 | (tex-thingatpt--beginning-of-symbol) | ||
| 3904 | (let ((beg (point))) | ||
| 3905 | (if (<= beg orig) | ||
| 3906 | (let ((real-end | ||
| 3907 | (progn | ||
| 3908 | (tex-thingatpt--end-of-symbol) | ||
| 3909 | (point)))) | ||
| 3910 | (cond ((and (<= orig real-end) (< beg real-end)) | ||
| 3911 | (cons beg real-end)) | ||
| 3912 | ((and (= orig real-end) (= beg real-end)) | ||
| 3913 | (cons beg (1+ beg)))))))))));; For 1-char TeX commands. | ||
| 3914 | |||
| 3915 | (cl-defmethod xref-backend-identifier-completion-table ((_backend | ||
| 3916 | (eql 'tex-etags))) | ||
| 3917 | (xref-backend-identifier-completion-table 'etags)) | ||
| 3918 | |||
| 3919 | (cl-defmethod xref-backend-identifier-completion-ignore-case ((_backend | ||
| 3920 | (eql | ||
| 3921 | 'tex-etags))) | ||
| 3922 | (xref-backend-identifier-completion-ignore-case 'etags)) | ||
| 3923 | |||
| 3924 | (cl-defmethod xref-backend-definitions ((_backend (eql 'tex-etags)) symbol) | ||
| 3925 | (xref-backend-definitions 'etags symbol)) | ||
| 3926 | |||
| 3927 | (cl-defmethod xref-backend-apropos ((_backend (eql 'tex-etags)) pattern) | ||
| 3928 | (xref-backend-apropos 'etags pattern)) | ||
| 3929 | |||
| 3930 | ;; The `xref-backend-references' method requires more code than the | ||
| 3931 | ;; others for at least two main reasons: TeX authors have typically been | ||
| 3932 | ;; free in their invention of new file types with new suffixes, and they | ||
| 3933 | ;; have also tended sometimes to include non-symbol characters in | ||
| 3934 | ;; command names. When combined with the default Semantic Symbol | ||
| 3935 | ;; Reference API, these two characteristics of TeX code mean that a | ||
| 3936 | ;; command like `xref-find-references' would often fail to find any hits | ||
| 3937 | ;; for a symbol at point, including the one under point in the current | ||
| 3938 | ;; buffer, or it would find only some instances and skip others. | ||
| 3939 | |||
| 3940 | (defun tex-find-references-syntax-table () | ||
| 3941 | (let ((st (if (boundp 'TeX-mode-syntax-table) | ||
| 3942 | (make-syntax-table TeX-mode-syntax-table) | ||
| 3943 | (make-syntax-table tex-mode-syntax-table)))) | ||
| 3944 | st)) | ||
| 3945 | |||
| 3946 | (defvar tex--xref-syntax-fun nil) | ||
| 3947 | |||
| 3948 | (defun tex-xref-syntax-function (str beg end) | ||
| 3949 | "Provide a bespoke `syntax-propertize-function' for \\[xref-find-references]." | ||
| 3950 | (let* (grpb tempstr | ||
| 3951 | (shrtstr (if end | ||
| 3952 | (progn | ||
| 3953 | (setq tempstr (seq-take str (1- (length str)))) | ||
| 3954 | (if beg | ||
| 3955 | (setq tempstr (seq-drop tempstr 1)) | ||
| 3956 | tempstr)) | ||
| 3957 | (seq-drop str 1))) | ||
| 3958 | (grpa (if (and beg end) | ||
| 3959 | (prog1 | ||
| 3960 | (list 1 "_") | ||
| 3961 | (setq grpb (list 2 "_"))) | ||
| 3962 | (list 1 "_"))) | ||
| 3963 | (re (concat beg (regexp-quote shrtstr) end)) | ||
| 3964 | (temp-rule (if grpb | ||
| 3965 | (list re grpa grpb) | ||
| 3966 | (list re grpa)))) | ||
| 3967 | ;; Simple benchmarks suggested that the speed-up from compiling this | ||
| 3968 | ;; function was nearly nil, so `eval' and its non-byte-compiled | ||
| 3969 | ;; function remain. | ||
| 3970 | (setq tex--xref-syntax-fun (eval | ||
| 3971 | `(syntax-propertize-rules ,temp-rule))))) | ||
| 3972 | |||
| 3973 | (defun tex--collect-file-extensions () | ||
| 3974 | "Gather TeX file extensions from `auto-mode-alist'." | ||
| 3975 | (let* ((mlist (when (rassq major-mode auto-mode-alist) | ||
| 3976 | (seq-filter | ||
| 3977 | (lambda (elt) | ||
| 3978 | (eq (cdr elt) major-mode)) | ||
| 3979 | auto-mode-alist))) | ||
| 3980 | (lcsym (intern-soft (downcase (symbol-name major-mode)))) | ||
| 3981 | (lclist (and lcsym | ||
| 3982 | (not (eq lcsym major-mode)) | ||
| 3983 | (rassq lcsym auto-mode-alist) | ||
| 3984 | (seq-filter | ||
| 3985 | (lambda (elt) | ||
| 3986 | (eq (cdr elt) lcsym)) | ||
| 3987 | auto-mode-alist))) | ||
| 3988 | (shortsym (when (stringp mode-name) | ||
| 3989 | (intern-soft (concat (string-trim-right mode-name "/.*") | ||
| 3990 | "-mode")))) | ||
| 3991 | (lcshortsym (when (stringp mode-name) | ||
| 3992 | (intern-soft (downcase | ||
| 3993 | (concat | ||
| 3994 | (string-trim-right mode-name "/.*") | ||
| 3995 | "-mode"))))) | ||
| 3996 | (shlist (and shortsym | ||
| 3997 | (not (eq shortsym major-mode)) | ||
| 3998 | (not (eq shortsym lcsym)) | ||
| 3999 | (rassq shortsym auto-mode-alist) | ||
| 4000 | (seq-filter | ||
| 4001 | (lambda (elt) | ||
| 4002 | (eq (cdr elt) shortsym)) | ||
| 4003 | auto-mode-alist))) | ||
| 4004 | (lcshlist (and lcshortsym | ||
| 4005 | (not (eq lcshortsym major-mode)) | ||
| 4006 | (not (eq lcshortsym lcsym)) | ||
| 4007 | (rassq lcshortsym auto-mode-alist) | ||
| 4008 | (seq-filter | ||
| 4009 | (lambda (elt) | ||
| 4010 | (eq (cdr elt) lcshortsym)) | ||
| 4011 | auto-mode-alist))) | ||
| 4012 | (exts (when (or mlist lclist shlist lcshlist) | ||
| 4013 | (seq-union (seq-map #'car lclist) | ||
| 4014 | (seq-union (seq-map #'car mlist) | ||
| 4015 | (seq-union (seq-map #'car lcshlist) | ||
| 4016 | (seq-map #'car shlist)))))) | ||
| 4017 | (ed-exts (when exts | ||
| 4018 | (seq-map | ||
| 4019 | (lambda (elt) | ||
| 4020 | (concat "*" (string-trim elt "\\\\" "\\\\'"))) | ||
| 4021 | exts)))) | ||
| 4022 | ed-exts)) | ||
| 4023 | |||
| 4024 | (defvar tex--buffers-list nil) | ||
| 4025 | (defvar-local tex--old-syntax-function nil) | ||
| 4026 | |||
| 4027 | (cl-defmethod xref-backend-references ((_backend (eql 'tex-etags)) identifier) | ||
| 4028 | "Find references of IDENTIFIER in TeX buffers and files." | ||
| 4029 | (require 'semantic/symref/grep) | ||
| 4030 | (defvar semantic-symref-filepattern-alist) | ||
| 4031 | (let (bufs texbufs | ||
| 4032 | (mode major-mode)) | ||
| 4033 | (dolist (buf (buffer-list)) | ||
| 4034 | (if (eq (buffer-local-value 'major-mode buf) mode) | ||
| 4035 | (push buf bufs) | ||
| 4036 | (when (string-match-p ".*\\.[tT]e[xX]" (buffer-name buf)) | ||
| 4037 | (push buf texbufs)))) | ||
| 4038 | (unless (seq-set-equal-p tex--buffers-list bufs) | ||
| 4039 | (let* ((amalist (tex--collect-file-extensions)) | ||
| 4040 | (extlist (alist-get mode semantic-symref-filepattern-alist)) | ||
| 4041 | (extlist-new (seq-uniq | ||
| 4042 | (seq-union amalist extlist #'string-match-p)))) | ||
| 4043 | (setq tex--buffers-list bufs) | ||
| 4044 | (dolist (buf bufs) | ||
| 4045 | (when-let ((fbuf (buffer-file-name buf)) | ||
| 4046 | (ext (file-name-extension fbuf)) | ||
| 4047 | (finext (concat "*." ext)) | ||
| 4048 | ((not (seq-find (lambda (elt) (string-match-p elt finext)) | ||
| 4049 | extlist-new))) | ||
| 4050 | ((push finext extlist-new))))) | ||
| 4051 | (unless (seq-set-equal-p extlist-new extlist) | ||
| 4052 | (setf (alist-get mode semantic-symref-filepattern-alist) | ||
| 4053 | extlist-new)))) | ||
| 4054 | (let* (setsyntax | ||
| 4055 | (punct (with-syntax-table (tex-find-references-syntax-table) | ||
| 4056 | (seq-positions identifier (list ?w ?_) | ||
| 4057 | (lambda (elt sycode) | ||
| 4058 | (not (memq (char-syntax elt) sycode)))))) | ||
| 4059 | (end (and punct | ||
| 4060 | (memq (1- (length identifier)) punct) | ||
| 4061 | (> (length identifier) 1) | ||
| 4062 | (concat "\\(" | ||
| 4063 | (regexp-quote | ||
| 4064 | (string (elt identifier | ||
| 4065 | (1- (length identifier))))) | ||
| 4066 | "\\)"))) | ||
| 4067 | (beg (and punct | ||
| 4068 | (memq 0 punct) | ||
| 4069 | (concat "\\(" | ||
| 4070 | (regexp-quote (string (elt identifier 0))) | ||
| 4071 | "\\)"))) | ||
| 4072 | (text-mode-hook | ||
| 4073 | (if (or end beg) | ||
| 4074 | (progn | ||
| 4075 | (tex-xref-syntax-function identifier beg end) | ||
| 4076 | (setq setsyntax (lambda () | ||
| 4077 | (setq-local syntax-propertize-function | ||
| 4078 | tex--xref-syntax-fun) | ||
| 4079 | (setq-local TeX-style-hook-applied-p t))) | ||
| 4080 | (cons setsyntax text-mode-hook)) | ||
| 4081 | text-mode-hook))) | ||
| 4082 | (unless (memq 'doctex-mode (derived-mode-all-parents mode)) | ||
| 4083 | (setq bufs (append texbufs bufs))) | ||
| 4084 | (when (or end beg) | ||
| 4085 | (dolist (buf bufs) | ||
| 4086 | (with-current-buffer buf | ||
| 4087 | (unless (local-variable-p 'tex--old-syntax-function) | ||
| 4088 | (setq tex--old-syntax-function syntax-propertize-function)) | ||
| 4089 | (setq-local syntax-propertize-function | ||
| 4090 | tex--xref-syntax-fun) | ||
| 4091 | (syntax-ppss-flush-cache (point-min))))) | ||
| 4092 | (unwind-protect | ||
| 4093 | (xref-backend-references nil identifier) | ||
| 4094 | (when (or end beg) | ||
| 4095 | (dolist (buf bufs) | ||
| 4096 | (with-current-buffer buf | ||
| 4097 | (when buffer-file-truename | ||
| 4098 | (setq-local syntax-propertize-function | ||
| 4099 | tex--old-syntax-function) | ||
| 4100 | (syntax-ppss-flush-cache (point-min)))))))))) | ||
| 4101 | |||
| 3746 | (make-obsolete-variable 'tex-mode-load-hook | 4102 | (make-obsolete-variable 'tex-mode-load-hook |
| 3747 | "use `with-eval-after-load' instead." "28.1") | 4103 | "use `with-eval-after-load' instead." "28.1") |
| 3748 | (run-hooks 'tex-mode-load-hook) | 4104 | (run-hooks 'tex-mode-load-hook) |