从 R 命令行我可以执行help foo
--foo
某个 R 命令在哪里 -- 并返回.html
帮助文件foo
。即使foo
它来自我刚刚加载的某个非标准库,这也适用。
问:LaTeX 中与此最接近的过程是什么?
这里我得到了帮助,发现mthelp
(texdoc
在 TeXLive 系统上)可以返回包、文档类和命令的帮助文件。但缺少 LaTeX 宏(例如\section
)
\section
问:获取标准 latex 命令(例如)或需要加载的包中的命令(例如\mathcal
来自 amsfonts)的完整文档的最快/最佳方法是什么?
到目前为止,我要么(1)寻找科普卡和达利,(2)使用帮助->关键词搜索在 WinEdt 中(返回LaTeX2e 帮助,这只对非常标准的 LaTeX 宏有用(例如\section
)。即便如此,文档也非常有限),(3)标准 Google 和论坛搜索,或(4)使用手册(有时很难mthelp
找到包含感兴趣的宏的适当包的手册)
也许我被 R 宠坏了,但这个过程效率太低了。我肯定做错了什么……对吧?
答案1
TeX 不是一种面向对象的编程语言,它不能像 Python 或 R 那样将文档数据附加到类和对象。没有回溯来了解某个宏是在哪个文件/包/类中定义的,也没有它的输入规范是什么。
我的方法是(1)用 Google 搜索未知的宏,找出它们在包中定义的位置,(2)texdoc <package>
+ 搜索该宏,如果这没有帮助(3)我查看包的源代码,通过(3a)打开源文件或通过(3b)使用 \show\macro关于所讨论的宏。恕我直言,这是你能得到的最接近的东西help macro
。它显示了宏的定义,告诉高级用户他们需要知道的大部分内容。
对于带有可选参数的宏,这没有多大帮助,因为\show
只显示特殊的内部宏,如\\macro
和\macro
(注意空格在宏名)。当然,我自己编写了一个 Perl+TeX 脚本,它从命令行向我显示这些定义(texdef -p <package> <macro>
)。发布它在我的待办事项清单上。
但是,如果您只想要宏的用户描述,即它需要多少个参数以及需要哪些参数,那么最好使用具有命令完成功能的编辑器,例如 Kile。这当然只适用于编辑器知道的命令,这些命令仅限于标准和一些更常见的包。
答案2
这实际上不是一个答案,但是对于评论来说太长了:
查找宏的文档的问题\foo
在于(几乎)不可能知道在哪里\foo
定义。例如,\section
很可能是由您使用的文档类定义的,因此如果它是 article,您需要说texdoc article
(或 miktex 中的等效内容),如果它是 memoir,则使用texdoc memoir
。但是,如果您正在使用扩展或更改功能的某个包\section
,则文档中的信息article
可能不足、不相关甚至具有误导性。
我能给出的最好建议是保持你的前言简洁,对你使用的每一个包写一个小注释,如果你不知道为什么\usepackage{foobar}
,那可能是因为你不使用它[1]。比如
% babel - hyphenation rules and other localization stuff
\usepackage[danish]{babel}
% The geometry package makes it easy to set the margins
\usepackage{geometry}
如果您在某个时候发现需要添加包mathrsfs
才能获得某种脚本数学字体(\mathscr
),请务必在附近记下\usepackage{mathrsfs}
。这样,您就更有可能知道在哪里查找文档。
[1] 这不完全正确,但我相信了解每个包的作用是很重要的。
答案3
与 不同R
,在 LaTeX 中,除了处理错误时,您几乎从不使用内置命令行,即使是错误通常也由 LaTeX IDE 和编辑器处理。几乎每次您需要某些 LaTeX 命令的帮助时,您都在文本编辑器中。也许这就是为什么 LaTeX 不提供您所说的那种帮助。如果有任何有关 LaTeX 命令的帮助,它通常会集成到您正在使用的编辑器中。例如在 vim 中,如果您安装了 LaTeX 支持,则所有标准 LaTeX 命令(使用 LaTeX 与标准类之一且不需要其他包时可用的命令)都可以直接从 vim 帮助系统中访问,就像任何 vim 命令一样。我只需输入即可:he \mbox
获得有关 LaTeX\mbox
命令的帮助。不同的编辑器具有不同的功能,以及访问帮助系统的不同方式。
正如其他答案所指出的,如果您正在使用其他类和包,通常很难知道您的命令在哪里定义。使用不同的类和包,您会得到不同的命令,有时类或包会以自己的方式重新定义标准命令之一(例如,exam
类的使用\part
方式与标准 LaTeX 类中的使用方式完全不同)。这意味着任何帮助系统都必须在您键入文件时监视文件,并跟踪您正在使用的包。同样,文本编辑器可能是最适合此目的的。支持 LaTeX 的 Vim 确实会以某种方式跟踪您的包,尽管它不提供有关它们的帮助,但它会创建一个菜单,其中包含它识别的每个包中最重要的命令。理论上,这可以扩展,以便编辑器在您向文件中添加更多包时加载帮助文件,并扩展其帮助系统以涵盖这些包。可能可以编写一个程序来解析文件.dtx
并尝试提取有关每个文件中定义的命令的信息。这可能并不容易,而且我认为它有点不可靠。
答案4
您可以使用以下代码显示包含给定字符串(例如给定的宏)的源代码部分。
如果您已经加载了所需的包,则可以在其中进行搜索。代码(和 之间\makeatletter
)\makeatother
修补了\input
原语,以便每次读取文件时,还会对其进行解析以在文件中查找给定的字符串。如果找到此字符串,它将与您的给定行数的上下文一起显示在终端上。它根本不是完善的代码(特别是,每次运行只能搜索一个字符串)。
要在特定文件中搜索,请执行\FindStringInFile {1}{5}{gathered}{amsmath.sty}
(如果文件不存在,则会崩溃)。要在之后加载的所有文件中搜索,请执行\FindStringInAnyLaterFile {1}{5}{math*}
。第一个和第二个参数是要在字符串前后显示的上下文行数。
在大多数简单情况下,代码不应该破坏文档的编译,但我无法做出任何保证。
\documentclass{minimal}
\makeatletter
% Standard macros
\def\FSIF@firstoftwo#1#2{#1}
\def\FSIF@secondoftwo#1#2{#2}
\def\FSIF@ifempty@NTF #1{%
\expandafter\ifx \expandafter a\detokenize\expandafter{#1}a%
\expandafter\FSIF@firstoftwo
\else
\expandafter\FSIF@secondoftwo
\fi
}
% Declare our variables
\newread\FSIF@read
\newcount\FSIF@line@int
\newcount\FSIF@pre@context@int
\newcount\FSIF@post@context@int
\newcount\FSIF@found@int
\gdef\FSIF@context{}
\def\FSIF@lines@found{}
\def\FSIF@line@part@i{}
\def\FSIF@line@part@ii{}
\def\FSIF@message@break{}
\def\FindStringInFile#1#2#3#4{%
\FSIF@pre@context@int#1\relax
\FSIF@post@context@int#2\relax
\gdef\FSIF@context{}%
\expandafter\FSIF@aux\expandafter{\detokenize{#3}}{#4}%
\FSIF@show@context
}
\def\FSIF@show@context{%
\begingroup
\newlinechar\endlinechar
\show\FSIF@context
\endgroup
}
\def\FSIF@aux #1#2{% `#1` is now detokenized
\begingroup
% Setup for nice display
\begingroup\lccode`\*\endlinechar
\lowercase{\endgroup \def\FSIF@message@break{*--------------------%
---------- #2 ------------------------------*}}%
%
% Define a macro delimited by `#1`
\def\FSIF@line@split##1#1##2\FSIF@mark##3\FSIF@stop{%
\def\FSIF@line@part@i{##1}%
\def\FSIF@line@part@ii{##2}%
}%
%
% Prepare to read the file, line by line (detokenized)
\FSIF@line@int 0\relax
\immediate\openin\FSIF@read #2\relax
\ifeof\FSIF@read\ERROR\fi
\def\FSIF@lines@found{}%
%
% Save each line in a different control sequence, built with
% `\FSIF@fileline{<file name>}{<line number>}`.
%
% If the string was found, store the line number in
% `\FSIF@lines@found`
\loop
\unless\ifeof\FSIF@read
\readline\FSIF@read to \FSIF@line@buffer
\advance\FSIF@line@int by 1\relax
\expandafter\expandafter\expandafter\let
\FSIF@fileline{#2}{\the\FSIF@line@int}\FSIF@line@buffer
\expandafter \FSIF@line@split \FSIF@line@buffer
\FSIF@mark #1\FSIF@mark \FSIF@stop
\FSIF@ifempty@NTF \FSIF@line@part@ii {}{%
\edef\FSIF@lines@found{\FSIF@lines@found\the\FSIF@line@int,}%
}%
\repeat
%
\expandafter\edef\csname FSIF@#2@lineno\endcsname{\the\FSIF@line@int}%
%
% Then add `\FSIF@context@int` context lines around each line.
% There can be overlaps...
\edef\FSIF@lines@found{\FSIF@lines@found
\number\numexpr\the\FSIF@line@int+\the\FSIF@pre@context@int,}%
%
\FSIF@pop@lines@found
\FSIF@line@int 0\relax
\loop
\advance\FSIF@line@int by 1\relax
% If we've exhausted this found-line's context, see the next one.
\ifnum\numexpr\the\FSIF@found@int+\the\FSIF@post@context@int
<\the\FSIF@line@int\relax
\FSIF@pop@lines@found
\fi
% If we're not yet at a context, step to one.
\ifnum\numexpr\the\FSIF@found@int-\the\FSIF@pre@context@int
>\the\FSIF@line@int\relax
\FSIF@line@int\numexpr\the\FSIF@found@int-\the\FSIF@pre@context@int
\xdef\FSIF@context{\FSIF@context\FSIF@message@break}%
\fi
% Now we're in a context, so store that line.
\xdef\FSIF@context{\FSIF@context\FSIF@fileline{#2}{\the\FSIF@line@int}}%
% If we've not reached the end, we're done.
\ifnum\FSIF@line@int<\csname FSIF@#2@lineno\endcsname\relax
\repeat
\endgroup
}
\def\FSIF@fileline#1#2{\csname FSIF@#1@#2\endcsname}
\def\FSIF@pop@lines@found{%
\expandafter\FSIF@pop@lines@found@aux \FSIF@lines@found\FSIF@stop}
\def\FSIF@pop@lines@found@aux #1,#2\FSIF@stop{%
\FSIF@found@int#1\relax \def\FSIF@lines@found{#2}}
\def\FSIF@new@@@input{\expandafter\FSIF@new@@@input@aux\romannumeral-`\0}
\def\FSIF@new@@@input@aux#1 {%
\expandafter\FSIF@aux\expandafter{\FSIF@string}{#1}%
\FSIF@show@context
\FSIF@old@@@input #1 }
\def\FindStringInAnyLaterFile#1#2#3{%
\FSIF@pre@context@int#1\relax
\FSIF@post@context@int#2\relax
\edef\FSIF@string{\detokenize{#3}}%
\gdef\FSIF@context{}%
% patch `\@@input`.
\let\FSIF@old@@@input\@@input
\let\@@input\FSIF@new@@@input
}
\makeatother
%
\FindStringInFile {1}{5}{gathered}{amsmath.sty}
\FindStringInAnyLaterFile {1}{5}{math*}
\usepackage{amsmath}
\usepackage{breqn}
\begin{document}
An equation,
\begin{align*}
x^2 + y^2 &= z^2 \\
x^2 - y^2 &= t^2
\end{align*}
\end{document}