源代码缩进

源代码缩进

我想知道是否可以像大多数编程语言一样缩进代码,如下所示:

\part
    \chapter
        \section
            \subsection    etc.

这将使源代码更具可读性。那么这可能吗?如果可以,怎么做?

答案1

是的,这是可能的。TeX 总是忽略源代码行开头的空格。但是,我不认为这对于普通文档来说更具可读性。对于\subsubsection我来说,缩进许多空格的几个段落实际上不可读。相反,我通常在分段命令前添加某些分隔线,例如 80-120x 。对于更高的分段命令,您可以使用两个或更多这样的分隔线。无论如何,在我看来,多个章节和部分不应该放在一个源文件中,而应该分成几个文件,然后使用或%将它们包含在主文档中。\include\input

如果你的问题实际上是如何去做这个自动地然后请注意,这当然取决于编辑器。我不知道有哪个编辑器可以对分段命令执行此操作。也许可以配置更高级的命令,但为此我们需要知道您正在使用哪一个。

答案2

缩进“是否可能”取决于当前的类别代码制度以及您希望缩进产生的效果。

在通常的类别代码制度下,通过空格和/或水平制表符缩进既不会影响输出文件(.pdf 文件)中文本的外观,也不会影响例如宏参数/等的标记的收集⟨balanced text⟩

在不寻常的类别代码制度下,缩进可能会影响输出文件中文本的外观和/或影响宏参数/ ⟨balanced text⟩等的标记的收集。例如,在- 或- 环境
的主体内,通过空格缩进确实会影响输出文件中文本的外观。环境并切换到一些不寻常的类别代码制度。verbatimverbatim*verbatimverbatim*

故事如下:

TeX 的读取和标记设备会逐行读取/处理输入。

在准备一行输入进行标记时,TeX 首先会转换该行的单个字符,使这些字符适合其内部字符表示方案。对于传统的 TeX 引擎,内部字符表示方案是美国信息交换标准代码 (ASCII)。对于 LuaTeX 引擎和 XeTeX 引擎,内部字符表示方案是 Unicode/utf8。
这意味着,输入中的字符可能以所使用的底层计算机平台指定的任何方式进行编码,并且在 TeX 引擎的内部字符表示方案中也有表示,在 TeX 内部,它将由 TeX 引擎内部字符表示方案中的代码点编号表示。

