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 次下载

GPL-3.0 许可证

140KB
3K SLoC

txtpp

Build Badge Version Badge License Badge Issue Badge

使用 Rust 编写的简单易用的通用文本文件预处理器。

您可以

  • 在当前文件中包含另一个文件,类似于 C 风格的 #include
  • 在当前文件中间执行一个命令并包含输出

您可以将 txtpp 作为命令行工具或作为 Rust crate 的库使用。 txtpp 经过了单元测试和集成测试的充分测试。

完整的 API 文档可在 docs.rs 上找到

安装

使用 cargo 安装

cargo install txtpp --features cli
txtpp --help  

示例

这些示例也是使用 txtpp 构建的!查看 文档目录。更多示例可以在 测试目录 中找到,它们作为集成测试使用。

包含文件

假设你有 2 个文件 foo.txt.txtppbar.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}
...

说明

  1. 第一行
    • {WHITESPACES}:任意数量的空白字符
    • {PREFIX1}:非空文本,不以空白字符开头,且不包含 TXTPP#
      • 对于多行指令,前缀必须非空,否则您将无法终止它。
    • TXTPP#:指令之前的前缀
    • {DIRECTIVE}:可以是以下指令之一
    • : (空格) 指令名称和其输入之间至少有一个空格。这将进行修剪。
    • {ARG1}:作为单个字符串的参数,直到行尾。将修剪前导和尾随空白字符(包括换行符)。
  2. 后续行:一些指令允许有超过一行(请参阅 规范 了解它们是什么)
    • {WHITESPACES}:这必须与第一行中的 {WHITESPACES} 完全匹配
    • {PREFIX2}:这必须是以下之一
      • 与第一行中 {PREFIX1} 的长度相同数量的空格字符(即 ' '
      • 与第一行中 {PREFIX1} 完全相同的字符串
      • 与第一行中的{PREFIX1}相同的字符串,不包含尾随空格,后面跟随换行符(即参数为空)
    • {ARG2}{ARG3} ...:向参数列表中添加更多参数。请注意,{WHITESPACES}{PREFIX2}不包括在参数中。与第一行不同,不删除前导空格,但仍然删除尾随空格。
  3. 结束:如果一行不匹配上述格式,则指令结束。结束行不会成为此指令的一部分,但可以是下一个指令的开始。

例如,您可以这样编写指令

        // TXTPP#run echo "hello world"

这将被大多数语言视为注释,以帮助语法高亮。

相同的示例作为块注释

        /* TXTPP#run echo "
           hello world
           "
          -TXTPP# */

这将执行命令echo "hello world"。在最后一行TXTPP#前面的-是必要的,以指示它是不同指令的开始。

执行

指令在解析后立即执行。它们可能会产生输出并将其包含在输出文件中,并/或产生副作用,例如创建临时文件。

如果指令有输出(如includerun),则将格式化为

  • 输出中的每一行都将预先加上{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:以下命令依次尝试
      1. (PowerShell 7) pwsh -NonInteractive -NoProfile -Command COMMAND
      2. (PowerShell 5/Windows PowerShell) powershell -NonInteractive -NoProfile -Command COMMAND
      3. (命令提示符) cmd /C COMMAND
    • 其他操作系统: sh -c COMMAND
    • 您可以使用 --shell 选项覆盖此设置。
  • 子进程的工作目录将是当前文件的目录。
  • 子进程将继承主进程的环境变量,并添加额外的环境变量
    • TXTPP_FILE:正在处理的当前文件的路径。目前这是绝对路径。
    • (目前只有一个环境变量)

示例

TXTPP#run echo "hello world"

注意事项

  1. 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

行为

  • 标签的生命周期如下
    1. 标签通过tag指令创建,并将监听下一个指令的输出。
    • 如果下一个指令没有输出(例如temp),标签将继续监听下一个指令的输出。
    1. 当存在具有输出的指令时,输出将被存储在标签中
    2. 当存在带有标签的非指令行时,标签将被存储的输出替换。
    3. 标签被替换后,它将被删除。
  • 一次只能有一个标签用于存储下一个指令的输出。然而,可以有多个标签处于“已存储”状态。
  • 标签不能成为另一个标签的前缀。例如,如果您有一个标签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