mcpField
L
latex-writing

latex-writing

github.com/dbosk文档处理1339 次安装今天更新
代码仓库

关于 latex-writing

latex-writing 是用于编写和审阅结构清晰的 LaTeX 文档的技能,重点涵盖语义标记、列表选择、交叉引用、引文、引号及文学编程中的代码规范。

主要功能

  1. 01选择语义恰当的列表环境
  2. 02避免孤立的单项列表
  3. 03指导使用 cleveref 交叉引用
  4. 04涵盖引文与引号规范
  5. 05在 .nw 文件中使用 noweb 表记

适用场景

  1. 01组织定义和 API 参数
  2. 02审阅 LaTeX 列表与引用用法
  3. 03在 .nw 文档中编写代码示例

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/dbosk/claude-skills --skill latex-writing

安装后在 Claude Code 中输入/latex-writing确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

CLAUDE.md
LICENSE.md
references/
cleveref-type-names.md
dual-beamer-article.md
minted-v3-and-floats.md
unicode-and-fonts.md

详细介绍

LaTeX 写作最佳实践

本指南介绍如何按照既定最佳实践,创建结构良好、语义正确的 LaTeX 文档。

核心原则:语义标记

使用与内容语义相符的 LaTeX 环境,而不只是关注视觉效果。

列表环境:如何选择

为术语-定义配对使用 description

如果内容包含标签及其后面的解释、定义或描述,请使用 description 环境:

\begin{description}
\item[Term] Definition or explanation of the term
\item[Label] Content associated with the label
\item[Property] Description of the property
\end{description}

绝对不要这样做:

\begin{itemize}
\item \textbf{Term:} Definition or explanation
\item \textbf{Label:} Content associated with label
\end{itemize}
description 的常见用例
  • API 参数:\item[username] The user's login name
  • 配置选项:\item[timeout] Maximum wait time in seconds
  • 术语表条目:\item[LaTeX] A document preparation system
  • 通过/失败示例:\item[Passes] Correct implementation...
  • 功能描述:\item[Auto-save] Automatically saves every 5 minutes
例外:教学元评注

不要使用可见的 description 列表来呈现面向教师的教学性 注释,例如 \enquote{哪些内容会变化}、\enquote{哪些内容保持不变}, 或教学材料中的顺序说明。这些内容应通过 didactic-notes 技能放入 \ltnote{...} 中。只有当带标签的内容属于面向学生的文档本身时, 才使用 description。

为简单列表使用 itemize

当列表项性质相同且不带标签时,请使用 itemize:

\begin{itemize}
\item First uniform item
\item Second uniform item
\item Third uniform item
\end{itemize}
为编号步骤或排名使用 enumerate

当顺序很重要时,请使用 enumerate:

\begin{enumerate}
\item First step in the process
\item Second step in the process
\item Third step in the process
\end{enumerate}
只有一个项目的列表应写成正文,而不是列表

只有一个 \item 的列表绝不正确:它会显示成一个孤立的项目符号, 没有同级项目可供枚举。在 exercise、definition、remark、 example、block 等语义环境中,这种情况十分常见:单个问题或 一行陈述被不必要地包装在 itemize 中。

% BAD — one bullet, nothing to list
\begin{exercise}
  \begin{itemize}
    \item Describe your algorithm for sorting laundry.
  \end{itemize}
\end{exercise}

% GOOD — prose
\begin{exercise}
  Describe your algorithm for sorting laundry.
\end{exercise}

两个简短句子分别写成两个项目符号,通常也不如直接写成正文。只有在 确实存在多个并列、可枚举的项目时,才使用 itemize/enumerate。 在同时包含 beamer/article 的幻灯片中,这一点尤为重要:孤立的项目 符号在幻灯片上显得难看,也会打断讲义的正文流畅度(参见 didactic-notes 技能)。

环境开头绝不要使用列表或代码块——先写引导文字

即使列表中确实有多个项目,也不能让它成为语义环境 (example、exercise、remark、definition、block)中的 第一项内容。如果一开始就是 \begin{enumerate}、\begin{itemize}、 \inputminted 或 \begin{minted},就会与环境的行内标签冲突:第一个 列表项(或第一行代码)会和 \enquote{示例 1.} 显示在同一行,彼此覆盖。 务必先写至少一句简短的引导语,再放入列表或代码。

