Skip to content

Commit

Permalink
split Notes into a slice of lines
Browse files Browse the repository at this point in the history
  • Loading branch information
mkobetic committed Dec 7, 2023
1 parent 176804e commit d4413c7
Show file tree
Hide file tree
Showing 22 changed files with 117 additions and 89 deletions.
2 changes: 1 addition & 1 deletion account.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ func (p *Parser) parseAccount(fn string) (*Account, error) {
}
match = accountBodyREX.Match(line)
if match == nil {
return a, fmt.Errorf("Unrecognized account line: %s", p.Text())
return a, fmt.Errorf("unrecognized account line: %s", p.Text())
}
if n := match["note"]; n != "" {
a.Description = n
Expand Down
2 changes: 1 addition & 1 deletion amount.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ func parseAmount(s string, c *Commodity) (*Amount, error) {
return NewAmount(bi, c), nil
}
if len(ss) != 2 {
return nil, fmt.Errorf("Malformed value %s", s)
return nil, fmt.Errorf("malformed value %s", s)
}
s = strings.Join(ss, "")
i, err := strconv.ParseInt(s, 10, 64)
Expand Down
15 changes: 15 additions & 0 deletions assert/assert.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,21 @@ func Equal(t *testing.T, actual, expected interface{}, args ...interface{}) bool
return false
}

func EqualStrings(t *testing.T, actual []string, expected ...string) bool {
t.Helper()
if len(actual) != len(expected) {
t.Errorf("length difference, expected: %d actual: %d\n", len(expected), len(actual))
return false
}
for i, v := range actual {
if v != expected[i] {
t.Errorf("element %d difference, expected: %s actual: %s\n", i, expected[i], v)
return false
}
}
return true
}

