simonmichael / hledger

Robust, fast, intuitive plain text accounting tool with CLI, TUI and web interfaces.
https://hledger.org
GNU General Public License v3.0
3.03k stars 321 forks source link

Add option to print with normalized output width #1045

Open alerque opened 5 years ago

alerque commented 5 years ago

I use hledger itself to process and normalize all my ledgers whether imported from other sources or manually composed. The print command makes sure the values for every posting in a transaction are aligned.

2016/01/01 Example transaction
    Expense:Foo  $6
    Expense:Foo:Baz  $3
    Cash

Becomes the much nicer:

2016/01/01 Example transaction
    Expense:Foo                  $6
    Expense:Foo:Baz              $3
    Cash                        $-9

However the column at which this alignment happens varies from transaction to transaction. Consider this case:

2016/01/01 Example transaction
    Expense:Foo  $6
    Cash

2016/01/01 Another transaction
    Expense:Bar:Baz  $6
    Cash

Normalizing this using print -x will return each transaction aligned at a a different place:

2016/01/01 Example transaction
    Expense:Foo              $6
    Cash                    $-6

2016/01/01 Another transaction
    Expense:Bar:Baz              $6
    Cash                        $-6

In this case ledger print is superior in that all transactions are aligned together:

2016/01/01 Example transaction
    Expense:Foo                                   $6
    Cash

2016/01/01 Another transaction
    Expense:Bar:Baz                               $6
    Cash

I considered normalizing through ledger, but there are many other ways in which hledger print is preferable, such as alignment of postings with commodity costs:

# Source
2016/01/01 Unit prices
    Expense:Foo  56 @ $6.00
    Cash  $-336

# Output of hledger print
2016/01/01 Unit prices
    Expense:Foo      56 @ $6.00
    Cash                  $-336

# Output of ledger print
2016/01/01 Unit prices
    Expense:Foo                                   56 @ $6
    Cash                                       $-336

Personally I really like having the final cost of the posting right aligned as in the hledger output.

What I would like is some kind of format option that specifies the right edge to align to (if possible without truncation of course).

The reason this would be preferable to a fully automatic width guesser that spans multiple transactions is that I could standardize on a width such that future changes such as renaming an account or moving transactions from one ledger to another would not cause churn in my Git commit history just because the length of an account string changed. Right now running git blame on a Ledger file shows quite a bit of useless results as every posting in a transaction can change when just one posting is edited (because the column amounts are aligned to changes).

alerque commented 5 years ago

Related: Automatically Sort and Align Ledger Transactions in VIM.

It looks like the vim-ledger plugin has some pattern matching based tools for this. They do help with my use case, but they are not a substitute for hledger supporting aligned output. For one thing it they do not handle multiple currency situations with different separators in the same file very well. Also without actually processing the numbers it doesn't understand how to make numbers match the commodity declaration (such as always adding the decimal separator and two digit precision). It's a stop-gap for me and I mention it here in case others are interested, but the wish still stands!

simonmichael commented 5 years ago

Related code: https://github.com/simonmichael/hledger/blob/master/hledger-lib/Hledger/Data/Transaction.hs#L206

Thanks. I've wanted to do something about this for a long time. Here's a summary of current behaviour:

input

2000/01/01
    a  $6.0 @ A1000.00
    b  3 USD @ 10 B
    cccccccccccccccccccccccccccccccccccccccccccccccc50  $1
    dddddddddddddddddddddddddddddddddddddddddddddddd50  123456789012 USD
    d

hledger print

;-------------------------------------------------52
2000/01/01
    a                                                      $6.0 @ A1000.00
    b                                                         3 USD @ 10 B
    cccccccccccccccccccccccccccccccccccccccccccccccc50                $1.0
    dddddddddddddddddddddddddddddddddddddddddddddddd50    123456789012 USD
    d

ledger print

;-------------------------------------------------52
2000/01/01 <Unspecified payee>
    a                                           $6.0 @ A1000
    b                                          3 USD @ B10
    cccccccccccccccccccccccccccccccccccccccccccccccc50        $1.0
    dddddddddddddddddddddddddddddddddddddddddddddddd50  123456789012 USD
    d

ledger-mode C-tab (ledger-post-align-xact)

;-------------------------------------------------52
2000/01/01
    a                                           $6.0 @ A1000.00
    b                                              3 USD @ 10 B
    cccccccccccccccccccccccccccccccccccccccccccccccc50  $1
    dddddddddddddddddddddddddddddddddddddddddddddddd50  123456789012 USD
    d

Or, with ledger-post-amount-alignment-at set to :decimal instead of :end :