% BAD — enumerate/minted butts against the "Exempel 1." label
\begin{example}[Att göra pannkakssmet]
  \begin{enumerate}
    \item Knäck tre ägg i en bunke.
    ...
  \end{enumerate}
\end{example}

\begin{example}[Hela programmet]
  \inputminted{python}{examples/pannkakor.py}
\end{example}

% GOOD — a lead-in sentence puts the list/code on its own line
\begin{example}[Att göra pannkakssmet]
  Följ stegen:
  \begin{enumerate}
    \item Knäck tre ägg i en bunke.
    ...
  \end{enumerate}
\end{example}

\begin{example}[Hela programmet]
  Det ser ut så här:
  \inputminted{python}{examples/pannkakor.py}
\end{example}

因此,规则并非 \enquote{禁止使用项目符号}——先用正文句子引出后, 就可以使用项目符号和代码。禁止的是让列表或代码块成为环境的开头。

在编号项目之间穿插评注(enumitem resume)

如果编号项目(调查/测验问题、要求、考试任务)需要附带解释性评注, 请让 \item 文本保持简洁,并将评注写成各个单项环境之间的正文; 使用 enumitem 恢复编号:

\begin{enumerate}
  \item \enquote{Have you programmed before this course?}
\end{enumerate}
Commentary motivating the question, referencing what it serves.
\begin{enumerate}[resume]
  \item \enquote{How do you plan to study in this course?}
\end{enumerate}
More commentary...
  • 共享同一段评注的项目应放在同一个环境中。
  • 需要 \usepackage{enumitem};在 beamer/article 双模式构建中,只在 article 驱动文件中加载该包(enumitem 与 beamer 的列表内部机制 冲突),并将此类列表放在 article 模式的正文中,幻灯片构建任务会 跳过这些内容(\mode*)。
  • 反模式:在问题文本后将评注直接附加到 \item 中——这样问题和其 理由就会混在一起。

识别模式

审阅或编写 LaTeX 时,请留意以下模式,这些模式表明应使用 description:

  • \item \textbf{SomeLabel:} → 应使用 \item[SomeLabel]
  • \item \emph{SomeLabel:} → 应使用 \item[SomeLabel]
  • \item SomeLabel --- → 应使用 \item[SomeLabel]
  • 每个条目都以粗体或强调文本开头的列表

修正常见反模式

反模式:在 Itemize 中使用粗体标签
% INCORRECT
\begin{itemize}
\item \textbf{Passes:} \verb|\documentclass{article}|
\item \textbf{Fails:} No documentclass declaration
\end{itemize}
正确:Description 环境
% CORRECT
\begin{description}
\item[Passes] \verb|\documentclass{article}|
\item[Fails] No documentclass declaration
\end{description}
反模式:使用手动格式,而非语义结构
% INCORRECT
\noindent\textbf{Configuration:} Set timeout to 30 seconds.\\
\textbf{Performance:} Optimized for large datasets.
正确:语义化的 Description
% CORRECT
\begin{description}
\item[Configuration] Set timeout to 30 seconds
\item[Performance] Optimized for large datasets
\end{description}

Literate Programming(.nw 文件)

重要:在 literate programming 文件(.nw)中编写 LaTeX 时,使用 noweb 的 [[code]] 表示法引用代码,而不是使用 \texttt 手动转义。

使用 [[code]] 表示法,而非 \texttt{...\_...}

noweb literate programming 系统提供了用于代码引用的特殊表示法,可自动处理下划线等特殊字符。

反模式:使用 \texttt 手动转义下划线

% INCORRECT - in .nw files
The \texttt{get\_submission()} method calls \texttt{\_\_getattribute\_\_}.
We store \texttt{\_original\_get\_submission} in the closure.
The \texttt{NOREFRESH\_GRADES} constant defines final grades.

正确:使用 [[code]] 表示法

% CORRECT - in .nw files
The [[get_submission()]] method calls [[__getattribute__]].
We store [[_original_get_submission]] in the closure.
The [[NOREFRESH_GRADES]] constant defines final grades.

