9 个版本
0.2.3 | 2023 年 10 月 30 日 |
---|---|
0.2.2 | 2023 年 9 月 30 日 |
0.2.1 | 2023 年 7 月 13 日 |
0.2.0 | 2023 年 6 月 19 日 |
0.1.4 | 2023 年 4 月 30 日 |
72 在 模板引擎 中
每月 38 次下载
140KB
3K SLoC
txtpp
使用 Rust 编写的简单易用的通用文本文件预处理器。
您可以
- 在当前文件中包含另一个文件,类似于 C 风格的
#include
- 在当前文件中间执行一个命令并包含输出
您可以将 txtpp
作为命令行工具或作为 Rust crate 的库使用。 txtpp
经过了单元测试和集成测试的充分测试。
完整的 API 文档可在 docs.rs 上找到
安装
使用 cargo
安装
cargo install txtpp --features cli
txtpp --help
示例
这些示例也是使用 txtpp 构建的!查看 文档目录。更多示例可以在 测试目录 中找到,它们作为集成测试使用。
包含文件
假设你有 2 个文件 foo.txt.txtpp
和 bar.txt
/// foo.txt.txtpp
hello
TXTPP#include bar.txt
world
/// bar.txt
bar
运行 txtpp foo.txt
将生成 foo.txt
/// foo.txt
hello
bar
world
如果 bar.txt.txtpp
也存在,它将首先被预处理器处理以生成 bar.txt
,然后使用结果。
执行命令
假设你有一个文件 fiz.txt.txtpp
,我们可以运行一个命令来包含上一个示例中的 foo.txt.txtpp
文件
/// fiz.txt.txtpp
hello
-TXTPP#run cat foo.txt.txtpp
world
运行 txtpp fiz.txt
将生成 fiz.txt
/// fiz.txt
hello
hello
TXTPP#include bar.txt
world
world
目录
功能摘要
txtpp
提供了可以在 .txtpp
文件中使用的指令。指令会将其自身替换为指令的输出。所有指令都以前缀 TXTPP#
开头。
include
- 包含另一个文件的内容。run
- 运行一个命令并包含命令的输出。temp
- 将文本存储在输入文件旁边的临时文件中。tag
- 在看到标签之前保留下一个指令的输出,并用输出替换标签。write
- 将内容写入输出文件。可用于转义指令。
指令概述
语法
指令是源文件中的单行或多行结构,如下所示
{WHITESPACES}{PREFIX1}TXTPP#{DIRECTIVE} {ARG1}
{WHITESPACES}{PREFIX2}{ARG2}
{WHITESPACES}{PREFIX2}{ARG3}
...
说明
- 第一行
{WHITESPACES}
:任意数量的空白字符{PREFIX1}
:非空文本,不以空白字符开头,且不包含TXTPP#
- 对于多行指令,前缀必须非空,否则您将无法终止它。
TXTPP#
:指令之前的前缀{DIRECTIVE}
:可以是以下指令之一{ARG1}
:作为单个字符串的参数,直到行尾。将修剪前导和尾随空白字符(包括换行符)。
- 后续行:一些指令允许有超过一行(请参阅 规范 了解它们是什么)
{WHITESPACES}
:这必须与第一行中的{WHITESPACES}
完全匹配{PREFIX2}
:这必须是以下之一- 与第一行中
{PREFIX1}
的长度相同数量的空格字符(即' '
) - 与第一行中
{PREFIX1}
完全相同的字符串 - 与第一行中的
{PREFIX1}
相同的字符串,不包含尾随空格,后面跟随换行符(即参数为空)
- 与第一行中
{ARG2}
、{ARG3}
...:向参数列表中添加更多参数。请注意,{WHITESPACES}
和{PREFIX2}
不包括在参数中。与第一行不同,不删除前导空格,但仍然删除尾随空格。
- 结束:如果一行不匹配上述格式,则指令结束。结束行不会成为此指令的一部分,但可以是下一个指令的开始。
例如,您可以这样编写指令
// TXTPP#run echo "hello world"
这将被大多数语言视为注释,以帮助语法高亮。
相同的示例作为块注释
/* TXTPP#run echo "
hello world
"
-TXTPP# */
这将执行命令echo "hello world"
。在最后一行TXTPP#
前面的-
是必要的,以指示它是不同指令的开始。
执行
指令在解析后立即执行。它们可能会产生输出并将其包含在输出文件中,并/或产生副作用,例如创建临时文件。
如果指令有输出(如include
和run
),则将格式化为
- 输出中的每一行都将预先加上
{WHITESPACES}
,以保持缩进一致
输出// TXTPP#run echo 1; echo 2
1 2
- 行结束符将被规范化为与输出文件相同。最后一行是否有尾随换行符将保持从命令/包含文件的输出中。如果指令的输出没有尾随换行符,则源文件的下一行将位于指令输出的最后一行上。例如
输出// TXTPP#run echo -n hello world
helloworld
请注意,通常,您无法将指令输出连接到上一行,因为指令始终从其自己的行开始。但是,您可以使用tag
(见下面)来实现这一点。如果有当前活动tag
指令正在监听输出,则输出将发送到标记,而不是输出文件,没有缩进,并且指令不会产生输出。
指令规范
本节包含每个指令的详细规范。
包含指令
用法
此指令用于将另一个文件的内容包含到当前文件中。
参数
单行。参数是FILE_PATH
行为
- 如果
FILE_PATH
是绝对路径,则将其原样使用。否则,它应该相对于当前文件(目录)。 - 如果
FILE_PATH
不是以.txtpp
结尾,并且FILE_PATH.txtpp
存在,则FILE_PATH.txtpp
将首先进行预处理以生成FILE_PATH
,并且结果将用作输出。请注意,您仍然需要包含FILE_PATH
,而不是FILE_PATH.txtpp
。
示例
TXTPP#include foo.txt
指令之后
用法
此指令用于显式指定依赖关系。
参数
单行。参数是FILE_PATH
行为
此指令的行为与 include
完全相同,但它仅更改依赖结构,不会影响输出。
如果存在隐式依赖关系,则这很有用。例如,一个 run
指令可以执行依赖于 txtpp 输出的命令。
示例
TXTPP#after foo.txt
TXTPP#run ./my-script.sh foo.txt
运行指令
用法
此指令用于运行命令并将命令的输出包含到当前文件中。
参数
可以有多行。参数之间使用单个空格连接以形成 COMMAND
行为
COMMAND
将作为一个子进程执行。- 默认的 shell 选择
- Windows:以下命令依次尝试
- (PowerShell 7)
pwsh -NonInteractive -NoProfile -Command COMMAND
- (PowerShell 5/Windows PowerShell)
powershell -NonInteractive -NoProfile -Command COMMAND
- (命令提示符)
cmd /C COMMAND
- (PowerShell 7)
- 其他操作系统:
sh -c COMMAND
- 您可以使用
--shell
选项覆盖此设置。
- Windows:以下命令依次尝试
- 子进程的工作目录将是当前文件的目录。
- 子进程将继承主进程的环境变量,并添加额外的环境变量
TXTPP_FILE
:正在处理的当前文件的路径。目前这是绝对路径。- (目前只有一个环境变量)
示例
TXTPP#run echo "hello world"
注意事项
txtpp
不会在run
指令中运行以避免复杂化。如果您想包含txtpp
文件的输出,可以查看 此 README 文件是如何构建的示例。
空指令
用法
空指令以空字符串为名称,不执行任何操作。它可以用来从输入中删除行。
参数
可以有多行。空指令的所有参数都将被忽略。
行为
无操作
示例
例如,您可以使用它来终止块注释
function hello() {
// GENERATED CODE
/* TXTPP#run ./codegen
-arg
-really_long_arg
--really-really-long-option
-TXTPP# */
}
如果您必须将块注释的结尾放在新行中,请确保正确格式化,以便将其视为指令的一部分。
function hello() {
// GENERATED CODE
/* TXTPP#run ./codegen
-arg
-really_long_arg
--really-really-long-option
-TXTPP#
-*/
}
在这两种情况下,整个块注释 /**/
将被 ./codegen
的输出替换。
临时指令
用法
此指令用于创建临时文件。
参数
至少需要 1 个参数。第一个参数指定保存输出的 FILE_PATH
(相对于当前文件)。其余参数通过 换行符 连接,以形成 CONTENT
,并以换行符结尾。
行为
FILE_PATH
的解析方式与包含指令相同。FILE_PATH
不能以.txtpp
结尾。这将会导致错误。- 这是为了避免未定义行为,因为预处理器可能会也可能不会选择由
temp
指令生成的文件。
- 这是为了避免未定义行为,因为预处理器可能会也可能不会选择由
CONTENT
将被保存到FILE_PATH
- 处理完毕后,
FILE_PATH
不会删除,但会与clean
一起删除。
示例
// In this example we will export a python script,
// and use that to generate JS code from a csv
function get_cities() {
return [
// TXTPP#temp gen_cities.g.py
// import csv
//
// with open('city.csv', 'r') as f:
// reader = csv.reader(f)
// next(reader) # skip header
// for city, country in reader:
// print(f"{{ city: \"{city}\", country: \"{country}\"}},")
/* --- generated code --- */
// TXTPP#run python gen_cities.g.py
/* --- generated code --- */
];
}
// Note we used /* */ to break the prefix pattern `// ` so that the directive can end
// You can also use an empty line to make it simple.
标签指令
用法
此指令用于创建一个标签以存储下一个指令的输出。
参数
仅支持单行。参数为TAG
行为
- 标签的生命周期如下
- 标签通过
tag
指令创建,并将监听下一个指令的输出。
- 如果下一个指令没有输出(例如
temp
),标签将继续监听下一个指令的输出。
- 当存在具有输出的指令时,输出将被存储在标签中
- 当存在带有标签的非指令行时,标签将被存储的输出替换。
- 标签被替换后,它将被删除。
- 标签通过
- 一次只能有一个标签用于存储下一个指令的输出。然而,可以有多个标签处于“已存储”状态。
- 标签不能成为另一个标签的前缀。例如,如果您有一个标签
Foo
,则不能有另一个标签FooBar
,反之亦然。 - 多个标签可以注入到源文件的同一条线上。然而,如果标签的输出包含另一个标签,则它将不会被替换。标签将从左到右替换。如果标签重叠,则左侧的将被替换。
- 仅替换标签的第一个出现。
- 在创建具有相同名称的另一个标签之前,必须删除每个标签。
- 输出中的换行符将被当前文件的行结束符替换。输出是否有尾随换行符将不会改变。
- 例如:如果存储的输出没有尾随换行符,则标签后的部分将与存储输出的最后一行在同一行上。
- 如果文件末尾有任何未使用的标签,则会有错误。
示例
在这个例子中,我们希望输出与原样相同,因为有一个<pre>
标签。run
指令的输出将被放入<pre>
标签中。
<div>
<!-- TXTPP#tag PRE_CONTENT -->
<!-- TXTPP#run python gen_pre.py
TXTPP# -->
<pre>PRE_CONTENT --></pre>
</div>
以下是不合法的,因为标签在使用输出存储之前被使用。
<div>
<!-- TXTPP#tag PRE_CONTENT -->
<pre>PRE_CONTENT --></pre>
<!-- TXTPP#run python gen_pre.py
TXTPP# -->
</div>
写入指令
用法
此指令将其参数写入输出文件。它可以用来逃避其他指令。
参数
可以有多行。每个参数在输出中为一行
行为
- 参数将按原样写入输出文件。
- 因为内容被视为指令的输出,所以标签不会被注入。
示例
-TXTPP#write the line below will be written to the output file as is
-TXTPP#run echo "hello world"
stuff
输出
the line below will be written to the output file as is
TXTPP#run echo "hello world"stuff
(要将stuff
放在单独的一行上,请向write
指令添加一个额外的换行符)
输出规范
本节指定了预处理器输出的详细情况。
行结束符
输出文件和临时输出文件将具有与输入.txtpp
文件一致的行结束符。如果输入文件有混合行结束符,则输出文件将与输入文件的第一行相同的行结束符。
如果输入文件没有行结束符,输出文件将使用操作系统相同的行结束符(即Windows上的\r\n
,Unix上的\n
)。
除非指定了--no-trailing-newline
,否则输出文件将带有尾随换行符。然而,这个标志不会影响临时输出文件。一个临时文件是否有尾随换行符取决于指令的末尾是否有空行。
依赖项
~6–16MB
~218K SLoC