use lsp_types::{GotoDefinitionParams, GotoDefinitionResponse, Location, Position, Range, Uri};
use rustledger_core::Directive;
use rustledger_parser::ParseResult;
use super::utils::{
byte_offset_to_position, get_word_at_source_position, is_account_type, is_currency_like_simple,
};
pub fn handle_goto_definition(
params: &GotoDefinitionParams,
source: &str,
parse_result: &ParseResult,
uri: &Uri,
) -> Option<GotoDefinitionResponse> {
let position = params.text_document_position_params.position;
let word = get_word_at_source_position(source, position)?;
tracing::debug!("Go-to-definition for word: {:?}", word);
if (word.contains(':') || is_account_type(&word))
&& let Some(location) = find_account_definition(&word, parse_result, source, uri)
{
return Some(GotoDefinitionResponse::Scalar(location));
}
if is_currency_like_simple(&word)
&& let Some(location) = find_currency_definition(&word, parse_result, source, uri)
{
return Some(GotoDefinitionResponse::Scalar(location));
}
None
}
fn find_account_definition(
account: &str,
parse_result: &ParseResult,
source: &str,
uri: &Uri,
) -> Option<Location> {
for spanned_directive in &parse_result.directives {
if let Directive::Open(open) = &spanned_directive.value {
let open_account = open.account.to_string();
if open_account == account || account.starts_with(&format!("{}:", open_account)) {
let (start_line, start_col) =
byte_offset_to_position(source, spanned_directive.span.start);
let (end_line, end_col) =
byte_offset_to_position(source, spanned_directive.span.end);
return Some(Location {
uri: uri.clone(),
range: Range {
start: Position::new(start_line, start_col),
end: Position::new(end_line, end_col),
},
});
}
}
}
None
}
fn find_currency_definition(
currency: &str,
parse_result: &ParseResult,
source: &str,
uri: &Uri,
) -> Option<Location> {
for spanned_directive in &parse_result.directives {
if let Directive::Commodity(comm) = &spanned_directive.value
&& comm.currency.as_ref() == currency
{
let (start_line, start_col) =
byte_offset_to_position(source, spanned_directive.span.start);
let (end_line, end_col) = byte_offset_to_position(source, spanned_directive.span.end);
return Some(Location {
uri: uri.clone(),
range: Range {
start: Position::new(start_line, start_col),
end: Position::new(end_line, end_col),
},
});
}
}
None
}