Skip to content

Commit

Permalink
Add pretty basic registry and balance feature.
Browse files Browse the repository at this point in the history
With this feature, users can see the register and balance report.
register can point to one particular account, without any vague match.
No support for commodity support.
  • Loading branch information
xkikeg committed Jul 5, 2024
1 parent f64aad7 commit ff2b2e5
Show file tree
Hide file tree
Showing 13 changed files with 1,371 additions and 24 deletions.
44 changes: 40 additions & 4 deletions cli/src/cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,24 +195,60 @@ pub struct BalanceCmd {
}

impl BalanceCmd {
pub fn run<W>(&self, _w: &mut W) -> Result<(), Error>
pub fn run<W>(self, w: &mut W) -> Result<(), Error>
where
W: std::io::Write,
{
todo!("not implemented");
let arena = Bump::new();
let mut ctx = report::ReportContext::new(&arena);
let (_, balance) = report::process(&mut ctx, load::Loader::new(self.source))?;
let accounts = ctx.all_accounts();
for account in &accounts {
if let Some(amount) = balance.get_balance(account) {
writeln!(w, "{}: {}", account.as_str(), amount.as_inline_display())?;
} else {
writeln!(w, "{}: not found, probably zero", account.as_str())?;
}
}
Ok(())
}
}

#[derive(Args, Debug)]
pub struct RegisterCmd {
source: std::path::PathBuf,
account: Option<String>,
}

impl RegisterCmd {
pub fn run<W>(&self, _w: &mut W) -> Result<(), Error>
pub fn run<W>(self, w: &mut W) -> Result<(), Error>
where
W: std::io::Write,
{
todo!("not implemented");
let arena = Bump::new();
let mut ctx = report::ReportContext::new(&arena);
let (txns, _) = report::process(&mut ctx, load::Loader::new(self.source))?;
let account = self
.account
.as_ref()
.map(|x| ctx.account(x).expect("TODO: Make this a proper error"));
let mut balance = report::Balance::default();
for txn in txns {
if let Some(account) = &account {
if let Some(p) = txn.postings.iter().find(|p| p.account == *account) {
let b = balance.increment(*account, p.amount.clone());
writeln!(
w,
"{} {} {}",
account.as_str(),
p.amount.as_inline_display(),
b.as_inline_display()
)?;
}
continue;
}
writeln!(w, "{:#?}", txn)?;
}
Ok(())
}
}
8 changes: 4 additions & 4 deletions core/src/load.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ use crate::{parse, repl};
pub enum LoadError {
#[error("failed to perform IO")]
IO(#[from] std::io::Error),
#[error("failed to parse file")]
Parse(#[from] Box<parse::ParseError>),
#[error("failed to parse file {1}")]
Parse(#[source] Box<parse::ParseError>, PathBuf),
#[error("unexpected include path {0}, maybe filesystem root is passed")]
IncludePath(PathBuf),
}
Expand Down Expand Up @@ -70,13 +70,13 @@ impl Loader {
T: FnMut(&Path, &parse::ParsedLedgerEntry<'_>) -> Result<(), E>,
E: std::error::Error + From<LoadError>,
{
let path = self.filesystem.canonicalize_path(path);
let path: Cow<'_, Path> = self.filesystem.canonicalize_path(path);
let content = self
.filesystem
.file_content_utf8(&path)
.map_err(LoadError::IO)?;
for entry in parse_options.parse_ledger(&content) {
match entry.map_err(|x| LoadError::Parse(Box::new(x)))? {
match entry.map_err(|e| LoadError::Parse(Box::new(e), path.clone().into_owned()))? {
repl::LedgerEntry::Include(p) => {
let include_path: PathBuf = p.0.as_ref().into();
let target = path
Expand Down
19 changes: 13 additions & 6 deletions core/src/parse/expr.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
//! Defines parsers related to value expression.

use crate::{
parse::{character::paren, primitive},
repl::{expr, pretty_decimal},
};

use winnow::{
ascii::space0,
combinator::{alt, delimited, dispatch, peek, preceded, separated_foldl1, terminated, trace},
error::{FromExternalError, ParserError},
error::{ContextError, FromExternalError, ParseError, ParserError},
stream::{AsChar, Stream, StreamIsPartial},
token::{any, one_of},
PResult, Parser,
};

use crate::repl::{expr, pretty_decimal};

use super::{character::paren, primitive};

/// Parses value expression.
pub fn value_expr<'i, I, E>(input: &mut I) -> PResult<expr::ValueExpr<'i>, E>
where
Expand All @@ -31,6 +30,14 @@ where
.parse_next(input)
}

impl<'i> TryFrom<&'i str> for expr::ValueExpr<'i> {
type Error = ParseError<&'i str, ContextError>;

fn try_from(value: &'i str) -> Result<Self, Self::Error> {
value_expr.parse(value)
}
}

fn paren_expr<'i, I, E>(input: &mut I) -> PResult<expr::ValueExpr<'i>, E>
where
I: Stream<Token = char, Slice = &'i str> + StreamIsPartial + Clone,
Expand Down
1 change: 1 addition & 0 deletions core/src/repl/pretty_decimal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ impl PrettyDecimal {
}

impl From<PrettyDecimal> for Decimal {
#[inline]
fn from(value: PrettyDecimal) -> Self {
value.value
}
Expand Down
6 changes: 5 additions & 1 deletion core/src/report.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
//! eval module contains functions for Ledger file evaluation.

mod book_keeping;
mod context;
mod error;
pub mod intern;
mod eval;
mod intern;

use std::borrow::Borrow;

pub use book_keeping::{process, Balance, Posting, Transaction};
pub use context::ReportContext;
pub use error::ReportError;
pub use intern::Account;

use crate::{load, repl::LedgerEntry};

Expand Down
Loading

0 comments on commit ff2b2e5

Please sign in to comment.