原因:

  • 自动转义特殊字符(下划线、反斜杠等)
  • 提高源代码的可读性(无需手动转义)
  • 遵循 literate programming 约定
  • 避免因忘记转义而导致 LaTeX 错误
  • 清晰地区分代码和正文
何时使用 [[code]],何时使用 \texttt

在 .nw 文件中使用 [[code]],适用于:

  • 函数和方法名:[[get_submissions()]]、[[__init__]]
  • 变量名:[[_includes]]、[[user_id]]
  • 类名:[[LazySubmission]]、[[Assignment]]
  • 常量:[[NOREFRESH_GRADES]]、[[MAX_RETRIES]]
  • 模块名:[[pickle]]、[[Canvas]]
  • 含有下划线或特殊字符的任何标识符

在 .nw 文件中使用 \texttt,适用于:

  • 不含特殊字符的简短非代码技术术语
  • 文件扩展名:\texttt{.py}、\texttt{.nw}
  • 不含下划线的简单命令

在常规 .tex 文件中(非 literate programming 文件):

  • 使用 \texttt 并正确转义,因为这里无法使用 [[...]]
  • 或使用 minted 或 listings 等包来处理代码
审阅时的识别模式

审阅 .nw 文件时,请留意以下反模式:

  • \texttt{..._...} → 应使用 [[...]]
  • \texttt{...__...} → 应使用 [[...]]
  • \item[SOME\_CONSTANT behavior] → 可以改写标签,并在正文中放入 [[SOME_CONSTANT]];也可以在标签中将常量包在 [[...]] 内——\item[ [[SOME_CONSTANT]] behavior]。如果选择 第二种方式,请在 ]] 和结尾的 ] 之间至少隔一个字符(通常是一个空格),以免连续出现三个方括号, 从而触发 runaway-argument 错误。
真实代码示例

记录方法:

% INCORRECT
The \texttt{\_\_getstate\_\_} method excludes \texttt{\_original\_get\_submission}.

% CORRECT
The [[__getstate__]] method excludes [[_original_get_submission]].

记录常量:

% INCORRECT
\item[NOREFRESH\_GRADES behavior] Submissions with final grades...

% CORRECT
\item[Final grade policy] Submissions with final grades (A, P, P+, complete)
  are never refreshed, maintaining the [[NOREFRESH_GRADES]] policy.

记录属性:

% INCORRECT
The decorator adds a \texttt{\_\_cache} dictionary and \texttt{\_\_all\_fetched} flag.

% CORRECT
The decorator adds a [[__cache]] dictionary and [[__all_fetched]] flag.

其他最佳实践

交叉引用
  • 始终对所有交叉引用使用 \cref{...}(cleveref 包)
  • 绝不要使用 \S\ref{...} 或手动输入章节/图表前缀
  • 使用描述性标签:\label{sec:introduction},而非 \label{s1}
  • 示例:
    • 章节:\cref{sec:background} → “第 2.1 节”
    • 图:\cref{fig:diagram} → “图 3”
    • 表:\cref{tab:results} → “表 1”
    • 多个:\cref{sec:intro,sec:conclusion} → “第 1 节和第 4 节”

反面示例:手动添加前缀

% INCORRECT
Section~\ref{sec:intro} shows...
\S\ref{sec:background} discusses...
Figure~\ref{fig:plot} demonstrates...

% CORRECT
\cref{sec:intro} shows...
\cref{sec:background} discusses...
\cref{fig:plot} demonstrates...

原因:cleveref 包会自动添加正确的前缀(章节、图等),并处理复数形式、范围和特定语言的格式。

引用类型名称:\cref 输出的名称必须与正文实际使用的词语一致,无论使用何种语言——如果文档说的是“步骤”,就不能渲染成“项目 5”(使用 \AtBeginDocument 钩子中的 \crefname 覆盖,并确保该钩子在 cleveref 之后注册,以免语言选项自身的钩子悄然覆盖它)。对于非英语文档,cleveref 还会从自身的包选项或全局类选项获取语言设置,而非从 babel 获取。一个文档中有多种类型时,可以按标签(\label[type]{...})或按环境处理(enumitem 的 \newlist,每个列表使用一个计数器——beamer 中除外)。完整指南见 references/cleveref-type-names.md(搜索:crefname、terminology、AtBeginDocument、label[type]、newlist、swedish、enumi、appendix)。

