刚接触Latex时,发现比起Mincrosft Word,Latex的排版是更方便的。但是随着使用的深入,在编辑文档时往往仍然会被复杂的语法体系困扰,这并没有完全达到Latex的“将排版与内容分离”的理念。

通过一些设置,我们可能可以较为轻松地进行排版。

Latex自定义宏、“头文件”与模板

在使用Latex时,我们通常会在文档的开头加入一些“头文件”,例如:

\documentclass[UTF8]{ctexart}
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage{geometry}
\geometry{a4paper,scale=0.8}
\title{更舒适地使用Latex}
\author{Anzrew}
\date{\today}
\begin{document}
\maketitle

特别是引用大量宏包的情况下,前面的“头文件”会变得很长,这样的文档不便于阅读和修改。在刚开始使用时,我总是打开同一个文件,复制粘贴前面的“头文件”,然后再开始写文档。前面很长的“头文件”也会让修改变得困难,并且不够优雅。

并且对于不同的模板,我们可能需要不同的“头文件”,这样的文档也不便于复用。

为了提高程序的简洁度和“头文件”的复用性,我们可以将“头文件”单独写成一个文件,放在全局目录下,例如/.../texlive/texmf-local/tex/latex/local/,然后在文档中使用\input{}命令引用这个文件。这样,我们就可以在不同的文档中使用同一个“头文件”了。

这样我们可以通过头文件来定义不同的模板,并且在合适的时候进行引用。

“头文件”模板的编写

我们可以将“头文件”模板的编写分为两个部分:宏包的引用和文档的设置。

下面是一个示例的“头文件”模板:

%%%%%%% default.tex %%%%%%%
%% 引用宏包 %%
\usepackage{ctex}
\usepackage{amsmath,amssymb,amsthm,multicol,titlesec,siunitx,graphicx,enumitem,booktabs,hyperref,xcolor,geometry}
%% 定义新定理 %%
\newtheorem*{example}{}
\newtheorem*{note}{}
%% 设置初始编号 %%
\setcounter{section}{0}
\numberwithin{table}{subsection}
\numberwithin{equation}{subsection}
%% 设置超链接 %%
\hypersetup{
    hidelinks, % 取消红框
    colorlinks=true,
    linkcolor=blue,
    citecolor=black
}
%% 设置代码环境 %%
\input{code}
%% 标题 %%
\title{请输入标题}
\author{请输入作者}
\date{\today}

也可以在其中交叉引用,更易于维护。

其中有些函数可以在后文覆盖,例如\title{}\author{}\date{}

也可以在其中定自定义的内容。

%%%%%%% code.tex %%%%%%%
\usepackage{listings}
\lstdefinestyle{lfonts}{
  basicstyle   = \scriptsize\ttfamily,
  stringstyle  = \color{purple},
  keywordstyle = \color{blue!60!black}\bfseries,
  commentstyle = \color{olive}\scshape,
}
\lstdefinestyle{lnumbers}{
  numbers     = left,
  numberstyle = \tiny,
  numbersep   = 1em,
  firstnumber = 1,
  stepnumber  = 1,
}
\lstdefinestyle{llayout}{
  breaklines       = true,
  tabsize          = 2,
  columns          = spacefixed,
}
\lstdefinestyle{lgeometry}{
  xleftmargin      = 20pt,
  xrightmargin     = 0pt,
  frame            = tb,
  framesep         = \fboxsep,
  framexleftmargin = 20pt,
}
\lstdefinestyle{lgeneral}{
  style = lfonts,
  style = lnumbers,
  style = llayout,
  style = lgeometry,
}
\lstset{style = lgeneral}
\lstset{language = C}

利用VsCode的Snippets功能设置自动补全与模板

在VsCode中,我们可以通过设置Snippets来实现自动补全和模板的功能。

在VsCode中,我们可以通过Ctrl+Shift+P打开命令面板,然后输入snippets,选择Configure User Snippets,然后选择latex.json,就可以打开latex.json文件了。

latex.json文件中,我们可以设置自动补全的功能,例如:

"\\R": {
    "prefix": "\\R",
    "body": [
        "\\mathbb{R}"
    ],
    "description": "实数集"
}

这样,我们就可以在文档中输入\R,然后按下Tab键,就可以自动补全为\mathbb{R}了。

我们也可以设置模板的功能,例如:

