all repos

clerk @ e2e9e2b27783c07fe5724268bf7ae828b3aacac7

missing tooling for ledger/hledger

clerk/journal/printer/transaction_postings.go (view raw)

Oleksandr Smirnov Oleksandr Smirnov
olexsmir@gmail.com
linter: add missing transaction status, 1 month ago
1
package printer
2
3
import (
4
	"fmt"
5
	"strings"
6
	"text/tabwriter"
7
8
	"olexsmir.xyz/clerk/journal/ast"
9
)
10
11
func (p *printer) writePostings(postings []*ast.Posting) {
12
	if len(postings) == 0 {
13
		return
14
	}
15
16
	maxAcct := measureTxAccts(postings)
17
	if p.cfg.AlignStyle == AlignTwoSpaces {
18
		p.writePostingsTwoSpaces(postings, maxAcct)
19
	} else {
20
		p.writePostingsTabbed(postings, maxAcct)
21
	}
22
}
23
24
func (p *printer) writePostingsTwoSpaces(postings []*ast.Posting, maxAcct int) {
25
	for _, pt := range postings {
26
		p.writePostingLine(pt, maxAcct)
27
		p.buf.WriteByte('\n')
28
		for _, c := range pt.Comments {
29
			p.buf.WriteString(p.indent)
30
			p.writeComment(&c)
31
			p.buf.WriteByte('\n')
32
		}
33
	}
34
}
35
36
func (p *printer) writePostingsTabbed(postings []*ast.Posting, maxAcct int) {
37
	var tmp strings.Builder
38
	tw := tabwriter.NewWriter(&tmp, 0, 0, 2, ' ', tabwriter.StripEscape)
39
40
	lp := &printer{cfg: p.cfg, indent: p.indent}
41
	for _, pt := range postings {
42
		lp.buf.Reset()
43
		lp.writePostingLine(pt, maxAcct)
44
		fmt.Fprintln(tw, lp.buf.String())
45
		for _, c := range pt.Comments {
46
			lp.buf.Reset()
47
			lp.buf.WriteString(lp.indent)
48
			lp.writeComment(&c)
49
			fmt.Fprintln(tw, lp.buf.String())
50
		}
51
	}
52
	tw.Flush()
53
54
	out := strings.TrimRight(tmp.String(), "\n")
55
	if out == "" {
56
		return
57
	}
58
	p.buf.WriteString(out)
59
	p.buf.WriteByte('\n')
60
}
61
62
func (p *printer) writePostingLine(pt *ast.Posting, maxAcct int) {
63
	p.buf.WriteString(p.indent)
64
65
	if pt.Status.Value != ast.StatusNone {
66
		p.buf.WriteString(pt.Status.Value.String())
67
		p.buf.WriteByte(' ')
68
	}
69
70
	acct := pt.Account.String()
71
	switch pt.Type {
72
	case ast.PostingVirtualUnbalanced:
73
		acct = "(" + acct + ")"
74
	case ast.PostingVirtualBalanced:
75
		acct = "[" + acct + "]"
76
	}
77
	p.buf.WriteString(acct)
78
79
	if pt.Amount != nil || pt.Balance != nil {
80
		switch p.cfg.AlignStyle {
81
		case AlignTwoSpaces:
82
			p.buf.WriteString("  ")
83
		case AlignRight:
84
			current := len(p.indent) + len(acct)
85
			if pt.Status.Value != ast.StatusNone {
86
				current++
87
			}
88
			if pad := p.cfg.AlignColumn - current; pad > 0 {
89
				p.writeSpaces(pad)
90
			}
91
			p.buf.WriteByte('\v')
92
		case AlignTab:
93
			current := len(p.indent) + len(acct)
94
			if pt.Status.Value != ast.StatusNone {
95
				current++
96
			}
97
			if pad := maxAcct + len(p.indent) - current; pad > 0 {
98
				p.writeSpaces(pad)
99
			}
100
			p.buf.WriteByte('\v')
101
		default:
102
			panic("impossible AlignStyle state")
103
		}
104
	}
105
106
	if pt.Amount != nil {
107
		p.writeAmount(pt.Amount)
108
		if pt.Cost != nil {
109
			p.writeCost(pt.Cost)
110
		}
111
	}
112
113
	if pt.Balance != nil {
114
		if pt.Amount != nil {
115
			p.buf.WriteByte(' ')
116
		}
117
		p.writeBalanceAssertion(pt.Balance)
118
	}
119
120
	if pt.Comment != nil && pt.Comment.Text != "" {
121
		if p.cfg.AlignStyle == AlignTwoSpaces {
122
			p.buf.WriteString("  ")
123
		} else {
124
			p.buf.WriteByte('\v')
125
		}
126
		p.buf.WriteString("; ")
127
		p.buf.WriteString(pt.Comment.Text)
128
	}
129
}
130
131
func measureTxAccts(postings []*ast.Posting) int {
132
	maxAcct := 0
133
	for _, p := range postings {
134
		n := len(p.Account.Name)
135
		if p.Type == ast.PostingVirtualUnbalanced || p.Type == ast.PostingVirtualBalanced {
136
			n += 2
137
		}
138
		if n > maxAcct {
139
			maxAcct = n
140
		}
141
	}
142
	return maxAcct
143
}