all repos

clerk @ c2e8832a2c559afe23407cc658d65dc877a5caea

missing tooling for ledger/hledger

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

Oleksandr Smirnov Oleksandr Smirnov
olexsmir@gmail.com
add support of subdirectives and it's highlights, 1 month ago
1
package printer
2
3
import (
4
	"strconv"
5
	"strings"
6
7
	"olexsmir.xyz/clerk/journal/ast"
8
)
9
10
func (p *printer) writeIncludeDirective(i *ast.IncludeDirective) {
11
	p.buf.WriteString("include ")
12
	p.buf.WriteString(quoteString(i.Path))
13
	p.writeInlineComment(i.Comment)
14
}
15
16
func (p *printer) writeAccountDirective(a *ast.AccountDirective) {
17
	p.buf.WriteString("account ")
18
	p.buf.WriteString(a.Account.String())
19
	p.writeInlineComment(a.Comment)
20
	for _, sd := range a.Subdirectives {
21
		p.buf.WriteByte('\n')
22
		p.buf.WriteString(p.indent)
23
		if sd.Name == "" {
24
			p.writeComment(sd.Comment)
25
			continue
26
		}
27
		p.buf.WriteString(sd.Name)
28
		p.buf.WriteByte(' ')
29
		p.buf.WriteString(sd.Value)
30
		p.writeInlineComment(sd.Comment)
31
	}
32
}
33
34
func (p *printer) writeCommodityDirective(c *ast.CommodityDirective) {
35
	p.buf.WriteString("commodity ")
36
	if c.FormatSub == nil {
37
		p.buf.WriteString(c.Commodity)
38
		p.writeInlineComment(c.Comment)
39
		return
40
	}
41
	if c.FormatSub.KeywordSpan.End.Offset == 0 {
42
		// inline form: "commodity $1,000.00"
43
		p.writeCommodityAmount(&c.FormatSub.Amount)
44
		p.writeInlineComment(c.Comment)
45
		return
46
	}
47
	p.buf.WriteString(c.Commodity)
48
	p.writeInlineComment(c.Comment)
49
	p.buf.WriteByte('\n')
50
	p.buf.WriteString(p.indent)
51
	p.buf.WriteString("format ")
52
	p.writeCommodityAmount(&c.FormatSub.Amount)
53
	p.writeInlineComment(c.FormatSub.Comment)
54
	p.writeBlockComments(c.BlockComments)
55
}
56
57
// writeCommodityAmount renders a commodity format amount, preserving the
58
// original commodity placement instead of the config's CommodityPos.
59
func (p *printer) writeCommodityAmount(a *ast.Amount) {
60
	prec := max(a.QuantityFmt.Precision, 2)
61
	if a.Commodity == "" {
62
		p.writeDecimal(a.Quantity, a.QuantityFmt, prec)
63
		return
64
	}
65
	switch a.CommodityPos {
66
	case ast.CommodityBefore:
67
		p.buf.WriteString(a.Commodity)
68
		if a.HasSpace {
69
			p.buf.WriteByte(' ')
70
		}
71
		p.writeDecimal(a.Quantity, a.QuantityFmt, prec)
72
	case ast.CommodityAfter:
73
		p.writeDecimal(a.Quantity, a.QuantityFmt, prec)
74
		if a.HasSpace {
75
			p.buf.WriteByte(' ')
76
		}
77
		p.buf.WriteString(a.Commodity)
78
	}
79
}
80
81
// writeBlockComments writes indented comment lines inside a directive block.
82
func (p *printer) writeBlockComments(cs []*ast.Comment) {
83
	for _, c := range cs {
84
		p.buf.WriteByte('\n')
85
		p.buf.WriteString(p.indent)
86
		p.writeComment(c)
87
	}
88
}
89
90
func (p *printer) writeAliasDirective(a *ast.AliasDirective) {
91
	p.buf.WriteString("alias ")
92
	p.buf.WriteString(a.From.String())
93
	p.buf.WriteString(" = ")
94
	p.buf.WriteString(a.To.String())
95
	p.writeInlineComment(a.Comment)
96
}
97
98
func (p *printer) writePayeeDirective(pd *ast.PayeeDirective) {
99
	p.buf.WriteString("payee ")
100
	p.buf.WriteString(quoteString(pd.Name.Name))
101
	p.writeInlineComment(pd.Comment)
102
}
103
104
func (p *printer) writeTagDirective(t *ast.TagDirective) {
105
	p.buf.WriteString("tag ")
106
	p.buf.WriteString(quoteString(t.Name))
107
	p.writeInlineComment(t.Comment)
108
}
109
110
func (p *printer) writeYearDirective(y *ast.YearDirective) {
111
	p.buf.WriteString("year ")
112
	p.writeInt(y.Year, 4)
113
	p.writeInlineComment(y.Comment)
114
}
115
116
func (p *printer) writeDecimalMarkDirective(d *ast.DecimalMarkDirective) {
117
	p.buf.WriteString("decimal-mark ")
118
	p.buf.WriteByte(d.Mark)
119
	p.writeInlineComment(d.Comment)
120
}
121
122
func (p *printer) writeDefaultCommodityDirective(d *ast.DefaultCommodityDirective) {
123
	p.buf.WriteString("D ")
124
	p.writeAmount(&d.Amount)
125
	p.writeInlineComment(d.Comment)
126
}
127
128
func (p *printer) writeConversionDirective(c *ast.ConversionDirective) {
129
	p.buf.WriteString("C ")
130
	p.writeAmount(&c.From)
131
	p.buf.WriteString(" = ")
132
	p.writeAmount(&c.To)
133
	p.writeInlineComment(c.Comment)
134
}
135
136
func (p *printer) writeMarketPriceDirective(m *ast.MarketPriceDirective) {
137
	p.buf.WriteString("P ")
138
	p.writeDate(m.DateTime.Date)
139
	p.writeTime(m.DateTime.Time)
140
	p.buf.WriteByte(' ')
141
	p.buf.WriteString(m.Commodity)
142
	p.buf.WriteByte(' ')
143
	p.writeAmount(&m.Amount)
144
	p.writeInlineComment(m.Comment)
145
}
146
147
func (p *printer) writeCommentBlockDirective(cb *ast.CommentBlockDirective) {
148
	p.buf.WriteString("comment")
149
	if cb.Header != "" {
150
		p.buf.WriteByte(' ')
151
		p.buf.WriteString(cb.Header)
152
	}
153
	p.buf.WriteByte('\n')
154
	if cb.Content != "" {
155
		p.buf.WriteString(cb.Content)
156
		if !strings.HasSuffix(cb.Content, "\n") {
157
			p.buf.WriteByte('\n')
158
		}
159
	}
160
	p.buf.WriteString("end\n")
161
}
162
163
func (p *printer) writeApplyDirective(a *ast.ApplyDirective) {
164
	p.buf.WriteString("apply ")
165
	p.buf.WriteString(a.Expr)
166
	p.writeInlineComment(a.Comment)
167
}
168
169
func (p *printer) writeEndDirective(e *ast.EndDirective) {
170
	p.buf.WriteString("end")
171
	if e.Expr != "" {
172
		p.buf.WriteByte(' ')
173
		p.buf.WriteString(e.Expr)
174
	}
175
	p.writeInlineComment(e.Comment)
176
}
177
178
func (p *printer) writeIgnoredDirective(e *ast.IgnoredDirective) {
179
	p.buf.WriteString("N ")
180
	p.buf.WriteString(e.Text)
181
	p.writeInlineComment(e.Comment)
182
}
183
184
func quoteString(s string) string {
185
	needsQuote := false
186
	for _, c := range s {
187
		if c == ' ' || c == '\t' || c == '"' || c == ';' || c == '#' {
188
			needsQuote = true
189
			break
190
		}
191
	}
192
	if !needsQuote {
193
		return s
194
	}
195
	return strconv.Quote(s)
196
}