4 files changed,
20 insertions(+),
35 deletions(-)
Author:
Oleksandr Smirnov
olexsmir@gmail.com
Committed at:
2026-08-15 18:59:46 +0300
Authored at:
2026-08-14 12:36:25 +0300
Change ID:
ysmnotqokxkwmrnwwtvvnskzpzynytpw
Parent:
83b23d2
M
internal/analyzer/analyzer.go
··· 35 35 Dates []ast.Date // unique transaction dats in sorted order 36 36 DateStrings []string // same order as Dates, "YYYY-MM-DD" 37 37 38 - // TransactionsByKey groups transactions by [TxDuplicateKey] signature. 39 - TransactionsByKey map[string][]*ast.Transaction 38 + TransactionsCountByDate map[string]int // counts transactions per date, keyed by [formatDate] 39 + TransactionsByKey map[string][]*ast.Transaction // groups transactions by [TxDuplicateKey] signature 40 40 } 41 41 42 42 type AccountInfo struct {
M
internal/analyzer/build.go
··· 17 17 } 18 18 19 19 a := &Analysis{ 20 - Files: rj.Occurrences, 21 - Accounts: make(map[string]*AccountInfo), 22 - AccountAliases: make(map[string]string), 23 - Commodities: make(map[string]*CommodityInfo), 24 - Payees: make(map[string]*PayeeInfo), 25 - Tags: make(map[string]*TagInfo), 26 - AccountsByPrefix: make(map[string][]string), 27 - PayeeTemplates: make(map[string][]PostingTemplate), 28 - TransactionsByKey: make(map[string][]*ast.Transaction), 20 + Files: rj.Occurrences, 21 + Accounts: make(map[string]*AccountInfo), 22 + AccountAliases: make(map[string]string), 23 + Commodities: make(map[string]*CommodityInfo), 24 + Payees: make(map[string]*PayeeInfo), 25 + Tags: make(map[string]*TagInfo), 26 + AccountsByPrefix: make(map[string][]string), 27 + PayeeTemplates: make(map[string][]PostingTemplate), 28 + TransactionsByKey: make(map[string][]*ast.Transaction), 29 + TransactionsCountByDate: make(map[string]int), 29 30 } 30 31 for _, item := range rj.Items { 31 32 if item.IsInclude { ··· 81 82 } 82 83 key := TxDuplicateKey(e) 83 84 a.TransactionsByKey[key] = append(a.TransactionsByKey[key], e) 85 + a.TransactionsCountByDate[formatDate(e.Date)]++ 84 86 case *ast.PeriodicTransaction: 85 87 a.PeriodicTransactions = append(a.PeriodicTransactions, e) 86 88 a.addPostings(fileIndex, e.Postings, nil) ··· 299 301 } 300 302 sort.Strings(out) 301 303 return out 304 +} 305 + 306 +// CountTransactionsOnDate returns the number of transactions on d. 307 +func (a *Analysis) CountTransactionsOnDate(d ast.Date) int { 308 + return a.TransactionsCountByDate[formatDate(d)] 302 309 } 303 310 304 311 func formatDate(d ast.Date) string {
M
internal/lsp/textdocument_hover.go
··· 321 321 if tx.Payee != nil { 322 322 fmt.Fprintf(&sb, "\n\n**Payee:** %s", tx.Payee.Name) 323 323 } 324 - fmt.Fprintf(&sb, "\n\n**Transactions:** %d", countTransactionsOnDate(an, tx.Date)) 324 + fmt.Fprintf(&sb, "\n\n**Transactions:** %d", an.CountTransactionsOnDate(tx.Date)) 325 325 fmt.Fprintf(&sb, "\n\n**Postings:** %d", len(tx.Postings)) 326 326 return sb.String() 327 -} 328 - 329 -func countTransactionsOnDate(an *analyzer.Analysis, d ast.Date) int { 330 - count := 0 331 - for _, tx := range an.Transactions { 332 - if tx.Date.Compare(d) == 0 { 333 - count++ 334 - } 335 - } 336 - return count 337 327 } 338 328 339 329 func writeDateSection(sb *strings.Builder, label string, d ast.Date) {
M
internal/lsp/textdocument_hover_test.go
··· 10 10 "go.lsp.dev/protocol" 11 11 "go.lsp.dev/uri" 12 12 13 - "olexsmir.xyz/clerk/internal/analyzer" 14 13 "olexsmir.xyz/clerk/internal/lsp/lsputil" 15 14 "olexsmir.xyz/clerk/internal/testutil/golden" 16 15 "olexsmir.xyz/clerk/journal/ast" ··· 44 43 } 45 44 } 46 45 47 -func TestCountTransactionsOnDate(t *testing.T) { 48 - tx := func(y, m, d int) *ast.Transaction { return &ast.Transaction{Date: ast.Date{Year: y, Month: m, Day: d}} } 49 - an := &analyzer.Analysis{Transactions: []*ast.Transaction{tx(2024, 1, 15), tx(2024, 1, 15), tx(2024, 2, 1)}} 50 - if got := countTransactionsOnDate(an, ast.Date{Year: 2024, Month: 1, Day: 15}); got != 2 { 51 - t.Errorf("got %d, want 2", got) 52 - } 53 - if got := countTransactionsOnDate(an, ast.Date{Year: 2025, Month: 1, Day: 15}); got != 0 { 54 - t.Errorf("got %d, want 0", got) 55 - } 56 -} 57 - 58 -func TestServerHover_DocumentNotFound(t *testing.T) { 46 +func TestServer_Hover_DocumentNotFound(t *testing.T) { 59 47 srv := NewServer("test") 60 48 res, err := srv.server.Hover(context.Background(), &protocol.HoverParams{ 61 49 TextDocumentPositionParams: protocol.TextDocumentPositionParams{