use super::types::{CodeAction, CodeActionEdit, CodeActionKind};
use perl_ast_utils::{find_function_insert_position, find_node_at_range, find_statement_start};
use perl_lsp_rename::TextEdit;
use perl_parser_core::{Node, NodeKind, SourceLocation};
pub fn get_refactoring_actions(source: &str, ast: &Node, range: (usize, usize)) -> Vec<CodeAction> {
let mut actions = Vec::new();
let enhanced_provider = super::enhanced::EnhancedCodeActionsProvider::new(source.to_string());
actions.extend(enhanced_provider.get_enhanced_refactoring_actions(ast, range));
if let Some(node) = find_node_at_range(ast, range) {
match &node.kind {
NodeKind::FunctionCall { .. } | NodeKind::Binary { .. } if actions.is_empty() => {
actions.push(CodeAction {
title: "Extract to variable".to_string(),
kind: CodeActionKind::RefactorExtract,
diagnostics: Vec::new(),
edit: extract_variable(source, node, range),
is_preferred: false,
});
}
NodeKind::Block { .. } if actions.is_empty() => {
actions.push(CodeAction {
title: "Extract to function".to_string(),
kind: CodeActionKind::RefactorExtract,
diagnostics: Vec::new(),
edit: extract_function(source, node, range),
is_preferred: false,
});
}
_ => {}
}
}
actions
}
fn extract_variable(source: &str, node: &Node, _range: (usize, usize)) -> CodeActionEdit {
let expr_text = &source[node.location.start..node.location.end];
let var_name = "$extracted_var";
let stmt_start = find_statement_start(source, node.location.start);
CodeActionEdit {
changes: vec![
TextEdit {
location: SourceLocation { start: stmt_start, end: stmt_start },
new_text: format!("my {} = {};\n", var_name, expr_text),
},
TextEdit { location: node.location, new_text: var_name.to_string() },
],
}
}
fn extract_function(source: &str, node: &Node, _range: (usize, usize)) -> CodeActionEdit {
let body_text = &source[node.location.start..node.location.end];
let func_name = "extracted_function";
let insert_pos = find_function_insert_position(source);
CodeActionEdit {
changes: vec![
TextEdit {
location: SourceLocation { start: insert_pos, end: insert_pos },
new_text: format!("\nsub {} {{\n{}\n}}\n", func_name, body_text),
},
TextEdit { location: node.location, new_text: format!("{}();", func_name) },
],
}
}