从 AsciiDoc 生成手册页

AsciiDoc 语言定义了一个名为 manpage 的文档类型,用于在 AsciiDoc 中编写手册页(man pages)。Asciidoctor 提供了一个转换器,可将此 AsciiDoc 结构转换为 groff 格式的手册页。本文档介绍了册页,探讨了手册页的 AsciiDoc 结构,并展示了如何使用 Asciidoctor 将 AsciiDoc 文档转换为 groff 格式的手册页和其他格式。

什么是手册页?

手册页(man page)是软件文档的一种形式,通常伴随类 Unix 操作系统上的软件。其规范化的结构允许 man 命令将手册页以格式化文档的形式显示在终端分页器中,例如 less

在 AsciiDoc 中编写手册页的好处在于,您可以将其转换为多种格式,包括 HTML 和 PDF。这使得手册页的源代码可以重用。

manpage 文档类型

manpage 文档类型声明 AsciiDoc 结构是手册页的源,并符合手册页的结构。请注意文档类型值中缺少空格。

通过声明 manpage 文档类型,AsciiDoc 处理器会期望文档符合以下结构。

文档头

在手册页中,文档头部是必需的。文档标题由程序名称后跟圆括号内的卷号组成(例如 progname(1))。文档标题不得包含空格。卷号是一位数字,后面可选跟一个字符。

文档属性

在使用 manpage 文档类型时,有几个内置文档属性会影响源的解析和转换方式。请参阅文档属性部分。

NAME 部分

第一部分是必需的,标题必须是“Name”(或“NAME”),并且必须包含一个段落(通常是一行),由一个或多个用逗号分隔的命令名称列表组成,名称与命令的用途之间用破折号分隔(例如 progname - 作用描述name1, name2 - 作用描述)。破折号两侧至少要有一个空格。如果给出多个名称,Asciidoctor 将为辅助名称生成指向主名称的别名文件。

SYNOPSIS 部分

第二部分是推荐的,如果存在,标题必须是“Synopsis”(或“SYNOPSIS”)。

后续章节是可选的,但典型的章节包括“Description”、“Options”、“Bugs”、“See Also”、“Copyright”和“Author”。您可以将章节标题写成全大写,但最好让手册页转换器为您处理。有关详细信息,请参阅生成手册页

由于 manpage 文档类型所需的结构是标准的 AsciiDoc,您可以选择在运行时声明 manpage 文档类型。当 doctype 属性未设置时,Asciidoctor 会将文档解析为 article,并且不会对其进行任何特殊处理。

以下是一个为 eve 命令编写的 AsciiDoc 手册页示例。请注意,它声明了 manpage 文档类型并符合所述结构。

示例 1. progname.adoc
= eve(1)
Andrew Stanton
v1.0.0
:doctype: manpage
:manmanual: EVE
:mansource: EVE
:man-linkstyle: pass:[blue R < >]

== Name

eve - analyzes an image to determine if it's a picture of a life form

== Synopsis

*eve* [_OPTION_]... _FILE_...

== Options

*-o, --out-file*=_OUT_FILE_::
  Write result to file _OUT_FILE_.

*-c, --capture*::
  Capture specimen if it's a picture of a life form.

== Exit status

*0*::
  Success.
  Image is a picture of a life form.

*1*::
  Failure.
  Image is not a picture of a life form.

== Resources

*Project web site:* https://eve.example.org

== Copying

Copyright (C) 2008 {author}. +
Free use of this software is granted under the terms of the MIT License.

尽管源文档名为 progname.adoc,但您可以随意命名文件。输出文件名由 doctitle 隐含定义的 mannamemanvolnum 属性决定。在此示例中,输出文件名是 eve.1

后端和转换器

Asciidoctor 提供了一个内置转换器,用于为声明了 manpage 文档类型并符合其要求的 AsciiDoc 文档生成 groff 格式的手册页。Asciidoctor 本身的手册页(即 man asciidoctor)就是使用此转换器从此 AsciiDoc 源生成的。

手册页转换器绑定到 manpage 后端(请勿与 manpage 文档类型混淆)。请注意后端值中缺少空格。

后端名称

manpage

转换器类

Asciidoctor::Converter::ManpageConverter

输出格式

groff

输出文件扩展名

.{manvolnum}(例如 .1)

生成手册页

首先,请确保您的源文档符合manpage 文档类型结构,并且 doctype 属性设置为 manpage。然后,要激活手册页转换器,您必须为 backend 选项指定 manpage。这样做将指示处理器使用手册页转换器来转换文档。

在本示例中,我们假设 progname.adoc 中的 doctitle 是 progname(1),其中 progname 是命令名称,1 是卷号。基于此信息,手册页转换器会将输出文件名设置为 progname.1

要生成手册页,请运行

$ asciidoctor -b manpage progname.adoc

-b CLI 选项是 --backend 的简写,因此之前的命令可以写成如下形式

$ asciidoctor --backend manpage progname.adoc

然后您可以使用 man 命令查看生成的手册页

$ man ./progname.1

在转换为手册页格式时,Asciidoctor 会将所有 0 级和 1 级章节的标题转换为大写。此转换是为了符合 *nix 系统上大多数手册页所使用的广泛采用的约定。通过在转换器中应用此转换,可以避免您在源文档中输入全大写的章节标题。它还使得文档可以移植到其他输出格式,因为这种样式仅适用于手册页输出。如果源中的标题是大写的,那么这种大小写将在所有输出格式中使用。

在 Ruby 2.4 之前,Ruby 只能大写拉丁字母。如果您使用的是 Ruby 2.4 或更高版本,Asciidoctor 将大写标题中被 Unicode 规范识别为具有大写等效的任何字母,这超出了拉丁字母的范围。