引文
  • 使用正确的引文命令(\cite、\citep、\citet),不要手动引用
  • 绝不要手动写 [1] 或 (Smith 2020)
引语(csquotes 包)
  • 始终使用 \enquote{...} 表示引语,绝不要手动输入引号
  • 自动处理嵌套引语:\enquote{outer \enquote{inner} quote}
  • 根据语言调整:瑞典语使用 »...« 或 "...",英语使用 "..." 或 '...'
  • 对于块引用,使用 \begin{displayquote}...\end{displayquote}

反面示例:手动输入引号

% INCORRECT
"This is a quote"
``This is a quote''
'single quotes'

正确:使用 csquotes

% CORRECT
\enquote{This is a quote}
\enquote{outer \enquote{inner} quote}

原因:手动输入的引号不会根据语言设置调整,还可能导致排版不一致。csquotes 包会根据文档语言正确处理所有引号样式。

引用原文与注明来源的转述

使用哪种命令取决于文本是否为源文中的逐字引用:

  • 逐字转载源文 → 使用带引文的整合式引用命令,让引语自带出处;不要写 \enquote{...} 再附上一个独立的 \cite/\autocite:
    • \textcquote[⟨prenote⟩][⟨postnote⟩]{key}{text} — 行内
    • \blockcquote[⟨postnote⟩]{key}{text} — 块引用(长引语)
  • 转述、重构的对话或转述的示例 → 这不是引语。使用 \textcite/\autocite 将来源整合到正文中,并将任何转述的话语放在普通的 \enquote 中。
  • 普通的 \enquote{...} 仅用于其他情况:表示存疑的引号、提及词语本身,以及回指已引用的引语。
% INCORRECT — verbatim source text as \enquote + detached citation
The study reports \enquote{much higher (63\%)} results \autocite[p.~167]{NCOL}.
% CORRECT — verbatim quotation carries its own citation
The study reports \textcquote[p.~167]{NCOL}{much higher (63\%)} results.

% CORRECT — a paraphrased/recounted example is attributed, NOT \textcquote'd
\Textcite[pp.~24--25]{NCOL} reports a study in which a child answers
\enquote{five} for one hand and \enquote{ten} for the other.

重要注意事项:\textcquote/\blockcquote 表示花括号中的文本是源文中的逐字原文。使用前请确认这些文字确实出现在源文中;不要将这些命令用于转述、重构的对话或提及词语本身——此类内容应改用 \textcite/\autocite 标明来源。(参见 backing-claims 技能——引用前请阅读并核实来源。)

强调
  • 在正文中,绝不要使用全大写来强调
  • 使用 \emph{...} 来强调词语或短语
  • 强调程度较强时,使用 \textbf{...} 或嵌套的 \emph{\emph{...}}
  • 让 LaTeX 处理排版样式

反例:使用全大写来强调

% INCORRECT
This is VERY important to understand.
We must do this NOW before moving forward.
The BENEFITS of classes are clear.

正确:使用语义强调

% CORRECT
This is \emph{very} important to understand.
We must do this \emph{now} before moving forward.
The \emph{benefits} of classes are clear.

原因:在正文中使用全大写会被视为大喊大叫,排版效果也不好。它更难阅读,显得不专业。请使用 \emph{...} 进行语义强调,由 LaTeX 以适当的方式呈现(通常为斜体,但可根据上下文和文档样式进行配置)。

例外:按照惯例使用大写字母书写的缩写和专有名称(例如 NASA、USA、PDF)可以保留大写,也无需强调。

浮动体:图和表格

核心原则:图像不是图,但图可以包含图像。请使用规范的图和表格环境,并添加标题和标签。

每个表格和图都必须有标题——没有例外。 无论多小,都不要在 center 环境或正文中直接放置裸露的 tabular 或 \includegraphics:请将其放入带有标题和标签的 table/figure 浮动体中,并使用 \cref 引用。标题应说明读者应从表格或图中理解什么(它所体现的规则或所展示的要点),而不只是说明主题。从其他地方移植文本时请注意这一点——源文档中的无标题表格不能作为先例。

错误——裸露的 tabular,没有标题,按位置引用:

The slot length follows from the title:
\begin{center}
\begin{tabular}{lr}
  Title & Minutes \\ \hline
  Redovisning & 15 \\
  Redovisning spec & 30 \\
\end{tabular}
\end{center}
The table above is the specification.

正确——带标题的浮动体,使用 \cref 引用:

The slot length follows from the title, see \cref{tab:slot-durations}.
\begin{table}
  \begin{sidecaption}{%
    The slot length that a title gives: 30 minutes for
    \enquote{Redovisning spec}, 15 for any other title.
  }[tab:slot-durations]
    \begin{tabular}{lr}
      \toprule
      \textbf{Title} & \textbf{Minutes} \\
      \midrule
      Redovisning & 15 \\
      Redovisning spec & 30 \\
      \bottomrule
    \end{tabular}
  \end{sidecaption}
\end{table}
\Cref{tab:slot-durations} is the specification.

浮动体会移动,因此绝不要用 \enquote{上方}、\enquote{下方}或\enquote{下表}来指代它;请使用 \cref。

使用 sidecaption(memoir 类)

使用 memoir 文档类时,优先使用 sidecaption,而不是传统的 \caption,以获得更好的版式和可访问性:

用于插图:

\begin{figure}
  \begin{sidecaption}{Clear description of image content}[fig:label]
    \includegraphics[width=0.7\textwidth]{path/to/image}
  \end{sidecaption}
\end{figure}

用于表格:

\begin{table}
  \begin{sidecaption}{Description of table content}[tab:label]
    \begin{tabular}{lcc}
      \toprule
      Header1 & Header2 & Header3 \\
      \midrule
      Data1 & Data2 & Data3 \\
      \bottomrule
    \end{tabular}
  \end{sidecaption}
\end{table}

sidecaption 的主要特点:

  • 标题位置:标题显示在内容(插图/表格)旁边,而非上方或下方
  • 节省空间:更充分地利用页面宽度,尤其适用于较窄的图片/表格
  • 提高可读性:标题与内容在视觉上紧密相连
  • 可访问性:标题文本与内容之间有清晰的语义区分
  • 标签一致:标签放在可选的第二个参数 [fig:label] 中

将内容推向其侧边标题所在的一侧。 较窄的插图或表格必须贴着放置标题的页边距——标题在右侧页边距时靠右,在左侧页边距时靠左;绝不能靠左而让标题远在右侧,也不能居中。memoir 不会自动这样排版:它会在一个全宽、左对齐的盒子中排版正文。

  • 使用 didactic ≥ 2.9(选项 sidecapalign=caption,默认值)时,这一过程会自动完成:正文中不要写 \centering、\raggedleft 或 \flushscap。注意:可伸缩空白会折叠(A\hfill B 最终会并排;可用 \makebox[\linewidth]{A\hfill B} 拉开),而正文中的脚注可能导致 varwidth 放弃处理(日志中会出现 \enquote{Failed to reprocess entire contents}),使正文保留在 memoir 原本放置的位置。
  • 使用 sidecapalign=off 或较旧版本的 didactic 时,在 sidecaption 正文开头放置 \flushscap。在 2.9 之前,它读取的是前一个浮动体的侧边,因此在外侧/内侧标题的双面文档中,可能会向错误方向对齐。
  • 不使用 didactic 时,只有当标题始终位于右侧页边距(单面文档或 \sidecapmargin{right})时,正文中的 \raggedleft 才有效。

检查生成的 PDF,确认浮动体与标题之间是否存在空隙。如果仍有空隙,请检查日志加载的是哪个 didactic.sty(grep -n 'didactic.sty' *.log):项目通常会将 didactic 作为 git 子模块打包(例如 doc/didactic,并链接为 doc/didactic.sty),且锁定在较旧版本,从而遮蔽 ~/texmf 中的版本。请更新子模块。

何时使用 sidecaption:

  • 无需占满正文宽度的中等大小插图/表格
  • 标题与内容相邻有助于理解的教学材料
  • 使用 memoir 类的文档(具有 memoir 特性的 Beamer 演示文稿)

传统标题的替代方案:

\begin{figure}
  \centering
  \includegraphics[width=0.7\textwidth]{path/to/image}
  \caption{Description of image content}
  \label{fig:label}