然后 — 根据 Donald E. Knuth 的 TeXbook — 该行末尾的任何空格字符都将被删除。(在此阶段,空格将由 TeX 内部字符代码 32 表示,因为 32 是 ASCII/Unicode/TeX 引擎内部字符表示方案中空格字符的代码点编号。)
(和Web2C 实现在 2019 年 TeX Live 发行之前,TeX 的一些实现与 TeXbook 中的内容略有不同:在这些实现中,不仅行尾的空格字符序列将被删除,而且行尾的空格字符和/或水平制表符(TeX 引擎内部字符表示方案中的代码点编号 9)组成的序列也将被删除。请参阅 egreg 的回答/更新针对这个问题为什么尾随制表符没有排版?

然后,将在行尾附加一个字符,其代码点编号在 TeX 引擎的内部字符表示方案等于整数参数的当前值\endlinechar
(通常的值为\endlinechar13(十进制),因此表示回车符,因为回车符在 ASCII/Unicode/TeX 引擎的内部字符表示方案中具有代码点编号 13。
通常分配给 TeX 内部字符 13(回车符)的类别代码为 5(行尾)。)

然后 TeX 将开始对该行进行标记。
即,TeX 将“查看”相关输入行的字符,并据此获取相关输入行的内容,以获取一组指令,用于将所谓的标记放入标记流中。
标记可以是控制序列标记(它们有两种类型:控制字标记和控制符号标记)或显式字符标记。
(控制字标记是其名称仅由类别代码 11 的字符和/或多个字符组成的控制序列标记。[名称由类别代码 11(字母)和非类别代码 11 的字符混合组成的控制字标记不能通过读取和标记输入来获得,而只能通过\csname..\endcsname/从其他标记创建它们来获得\ifcsname..\endcsname。]
控制符号标记是一种控制序列标记,其名称由类别代码不是 11(字母)的单个字符组成。
显式字符标记具有两个属性:字符代码和类别。在 TeX 术语中,显式字符标记的字符代码表示 TeX 引擎内部字符表示方案中字符的代码点编号,在传统引擎中为 ASCII,在 XeTeX/LuaTeX 引擎中为 Unicode,ASCII 是其子集。在 TeX 术语中,显式字符标记的类别会影响 TeX 引擎在进一步处理该显式字符标记时的操作:开始/结束一个组;进入/离开数学模式;表示对齐制表符;表示宏参数;表示下标或上标;表示空格;表示应出现在输出文件中的字体字形的某种组合;...
在标记化时,会将类别分配给显式字符标记。在标记化过程中将哪个类别分配给显式字符标记取决于标记化时相关字符具有哪个类别代码。
例如,当 TeX 不打算收集控制序列标记的名称并且在输入中找到字符A(在准备标记化的行时,该字符被转换为 TeX 内部字符表示方案,ASCII 或 Unicode,而根据 ASCII/Unicode 标准,字符的代码点为A数字 65),它将在标记流中插入一个显式字符标记,其 TeX 内部字符代码为 65,并且 — 通常类别代码 11(字母)分配给字符代码 65 — 其类别为 11(字母)。
我使用了术语“显式字符标记”。还有隐式字符标记:这是当您这样做时,例如,\let\foobar=A.\foobar将是一个控制字标记,其含义与显式字符标记相同,其 TeX 内部字符代码为 65 且类别为 11(字母)。您可以\foobar同时使用 for \if-comparisons 和 for -comparisons,就好像它是TeX 内部字符代码 65 和类别 11(字母)的\ifcat显式字符标记。但是,例如,您不能将其用作字母常量。)A\foobar

当对输入行进行标记时,TeX 的读取和标记装置可以处于以下三种状态之一:

状态 S:跳过空白。

在对控制字标记进行标记之后/在对名称仅由类别代码 11(字母)的字符组成的控制序列标记进行标记之后,读取和标记设备切换到状态 S(跳过空格)。

在对显式空格标记(TeX 内部字符代码 32,类别 10(空格)——空格在 ASCII/Unicode/TeX 引擎的内部字符表示方案中编号为 32)进行标记之后,以及在对名称由类别代码 10(空格)的字符组成的控制符号标记进行标记之后(例如,在对控制空间进行标记之后,\␣即,其名称由 TeX 内部字符代码 32 的单个字符组成的控制符号),读取装置将切换到状态 S。

当读取和标记化设备处于状态 S(跳过空格)时,TeX 不会从输入中获取类别代码 10(空格)的字符作为将任何标记放入标记流中的指令,而 TeX 会简单地删除这些字符,让读取和标记化设备处于状态 S(跳过空格)。

当在状态 S(跳过空格)下遇到类别代码 5(行尾)的字符时,TeX 不会在标记流中插入任何标记,而只是删除该字符并开始处理下一行输入(如果存在),从而删除当前输入行上剩余的任何信息,并将读取和标记化设备切换到状态 N(新行)。

状态 M:线的中间。

在对显式空格字符标记(TeX 内部字符代码 32、类别 10)以外的显式字符标记进行标记之后,以及在对控制符号标记(名称仅由不同于 11 的类别代码的单个字符组成的控制序列标记)进行标记之后,读取和标记设备都会切换到状态 M(行中间)。

当读取和标记化装置处于状态 M(行中间)时,TeX 将从输入中获取类别代码 10(空格)的任何字符,以便将 TeX 内部字符代码 32 和类别 10(空格)的显式字符标记放入标记流中。然后它将读取和标记化装置切换到状态 S(跳过空格)。
在通常的类别代码制度下,空格字符(ASCII/Unicode/TeX 引擎的内部字符表示方案中的代码点编号 32)和水平制表符字符(ASCII/Unicode/TeX 引擎的内部字符表示方案中的代码点编号 9)都是类别代码 10(空格)。因此,在通常的类别代码制度下,空格和水平制表符是可以互换的/以相同的方式处理。

当在状态 M(行中)下遇到类别代码 5(行尾)的字符时,TeX 将在标记流中插入一个空格标记(即,TeX 内部字符代码 32 和类别 10(空格)的显式字符标记),并开始处理下一行输入,从而丢弃当前输入行上剩余的任何信息,并将读取和标记化设备切换到状态 N(新行)。

状态 N:新行。

当 TeX 即将开始读取和标记另一行输入时,读取和标记设备将切换到状态 N。

当读取和标记化设备处于状态 N(新行)时,TeX 不会从输入中获取类别代码 10(空格)的字符作为将任何标记放入标记流中的指令,而 TeX 会简单地删除这些字符,让读取和标记化设备处于状态 N(新行)。

当在状态 N(新行)下遇到类别代码 5(行尾)的字符时,TeX 会将控制序列标记插入\par到标记流中,并开始处理下一行输入(如果存在),从而丢弃当前输入行上剩余的任何信息,并将读取和标记化设备切换到状态 N(新行)。

TeX 输入中连续两个换行符会产生什么效果?

由于\endlinechar在准备用于标记化的输入行时出现的 -thingie,通常在每行输入的末尾都会有一个 TeX 内部字符代码 13 的字符(13 = ASCII/Unicode/TeX 引擎的内部字符表示方案中的回车符),而通常分配给内部字符代码 13 的类别代码是 5(行尾)。

两个连续的换行符通常意味着在遇到第一个换行符和第二个换行符时插入 TeX 内部字符 13(13 = ASCII/Unicode/TeX 引擎的内部字符表示方案中的回车符),而 TeX 内部字符 13 通常具有类别代码 5(行尾)。

在处理这两个字符中的第一个时,读取和标记化装置可能处于状态 S(跳过空格)或状态 M(行中间)。在第二种情况下,当相关行被标记化时,此字符不会将标记插入到标记流中。在后一种情况下,当相关行被标记化时,此字符将导致将显式空格标记(TeX 内部字符代码 32,类别 13)插入到标记流中。在任何情况下,处理完此字符后,读取装置的状态都将切换到状态 N。

当处理这两个字符中的第二个时,读取和标记化装置无论如何都会处于状态 N(新行)。在此状态下,此字符会导致将控制字标记插入\par到标记流中。

(只要\par没有重新定义处理\par,依次——在其他东西下面——就会取消所讨论段落末尾的任何水平粘连。由于显式空格标记而插入的粘连(反过来可能由于\endlinechar状态 M 中的插入东西而产生)也将被取消。)

这就是在输入中插入两个连续的换行符通常可以结束当前段落的方式。


概要:

在准备输入行进行标记化时,TeX 将删除行尾的空格字符(以及 2019 年之前的 Web2C 实现的水平制表符)。

在通常的类别代码制度下,行首的空格字符和水平制表符不起作用:

当 TeX 即将对另一行输入进行标记时,读取和标记设备处于状态 N(新行)。

TeX 将输入中的空格转换为 TeX 内部字符代码 32。TeX
将输入中的水平制表符转换为 TeX 内部字符代码 9。

通常将类别代码 10(空格)分配给 TeX 内部字符代码 32 和 9。

当 TeX 在标记化过程中处于状态 N(换行符)时,处理类别代码为 10(空格)的字符时,它将简单地删除该字符,即,它不会将任何标记放入标记流中,并且将保持状态 N,这决定了对输入中出现的连续空格进行相同的处理。


在环境中verbatimverbatim*为空格字符分配了除 10(空格)之外的类别代码。

verbatim-environment 中,类别代码 13(活动)被分配给空格字符,因此在该环境中,对空格进行标记会产生一个明确的字符标记,其为 TeX 内部字符代码 32 和类别 13(活动)。类别 13(活动)的字符标记可以像控制序列标记一样以多种方式使用。即,在 -environment 中,verbatim空格字符将充当宏。该宏反过来在 -environment verbatim(通过\let-assignment)中定义为等于该宏,\@xobeysp该宏反过来通过\leavevmode确保水平模式、\nobreak防止换行并提供 控制空间,在水平模式下,当 spacefactor 为 1000 时,由于显式空格标记,会导致在插入的粘连宽度中插入空格/水平粘连。

verbatim*在旧版 LaTeX 环境在撰写此答案的初始版本时,我查看了“The LaTeX 2e Sources 2003/12/01”的副本)类别代码 12(其他)将被分配给空格字符(ASCII 32),因此在该环境中,对空格进行标记会产生 TeX 内部字符代码 32 和类别 12(其他)的明确字符标记。