请记住,您不仅限于使用手册页转换器来转换使用 manpage 文档类型的 AsciiDoc 文档。您同样可以将其转换为 HTML,如下所示。

$ asciidoctor progname.adoc

源文档的结构仍然被强制执行,但输出文档的外观将与其他任何 AsciiDoc 文档的输出一样。

重用手册页

您可能有一个手册页,您想将其重用于记录等效命令(但不是别名)。您可以通过在转换文档时提供替代的手册页标题、名称和/或用途来实现。

如果您想更改 mantitlemanvolnum 属性,则必须在调用 Asciidoctor 时覆盖 doctitle 属性。

$ asciidoctor -b manpage -a doctitle="othername(7)" progname.adoc

此命令将 mantitle 设置为“othername”,将 manvolnum 设置为“7”,并生成文件 progname.7。但是,mantitle 仅在手册页顶部的隐藏信息部分中使用。您可能想做的是也更改 manname,这是在标题、Name 部分和输出文件名中使用的名称。

更改 manname 的一种方法是在调用 Asciidoctor 时同时设置 mannamemanpurpose 属性。但首先,在这种情况下,您需要隐藏默认的 Name 部分,以免出现两个 Name 部分。

ifndef::manname,manpurpose[]
== Name

progname - description of progname
endif::[]

现在,您可以在调用 Asciidoctor 时替换 Name 部分中的信息

$ asciidoctor -b manpage \
  -a doctitle="othername(7)" \
  -a manname=othername \
  -a manpurpose="description of othername" \
  progname.adoc

此命令生成文件 othername.7

如果您只想覆盖 manname 属性而不覆盖 manpurpose 属性,请按照下一个示例中的方式重新配置 Name 部分。

ifndef::manname[:manname: progname]

== Name

{manname} - description of progname

现在,您可以在不覆盖 manpurpose 属性的情况下覆盖 manname 属性。

$ asciidoctor -b manpage \
  -a doctitle="othername(7)" \
  -a manname=othername \
  progname.adoc

重要的是要记住,Asciidoctor 默认从 Name 部分派生 mannamemanpurpose 属性。这就是为什么仅在调用 Asciidoctor 时覆盖属性是不够的。

但是,如果您想从没有 Name 部分的文档创建格式良好的手册页,您可以通过在 CLI 中设置 mannamemanpurpose 属性来有效地插入一个。

$ asciidoctor -b manpage \
  -a doctitle="README(1)" \
  -a doctype=manpage \
  -a manname=README \
  -a manpurpose="Information about this project" \
  README.adoc

您现在可以使用 man 命令将 README 作为手册页查看

man ./README.1

请记住,格式良好的手册页需要名称和用途。

将手册页转换为 PostScript / PDF

创建手册页后,您可以使用 man 命令将其转换为 PostScript。

假设 Asciidoctor 手册页转换器生成的输出文件是 progname.1,其中 progname 是命令名称,1 是卷号。您可以使用以下 man 命令将 progname.1 转换为 PostScript 并将输出重定向到 progname.ps

$ man -t ./progname.1 > progname.ps

或者,您可以将 man 命令的输出重定向到 ps2pdf 以进一步转换为 PDF。

$ man -t ./progname.1 | ps2pdf - progname.pdf

现在让我们以这种方式将前面的示例转换为 PDF。

$ man -t ./eve.1 | ps2pdf - eve.pdf

使用相同的命令序列,您可以将 Asciidoctor 本身的手册页转换为 PDF。

$ asciidoctor -h manpage | man -t -l - | ps2pdf - asciidoctor.pdf

在这种情况下,-l - 读取由 asciidoctor 命令的帮助模式生成的手册页内容。

请注意,本节中的文件不是使用 Asciidoctor 生成的。如果您想直接从 Asciidoctor 生成 PDF 文件,您可能会有兴趣查看Asciidoctor PDF。另一种方法是将 AsciiDoc 文档转换为 DocBook,使用内置的 DocBook 转换器(例如 -b docbook),然后使用 DocBook 工具链将该文档转换为 PDF。

文档属性

几个内置的文档属性仅影响 manpage 文档类型和输出。这些属性(或它们派生的属性)必须在文档头部设置。

手册页的内置文档属性
属性 描述 值(从上面的示例解析)

mantitle

可以通过覆盖 doctitle 属性来设置。必须同时包含手册页名称和卷号。

ASCIIDOCTOR(1)

manvolnum

可以通过覆盖 doctitle 属性来设置。必须同时包含手册页名称和卷号。

ASCIIDOCTOR(1)

manname

设置命令名称的替代方法。仅当也设置了 manpurpose 时才使用。

asciidoctor

manpurpose

设置命令用途的替代方法。

converts AsciiDoc source files

man-linkstyle

设置手册页输出中链接的样式。有效的链接格式序列。

blue R < >

mansource

手册页所属的源。在生成 DocBook 时,它会成为 DocBook 的refmiscinfo 属性,并显示在页脚中。

Asciidoctor

manversion

手册页的版本。如果未指定,则默认为 revnumber。在生成 DocBook 时,它会成为 DocBook 的refmiscinfo 属性,并显示在页脚中。Asciidoctor 不使用。

2.0.26

manmanual

手册名称。在生成 DocBook 时,它会成为 DocBook 的refmiscinfo 属性,并显示在页脚中。

Asciidoctor Manual

另请参阅

请参阅Asciidoctor 手册页的 AsciiDoc 源以查看完整示例。Asciidoctor 的手册页是使用手册页转换器生成的。 git 的手册页也是从 AsciiDoc 文档生成的,因此您可以将它们用作另一个示例来遵循。