3个版本
0.5.0 | 2024年7月21日 |
---|
#260 在 过程宏
674 每月下载量
用于 25 个crate (4 个直接使用)
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
不解析注释(除了一些情况外),因此所有注释都在处理开始时提取。通常,注释与下一个语法元素相关联,除了行尾 //
注释,这些注释与当前行的第一个语法元素相关联。
当构建拆分组时,如果当前语法元素有一个与提取的注释匹配行/列的标记,则将注释添加到拆分组中。
宏
宏使用了一些技巧进行格式化
- 如果它解析为 Rust 代码(表达式或语句列表),则按常规格式化。
- 如果不解析为 Rust 代码,则通过
; 和
,
拆分,因为那些通常是分隔符,然后尝试上述操作中的每个块。 - 否则,将宏中的每个标记与空格连接(还有几个其他针对每个情况的调整)
优先格式化宏的最终用户使用,而不是格式化 macro_rules
,因为宏的使用比定义更频繁。大多数宏看起来像正常的 Rust 语法,因此可以使用许多常规格式化规则。
问答
有关许多问题和答案,请参阅这篇 Reddit 帖子。
对于其他问题或错误报告等,请使用此处的问题和/或讨论。
依赖项
约9-20MB
约298K SLoC