|
@@ -9,13 +9,12 @@ pub use rust_decimal::Decimal;
|
|
|
|
|
|
use crate::prelude::*;
|
|
|
|
|
|
-pub mod spec;
|
|
|
-
|
|
|
+mod format;
|
|
|
mod parse;
|
|
|
-pub use parse::parse_ledger;
|
|
|
+pub mod spec;
|
|
|
|
|
|
-mod format;
|
|
|
pub use format::format_ledger;
|
|
|
+pub use parse::parse_ledger;
|
|
|
|
|
|
pub struct UnitTag;
|
|
|
impl stringstore::NamespaceTag for UnitTag {
|
|
@@ -50,6 +49,8 @@ impl std::fmt::Debug for Datestamp {
|
|
|
|
|
|
#[derive(Clone, Debug, PartialEq, PartialOrd, Ord, Eq)]
|
|
|
pub struct Change {
|
|
|
+ pub source: Option<io::Span>,
|
|
|
+
|
|
|
pub account: Spanned<AccountName>,
|
|
|
pub amount: Spanned<Decimal>,
|
|
|
pub balance: Option<Spanned<Decimal>>,
|
|
@@ -58,10 +59,12 @@ pub struct Change {
|
|
|
|
|
|
#[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Ord)]
|
|
|
pub struct Transaction {
|
|
|
+ pub source: Option<io::Span>,
|
|
|
+
|
|
|
pub datestamp: Datestamp,
|
|
|
pub title: Option<String>,
|
|
|
pub annotations: Vec<String>,
|
|
|
- pub changes: Vec<Spanned<Change>>,
|
|
|
+ pub changes: Vec<Change>,
|
|
|
}
|
|
|
|
|
|
impl Transaction {
|
|
@@ -69,14 +72,14 @@ impl Transaction {
|
|
|
self.changes.iter().any(|b| b.account.as_ref() == &account)
|
|
|
}
|
|
|
|
|
|
- pub fn change_for(&self, account: AccountName) -> Option<&Spanned<Change>> {
|
|
|
+ pub fn change_for(&self, account: AccountName) -> Option<&Change> {
|
|
|
self.changes.iter().find(|b| b.account.as_ref() == &account)
|
|
|
}
|
|
|
|
|
|
pub fn split_changes(
|
|
|
&self,
|
|
|
account: AccountName,
|
|
|
- ) -> Option<(&Spanned<Change>, impl Iterator<Item = &Spanned<Change>>)> {
|
|
|
+ ) -> Option<(&Change, impl Iterator<Item = &Change>)> {
|
|
|
let index = self
|
|
|
.changes
|
|
|
.iter()
|
|
@@ -109,21 +112,52 @@ impl Transaction {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+pub type TransactionRef = std::rc::Rc<std::cell::RefCell<Transaction>>;
|
|
|
+
|
|
|
+#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
|
|
+enum RawLedgerEntry {
|
|
|
+ Transaction(Transaction),
|
|
|
+ Comment(Spanned<String>),
|
|
|
+}
|
|
|
+
|
|
|
+impl RawLedgerEntry {
|
|
|
+ pub fn as_transaction(&self) -> Option<&Transaction> {
|
|
|
+ match self {
|
|
|
+ Self::Transaction(tx) => Some(tx),
|
|
|
+ _ => None,
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ pub fn as_transaction_mut(&mut self) -> Option<&mut Transaction> {
|
|
|
+ match self {
|
|
|
+ Self::Transaction(tx) => Some(tx),
|
|
|
+ _ => None,
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ pub fn span(&self) -> io::Span {
|
|
|
+ match self {
|
|
|
+ Self::Transaction(ts) => ts.source.unwrap_or_default(),
|
|
|
+ Self::Comment(c) => c.span(),
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
|
|
pub enum LedgerEntry {
|
|
|
- Transaction(Spanned<Transaction>),
|
|
|
+ Transaction(TransactionRef),
|
|
|
Comment(Spanned<String>),
|
|
|
}
|
|
|
|
|
|
impl LedgerEntry {
|
|
|
- pub fn as_transaction(&self) -> Option<&Spanned<Transaction>> {
|
|
|
+ pub fn as_transaction(&self) -> Option<&TransactionRef> {
|
|
|
match self {
|
|
|
Self::Transaction(tx) => Some(tx),
|
|
|
_ => None,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- pub fn as_transaction_mut(&mut self) -> Option<&mut Spanned<Transaction>> {
|
|
|
+ pub fn as_transaction_mut(&mut self) -> Option<&mut Transaction> {
|
|
|
match self {
|
|
|
Self::Transaction(tx) => Some(tx),
|
|
|
_ => None,
|
|
@@ -132,7 +166,7 @@ impl LedgerEntry {
|
|
|
|
|
|
pub fn span(&self) -> io::Span {
|
|
|
match self {
|
|
|
- Self::Transaction(ts) => ts.span(),
|
|
|
+ Self::Transaction(ts) => ts.source.unwrap_or_default(),
|
|
|
Self::Comment(c) => c.span(),
|
|
|
}
|
|
|
}
|
|
@@ -143,9 +177,11 @@ pub struct Hoard {
|
|
|
path: std::path::PathBuf,
|
|
|
spec_root: spec::SpecRoot,
|
|
|
|
|
|
- ledger_data: Vec<LedgerEntry>,
|
|
|
+ comments: Vec<Spanned<String>>,
|
|
|
+
|
|
|
+ raw_ledger_data: Vec<RawLedgerEntry>,
|
|
|
|
|
|
- account_ledger_data: HashMap<AccountName, Vec<Spanned<Transaction>>>,
|
|
|
+ account_ledger_data: HashMap<AccountName, Vec<Transaction>>,
|
|
|
}
|
|
|
|
|
|
impl Hoard {
|
|
@@ -162,7 +198,8 @@ impl Hoard {
|
|
|
let mut r = Self {
|
|
|
path: path.into(),
|
|
|
spec_root,
|
|
|
- ledger_data: vec![],
|
|
|
+ raw_ledger_data: vec![],
|
|
|
+ comments: vec![],
|
|
|
account_ledger_data: Default::default(),
|
|
|
};
|
|
|
|
|
@@ -225,7 +262,7 @@ impl Hoard {
|
|
|
|
|
|
let sf = io::SourceFile::new_from_string(path.into_os_string());
|
|
|
if let Ok(data) = fsdata.fetch(&sf) {
|
|
|
- self.ledger_data
|
|
|
+ self.raw_ledger_data
|
|
|
.extend(parse_ledger(sf, &self.spec_root, data.text())?);
|
|
|
} else {
|
|
|
log::error!(
|
|
@@ -250,8 +287,8 @@ impl Hoard {
|
|
|
}
|
|
|
|
|
|
fn preprocess_ledger_data(&mut self) {
|
|
|
- for entry in &self.ledger_data {
|
|
|
- let LedgerEntry::Transaction(tx) = &entry else {
|
|
|
+ for entry in &self.raw_ledger_data {
|
|
|
+ let RawLedgerEntry::Transaction(tx) = &entry else {
|
|
|
continue;
|
|
|
};
|
|
|
for bal in &tx.changes {
|
|
@@ -271,14 +308,14 @@ impl Hoard {
|
|
|
self.ledger_data.as_mut_slice()
|
|
|
}
|
|
|
|
|
|
- pub fn ledger_data_for(&self, aname: AccountName) -> Option<&[Spanned<Transaction>]> {
|
|
|
+ pub fn ledger_data_for(&self, aname: AccountName) -> Option<&[Transaction]> {
|
|
|
self.account_ledger_data.get(&aname).map(Vec::as_slice)
|
|
|
}
|
|
|
|
|
|
pub fn ledger_data_for_mut(
|
|
|
&mut self,
|
|
|
aname: AccountName,
|
|
|
- ) -> Option<&mut [Spanned<Transaction>]> {
|
|
|
+ ) -> Option<&mut [Transaction]> {
|
|
|
self.account_ledger_data
|
|
|
.get_mut(&aname)
|
|
|
.map(Vec::as_mut_slice)
|