\end{figure}

在以下情况下,使用传统的 \caption + \label:

  • 不使用 memoir 类
  • 插图/表格占满正文宽度
  • 标题自然地放在内容下方(例如宽表格)
引用插图和表格

引用插图和表格时,始终使用 \cref{fig:label}(cleveref 宏包):

As shown in \cref{fig:memory-hierarchy}, secondary memory is slower but non-volatile.

The results in \cref{tab:benchmark} demonstrate...

绝不要硬编码引用,如 “Figure 1”“Table 3.2”,也不要使用 Figure~\ref{fig:label} 之类的手动前缀——让 cleveref 自动处理编号和前缀。

原样文本与代码
  • 代码块使用 minted(首选,支持语法高亮;需要 -shell-escape)或 listings
  • 行内代码片段使用 \verb 或 \mintinline
  • 绝不要将代码作为普通文本粘贴
  • minted v3(TeX Live 2024+)注意事项——参见 references/minted-v3-and-floats.md(搜索:outputdir、Pygments lexer): [outputdir=...] 宏包选项已移除(现在会报错;应加载普通的 \usepackage{minted});此外,minted/\mintinline 的语言参数若跨行 会导致 Pygments lexer " python" is unknown 错误。每次 minted 调用的参数都应放在同一行;只在多个 \mintinline{...}{...} 调用之间换行,切勿在调用内部换行。
调试 ! LaTeX Error: Float(s) lost.

在 beamer/article 双模式教学内容 + memoir 构建中,这种致命且不显示位置的错误(在 \end{document} 处报告)通常由仅幻灯片的 \begin{frame}<presentation> frame 中的引用或脚注引起(它会抑制输出,但仍会执行主体内容,因此边注脚注会变成孤立内容),而不是普通 frame 中的引用;后者没有问题。运行一次精简的 pdflatex -halt-on-error,越过 latexmk/biber 的噪声,查看真正的错误,并通过最小复现进行诊断。修复方法:用 \mode<presentation>{...} 包住仅幻灯片的 frame(或用 \only<presentation>{...} 过滤引用)。**注意:**不能将 \mode<presentation>{...} 包装用于 [fragile] frame——组的结束 } 会落在 verbatim .vrb 扫描范围之外,导致 slides 构建失败,并报错 ! Extra }, or forgotten \endgroup。对于仅幻灯片的 fragile frame,如果实际上不需要 [fragile](其中没有 verbatim/minted/listings),就移除它;否则保留 \begin{frame}<presentation>[fragile],并用 \only<presentation>{\autocite{...}} 保护每个引用。完整诊断参见: references/minted-v3-and-floats.md 和 didactic-notes 技能中的 references/footnotes-and-citations.md。

beamer/article 双模式构建(一个源文件,两种输出)

对于从相同内容文件编译两次的论文(memoir + beamerarticle 文章和 beamer 幻灯片,内容文件以 \mode* 开头),请遵循 references/dual-beamer-article.md(搜索:pyblock frame、ProvideSemanticEnv、restatable、biber root)。简要来说,有四条规则:

  • 每个 PythonTeX pyblock 都必须放在一个 \begin{frame}[fragile] 中,并且该 frame 必须在两种模式下都能渲染——幻灯片构建任务会跳过 frame 外的 pyblock,导致共享的 PythonTeX 会话数据不同步(症状:输出互换、?? PythonTeX ??)。
  • 研究问题和假设应放在语义化且带有 cleveref 标签的环境中(didactic 的 question;在 \DeclareTranslation 后通过 \ProvideSemanticEnv 声明例如 hypothesis),并写在 \begin{restatable}{question}{tag}(thm-restate)中,再用 \tag* 重述——共享导言区中需提供 beamer 兼容层;通过 \cref{rq:*} 引用,绝不要直接写“RQ1”/“H2”。
  • 仅幻灯片的 frame:用 \mode<presentation>{...} 包装(注意上文关于 fragile 的限制);仅用于文章的正文应放在 frame 之外;不要让幻灯片项目符号列表与相邻的文章正文重复。
  • **出处应与引文一同出现,并放在 frame 内。**幻灯片上展示的逐字引文必须在幻灯片上标注来源(在引文本身加脚注/\footcite):如果出处放在 frame 后的仅文章正文中,幻灯片上的引文就会没有出处。将出处附在引文上后,它会在 beamer 幻灯片页脚处显示,并在文章中显示为边注/脚注——一个源文件即可满足两种构建任务。
  • Biber 重跑应从项目根目录执行(biber ltxobj/<jobname>),绝不要从输出目录内部执行。
