use rustledger_core::Directive;
use rustledger_parser::ParseResult;
use crate::types::EditorLocation;
use super::helpers::{get_word_at_position, is_account_type, is_currency_like};
use super::line_index::{EditorCache, LineIndex};
pub fn get_definition_cached(
source: &str,
line: u32,
character: u32,
parse_result: &ParseResult,
cache: &EditorCache,
) -> Option<EditorLocation> {
let word = get_word_at_position(source, line, character)?;
if (word.contains(':') || is_account_type(&word))
&& let Some(location) =
find_account_definition_cached(&word, parse_result, &cache.line_index)
{
return Some(location);
}
if is_currency_like(&word)
&& let Some(location) =
find_currency_definition_cached(&word, parse_result, &cache.line_index)
{
return Some(location);
}
None
}
fn find_account_definition_cached(
account: &str,
parse_result: &ParseResult,
line_index: &LineIndex,
) -> Option<EditorLocation> {
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 (line, character) = line_index.offset_to_position(spanned_directive.span.start);
return Some(EditorLocation { line, character });
}
}
}
None
}
#[allow(dead_code)] pub fn get_definition(
source: &str,
line: u32,
character: u32,
parse_result: &ParseResult,
) -> Option<EditorLocation> {
let cache = EditorCache::new(source, parse_result);
get_definition_cached(source, line, character, parse_result, &cache)
}
fn find_currency_definition_cached(
currency: &str,
parse_result: &ParseResult,
line_index: &LineIndex,
) -> Option<EditorLocation> {
for spanned_directive in &parse_result.directives {
if let Directive::Commodity(comm) = &spanned_directive.value
&& comm.currency.as_ref() == currency
{
let (line, character) = line_index.offset_to_position(spanned_directive.span.start);
return Some(EditorLocation { line, character });
}
}
None
}
#[cfg(test)]
mod tests {
use super::*;
use rustledger_parser::parse;
#[test]
fn test_get_definition_account() {
let source = r#"2024-01-01 open Assets:Bank USD
2024-01-15 * "Coffee"
Assets:Bank -5.00 USD
Expenses:Food
"#;
let result = parse(source);
let location = get_definition(source, 3, 4, &result);
assert!(location.is_some());
let loc = location.unwrap();
assert_eq!(loc.line, 0); }
}