func NotNil(t *testing.T, v interface{}, args ...interface{}) bool {
t.Helper()
if v != nil {
Expand Down
4 changes: 2 additions & 2 deletions cmd/coin/format.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ func (cmd *cmdFormat) execute(f io.Writer) {
func (cmd *cmdFormat) writeTransactions(f io.Writer) {
for _, t := range coin.Transactions {
if cmd.trimWS {
t.Description = trimWS(t.Description)
t.Note = trimWS(t.Note)
t.Description = trimWS(t.Description)[0]
t.Notes = trimWS(t.Notes...)
}
t.Write(f, cmd.ledger)
fmt.Fprintln(f)
Expand Down
16 changes: 4 additions & 12 deletions cmd/coin/postings.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ func (ps postings) print(f io.Writer, opts *options) {
args = append(args, trimLocation(s.Transaction.Location()))
}
fmt.Fprintf(f, fmtString, args...)
if opts.showNotes && (len(s.Note) > 0 || len(s.Transaction.Note) > 0) {
if opts.showNotes && (len(s.Notes) > 0 || len(s.Transaction.Notes) > 0) {
printNotes(f, strings.Repeat(" ", len(args[0].(string)))+" ;", s)
}
}
Expand Down Expand Up @@ -124,24 +124,16 @@ func (ps postings) printLong(f io.Writer, opts *options) {
args = append(args, trimLocation(s.Transaction.Location()))
}
fmt.Fprintf(f, fmtString, args...)
if opts.showNotes && (len(s.Note) > 0 || len(s.Transaction.Note) > 0) {
if opts.showNotes && (len(s.Notes) > 0 || len(s.Transaction.Notes) > 0) {
printNotes(f, strings.Repeat(" ", len(args[0].(string)))+" ;", s)
}
}
}

func printNotes(w io.Writer, prefix string, p *coin.Posting) {
var notes string
if len(p.Note) > 0 {
notes = p.Note
for _, line := range append(p.Notes, p.Transaction.Notes...) {
fmt.Fprintln(w, prefix, line)
}
if len(p.Transaction.Note) > 0 {
if len(notes) > 0 {
notes += "\n"
}
notes += p.Transaction.Note
}
printLines(w, prefix, notes)
}

type options struct {
Expand Down
26 changes: 6 additions & 20 deletions cmd/coin/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@ package main

import (
"bufio"
"bytes"
"compress/gzip"
"encoding/base64"
"fmt"
"io"
"sort"
"strings"
Expand Down Expand Up @@ -47,16 +45,10 @@ func trim(ps []*coin.Posting, begin, end coin.Date) []*coin.Posting {
return ps
}

func trimWS(in string) string {
lines := bufio.NewScanner(strings.NewReader(in))
var w strings.Builder
lIsFirst := true
for lines.Scan() {
if !lIsFirst {
w.WriteByte('\n')
}
lIsFirst = false
words := bufio.NewScanner(bytes.NewReader(lines.Bytes()))
func trimWS(in ...string) (out []string) {
for _, line := range in {
var w strings.Builder
words := bufio.NewScanner(strings.NewReader(line))
words.Split(bufio.ScanWords)
wIsFirst := true
for words.Scan() {
Expand All @@ -66,13 +58,7 @@ func trimWS(in string) string {
w.Write(words.Bytes())
wIsFirst = false
}
out = append(out, w.String())
}
return w.String()
}

func printLines(w io.Writer, prefix string, lines string) {
text := bufio.NewScanner(strings.NewReader(lines))
for text.Scan() {
fmt.Fprintln(w, prefix, text.Text())
}
return out
}
8 changes: 4 additions & 4 deletions cmd/coin/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ import (

func Test_TrimWS(t *testing.T) {
for _, tc := range []struct {
in, out string
in, out []string
}{
{" a bb \n ddd \n ", "a bb\nddd\n"},
{"xx[ 7 ]\n !yyy", "xx[ 7 ]\n!yyy"},
{[]string{" a bb ", " ddd ", " "}, []string{"a bb", "ddd", ""}},
{[]string{"xx[ 7 ]", " !yyy"}, []string{"xx[ 7 ]", "!yyy"}},
} {
assert.Equal(t, trimWS(tc.in), tc.out)
assert.EqualStrings(t, trimWS(tc.in...), tc.out...)
}
}
6 changes: 4 additions & 2 deletions cmd/csv2coin/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ func transactionFrom(row []string, fields map[string]Fields, allRules *Rules) *c
return fields[name].Value(row, fields)
}
acctId := valueFor("account")
description := valueFor("description")
description := trim(valueFor("description"))
rules := allRules.AccountRulesFor(acctId)
check.If(rules != nil, "Can't find rules for account id %s", acctId)
account := rules.Account
Expand All @@ -133,7 +133,9 @@ func transactionFrom(row []string, fields map[string]Fields, allRules *Rules) *c
Posted: posted,
}

t.Note = valueFor("note")
if n := trim(valueFor("note")); len(n) > 0 {
t.Notes = []string{n}
}

var amount *coin.Amount
if amt := valueFor("amount"); amt != "" {
Expand Down
2 changes: 1 addition & 1 deletion cmd/csv2coin/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ func Test_Sample1(t *testing.T) {
txs := readTransactions(r, rules.sources["src"], rules)
for i, exp := range []string{
// symbol=VXF, quantity=123.999, amount=1630.59
`2019/09/10 DRIP ; blah blah VALUE = 1630.59
`2019/09/10 DRIP ; blah blah VALUE = 1630.59
Assets:Investments:XXX:VXF 123.999 VXF
Income:Dividends -1630.59 USD
`,
Expand Down
21 changes: 21 additions & 0 deletions cmd/csv2coin/utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package main

import (
"bufio"
"strings"
)

func trim(in string) string {
scanner := bufio.NewScanner(strings.NewReader(strings.TrimSpace(in)))
scanner.Split(bufio.ScanWords)
var w strings.Builder
isFirst := true
for scanner.Scan() {
if !isFirst {
w.WriteByte(' ')
}
w.Write(scanner.Bytes())
isFirst = false
}
return w.String()
}
18 changes: 18 additions & 0 deletions cmd/csv2coin/utils_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package main

import (
"testing"

"github.com/mkobetic/coin/assert"
)

func Test_Trim(t *testing.T) {
for _, tc := range []struct {
in, out string
}{
{" a bb ddd ", "a bb ddd"},
{"xx[ 7 ] !yyy", "xx[ 7 ] !yyy"},
} {
assert.Equal(t, trim(tc.in), tc.out)
}
}
4 changes: 2 additions & 2 deletions coin.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func MustFindCommodity(id string, location string) *Commodity {
if c := Commodities[id]; c != nil {
return c
}
panic(fmt.Errorf("Can't find commodity %s\n\t%s\n", id, location))
panic(fmt.Errorf("cannot find commodity %s\n\t%s\n", id, location))
}

func LoadPrices() {
Expand Down Expand Up @@ -280,7 +280,7 @@ func MustFindAccount(pattern string) *Account {
}
as := FindAccounts(pattern)
if len(as) == 0 {
panic(fmt.Errorf("Can't find account %s", pattern))
panic(fmt.Errorf("cannot find account %s", pattern))
}
if len(as) == 1 {
return as[0]
Expand Down
12 changes: 6 additions & 6 deletions commodity.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,11 @@ func (c *Commodity) Location() string {

/*
commodity USD
note American Dollars
format 1000.00 USD
nomarket
default
note American Dollars
format 1000.00 USD
nomarket
default
*/
func (c *Commodity) Write(w io.Writer, ledger bool) error {
format := "1"
Expand Down Expand Up @@ -151,7 +151,7 @@ func (p *Parser) parseCommodity(fn string) (*Commodity, error) {
}
match = commodityBodyREX.Match(line)
if match == nil {
return c, fmt.Errorf("Unrecognized commodity line: %s", p.Text())
return c, fmt.Errorf("unrecognized commodity line: %s", p.Text())
}
if n := match["note"]; n != "" {
c.Name = n
Expand Down Expand Up @@ -216,7 +216,7 @@ func (c *Commodity) convert(amount *Amount, c2 *Commodity, previous []*Commodity
}
}
// Didn't find any path that leads to c
return nil, fmt.Errorf("Cannot convert %s => %s", c2.Id, c.Id)
return nil, fmt.Errorf("cannot convert %s => %s", c2.Id, c.Id)
}

func (c *Commodity) NewAmountFloat(f float64) *Amount {
Expand Down
4 changes: 2 additions & 2 deletions date.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func (d *Date) String() string {
func (d *Date) Set(s string) (err error) {
match := DateREX.Match([]byte(s))
if match == nil {
return fmt.Errorf("Invalid date: %s", s)
return fmt.Errorf("invalid date: %s", s)
}
d.Time, err = parseDate(match, 0)
return err
Expand Down Expand Up @@ -59,7 +59,7 @@ func MustParseDate(s string) time.Time {

func parseDate(match map[string]string, idx int) (t time.Time, err error) {
if idx > 0 {
return t, fmt.Errorf("Multiple date fields not implemented!")
return t, fmt.Errorf("multiple date fields not implemented!")
}
// Set date to today
y, m, d := Year, Month, Day
Expand Down
5 changes: 4 additions & 1 deletion gnucash/split.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@ type Split struct {

func resolveSplits(splits []*Split, t *coin.Transaction) {
for _, gs := range splits {
s := &coin.Posting{Note: gs.Memo, Transaction: t}
s := &coin.Posting{Transaction: t}
if n := gs.Memo; len(n) > 0 {
s.Notes = []string{n}
}
t.Postings = append(t.Postings, s)
s.Account = mustFindAccount(gs.AccountGuid)
s.Account.Postings = append(s.Account.Postings, s)
Expand Down
4 changes: 2 additions & 2 deletions gnucash/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ func resolveTransactions(transactions []*Transaction) {
Code: gt.Num,
Description: ds[0],
}
if len(ds) == 2 {
t.Note = ds[1]
if len(ds) == 2 && len(ds[1]) > 0 {
t.Notes = []string{ds[1]}
}
t.Posted = mustParseTimeStamp(gt.PostedStamp)
resolveSplits(gt.Splits, t)
Expand Down
2 changes: 1 addition & 1 deletion parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,6 @@ func (p *Parser) Next(fn string) (Item, error) {
case '0' <= line[0] && line[0] <= '9':
return p.parseTransaction(fn)
default:
return nil, fmt.Errorf("Unrecognized item: %s", line)
return nil, fmt.Errorf("unrecognized item: %s", line)
}
}
7 changes: 2 additions & 5 deletions posting.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
)

type Posting struct {
Note string
Notes []string

Transaction *Transaction
Account *Account
Expand All @@ -19,10 +19,7 @@ type Posting struct {
}

func (s *Posting) Write(w io.Writer, accountOffset, accountWidth, amountWidth int, ledger bool) error {
var notes []string
if s.Note != "" {
notes = strings.Split(s.Note, "\n")
}
notes := s.Notes
commodity := s.Quantity.Commodity
line := fmt.Sprintf("%*s%-*s %*.*f %s",
accountOffset, "",
Expand Down
2 changes: 1 addition & 1 deletion price.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ var priceREX = rex.MustCompile(`P %s\s+%s\s+%s`, DateREX, CommodityREX, AmountRE
func (p *Parser) parsePrice(fn string) (*Price, error) {
match := priceREX.Match(p.Bytes())
if match == nil {
return nil, fmt.Errorf("Invalid price line")
return nil, fmt.Errorf("invalid price line")
}
date := mustParseDate(match, 0)
currencyId := string(match["commodity2"])
Expand Down
2 changes: 1 addition & 1 deletion rules.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ func ScanRules(line []byte, s *bufio.Scanner) (*RuleIndex, error) {
} else {
r := ri.SetsByName[string(match[4])]
if r == nil {
panic(fmt.Errorf("Invalid rule set ref: %s", string(match[4])))
panic(fmt.Errorf("invalid rule set ref: %s", string(match[4])))
}
rules = append(rules, r)
}
Expand Down
Loading

0 comments on commit d4413c7

Please sign in to comment.