8 files changed,
116 insertions(+),
26 deletions(-)
Author:
Oleksandr Smirnov
olexsmir@gmail.com
Committed at:
2026-09-26 17:07:40 +0300
Authored at:
2026-09-25 23:03:28 +0300
Change ID:
szqykqltlqvpomtqkyuwkrkumwnutvqt
Parent:
4481c7d
jump to
M
internal/settings/format.go
··· 43 43 } 44 44 switch { 45 45 case strings.EqualFold(c, "after"): 46 - s.Format.CommodityPos = printer.CommodityAfter 46 + s.Format.CommodityPos = printer.CommodityPosAfter 47 47 case strings.EqualFold(c, "before"): 48 - s.Format.CommodityPos = printer.CommodityBefore 48 + s.Format.CommodityPos = printer.CommodityPosBefore 49 49 default: 50 50 return nil, fmt.Errorf("invalid value %q (want %q or %q)", c, "after", "before") 51 + } 52 + case "commodity_space": 53 + c, ok := val.(string) 54 + if !ok { 55 + return nil, fmt.Errorf("invalid value %v (want string)", val) 56 + } 57 + switch { 58 + case strings.EqualFold(c, "preserve"): 59 + s.Format.CommoditySpace = printer.CommoditySpacePreserve 60 + case strings.EqualFold(c, "always"): 61 + s.Format.CommoditySpace = printer.CommoditySpaceAlways 62 + case strings.EqualFold(c, "never"): 63 + s.Format.CommoditySpace = printer.CommoditySpaceNever 64 + default: 65 + return nil, fmt.Errorf("invalid value %q (want %q, %q or %q)", c, "preserve", "always", "never") 51 66 } 52 67 default: 53 68 return []string{fmt.Sprintf("unknown format option %q", name)}, nil
M
journal/printer/amount.go
··· 32 32 } 33 33 34 34 switch p.cfg.CommodityPos { 35 - case CommodityBefore: 35 + case CommodityPosBefore: 36 36 p.buf.WriteString(comm) 37 - if a.HasSpace { 38 - p.buf.WriteByte(' ') 39 - } 37 + p.writeCommoditySpace(a) 40 38 p.writeDecimal(a.Quantity, a.QuantityFmt, prec) 41 - case CommodityAfter: 39 + case CommodityPosAfter: 42 40 p.writeDecimal(a.Quantity, a.QuantityFmt, prec) 41 + p.writeCommoditySpace(a) 42 + p.buf.WriteString(comm) 43 + default: 44 + panic("impossible CommodityPos value") 45 + } 46 +} 47 + 48 +func (p *printer) writeCommoditySpace(a *ast.Amount) { 49 + switch p.cfg.CommoditySpace { 50 + case CommoditySpacePreserve: 43 51 if a.HasSpace { 44 52 p.buf.WriteByte(' ') 45 53 } 46 - p.buf.WriteString(comm) 54 + case CommoditySpaceAlways: 55 + p.buf.WriteByte(' ') 56 + case CommoditySpaceNever: 47 57 default: 48 - panic("impossible CommodityPos value") 58 + panic("impossible CommoditySpace value") 49 59 } 50 60 } 51 61
M
journal/printer/printer.go
··· 34 34 type CommodityPos int 35 35 36 36 const ( 37 - CommodityAfter CommodityPos = iota // "10.00 EUR" 38 - CommodityBefore // "$10.00" 37 + CommodityPosAfter CommodityPos = iota // "10.00 EUR" 38 + CommodityPosBefore // "$10.00" 39 39 ) 40 40 41 41 func (c CommodityPos) String() string { 42 42 switch c { 43 - case CommodityAfter: 43 + case CommodityPosAfter: 44 44 return "after" 45 - case CommodityBefore: 45 + case CommodityPosBefore: 46 46 return "before" 47 47 default: 48 48 panic("invalid commodity pos value") 49 49 } 50 50 } 51 + 52 +// CommoditySpace controls the space between quantity and commodity 53 +type CommoditySpace int 54 + 55 +const ( 56 + CommoditySpacePreserve CommoditySpace = iota // "$10" / "$ 10" 57 + CommoditySpaceAlways // "$ 10" 58 + CommoditySpaceNever // "$10" 59 +) 51 60 52 61 type Config struct { 53 - TabIndent bool // true = tabs, false = spaces 54 - IndentWidth int // spaces per indent level (default: 2) 55 - PreserveBlankLines bool // preserve consecutive blank lines as-is 56 - AlignStyle AlignStyle // (default AlignTwoSpaces) 57 - AlignColumn int // fixed column for AlignRight 58 - CommodityPos CommodityPos // where to place commodity 62 + TabIndent bool // true = tabs, false = spaces 63 + IndentWidth int // spaces per indent level (default: 2) 64 + PreserveBlankLines bool // preserve consecutive blank lines as-is 65 + AlignStyle AlignStyle // (default AlignTwoSpaces) 66 + AlignColumn int // fixed column for AlignRight 67 + CommodityPos CommodityPos // where to place commodity 68 + CommoditySpace CommoditySpace // space between quantity and commodity 59 69 } 60 70 61 71 var DefaultConfig = Config{ ··· 64 74 PreserveBlankLines: false, 65 75 AlignStyle: AlignTwoSpaces, 66 76 AlignColumn: 70, 67 - CommodityPos: CommodityAfter, 77 + CommodityPos: CommodityPosAfter, 78 + CommoditySpace: CommoditySpacePreserve, 68 79 } 69 80 70 81 func (c *Config) indent() string {
M
journal/printer/printer_test.go
··· 45 45 } 46 46 47 47 var testsWithConfig = map[string]*Config{ 48 - "align_right": {AlignStyle: AlignRight, AlignColumn: 50}, 49 - "align_tab": {AlignStyle: AlignTab, AlignColumn: 50}, 50 - "commodity_before": {CommodityPos: CommodityBefore}, 51 - "preserve_blanks": {PreserveBlankLines: true}, 52 - "tab_indent": {TabIndent: true}, 53 - "indent_width": {IndentWidth: 4}, 48 + "align_right": {AlignStyle: AlignRight, AlignColumn: 50}, 49 + "align_tab": {AlignStyle: AlignTab, AlignColumn: 50}, 50 + "commodity_pos_before": {CommodityPos: CommodityPosBefore}, 51 + "preserve_blanks": {PreserveBlankLines: true}, 52 + "commodity_space_preserve": {CommoditySpace: CommoditySpacePreserve}, 53 + "commodity_space_always": {CommoditySpace: CommoditySpaceAlways}, 54 + "commodity_space_never": {CommoditySpace: CommoditySpaceNever}, 55 + "tab_indent": {TabIndent: true}, 56 + "indent_width": {IndentWidth: 4}, 54 57 } 55 58 56 59 func TestRoundTrip_WithConfig(t *testing.T) {
A
journal/printer/testdata/commodity_space_always.txtar
··· 1 +-- input -- 2 +2026-01-15 * Groceries 3 + Expenses:Food 50.00$ 4 + Assets:Cash 5 + 6 +2026-01-16 Salary 7 + Assets:Cash 2000.00$ 8 + Income:Salary -2000.00 $ 9 + 10 +-- expect -- 11 +2026-01-15 * Groceries 12 + Expenses:Food 50.00 $ 13 + Assets:Cash 14 + 15 +2026-01-16 Salary 16 + Assets:Cash 2000.00 $ 17 + Income:Salary -2000.00 $
A
journal/printer/testdata/commodity_space_never.txtar
··· 1 +-- input -- 2 +2026-01-15 * Groceries 3 + Expenses:Food 50.00 $ 4 + Assets:Cash 5 + 6 +2026-01-16 Salary 7 + Assets:Cash 2000.00$ 8 + Income:Salary -2000.00 $ 9 + 10 +-- expect -- 11 +2026-01-15 * Groceries 12 + Expenses:Food 50.00$ 13 + Assets:Cash 14 + 15 +2026-01-16 Salary 16 + Assets:Cash 2000.00$ 17 + Income:Salary -2000.00$
A
journal/printer/testdata/commodity_space_preserve.txtar
··· 1 +-- input -- 2 +2026-01-15 * Groceries 3 + Expenses:Food 50.00$ 4 + Assets:Cash 5 + 6 +2026-01-16 Salary 7 + Assets:Cash $ 2000.00 8 + Income:Salary -2000.00 $ 9 + 10 +-- expect -- 11 +2026-01-15 * Groceries 12 + Expenses:Food 50.00$ 13 + Assets:Cash 14 + 15 +2026-01-16 Salary 16 + Assets:Cash 2000.00 $ 17 + Income:Salary -2000.00 $