> For the complete documentation index, see [llms.txt](https://ayakaleaf-pro.ayaka.space/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ayakaleaf-pro.ayaka.space/latex/zh-cn/lei-wen-jian/03-writing-your-own-package.md).

# 编写你自己的宏包

有时，在文档中使用自己的命令和宏的最佳选择是从零开始编写一个新宏包。本文介绍一个新宏包的主要结构。

## 引言

在编写新宏包之前，首先要做的是确定你是否真的需要一个新宏包。建议先 [在 CTAN（Comprehensive TeX Archive Network，综合 TeX 存档网络）上搜索](http://www.ctan.org/ctan-portal/search/) ，看看是否已经有人创建了与你需要的类似内容。

另一个需要牢记的重要事情是 [宏包和类之间的区别](/latex/zh-cn/lei-wen-jian/01-understanding-packages-and-class-files.md)。选错会影响最终产品的灵活性。

## 总体结构

所有宏包文件的结构大致可描述为接下来的四个部分：

* ***标识***。该文件将自己声明为使用 LaTeX2ε 语法编写的宏包。
* ***预备声明***。在这里导入所需的外部宏包。此外，文件的这一部分还编写声明的选项所需的命令和定义。
* ***选项***。宏包声明并处理这些选项。
* ***更多声明***。宏包的主体部分。宏包执行的几乎所有内容都在这里定义。

在接下来的小节中，将更详细地介绍结构以及一个工作示例， *examplepackage.sty*，将会展示。

### 标识

所有宏包都必须包含两个简单命令：

```latex
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{examplepackage}[2014/08/24 Example LaTeX package]
```

命令 `\NeedsTeXFormat{LaTeX2e}` 为该宏包设置 LaTeX 版本以便正常工作。此外，还可以在方括号中添加日期，以指定所需的最早发布版本日期。

命令 `\ProvidesPackage{examplepackage}[...]` 将此宏包标识为 *examplepackage* ，并且在方括号内包含发布日期和一些附加信息。日期应采用 YYYY/MM/DD 的格式

[在 Overleaf 中打开一个宏包编写示例](https://www.sharelatex.com/project/new/template?zipUrl=/project/53f11ec1eceb82a67658cb02/download/zip\&templateName=PackageExample\&compiler=pdflatex)

### 预备声明

大多数宏包都会扩展并定制已有宏包，并且还需要一些外部宏包才能工作。下面向示例宏包“examplepackage.sty”添加更多代码。

```latex
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{examplepackage}[2014/08/21 Example package]

\RequirePackage{imakeidx}
\RequirePackage{xstring}
\RequirePackage{xcolor}
\definecolor{greycolour}{HTML}{525252}
\definecolor{sharelatexcolour}{HTML}{882B21}
\definecolor{mybluecolour}{HTML}{394773}
\newcommand{\wordcolour}{greycolour}
```

这一部分中的命令要么初始化一些参数，之后将用于管理选项；要么导入外部文件。

命令 `\RequirePackage` 与众所周知的 `\usepackage`非常相似，在方括号中添加可选参数也同样适用。唯一的区别是 `\usepackage` 不能在 `\documentclass` 命令之前使用。强烈建议在编写新宏包或类时使用 `\RequirePackage` 。

[在 Overleaf 中打开一个宏包编写示例](https://www.sharelatex.com/project/new/template?zipUrl=/project/53f11ec1eceb82a67658cb02/download/zip\&templateName=PackageExample\&compiler=pdflatex)

### 选项

为了让宏包具有一定的灵活性，一些额外选项非常有用。文件“examplepackage.sty”的下一部分处理传递给导入宏包语句的参数。

```latex
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{examplepackage}[2014/08/21 Example package]

\RequirePackage{imakeidx}
\RequirePackage{xstring}
\RequirePackage{xcolor}
\definecolor{greycolour}{HTML}{525252}
\definecolor{sharelatexcolour}{HTML}{882B21}
\definecolor{mybluecolour}{HTML}{394773}
\newcommand{\wordcolour}{greycolour}

\DeclareOption{red}{\renewcommand{\wordcolour}{sharelatexcolour}}
\DeclareOption{blue}{\renewcommand{\wordcolour}{mybluecolour}}
\DeclareOption*{\PackageWarning{examplepackage}{Unknown ‘\CurrentOption’}}
\ProcessOptions\relax
```

下面是一些可以处理传递给宏包的选项的主要命令的说明。

命令 `\DeclareOption{}{}` 用于处理给定选项。它接受两个参数，第一项是选项名称，第二项是在传入该选项时要执行的代码。

命令 `\OptionNotUsed` 会在编译器和日志中打印一条消息，该选项将不会被使用。

命令 `\Declareoption*{}` 处理所有未被明确定义的选项。它只接受一个参数，即在传入未知选项时要执行的代码。在这种情况下，它将通过下一个命令打印警告：

`\PackageWarning{}{}`。参见 [错误处理](#handling-errors) 了解该命令的作用。

`\CurrentOption` 用于存储在某一时刻正在处理的宏包选项名称。

命令 `\ProcessOptions\relax` 会为每个选项执行代码，并且必须放在所有选项处理命令之后。这个命令还有一个带星号的版本，它将按照调用命令指定的确切顺序执行这些选项。

在示例中，如果选项 *red* 或 *blue* 被传递给 `\usepackage` 文档中的命令，命令 `\wordcolor` 会被重新定义。两种颜色以及默认的灰色都定义在 [预备声明](#preliminary-declaration) 在导入 *xcolor* 宏包。

[在 Overleaf 中打开一个宏包编写示例](https://www.sharelatex.com/project/new/template?zipUrl=/project/53f11ec1eceb82a67658cb02/download/zip\&templateName=PackageExample\&compiler=pdflatex)

### 更多声明

在这一部分，大多数命令都会出现。在“examplepackage.sty”中。下面可以看到完整的宏包文件。

```latex
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{examplepackage}[2014/08/21 Example package]

\RequirePackage{imakeidx}
\RequirePackage{xstring}
\RequirePackage{xcolor}
\definecolor{greycolour}{HTML}{525252}
\definecolor{sharelatexcolour}{HTML}{882B21}
\definecolor{mybluecolour}{HTML}{394773}
\newcommand{\wordcolour}{greycolour}

\DeclareOption{red}{\renewcommand{\wordcolour}{sharelatexcolour}}
\DeclareOption{blue}{\renewcommand{\wordcolour}{mybluecolour}}
\DeclareOption*{\PackageWarning{examplepackage}{Unknown ‘\CurrentOption’}}
\ProcessOptions\relax

%%Numbered environment
\newcounter{example}[section]
\newenvironment{example}[1][]{\refstepcounter{example}\par\medskip
\noindent \textbf{My~environment~\theexample. #1} \rmfamily}{\medskip}

%%Important words are added to the index and printed in different colour
\newcommand{\important}[1]
{\IfSubStr{#1}{!}
    {\textcolor{\wordcolour}{\textbf{\StrBefore{#1}{!}~\StrBehind{#1}{!}}}\index{#1}}
    {\textcolor{\wordcolour}{\textbf{#1}}\index{#1}\kern-1pt}
}
```

该宏包定义了新的环境 `示例`，以及一个新的命令 `\important`，它会以特殊颜色打印单词并将其添加到索引中。

要充分理解每个命令，请参见 [参考指南](#reference-guide) 以及 [进一步阅读部分中的链接](#further-reading).

下面是一个使用该宏包的文档， *examplepackage.sty*.

```latex
\documentclass{article}
\usepackage[utf8]{inputenc}

\usepackage[red]{examplepackage}

\makeindex

\title{Package Example}
\author{Team Learn ShareLaTeX}
\date{ }

\begin{document}

\maketitle

\section{Introduction}
在这份文档中测试了一个新宏包。该宏包允许特殊的编号
环境创建不同类型的列表，它们用于封装实现特定排版功能所需的 LaTeX 代码。一个环境以

\begin{example}
这段文本位于一个特殊环境中，
开头会打印一些加粗文本，并设置新的缩进。
\end{example}

此外，还有一个专门用于 \important{important!words} 的特殊命令，它将会
根据在
\important{package} 导入语句中使用的参数，以特殊的 \important{colour} 颜色打印。因为它很 \important{important}。

\printindex

\end{document}
```

![WrittingPackagesEx1.png](/files/9c39e685dba572ff02f538084dbb04337a38b63f)

注意命令

```latex
\usepackage[red]{examplepackage}
```

[在 Overleaf 中打开一个宏包编写示例](https://www.sharelatex.com/project/new/template?zipUrl=/project/53f11ec1eceb82a67658cb02/download/zip\&templateName=PackageExample\&compiler=pdflatex)

## 错误处理

在开发新宏包时，处理可能出现的错误非常重要，以便让用户知道出了问题。编译器中报告错误的主要命令有四个。

* `\PackageError{*package-name*}{*error-text*}{*help-text*}`。它接受三个参数，每个都放在花括号中：宏包名称、要显示的错误文本（编译过程将暂停），以及当由于该错误而导致编译暂停时，用户按下“h”后将打印的帮助文本。
* `\PackageWarning{*package-name*}{*warning-text*}`。在这种情况下，文本会显示出来，但编译过程不会停止。它会显示警告发生的行号。
* `\PackageWarningNoLine{*package-name*}{*warning-text*}`。其作用与前一个命令相同，但不会显示警告发生的行。
* `\PackageInfo{*package-name*}{*info-text*}`。在这种情况下，第二个参数中的信息只会打印到 transcript 文件中，包括行号。

[在 Overleaf 中打开一个宏包编写示例](https://www.sharelatex.com/project/new/template?zipUrl=/project/53f11ec1eceb82a67658cb02/download/zip\&templateName=PackageExample\&compiler=pdflatex)

## 参考指南

**宏包和类中常用命令列表**

* `\newcommand{*name*}{*definition*}`。定义一个 [新命令](/latex/zh-cn/ming-ling/01-commands.md#defining-a-new-command)，第一个参数是新命令的名称，第二个参数是该命令将执行的内容。
* `\renewcommand{}{}`。与 `\newcommand` 相同，但会覆盖现有命令。
* `\providecommand{}{}`。其作用与 `\newcommand` 相同，但如果该命令已定义，它会被静默忽略。
* `\CheckCommand{}{}`。语法与 `\newcommand`相同，但它会检查该命令是否存在且是否具有预期的定义；如果命令当前的定义不是 `\CheckCommand` 所期望的。
* `\setlength{}{}`。将第一个参数所表示元素的长度设置为第二个参数写入的值。
* `\mbox{}`。创建一个包含花括号内所写元素的盒子。
* `\fbox{}`。与 `\mbox`，但实际上会在内容周围打印一个盒子。

## 进一步阅读

更多信息请参见

* [理解宏包和类文件](/latex/zh-cn/lei-wen-jian/01-understanding-packages-and-class-files.md)
* [编写自己的类](/latex/zh-cn/lei-wen-jian/04-writing-your-own-class.md)
* [命令](/latex/zh-cn/ming-ling/01-commands.md) 和 [环境](/latex/zh-cn/ming-ling/02-environments.md)
* [LaTeX 中的长度](/latex/zh-cn/ge-shi-hua/01-lengths-in-latex.md)
* [在 LaTeX 中使用颜色](/latex/zh-cn/ge-shi-hua/13-using-colors-in-latex.md)
* [大型项目中的管理](/latex/zh-cn/wen-dang-jie-gou/07-management-in-a-large-project.md)
* [LaTeX2ε 宏包与宏包编写者指南](http://www.latex-project.org/guides/clsguide.pdf)
* [TeX 编程笔记](http://pgfplots.sourceforge.net/TeX-programming-notes.pdf)
* [不到一小时的分钟：使用 LaTeX 资源](https://tug.org/pracjourn/2005-4/hefferon/hefferon.pdf)
* [The LaTeX Companion. Second edition](http://ptgmedia.pearsoncmg.com/images/9780201362992/samplepages/0201362996.pdf)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://ayakaleaf-pro.ayaka.space/latex/zh-cn/lei-wen-jian/03-writing-your-own-package.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
