use ktrs_ast::{Ast, NodeId};
use ktrs_syntax::SyntaxKind::{FUNCTION_LITERAL, LITERAL_STRING_TEMPLATE_ENTRY, RBRACE, STRING_TEMPLATE, WHEN_ENTRY};
use super::helpers::{is_followed_by_trim_indent, is_followed_by_trim_margin, is_multi_line};
use super::{LTOKEN_SET, WrappingRule, matching_rtoken};
use crate::ast_node_edit::AstNodeEdit;
use crate::ast_node_extension::AstNodeExtension;
use crate::rule::Emit;
impl WrappingRule {
pub(super) fn rearrange_closing_quote(&self, ast: &mut Ast, node: NodeId, emit: &mut Emit<'_>) {
let applies = ast
.parent(node)
.filter(|&it| ast.element_type(it) == STRING_TEMPLATE)
.filter(|&it| is_multi_line(ast, it))
.filter(|&it| is_followed_by_trim_indent(ast, it) || is_followed_by_trim_margin(ast, it))
.filter(|_| !ast.prev_sibling(node).is_none_or(|it| ast.text(it).chars().all(char::is_whitespace)))
.is_some();
if applies {
emit(ast, ast.start_offset(node), "Missing newline before \"\"\"", true).if_autocorrect_allowed(|| {
let entry = ast.new_leaf(LITERAL_STRING_TEMPLATE_ENTRY, "\n");
ast.raw_insert_before_me(node, entry);
});
}
}
pub(super) fn rearrange_arrow(&self, ast: &mut Ast, node: NodeId, emit: &mut Emit<'_>) {
let parent = ast.parent(node).expect("NullPointerException: parent!!");
let parent_type = ast.element_type(parent);
if
(parent_type != FUNCTION_LITERAL && parent_type != WHEN_ENTRY)
|| !ast.text_contains(parent, '\n')
|| (parent_type == WHEN_ENTRY && must_be_followed_by_newline(ast, node))
|| (parent_type == WHEN_ENTRY && ast.is_white_space_with_newline(ast.prev_leaf(node)))
{
return;
}
if !ast.is_white_space_with_newline(ast.next_code_leaf(node).and_then(|it| ast.prev_leaf(it))) {
self.require_newline_after_leaf(ast, node, emit, None);
}
let Some(r) = ast.next_sibling_matching(node, |it| ast.element_type(it) == RBRACE) else { return };
if !ast.is_white_space_with_newline(ast.prev_leaf(r)) {
let indent = ast.indent(node);
self.require_newline_before_leaf(ast, r, emit, &indent);
}
}
pub(super) fn require_newline_before_leaf(&self, ast: &mut Ast, node: NodeId, emit: &mut Emit<'_>, indent: &str) {
let message = format!("Missing newline before \"{}\"", ast.text(node));
emit(ast, ast.start_offset(node) - 1, &message, true).if_autocorrect_allowed(|| ast.upsert_whitespace_before_me(node, indent));
}
pub(super) fn require_newline_after_leaf(
&self,
ast: &mut Ast,
node_after_which_newline_is_required: NodeId,
emit: &mut Emit<'_>,
indent: Option<String>,
) {
let node_to_fix = node_after_which_newline_is_required;
let message = format!("Missing newline after \"{}\"", ast.text(node_after_which_newline_is_required));
emit(ast, ast.start_offset(node_after_which_newline_is_required) + 1, &message, true).if_autocorrect_allowed(|| {
let temp_indent = indent.unwrap_or_else(|| self.indent_config.child_indent_of(ast, node_to_fix));
ast.upsert_whitespace_after_me(node_to_fix, &temp_indent);
});
}
}
fn must_be_followed_by_newline(ast: &Ast, node: NodeId) -> bool {
let next_code_sibling = ast.next_code_sibling(node); let mut l_token = next_code_sibling
.and_then(|it| ast.next_leaf_matching(it, |it| ast.is_white_space_with_newline(it)))
.and_then(|it| ast.prev_code_leaf(it));
if let Some(l) = l_token
&& !LTOKEN_SET.contains(ast.element_type(l))
{
l_token = ast.prev_leaf_matching(l, |it| LTOKEN_SET.contains(ast.element_type(it)) || it == node);
}
if let Some(l) = l_token
&& LTOKEN_SET.contains(ast.element_type(l))
{
let r_element_type = matching_rtoken(ast.element_type(l));
let r_token = ast.next_sibling_matching(l, |it| Some(ast.element_type(it)) == r_element_type);
return r_token.and_then(|it| ast.parent(it)) == ast.parent(l);
}
next_code_sibling.is_some_and(|it| !ast.text_contains(it, '\n'))
}