编码和字体(取决于引擎)

Unicode/字体构建失败在 pdfLaTeX 与 XeLaTeX/LuaLaTeX 上的修复方法正好相反,因此请先确认引擎(grep 'This is' file.log)。 完整指南见 references/unicode-and-fonts.md(搜索: DeclareUnicodeCharacter、iftex、newunicodechar、fontenc、pdffonts):

  • pdfLaTeX — ! LaTeX Error: Unicode character … (U+XXXX) not set up — 某个非 ASCII 字节没有映射(反向引号、各种破折号、≈、方框绘图字符)。请在导言区使用 \usepackage[utf8]{inputenc} 然后使用 \DeclareUnicodeCharacter{XXXX}{...} 修复,不要编辑源文件。 (inputenc 用于定义可移植的 \DeclareUnicodeCharacter;没有它可能会出现 Undefined control sequence。)
  • XeLaTeX/LuaLaTeX — 不会出现“not set up”错误(原生支持 UTF-8),而且此处的 \DeclareUnicodeCharacter 未定义(inputenc 会被忽略)。请使用 \ifpdftex … \fi(iftex 包)将仅适用于 pdfLaTeX 的映射括起来;使用 \newunicodechar 重新映射字形。
  • pdfLaTeX — 代码呈现为比例衬线字体(下划线提取为 ˙,引号变成弯引号)——没有 \usepackage[T1]{fontenc},就无法选择仅支持 T1 编码的等宽字体(例如 Bera Mono)。请加载该包(放在 \ifpdftex 分支中)。
  • 构建系统可能会切换引擎。 latexmk -pdf 与 -xelatex 不同,Makefile 规则也可能由 .nw 文件生成,因此 make/子模块更新可能会切换引擎——请重新检查 .log 横幅,不要想当然。
  • 诊断问题,不要猜测: pdffonts -f N -l N file.pdf 可显示某个页面嵌入了哪些字体;pdftotext -f N -l N 可通过字形→Unicode 映射揭示编码。
路径
  • 路径中始终使用正斜杠:figures/diagram.pdf,而非 figures\diagram.pdf
  • 使用与平台无关的路径规范

LaTeX 编写工作流

编写或编辑 LaTeX 内容时:

  1. 检查文件类型:你是否在 .nw 文学编程文件中?如果是,请使用 [[code]] 表示法,而非 \texttt{...\_...}
  2. 识别内容结构:这是由统一条目组成的列表,还是术语—定义对?
  3. 选择语义环境:让环境与内容含义相匹配
  4. 使用恰当的命令:使用 LaTeX 的语义命令,而非手动格式化
  5. 核对交叉引用:确保标签和引用描述清晰且正确
  6. 检查反模式:检查 itemize 中的 \textbf{Label:},以及 .nw 文件中的 \texttt{..._...}

审查 LaTeX 代码时

检查以下常见问题:

  • 使用 \textbf{Label:} 的列表,而非 description 环境
  • 使用硬编码数字,而非 \ref
  • 手动添加交叉引用前缀(\S\ref、Section~\ref、Figure~\ref),而非使用 \cref
  • 手动设置引用格式,而非使用 \cite 命令
  • 使用手动引号("..."、'...'、`...`),而非使用 \enquote{...}
  • 逐字引用 的源文本使用 \enquote{...} + 独立的 \cite/\autocite,而非使用 \textcquote/\blockcquote(反之,若 \textcquote/\blockcquote 包裹的是改写内容而非逐字引用,也有问题)
  • 图片未使用 figure 环境
  • 代码格式不正确(未使用 listings/verbatim)
  • 路径中使用 Windows 风格的反斜杠
  • 未使用 iftex 保护引擎专用的 Unicode/字体设置——例如,无条件使用 \DeclareUnicodeCharacter(仅适用于 pdfLaTeX),这会导致 XeLaTeX/LuaLaTeX 报错(参见 references/unicode-and-fonts.md)
  • pdfLaTeX:非 ASCII 字符没有对应的 \DeclareUnicodeCharacter 映射,或使用了 \DeclareUnicodeCharacter,却没有 \usepackage[utf8]{inputenc}
  • pdfLaTeX:等宽字体/代码被渲染为比例衬线字体——缺少适用于仅支持 T1 编码字体(如 Bera Mono)的 \usepackage[T1]{fontenc}
  • Beamer/article 双模式构建:pyblock 位于不同时用于两种模式的 \begin{frame}[fragile] 外部(这会导致 PythonTeX 会话不同步),或在正文中使用字面文本 "RQ1"/"H2",而非通过 \cref 引用语义化的问题/假设环境(参见 references/dual-beamer-article.md)