与类别 11(字母)和类别 12(其他)的其他字符标记一样,TeX 在处理字符代码 32 和类别 12(其他)的显式字符标记时会插入字体的字形。在verbatim- 和verbatim*- 环境中使用的字体是\ttfamily—typewriter-family,通过控制序列指定\verbatim@font,通常是 OT1-font-encoding 中的“Computer Modern Typewriter”,而在 OT1-font-encoding 中的字体“Computer Modern Typewriter”中,与 TeX 内部字符代码 32 和类别 12(其他)的字符标记相连的插槽 32 中的字形是这个漂亮的下划线

verbatim*在较新的 LaTeX 版本环境中(在编辑这个答案时,我查看了“LaTeX 2e Sources 2019-10-01 Patch level 2”的副本)类别代码 13(活动)将被分配给空格字符(ASCII 32),并且活动空间仍然等于\@xobeysp\@xobeysp被重新定义为(传统 tex/pdftex 引擎)等于\asciispace,一个宏,它提供当前字体的第 32 个插槽中的字形或(xetex/luatex 引擎)以确保水平模式并传递当前字体中字母 x 宽度的水平框的副本(应该是逐字排版的字体,通过指定\verbatim@font),包含来自 OT1 字体编码中“Computer Modern Typewriter”字体的第 32 个插槽的字符。使用 xetex/luatex 引擎,可以确保重新定义\verbatim@font使用另一种打字机字体进行逐字输出不会破坏可见空间机制,因为这里包含可见空间内容的框是通过在明确切换到“Computer Modern Typewriter”字体后选择插槽 32 中的字形创建的,同时可以确保“Computer Modern Typewriter”字体在插槽 32 中包含所需的下划线状可见空间字形。

