Add support for category comments in Nix option collection
The nix module now parses `/* */` comments as categories and associates them with subsequent options. The output format has been updated to include the category prefix before the option path. The internal state is maintained during traversal to ensure correct category propagation through nested structures.
This commit is contained in:
@@ -17,8 +17,8 @@ fn main() {
|
||||
eprintln!();
|
||||
}
|
||||
|
||||
let options: Vec<(String, bool)> = nix::collect_nix_options_with_path(&ast.syntax(), "");
|
||||
for (path, value) in options {
|
||||
println!("{} = {};", path, value);
|
||||
let options: Vec<(String, String, bool)> = nix::collect_nix_options(&ast.syntax());
|
||||
for (category, path, value) in options {
|
||||
println!("{}: {} = {};", category, path, value);
|
||||
}
|
||||
}
|
||||
|
||||
144
src/nix.rs
144
src/nix.rs
@@ -1,66 +1,96 @@
|
||||
use rnix::{NodeOrToken, SyntaxKind, SyntaxNode};
|
||||
use rnix::{NodeOrToken, SyntaxKind, SyntaxNode, SyntaxToken};
|
||||
|
||||
pub fn collect_nix_options_with_path(node: &SyntaxNode, current_path: &str) -> Vec<(String, bool)> {
|
||||
let mut result: Vec<(String, bool)> = Vec::new();
|
||||
pub fn collect_nix_options(node: &SyntaxNode) -> Vec<(String, String, bool)> {
|
||||
collect_nix_options_with_path(node, "", "")
|
||||
}
|
||||
|
||||
for child in node.children_with_tokens() {
|
||||
if let NodeOrToken::Node(child_node) = child {
|
||||
match child_node.kind() {
|
||||
SyntaxKind::NODE_ATTRPATH_VALUE => {
|
||||
let mut attr_path: String = String::new();
|
||||
let mut value_node: Option<SyntaxNode> = None;
|
||||
fn collect_nix_options_with_path(
|
||||
node: &SyntaxNode,
|
||||
current_path: &str,
|
||||
current_category: &str,
|
||||
) -> Vec<(String, String, bool)> {
|
||||
let mut result: Vec<(String, String, bool)> = Vec::new();
|
||||
let mut category: String = current_category.to_string();
|
||||
|
||||
for grand in child_node.children_with_tokens() {
|
||||
if let NodeOrToken::Node(grand_node) = grand {
|
||||
match grand_node.kind() {
|
||||
SyntaxKind::NODE_ATTRPATH => {
|
||||
attr_path = grand_node.text().to_string();
|
||||
}
|
||||
SyntaxKind::NODE_IDENT | SyntaxKind::NODE_LITERAL => {
|
||||
let text: String = grand_node.text().to_string();
|
||||
if text == "true" || text == "false" {
|
||||
value_node = Some(grand_node);
|
||||
}
|
||||
}
|
||||
SyntaxKind::NODE_ATTR_SET => {
|
||||
let new_path: String = if current_path.is_empty() {
|
||||
attr_path.clone()
|
||||
} else {
|
||||
format!("{}.{}", current_path, attr_path)
|
||||
};
|
||||
let children: Vec<NodeOrToken<SyntaxNode, SyntaxToken>> = node.children_with_tokens().collect();
|
||||
|
||||
result.extend(collect_nix_options_with_path(
|
||||
&grand_node,
|
||||
&new_path,
|
||||
));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(value_node) = value_node {
|
||||
let full_path: String = if current_path.is_empty() {
|
||||
attr_path
|
||||
} else {
|
||||
format!("{}.{}", current_path, attr_path)
|
||||
};
|
||||
|
||||
let value_text: String = value_node.text().to_string();
|
||||
let mut bool_value: bool = false;
|
||||
|
||||
if value_text == "true" {
|
||||
bool_value = true;
|
||||
}
|
||||
|
||||
result.push((full_path, bool_value));
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
result.extend(collect_nix_options_with_path(&child_node, current_path));
|
||||
for i in 0..children.len() {
|
||||
match &children[i] {
|
||||
NodeOrToken::Token(token) if token.kind() == SyntaxKind::TOKEN_COMMENT => {
|
||||
let text: &str = token.text();
|
||||
if text.starts_with("/*") && text.ends_with("*/") {
|
||||
let content: String = text
|
||||
.trim_start_matches("/*")
|
||||
.trim_end_matches("*/")
|
||||
.trim()
|
||||
.to_string();
|
||||
category = content;
|
||||
}
|
||||
}
|
||||
|
||||
NodeOrToken::Node(child_node)
|
||||
if child_node.kind() == SyntaxKind::NODE_ATTRPATH_VALUE =>
|
||||
{
|
||||
let mut attr_path: String = String::new();
|
||||
let mut value_node: Option<SyntaxNode> = None;
|
||||
|
||||
for grand in child_node.children_with_tokens() {
|
||||
if let NodeOrToken::Node(grand_node) = grand {
|
||||
match grand_node.kind() {
|
||||
SyntaxKind::NODE_ATTRPATH => {
|
||||
attr_path = grand_node.text().to_string();
|
||||
}
|
||||
SyntaxKind::NODE_IDENT | SyntaxKind::NODE_LITERAL => {
|
||||
let text: String = grand_node.text().to_string();
|
||||
if text == "true" || text == "false" {
|
||||
value_node = Some(grand_node);
|
||||
}
|
||||
}
|
||||
SyntaxKind::NODE_ATTR_SET => {
|
||||
let new_path: String = if current_path.is_empty() {
|
||||
attr_path.clone()
|
||||
} else {
|
||||
format!("{}.{}", current_path, attr_path)
|
||||
};
|
||||
|
||||
result.extend(collect_nix_options_with_path(
|
||||
&grand_node,
|
||||
&new_path,
|
||||
&category,
|
||||
));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(value_node) = value_node {
|
||||
let full_path: String = if current_path.is_empty() {
|
||||
attr_path
|
||||
} else {
|
||||
format!("{}.{}", current_path, attr_path)
|
||||
};
|
||||
|
||||
let value_text: String = value_node.text().to_string();
|
||||
let mut bool_value: bool = false;
|
||||
|
||||
if value_text == "true" {
|
||||
bool_value = true;
|
||||
}
|
||||
|
||||
result.push((category.clone(), full_path, bool_value));
|
||||
}
|
||||
}
|
||||
|
||||
NodeOrToken::Node(child_node) => {
|
||||
result.extend(collect_nix_options_with_path(
|
||||
child_node,
|
||||
current_path,
|
||||
&category,
|
||||
));
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user