对 .nw 文学编程文件的额外检查:

  • \texttt{..._...} 或 \texttt{...__...} → 应使用 [[...]] 表示法
  • 描述标签中含有下划线,例如 \item[FOO\_BAR behavior] → 使用更合适的标签,并在文本中使用 [[FOO_BAR]]
  • 代码引用中任何手动转义的下划线 → 改用 [[...]]

Beamer:演示模式与文章模式

创建同时生成文章版本的 Beamer 演示文稿时,使用 \mode<presentation> 和 \mode<article>,为每种格式提供合适的内容。

何时拆分内容

冗长的文本环境:定义、备注、示例、区块等语义环境中的正文超过 2-3 行时,对于幻灯片而言过于冗长。

解决方案:为演示文稿提供简洁版本,为文章提供完整说明:

\begin{frame}
  \mode<presentation>{%
    \begin{remark}[Key Point]
      \begin{itemize}
        \item Concise point 1
        \item Concise point 2
        \item Concise point 3
      \end{itemize}
    \end{remark}
  }
  \mode<article>{%
    \begin{remark}[Key Point]
      Full explanatory paragraph with detailed reasoning and context
      that would overwhelm a slide but provides value in written form.

      Additional paragraphs can elaborate on nuances and implications.
    \end{remark}
  }
\end{frame}
视觉元素

使用 \textbytext 的并排布局:

  • 演示文稿:\textbytext(无星号,列宽,适用于 beamer 帧)
  • 文章:\textbytext*(带星号,全宽,更适合印刷文档)
\begin{frame}
  \mode<presentation>{%
    \textbytext{Left content}{Right content}
  }
  \mode<article>{%
    \textbytext*{Left content}{Right content}
  }
\end{frame}
原则

幻灯片需要清晰的视觉效果和简洁性(项目符号、短语)。文章则可以提供深度和解释(完整句子、段落)。应针对不同媒介设计合适的内容。

使用 Mentipy 的互动问题

对于需要嵌入实时投票的幻灯片或教学文章,可在 PythonTeX 区块或其他 Python 区块中使用 mentipy.latex。面向学生的问题优先使用 mc、open_text、scale 和 word_cloud,然后运行 mentipy serve 发布投票;URL 更改后重新编译,以嵌入更新后的二维码。讲义使用 layout="article" 或 layout="article+qr";Beamer 幻灯片使用 layout="slide"。

标准导言区

对于新的 LaTeX 文档,请使用 references/preamble.tex 中的标准导言区。将其原样复制到项目的 doc/preamble.tex,并在 \documentclass 后使用 \input{preamble} 引入。

文档结构:

\documentclass[a4paper,oneside]{memoir}
\input{preamble}

\title{Document Title}
\author{Author Name}
\date{\today}

\begin{document}
\frontmatter
\maketitle
\tableofcontents

\mainmatter
% Content here

\backmatter
\end{document}

标准导言区提供:

  • 语言支持、参考文献、数学和引文功能
  • 代码高亮和 noweb 支持
  • 交叉引用和表格
  • enumitem、acro 和 siunitx 等常用实用工具

这可确保所有文档和项目的格式保持一致。

请记住

LaTeX 是一种基于语义标记的文档准备系统,而不是文字处理器。目标是描述内容是什么,而不是它应该是什么样子。让 LaTeX 根据你提供的语义结构处理格式。

评论

支持 Markdown