在环境中verbatimverbatim*水平制表符的类别代码仍然是 10(空格),因此在环境中verbatimverbatim*您可以使用水平制表符 (↹) 以不影响输出外观的方式缩进源代码,并获得由显式空格标记创建的水平粘合的不可见空格:

\documentclass{article}
\begin{document}

\begin{verbatim}
ABC
DEF
\end{verbatim}

\begin{verbatim}
	ABC
	DEF
	\end{verbatim}

\begin{verbatim*}
A B C
D E F
\end{verbatim*}

\begin{verbatim*}
	A B C
	D E F
	\end{verbatim*}

\begin{verbatim*}
A	B	C
D	E	F
\end{verbatim*}

\begin{verbatim*}
	A	B	C
	D	E	F
	\end{verbatim*}

\end{document}

在此处输入图片描述

当然我的解释verbatimverbatim*的解释只是粗略地概述了事物的工作原理。如果你对细节感兴趣,请随意研究LaTeX 2ε 来源,文件 J:ltmiscen.dtx,第 1.3 节逐字

因此,在通常的类别代码制度下,您可以根据需要通过空格和/或水平制表符缩进代码。

verbatim在像/这样的环境中verbatim*,确实会切换到一些不寻常的类别代码机制,您无法通过空格缩进代码,因为在这些环境中,输入行开头的空格将转换为标记,进而产生可见的输出,而不仅仅是被跳过。在verbatim/中verbatim*,没有视觉效果的缩进只能通过水平制表符来实现。

顺便一提:

由于在准备输入行进行标记时删除了行尾的空格字符,因此即使在verbatim和这样的环境中verbatim*(如 LaTeX 2ε 内核中所定义)也不可能产生在行尾有可见空格的输出。

即输入(此处 ␣ 表示空格字符)

\begin{verbatim*}
␣␣␣\TeX␣is␣funny␣␣␣
␣␣␣\TeX␣is␣funny␣␣␣
\end{verbatim*}

没有产生输出(此处的 ␣ 表示通常用于提供空间可见表示的开框字形)

␣␣␣\TeX␣is␣funny␣␣␣
␣␣␣\TeX␣is␣funny␣␣␣

但确实产生了输出(此处的 ␣ 表示通常用于提供空间可见表示的开框字形)

␣␣␣\TeX␣is␣funny
␣␣␣\TeX␣is␣funny

一个展示偏离通常的类别代码制度的方面的例子——所有缩进仅通过空格完成:

\documentclass{article}
\begin{document}

\section{This is a section}

  \subsection{This is a a subsection}

  This is text that gets read and tokenized under normal category-code-r\'egime.
  This is text that gets read and tokenized under normal category-code-r\'egime.

  \begin{verbatim*}
  This is text that gets read and tokenized under verbatim's category-code-regime.
  This is text that gets read and tokenized under verbatim's category-code-regime.
  \end{verbatim*}

  \begin{itemize}
    \item This is an item that gets read and tokenized
          under normal category-code-r\'egime.
    \item \begin{verbatim*}
          This is an item that gets read and tokenized 
          under verbatim's category-code-regime.
          \end{verbatim*}
    \item This is another item that gets read and tokenized
          under normal category-code-r\'egime.
  \end{itemize}

\end{document}

在此处输入图片描述

答案3

有没有办法让编辑器/前端默认执行此操作,因为缩进每一行有点繁琐;或者也许有支持此功能的前端/编辑器?

latexindent.pl可以为您执行此缩进。

假设您从以下文件开始,myfile.tex并且sam.yaml

myfile.tex

 \part
part text
part text
part text
\chapter
chapter text
chapter text
chapter text
\section
section text
section text
section text
\subsection
subsection text
subsection text
subsection text

sam.yaml

indentRules:
   part: "\t"
   chapter: "\t"
   section: "\t"
   subsection: "\t"
indentAfterHeadings:
    part:
       indentAfterThisHeading: 1
       level: 1
    chapter: 
       indentAfterThisHeading: 1
       level: 2
    section:
       indentAfterThisHeading: 1
       level: 3
    subsection:
       indentAfterThisHeading: 1
       level: 4

运行以下命令

   latexindent.pl myfile.tex -l=sam.yaml -o=output.tex

那么你将收到以下文件:

output.tex

\part
    part text
    part text
    part text
    \chapter
        chapter text
        chapter text
        chapter text
        \section
            section text
            section text
            section text
            \subsection
                subsection text
                subsection text
                subsection text

这个和许多其他选项在文档中有详细说明,并且可以通过 YAML 界面进行自定义。

答案4

在 TeXstudio 中,自动缩进默认是启用的。

相关内容