all repos

clerk @ a7ca45c

missing tooling for ledger/hledger
7 files changed, 35 insertions(+), 25 deletions(-)
journal: parse the conversion value
Author: Oleksandr Smirnov olexsmir@gmail.com
Committed at: 2026-06-22 18:00:13 +0300
Authored at: 2026-06-17 15:18:16 +0300
Change ID: xmmlvwpyrrszxytmutwvowtoywrmvnlq
Parent: 2f5968c
M journal/ast/dump.go
···
        292
        292
         	indent(b, depth+1)

      
        293
        293
         	fmt.Fprintf(b, "IsInclusive: %v\n", ba.IsInclusive)

      
        294
        294
         	dumpAmount(b, &ba.Amount, depth+1)

      
        
        295
        +	if ba.Cost != nil {

      
        
        296
        +		dumpCost(b, ba.Cost, depth+1)

      
        
        297
        +	}

      
        295
        298
         }

      
        296
        299
         

      
        297
        300
         func dumpAccount(b *strings.Builder, a Account, depth int) {

      
M journal/ast/entries.go
···
        111
        111
         	IsStrict    bool // ==  vs =

      
        112
        112
         	IsInclusive bool // ===

      
        113
        113
         	Amount      Amount

      
        
        114
        +	Cost        *Cost // price after @/@@

      
        114
        115
         	Span        token.Span

      
        115
        116
         }

      
        116
        117
         

      
M journal/parser/parser.go
···
        952
        952
         	}

      
        953
        953
         	if p.got(token.EQ) || p.got(token.EQEQ) || p.got(token.EQEQEQ) {

      
        954
        954
         		posting.Balance = p.parseBalanceAssertion()

      
        955
        
        -		p.skipWhitespace()

      
        956
        
        -		if p.got(token.AT) || p.got(token.ATAT) {

      
        957
        
        -			p.parseCost()

      
        958
        
        -		}

      
        959
        955
         	}

      
        960
        956
         

      
        961
        957
         	posting.Comment = p.parseOptInlineComment()

      ···
        1000
        996
         	p.skipWhitespace()

      
        1001
        997
         

      
        1002
        998
         	ba.Amount = *p.parseAmount()

      
        
        999
        +	p.skipWhitespace()

      
        
        1000
        +	if p.got(token.AT) || p.got(token.ATAT) {

      
        
        1001
        +		c := p.parseCost()

      
        
        1002
        +		ba.Cost = c

      
        
        1003
        +	}

      
        1003
        1004
         	ba.Span = p.span(s)

      
        1004
        1005
         	return ba

      
        1005
        1006
         }

      
M journal/parser/testdata/transaction_with_costs.golden
···
        77
        77
                   HasSpace: true

      
        78
        78
                   Precision: 0

      
        79
        79
                   Decimal: "."

      
        80
        
        -      BalanceAssertion j:10:34-10:45

      
        
        80
        +      BalanceAssertion j:10:34-11:0

      
        81
        81
                 IsStrict: false

      
        82
        82
                 IsInclusive: false

      
        83
        83
                 Amount j:10:36-10:36

      ···
        87
        87
                   HasSpace: true

      
        88
        88
                   Precision: 2

      
        89
        89
                   Decimal: "."

      
        
        90
        +        Cost(unit) j:10:46-11:0

      
        
        91
        +          Amount j:10:48-10:48

      
        
        92
        +            Quantity: 1

      
        
        93
        +            Commodity: "USD"

      
        
        94
        +            CommodityPos: After

      
        
        95
        +            HasSpace: true

      
        
        96
        +            Precision: 0

      
        
        97
        +            Decimal: "."

      
        90
        98
             Posting j:11:1-13:0

      
        91
        99
               Account j:11:2-12:0

      
        92
        100
                 SubAccount: "assets" j:11:2-11:8

      
