> For the complete documentation index, see [llms.txt](https://overleaf-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://overleaf-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 示例宏包]

\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 示例宏包]

\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}{未知的‘\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 示例宏包]

\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}{未知的‘\CurrentOption’}}
\ProcessOptions\relax

%%编号环境
\newcounter{example}[section]
\newenvironment{example}[1][]{\refstepcounter{example}\par\medskip
\noindent \textbf{我的~环境~\theexample. #1} \rmfamily}{\medskip}

%%重要单词会被加入索引并以不同颜色打印
\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{宏包示例}
\author{Team Learn ShareLaTeX}
\date{ }

\begin{document}

\maketitle

\section{引言}
在本文档中，将测试一个新宏包。这个宏包允许特殊编号的
环境

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

此外，还有一个专门用于 \important{重要!单词} 的特殊命令，它将会
根据在
\important{宏包} 导入语句中使用的参数，以特殊的 \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*}`。在这种情况下，第二个参数中的信息只会打印到转录文件中，并包含行号。

[在 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` 所期望的那样，LaTeX 会显示警告。
* `\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. 第二版](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://overleaf-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.
