3个版本

0.5.0 2024年7月21日

#260过程宏

Download history 351/week @ 2024-07-19 196/week @ 2024-07-26 127/week @ 2024-08-02 148/week @ 2024-08-09 165/week @ 2024-08-16

674 每月下载量
用于 25 个crate (4 个直接使用)

ISC 许可证

245KB
6K SLoC

Gene Michaels

状态: Delta(gamma之后的那个)。我已经使用它多年而没有出现重大问题,并且我已经在各种代码库上进行了测试,它不会让它们崩溃。我认为其他人也可能使用它!现在,在格式化前重新解析并确认所有注释作为安全检查。此外,超过500KB的文件可能会耗尽你的内存并触发OOM杀手。

  • 格式化一切
  • 不格式化某些东西
  • 这是一首俳句

以Gene Michaels命名。

一切包括宏和注释。在这个仓库中使用了狗粮。

与Rustfmt的差异

  • 这会格式化所有宏,Rustfmt只在特定条件下格式化宏
  • 这是完全确定的,Rustfmt保留了某些风格选择
  • Rustfmt有一些 限制 在它通常格式化的内容上,这总是格式化一切(如果不这样做,则是错误)
  • 这还会根据Markdown规则重新格式化注释

用法

运行 cargo install genemichaels

运行 genemichaels 默认会格式化当前包中的所有文件(查看当前目录中的 Cargo.toml)。你也可以传递一个要格式化的文件名列表。

VS Code

如果你使用VS Code,添加以下设置

  "rust-analyzer.rustfmt.overrideCommand": [
    "${userHome}/.cargo/bin/genemichaels", "--stdin"
  ]

来无拘无束地使用它。

配置

配置文件是可选的,如果没有提供,则具有(我认为)合理的默认值。默认配置文件名为 .genemichaels.json,位于 Cargo.toml 相同目录中或当前目录中(如果没有在项目中),如果不在项目中,则使用当前目录。

该配置包含用于调整格式化输出的参数,适用于建立项目约定。不影响输出的内容(线程数、详细程度等)是命令行参数。

配置文件是json格式,但如果您想添加注释,它将首先删除以//开头的行。

以下是配置文件。所有显示的值都是默认值,如果默认值对您有效,则可以省略键。

{
  // Ideal maximum line width. If there's an unbreakable element the line won't be split.
  "max_width": 120,
  // When breaking a child element, also break all parent elements.
  "root_splits": false,
  // Break a `()` or `{}` if it has greater than this number of children.  Set to `null` to
  // disable breaking due to high child counts.
  "split_brace_threshold": 1,
  // Break a `#[]` on a separate line before the element it's associated with.
  "split_attributes": true,
  // Put the `where` clause on a new line.
  "split_where": true,
  // Maximum relative line length for comments (past the comment indentation level). Can be
  // `null` to disable relative wrapping.  If disabled, still wraps at `max_width`.
  "comment_width": 80,
  // If reformatting comments results in an error, abort formatting the document.
  "comment_errors_fatal": false,
  // Genemichaels will replace line breaks with it's own deterministic line breaks.  You can
  // use this to keep extra line breaks (1 will keep up to 1 extra line break) during comment
  // extraction. This is unused during formatting.
  "keep_max_blank_lines": 0
}

禁用特定注释的格式化

由于假设注释是markdown格式,因此它们将按照markdown规则进行格式化。要禁用某些注释的格式化,请以//开头,如下所示

//. fn main() {
//.    println!("hi");
//. }

禁用特定文件的格式化

要跳过特定文件,在源文件的前5行中添加包含nogenemichaels的注释,例如

// nogenemichaels
...

程序化使用

执行cargo add genemichaels

有三个主要功能

  • genemichaels::format_str - 格式化字符串(完整的rust源文件,目前不支持代码片段)。
  • genemichaels::format_ast - 格式化AST元素(实现了genemichaels::Formattable,大多数syn::*结构体都)。如果有的话,需要单独传递注释。
  • genemichaels::extract_comments - 将源代码字符串提取为注释,将每个注释映射到语法元素的起始位置

如果您想格式化TokenStream,请使用syn::parse2::<syn::File>(token_stream)将其解析为AST,然后调用format_ast

格式化函数还返回丢失的注释——在处理过程中未格式化/添加到格式化源代码中的注释。在理想的世界里,这不会存在,但右现在,注释是逐个添加的,并且并非所有源令牌都支持注释。

它是如何工作的

从非常高的层次来看

  • 语法树被转换为线性段列表,其中每个段恰好是“分割组”的一个成员。一个分割组有一个布尔状态开关:分割或不分割。

    例如,match {}的分割组可能包含段match { <break>}。这些段与其他组的段交织在一起,例如其他段可能位于{}之间。

    所有分割组都以未分割状态开始。

    当分割组的分割状态切换时,<break>及其之后的行上的所有内容都将移动到该行之后的行上。

该算法基本上将节点包装起来,直到所有行的宽度小于最大行宽。

这是一个简化的解释;还有其他一些因素

  • 对齐
  • 根据其组是否拆分而变化的段(例如,上面的 <break> 仅在组拆分时换行,与无条件换行不同)

多线程

默认情况下,Gene Michaels在所有可用核心上格式化多个文件,但这会使用更多的内存。如果你有一个特别大的文件的项目,可以在配置中限制到更少的核数。

注释

注释值得特别提及,因为它们是离线处理的。

syn 不解析注释(除了一些情况外),因此所有注释都在处理开始时提取。通常,注释与下一个语法元素相关联,除了行尾 // 注释,这些注释与当前行的第一个语法元素相关联。

当构建拆分组时,如果当前语法元素有一个与提取的注释匹配行/列的标记,则将注释添加到拆分组中。

宏使用了一些技巧进行格式化

  1. 如果它解析为 Rust 代码(表达式或语句列表),则按常规格式化。
  2. 如果不解析为 Rust 代码,则通过 ;, 拆分,因为那些通常是分隔符,然后尝试上述操作中的每个块。
  3. 否则,将宏中的每个标记与空格连接(还有几个其他针对每个情况的调整)

优先格式化宏的最终用户使用,而不是格式化 macro_rules,因为宏的使用比定义更频繁。大多数宏看起来像正常的 Rust 语法,因此可以使用许多常规格式化规则。

问答

有关许多问题和答案,请参阅这篇 Reddit 帖子

对于其他问题或错误报告等,请使用此处的问题和/或讨论。

依赖项

约9-20MB
约298K SLoC