"TeX Template": {
    "prefix": "temp",
    "body": [
        "\\documentclass[12pt,onecolumn,a4paper]{article}",
        "\\input{default}",
        "",
        "%%%%%%%%% 正文 %%%%%%%%%",
        "\\begin{document}",
        "",
        "\\title{}",
        "%% 制作标题 %%",
        "\\maketitle",
        "",
        "%% 制作目录 %%",
        "% \\tableofcontents %节标题目录",
        "% \\listoftables %表格目录",
        "% \\listoffigures %图片目录",
        "",
        "%% 节标题 %%",
        "\\section{title}",
        "",
        "\\end{document}"
    ],
    "description": "TeX file template"
},

在这里我们直接引用了刚刚才写的“头文件”模板,让整体代码更加简洁。

Latex自定义宏

与自动补全类似,Latex中的宏是一种命令,可以用来简化一些常用的命令。例如,我们可以定义一个宏\R,用来表示实数集$\mathbb{R}$,这样我们就可以在文档中使用\R来表示$\mathbb{R}$了。

\newcommand{\R}{\mathbb{R}}

刚才的“头文件”模板中也定义一些常用的宏,例如:


%%%%%%% report.tex(的一部分) %%%%%%%
\newcommand{\generateReportInfo}[7]{
  \newcommand{\mytitle}{#1}
  \title{\heiti{\mytitle}}
  \author{%
    \begin{tabular}{p{2cm}l}\hfill& : {\kaishu #2} \\ 
      & \\\hfill& : #3 \\ 
      & \\\hfill\hfill\hfill& : {\kaishu #4} \\ 
      & \\\hfill\hfill\hfill& : #5 \\
    \end{tabular}
  }
  \date{#6}
  
  %% 设置页眉页脚 %%
  \pagestyle{fancy}
  \fancyhf{}
  \fancyhead[L]{#7}
  \fancyhead[C]{\mytitle}
  \fancyhead[R]{\rightmark}
  \fancypagestyle{plain}{
    \fancyhf{}
    \renewcommand{\headrulewidth}{0pt}
  }
  \cfoot{\thepage}

  \maketitle
  \newpage
}

引用“头文件”report之后只用在文档中输入:

\generateReportInfo{XXXX实验}{A}{1111111}{\Today}{0}{XX实验}{XX实验报告}

就可以自动生成实验报告的信息了。

这样就可以更方便的管理模板,并且可以在不同的文档中复用。从而更集中地在文字而非形式上了。

目前我正在写我常用的数学公式的宏以及补全,这可以提高我的效率。

用markdown写Latex文档

在日常编辑时,要频繁使用许多\...{}的指令,尤其是简单地实现制作节标题,插入图片、表格、列表等等。这些指令的使用会浪费时间(即使设置了宏或者代码块地补全),让文档的可读性变差,也会让文档的修改变得困难。

想用markdown编写,tex编译,这样就可以用更轻便的方式编辑文档了。但是尝试了pandoc等工具后发现,这样的方式并不是很方便(尤其是对中文编码的支持),自定义格式也比较困难。

markdown宏包

通过markdown宏包,我们可以使用markdown来写Latex文档,用更轻便的方式编辑文档。

如下编写“头文件”:

%%%%%%% md.tex %%%%%%%
%% 引用宏包 %%
\input{default}
\usepackage{markdown}
% 设置markdown %%
\markdownSetup{smartEllipses = true}
\markdownSetup{hashEnumerators = true}
\markdownSetup{fencedCode = true}
\markdownSetup{pipeTables = true}
\markdownSetup{hybrid = true}
\markdownSetup{
  renderers = {
    image = {\begin{figure}[htb]
      \centering
      \includegraphics[width = .8\linewidth]{#3}%
      \ifx\empty#4\empty\else
        \caption{#4}\label{fig:#1}%
      \fi
    \end{figure}},
  }
}

通过在内置的markdown环境或者插入markdown文件的方式来编写文档。

\begin{markdown}
# 我是一级标题
## 我是二级标题
- 我是列表
- 我是列表
\end{markdown}
\markdownInput{markdown.md}

hybrid = true的选项允许我们在markdown环境中使用Latex指令,例如:

\begin{markdown}
# 我是一级标题
\begin{equation}
  \label{eq:1}
  \frac{\partial u}{\partial t} = \frac{\partial^2 u}{\partial x^2}
\end{equation}
\end{markdown}

编译参数

使用markdown宏包需要在编译时加入--shell-escape选项,将相应内容交由Lua解释器处理。

xelatex --shell-escape test.tex

如果使用VsCode的Latex Workshop插件,可以在settings.json中更改:

"latex-workshop.latex.tools": [
    {
      "name": "xelatex",
      "command": "xelatex",
      "args": [
        "--shell-escape", // 添加这一行
        "-synctex=1",
        "-interaction=nonstopmode",
        "-file-line-error",
        "%DOCFILE%"
      ]
    },
]

参考了https://liam.page/2020/03/30/writing-manuscript-in-Markdown-and-typesetting-with-LaTeX/的markdown宏包的使用方法。

通过这样的方式,通过一系列的配置和模板的编写,我们可以更加舒适地使用Latex了。

附录:我的“头文件”模板

%%%%%%% default.tex %%%%%%%
%% 引用宏包 %%
\usepackage{ctex}
\usepackage{amsmath,amssymb,amsthm,multicol,titlesec,siunitx,graphicx,enumitem,booktabs,hyperref,xcolor,geometry}

%% 定义新定理 %%
\newtheorem*{example}{}
\newtheorem*{note}{}

%% 设置初始编号 %%
\setcounter{section}{0}
\numberwithin{table}{subsection}
\numberwithin{equation}{subsection}

%% 设置超链接 %%
\hypersetup{
    hidelinks, % 取消红框
    colorlinks=true,
    linkcolor=blue,
    citecolor=black
}

%% 设置代码环境 %%
\input{code}

%% 标题 %%
\title{请输入标题}
\author{AnZrew}
\date{\today}
%%%%%%% code.tex %%%%%%%
\usepackage{listings}

\lstdefinestyle{lfonts}{
  basicstyle   = \scriptsize\ttfamily,
  stringstyle  = \color{purple},
  keywordstyle = \color{blue!60!black}\bfseries,
  commentstyle = \color{olive}\scshape,
}
\lstdefinestyle{lnumbers}{
  numbers     = left,
  numberstyle = \tiny,
  numbersep   = 1em,
  firstnumber = 1,
  stepnumber  = 1,
}
\lstdefinestyle{llayout}{
  breaklines       = true,
  tabsize          = 2,
  columns          = spacefixed,
}
\lstdefinestyle{lgeometry}{
  xleftmargin      = 20pt,
  xrightmargin     = 0pt,
  frame            = tb,
  framesep         = \fboxsep,
  framexleftmargin = 20pt,
}
\lstdefinestyle{lgeneral}{
  style = lfonts,
  style = lnumbers,
  style = llayout,
  style = lgeometry,
}

\lstset{style = lgeneral}
\lstset{language = C}
%%%%%%% md.tex %%%%%%%
%% 引用宏包 %%
\input{default}
\usepackage{markdown}

% 设置markdown %%

\markdownSetup{smartEllipses = true}
\markdownSetup{hashEnumerators = true}
\markdownSetup{fencedCode = true}
\markdownSetup{pipeTables = true}
\markdownSetup{hybrid = true}
\markdownSetup{
  renderers = {
    image = {\begin{figure}[htb]
      \centering
      \includegraphics[width = .8\linewidth]{#3}%
      \ifx\empty#4\empty\else
        \caption{#4}\label{fig:#1}%
      \fi
    \end{figure}},
  }
}
%%%%%%% lab-report.tex %%%%%%%

\input{default}
\usepackage{fancyhdr}
\geometry{left=2cm,right=2cm,top=2cm,bottom=2cm}
\usepackage{tikz}

%% 设置标题格式 %%
\pretitle{\vspace*{\fill}\begin{center}\Huge\bfseries}
    \posttitle{\end{center}\vspace{3cm}}
    \preauthor{\begin{center}\large}
    \postauthor{\end{center}\vspace*{\fill}}

%% 生成封面 %%
\newcommand{\generateInfo}[7]{
  \newcommand{\mytitle}{#1}
  \title{\heiti{\mytitle}}
  \author{%
    \begin{tabular}{p{2cm}l}\hfill& : {\kaishu #2} \\ 
      & \\\hfill& : #3 \\ 
      & \\\hfill\hfill\hfill& : {\kaishu #4} \\ 
      & \\\hfill\hfill\hfill& : #5 \\
    \end{tabular}
  }
  \date{#6}
  
  %% 设置页眉页脚 %%
  \pagestyle{fancy}
  \fancyhf{}
  \fancyhead[L]{#7}
  \fancyhead[C]{\mytitle}
  \fancyhead[R]{\rightmark}

  \fancypagestyle{plain}{
    \fancyhf{}
    \renewcommand{\headrulewidth}{0pt}
  }
  \cfoot{\thepage}

  \maketitle
  \newpage
}

// latex.json
{
	"TeX Template": {
		"prefix": "temp",
		"body": [
			"\\documentclass[12pt,onecolumn,a4paper]{article}",
			"\\input{default}",
			"",
			"%%%%%%%%% 正文 %%%%%%%%%",
			"\\begin{document}",
			"",
			"\\title{}",
			"%% 制作标题 %%",
			"\\maketitle",
			"",
			"%% 制作目录 %%",
			"% \\tableofcontents %节标题目录",
			"% \\listoftables %表格目录",
			"% \\listoffigures %图片目录",
			"",
			"%% 节标题 %%",
			"\\section{title}",
			"",
			"\\end{document}"
		],
		"description": "TeX file template"
	},
	"Section Title": {
		"prefix": "sectitleincontents",
		"body": [
			"% \\addcontentsline{toc}{subsection}{title} %把不计入counter的部分加入目录文件(.toc)中,使其出现在目录里",
		"% \\subsection*{title}",
		],
		"description": "Insert a section title"
	},
	"Code Block": {
		"prefix": "codeblock",
		"body": [
			"\\begin{lstlisting}[language=C++]",
			"printf(\"Hello World!\");",
			"\\end{lstlisting}"
		],
		"description": "Insert a code block"
	},
	"Enumerate List": {
		"prefix": "enumlist",
		"body": [
			"\\begin{enumerate}[itemsep=0pt,parsep=0pt]",
			"    \\item ",
			"    \\item ",
			"\\end{enumerate}"
		],
		"description": "Insert an enumerated list"
	},
	"Itemize List": {
		"prefix": "itemlist",
		"body": [
			"\\begin{itemize}[itemsep=0pt,parsep=0pt]",
			"    \\item ",
			"    \\item ",
			"\\end{itemize}"
		],
		"description": "Insert an itemized list"
	},
	"Example Block": {
		"prefix": "exblock",
		"body": [
			"\\begin{example}",
			"    example",
			"    哈哈哈,我疯了",
			"\\end{example}"
		],
		"description": "Insert an example block"
	},
	"Quotation Block": {
		"prefix": "quotblock",
		"body": [
			"\\begin{quotation}",
			"    quotation",
			"\\end{quotation}"
		],
		"description": "Insert a quotation block"
	},
	"Equation Block": {
		"prefix": "eqblock",
		"body": [
			"\\begin{equation}",
			"    a^2+b^2=c^2 \\Rightarrow 3^2+4^2=5^2",
			"    \\label{EquationTest}",
			"\\end{equation}"
		],
		"description": "Insert an equation block"
	},
	"Figure Block": {
		"prefix": "figblock",
		"body": [
			"\\begin{figure}[h]",
			"    \\centering \\includegraphics[scale=]{图片名字}",
			"    \\caption{caption}",
			"\\end{figure}"
		],
		"description": "Insert a figure block"
	},
	"Table Block": {
		"prefix": "tableblock",
		"body": [
			"\\begin{table}[h]",
			"    \\centering",
			"    \\setlength{\\tabcolsep}{5mm}",
			"    \\begin{tabular}{cc}",
			"        \\toprule",
			"         &  \\\\", 
			"        \\midrule",
			"         & \\\\",
			"         & \\\\",
			"        \\bottomrule",
			"    \\end{tabular}",
			"    \\caption{}",
			"\\end{table}"
		],
		"description": "Insert a table block"
	},
	"Bibliography Without BibTeX": {
		"prefix": "thebibliography",
		"body": [
			"\\begin{thebibliography}{99}",  
			"    \\bibitem{ref1}",
			"    \\bibitem{ref2}",
			"\\end{thebibliography}"
		],
		"description": "Insert a bibliography without BibTeX"
	},
	"Hyperlink": {
		"prefix": "hyperlink",
		"body": [
			"\\url{<网址>}",
			"\\href{URL}{text}",
			"\\hyperref[<标签>]{<文字>}"
		],
		"description": "Insert hyperlink references"
	},
	"Cross Reference": {
		"prefix": "crossref",
		"body": [
			"\\label{test:test}",
			"~\\ref{test:test}",
			"~\\pageref{test:test}"
		],
		"description": "Insert cross references"
	}
}