use ink_analyzer_ir::syntax::{SyntaxNode, TextRange, TextSize};
use ink_analyzer_ir::{FromSyntax, InkAttribute, InkFile};
use itertools::Itertools;
use super::utils;
use crate::analysis::text_edit;
use crate::TextEdit;
mod attr;
pub mod entity;
mod item;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Action {
pub label: String,
pub kind: ActionKind,
pub range: TextRange,
pub edits: Vec<TextEdit>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum ActionKind {
QuickFix,
Refactor,
}
pub fn actions(file: &InkFile, range: TextRange) -> Vec<Action> {
let mut results = Vec::new();
item::actions(&mut results, file, range);
attr::actions(&mut results, file, range);
results
.into_iter()
.unique_by(|item| item.edits.clone())
.map(|item| Action {
edits: text_edit::format_edits(item.edits, file).collect(),
..item
})
.collect()
}
impl Action {
pub(crate) fn remove_attribute(attr: &InkAttribute) -> Self {
Self {
label: format!("Remove `{}` attribute.", attr.syntax()),
kind: ActionKind::QuickFix,
range: attr.syntax().text_range(),
edits: vec![TextEdit::delete(attr.syntax().text_range())],
}
}
pub(crate) fn remove_item(item: &SyntaxNode) -> Self {
Self {
label: "Remove item.".to_string(),
kind: ActionKind::QuickFix,
range: item.text_range(),
edits: vec![TextEdit::delete(item.text_range())],
}
}
pub(crate) fn move_item(
item: &SyntaxNode,
offset: TextSize,
label: String,
indent_option: Option<&str>,
) -> Self {
Self::move_item_with_affixes(item, offset, label, indent_option, None, None)
}
pub(crate) fn move_item_with_affixes(
item: &SyntaxNode,
offset: TextSize,
label: String,
indent_option: Option<&str>,
prefix_option: Option<&str>,
suffix_option: Option<&str>,
) -> Self {
let mut insert_text = utils::item_indenting(item).map_or(item.to_string(), |item_indent| {
utils::reduce_indenting(item.to_string().as_str(), item_indent.as_str())
});
if let Some(indent) = indent_option {
insert_text = utils::apply_indenting(insert_text.as_str(), indent);
}
if let Some(prefix) = prefix_option {
insert_text = format!("{prefix}{insert_text}");
}
if let Some(suffix) = suffix_option {
insert_text = format!("{insert_text}{suffix}");
}
Self {
label,
kind: ActionKind::QuickFix,
range: item.text_range(),
edits: vec![
TextEdit::insert(insert_text, offset),
TextEdit::delete(item.text_range()),
],
}
}
}