M journal/printer/amount.go
···
        5
        5
         	"olexsmir.xyz/clerk/journal/ast"

      
        6
        6
         )

      
        7
        7
         

      
        8
        
        -func (p *printer) writeAmount(a *ast.Amount, pos CommodityPos) {

      
        
        8
        +func (p *printer) writeAmount(a *ast.Amount) {

      
        9
        9
         	if a == nil {

      
        10
        10
         		return

      
        11
        11
         	}

      ···
        15
        15
         		return

      
        16
        16
         	}

      
        17
        17
         

      
        18
        
        -	prec := a.QuantityFmt.Precision

      
        19
        
        -	if prec < 2 {

      
        20
        
        -		prec = 2

      
        21
        
        -	}

      
        
        18
        +	prec := max(a.QuantityFmt.Precision, 2)

      
        22
        19
         

      
        23
        20
         	comm := a.Commodity

      
        24
        21
         	if comm == "" {

      ···
        26
        23
         		return

      
        27
        24
         	}

      
        28
        25
         

      
        29
        
        -	switch pos {

      
        
        26
        +	switch p.cfg.CommodityPos {

      
        30
        27
         	case CommodityBefore:

      
        31
        28
         		p.buf.WriteString(comm)

      
        32
        29
         		if a.HasSpace {

      ···
        44
        41
         	}

      
        45
        42
         }

      
        46
        43
         

      
        47
        
        -func (p *printer) writeCost(c *ast.Cost, pos CommodityPos) {

      
        48
        
        -	if c == nil {

      
        49
        
        -		return

      
        50
        
        -	}

      
        
        44
        +func (p *printer) writeCost(c *ast.Cost) {

      
        51
        45
         	if c.IsTotal {

      
        52
        46
         		p.buf.WriteString(" @@ ")

      
        53
        47
         	} else {

      
        54
        48
         		p.buf.WriteString(" @ ")

      
        55
        49
         	}

      
        56
        
        -	p.writeAmount(&c.Amount, pos)

      
        
        50
        +	p.writeAmount(&c.Amount)

      
        57
        51
         }

      
        58
        52
         

      
        59
        
        -func (p *printer) writeBalanceAssertion(ba *ast.BalanceAssertion, pos CommodityPos) {

      
        
        53
        +func (p *printer) writeBalanceAssertion(ba *ast.BalanceAssertion) {

      
        60
        54
         	if ba == nil {

      
        61
        55
         		return

      
        62
        56
         	}

      ···
        68
        62
         	default:

      
        69
        63
         		p.buf.WriteString("= ")

      
        70
        64
         	}

      
        71
        
        -	p.writeAmount(&ba.Amount, pos)

      
        
        65
        +	p.writeAmount(&ba.Amount)

      
        
        66
        +	if ba.Cost != nil {

      
        
        67
        +		p.writeCost(ba.Cost)

      
        
        68
        +	}

      
        72
        69
         }

      
        73
        70
         

      
        74
        71
         func (p *printer) writeDecimal(d decimal.Decimal, fmt ast.QuantityFormat, forcePrec int) {

      
M journal/printer/directives.go
···
        59
        59
         

      
        60
        60
         func (p *printer) writeDefaultCommodityDirective(d *ast.DefaultCommodityDirective) {

      
        61
        61
         	p.buf.WriteString("D ")

      
        62
        
        -	p.writeAmount(&d.Amount, p.cfg.CommodityPos)

      
        
        62
        +	p.writeAmount(&d.Amount)

      
        63
        63
         	p.writeInlineComment(d.Comment)

      
        64
        64
         }

      
        65
        65
         

      
        66
        66
         func (p *printer) writeConversionDirective(c *ast.ConversionDirective) {

      
        67
        67
         	p.buf.WriteString("C ")

      
        68
        
        -	p.writeAmount(&c.From, p.cfg.CommodityPos)

      
        
        68
        +	p.writeAmount(&c.From)

      
        69
        69
         	p.buf.WriteString(" = ")

      
        70
        
        -	p.writeAmount(&c.To, p.cfg.CommodityPos)

      
        
        70
        +	p.writeAmount(&c.To)

      
        71
        71
         	p.writeInlineComment(c.Comment)

      
        72
        72
         }

      
        73
        73
         

      ···
        78
        78
         	p.buf.WriteByte(' ')

      
        79
        79
         	p.buf.WriteString(m.Commodity)

      
        80
        80
         	p.buf.WriteByte(' ')

      
        81
        
        -	p.writeAmount(&m.Amount, p.cfg.CommodityPos)

      
        
        81
        +	p.writeAmount(&m.Amount)

      
        82
        82
         	p.writeInlineComment(m.Comment)

      
        83
        83
         }

      
        84
        84
         

      
M journal/printer/transaction_postings.go
···
        104
        104
         	}

      
        105
        105
         

      
        106
        106
         	if pt.Amount != nil {

      
        107
        
        -		p.writeAmount(pt.Amount, p.cfg.CommodityPos)

      
        
        107
        +		p.writeAmount(pt.Amount)

      
        108
        108
         		if pt.Cost != nil {

      
        109
        
        -			p.writeCost(pt.Cost, p.cfg.CommodityPos)

      
        
        109
        +			p.writeCost(pt.Cost)

      
        110
        110
         		}

      
        111
        111
         	}

      
        112
        112
         

      ···
        114
        114
         		if pt.Amount != nil {

      
        115
        115
         			p.buf.WriteByte(' ')

      
        116
        116
         		}

      
        117
        
        -		p.writeBalanceAssertion(pt.Balance, p.cfg.CommodityPos)

      
        
        117
        +		p.writeBalanceAssertion(pt.Balance)

      
        118
        118
         	}

      
        119
        119
         

      
        120
        120
         	if pt.Comment != nil && pt.Comment.Text != "" {