;-------------------------------------------------52
2000/01/01
    a                                             $6.0 @ A1000.00
    b                                              3 USD @ 10 B
    cccccccccccccccccccccccccccccccccccccccccccccccc50  $1
    dddddddddddddddddddddddddddddddddddddddddddddddd50  123456789012 USD
    d
simonmichael commented 5 years ago

Some impressions of pros and cons:

hledger

Pro

Con

ledger

Pro

Con

ledger-mode (:end)

Pro

Con

ledger-mode (:decimal)

Pro

Con

simonmichael commented 5 years ago

What do y'all like about these ? My beancount is broken, do it or other ledgerlikes do anything interesting ? Here's a quick

hledger proposal A

proposal B

Note these rules all try to produce mostly-tidy output while looking at just one transaction at a time; we could align perfectly by looking at the whole output, but presumably that's not good for efficiency.

alerque commented 5 years ago

I won't mention what vim-ledger does with your example input because it's badly broken, but here is what I would like to see:

2000/01/01
    a                                                   $6.0 @ A1000.00
    b                                                     3 USD @ 10 B
    cccccccccccccccccccccccccccccccccccccccccccccccc50            $1.0
    dddddddddddddddddddddddddddddddddddddddddddddddd50  123456789012 USD
    d

This is very similar to your proposal A, but tweaked as follows

simonmichael commented 5 years ago

Ie, align the decimal place of the rightmost amount, whether it be the posting amount or a price amount ? That seems weird to me. Also if we're going to align around column 50 it might as well be 52 to minimise change when converting between ledger/ledger-mode/hledger.

alerque commented 5 years ago

I didn't have a better idea how to align price amounts that do not have a total amount shown in the posting, so the price seemed like the right thing to match. Did you have a better idea?

I picked 50 out of a hat because for typical 2 digit precision currency that places the right edge of amounts at 52 to match ledger's default. I don't know about ledger-mode, but vim-ledger's defaults are wildly out of whack with that, but configurable (and I'm going to propose making it match by default, I'm trying to get maitainership on that because it needs help).

simonmichael commented 5 years ago

ledger and ledger-mode align the main posting amount, allowing any unit/total price to hang off to the right.

I see. Showing two decimal places is fairly common, so if we align the decimal point at 50, it may often match ledger's output. Whereas if we align the right-most digit, 52 would work better.

Whether an amount-aligning option like --align=point|number|all[,COL] is worth the trouble I don't know.

You could also go all out and align each separate part for readability, at the cost of more screen space:

2000/01/01
    a                                                             $6.0     @ A1000.00
    b                                                              3   USD @    10    B
    cccccccccccccccccccccccccccccccccccccccccccccccc50            $1.0
    dddddddddddddddddddddddddddddddddddddddddddddddd50  123456789012   USD
    d
alerque commented 5 years ago

Just be sure that last suggestion is behind an --ocd flag and we're golden. :1st_place_medal:

For myself --align=point will likely be the only one to get any mileage but I'm sure opinions will differ on that. Sometimes matching ledger is good enough for me, fully matching is not the goal because it handles some other things less well (or else I'd be using that!), but having the chance of coinciding does make comparing output easier.

simonmichael commented 5 years ago

Ok, let's aim to align posting amount's decimal point at 50 for a start and see how that looks. Probably as a separate code path for now, to allow comparing old and new output for a while.

alerque commented 5 years ago

ledger and ledger-mode align the main posting amount, allowing any unit/total price to hang off to the right.

Sure, but since when was the unit quantity EVER the most likely thing to be comparable to other posting amounts? The unit price may not match in amount, but at least it's more likely to be the same commodity (and hence more useful to align), while the total price is almost certainly going to correspond to something else in the transaction. Hence I don't think following ledger's lead of hanging the unit/total price out of the way here is a good idea. Those are specifically the numbers I think are most useful to align with other posting amounts.

simonmichael commented 5 years ago

You could be right. I more often have unit prices, not total prices, which are less comparable. And to me aligning two semantically different things feels weird. I think it will take some testing/real world use to know. We might even end up finding the simple right-align all behaviour is fastest and best after all. Are people really wanting to "sum up" amounts when reading print output ?

simonmichael commented 5 years ago

align posting amount's decimal point at 50 for a start

It's a bit tricky! I believe I see how to do it, but I probably won't do it this month. If @alerque or anyone wants to tackle it sooner I can share WIP and notes.

alerque commented 5 years ago

I can't promise my Haskell will get anywhere substantial, but I'd be happy to poke at WIP if you put it in a branch somewhere. I'll be doing lots more accounting this month so I might get ants in my pants and try to make something work.

simonmichael commented 5 years ago

Great! Pushed as #1052.