use rnix::{Root, SyntaxKind, SyntaxNode};
use crate::change::Change;
use super::context::Context;
pub type Node = SyntaxNode;
pub fn parse_node(s: &str) -> Node {
Root::parse(s).syntax()
}
pub fn substitute_child(parent: &SyntaxNode, index: usize, new_child: &SyntaxNode) -> Node {
let green = parent
.green()
.replace_child(index, new_child.green().into());
parse_node(&green.to_string())
}
pub fn empty_node() -> Node {
Root::parse("").syntax()
}
pub fn get_sibling_whitespace(node: &SyntaxNode) -> Option<Node> {
if let Some(prev) = node.prev_sibling_or_token()
&& prev.kind() == SyntaxKind::TOKEN_WHITESPACE
{
return Some(parse_node(prev.as_token().unwrap().green().text()));
}
if let Some(next) = node.next_sibling_or_token()
&& next.kind() == SyntaxKind::TOKEN_WHITESPACE
{
return Some(parse_node(next.as_token().unwrap().green().text()));
}
None
}
pub fn insertion_index_after(node: &SyntaxNode) -> usize {
let element: rnix::SyntaxElement = node.clone().into();
let mut cursor = element.next_sibling_or_token();
let mut last_index = node.index() + 1;
while let Some(ref tok) = cursor {
match tok.kind() {
SyntaxKind::TOKEN_WHITESPACE => {
let text = tok.to_string();
if text.contains('\n') {
break;
}
last_index = tok.index() + 1;
}
SyntaxKind::TOKEN_COMMENT => {
last_index = tok.index() + 1;
}
_ => break,
}
cursor = tok.next_sibling_or_token();
}
last_index
}
pub fn adjacent_whitespace_index(child: &rnix::SyntaxElement) -> Option<usize> {
if let Some(prev) = child.prev_sibling_or_token()
&& prev.kind() == SyntaxKind::TOKEN_WHITESPACE
{
Some(prev.index())
} else if let Some(next) = child.next_sibling_or_token()
&& next.kind() == SyntaxKind::TOKEN_WHITESPACE
{
Some(next.index())
} else {
None
}
}
pub fn should_remove_input(change: &Change, ctx: &Option<Context>, input_id: &str) -> bool {
if !change.is_remove() {
return false;
}
if let Some(id) = change.id()
&& id.to_string() == input_id
{
return true;
}
if let Some(ctx) = ctx
&& ctx.first_matches(input_id)
{
return true;
}
false
}
pub fn should_remove_nested_input(change: &Change, ctx: &Option<Context>, input_id: &str) -> bool {
if !change.is_remove() {
return false;
}
if let Some(id) = change.id() {
return id.matches_with_ctx(input_id, ctx.clone());
}
false
}
pub fn make_quoted_string(s: &str) -> Node {
parse_node(&format!("\"{}\"", s))
}
pub fn make_toplevel_url_attr(id: &str, uri: &str) -> Node {
parse_node(&format!("inputs.{}.url = \"{}\";", id, uri))
}
pub fn make_toplevel_flake_false_attr(id: &str) -> Node {
parse_node(&format!("inputs.{}.flake = false;", id))
}
pub fn make_toplevel_nested_follows_attr(parent_id: &str, nested_id: &str, target: &str) -> Node {
parse_node(&format!(
"inputs.{}.inputs.{}.follows = \"{}\";",
parent_id, nested_id, target
))
}
pub fn make_toplevel_follows_attr(id: &str, target: &str) -> Node {
parse_node(&format!("inputs.{}.follows = \"{}\";", id, target))
}
pub fn make_url_attr(id: &str, uri: &str) -> Node {
parse_node(&format!("{}.url = \"{}\";", id, uri))
}
pub fn make_flake_false_attr(id: &str) -> Node {
parse_node(&format!("{}.flake = false;", id))
}
pub fn make_attrset_url_attr(id: &str, uri: &str, indent: &str) -> Node {
parse_node(&format!(
"{} = {{\n{} url = \"{}\";\n{}}};",
id, indent, uri, indent
))
}
pub fn make_attrset_url_flake_false_attr(id: &str, uri: &str, indent: &str) -> Node {
parse_node(&format!(
"{} = {{\n{} url = \"{}\";\n{} flake = false;\n{}}};",
id, indent, uri, indent, indent
))
}
pub fn make_nested_follows_attr(input: &str, target: &str) -> Node {
parse_node(&format!("inputs.{}.follows = \"{}\";", input, target))
}
pub fn make_follows_attr(target: &str) -> Node {
parse_node(&format!("follows = \"{}\";", target))
}