#![allow(dead_code)]
use super::ast_utils;
use super::scope_analyzer::ScopeAnalysis;
use crate::database::WindjammerDatabase;
use tower_lsp::lsp_types::*;
use windjammer::parser::Parameter;
pub struct ExtractFunction<'a> {
#[allow(dead_code)]
db: &'a WindjammerDatabase,
uri: Url,
range: Range,
}
impl<'a> ExtractFunction<'a> {
pub fn new(db: &'a WindjammerDatabase, uri: Url, range: Range) -> Self {
Self { db, uri, range }
}
pub fn execute(&self, function_name: &str, source: &str) -> Result<WorkspaceEdit, String> {
let start_byte = ast_utils::position_to_byte_offset(source, self.range.start);
let end_byte = ast_utils::position_to_byte_offset(source, self.range.end);
let selected_text = &source[start_byte..end_byte];
if selected_text.trim().is_empty() {
return Err("Selection is empty".to_string());
}
let analysis = self.analyze_scope()?;
let new_function = self.generate_function(function_name, &analysis, selected_text);
let function_call = self.generate_call(function_name, &analysis);
let mut edits = vec![];
edits.push(TextEdit {
range: self.range,
new_text: function_call,
});
let insert_position = Position {
line: self.range.start.line.saturating_sub(2),
character: 0,
};
edits.push(TextEdit {
range: Range {
start: insert_position,
end: insert_position,
},
new_text: format!("{}\n\n", new_function),
});
let mut changes = std::collections::HashMap::new();
changes.insert(self.uri.clone(), edits);
Ok(WorkspaceEdit {
changes: Some(changes),
document_changes: None,
change_annotations: None,
})
}
fn analyze_scope(&self) -> Result<ScopeAnalysis, String> {
Ok(ScopeAnalysis {
parameters: vec![],
return_values: vec![],
local_variables: vec![],
captured: vec![],
has_early_return: false,
has_control_flow: false,
})
}
fn generate_function(&self, name: &str, analysis: &ScopeAnalysis, body: &str) -> String {
let parameters: Vec<Parameter> = analysis
.parameters
.iter()
.map(|var| Parameter {
name: var.name.clone(),
pattern: None,
type_: windjammer::parser::Type::Custom(
var.type_name
.clone()
.unwrap_or_else(|| "unknown".to_string()),
),
ownership: windjammer::parser::OwnershipHint::Inferred,
is_mutable: false,
})
.collect();
let return_type = if analysis.return_values.is_empty() {
None
} else if analysis.return_values.len() == 1 {
Some(windjammer::parser::Type::Custom(
analysis.return_values[0]
.type_name
.clone()
.unwrap_or_else(|| "unknown".to_string()),
))
} else {
let types: Vec<windjammer::parser::Type> = analysis
.return_values
.iter()
.map(|var| {
windjammer::parser::Type::Custom(
var.type_name
.clone()
.unwrap_or_else(|| "unknown".to_string()),
)
})
.collect();
Some(windjammer::parser::Type::Tuple(types))
};
ast_utils::generate_function(name, ¶meters, &return_type, body, 0)
}
fn generate_call(&self, name: &str, analysis: &ScopeAnalysis) -> String {
let args: Vec<String> = analysis
.parameters
.iter()
.map(|var| var.name.clone())
.collect();
let call = ast_utils::generate_function_call(name, &args);
if analysis.return_values.is_empty() {
call
} else if analysis.return_values.len() == 1 {
format!("let {} = {}", analysis.return_values[0].name, call)
} else {
let vars = analysis
.return_values
.iter()
.map(|v| v.name.clone())
.collect::<Vec<_>>()
.join(", ");
format!("let ({}) = {}", vars, call)
}
}
}
#[cfg(test)]
mod tests {
#[test]
fn test_extract_function_creation() {
}
}