src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

commit 4837130a3e1358de58b2ce3e8c8a24497b2ca89a
parent 354c1cca7947cf0743f718f5ec9b26ec068f695e
Author: dwrz <dwrz@dwrz.net>
Date:   Sat, 20 May 2023 19:16:14 +0000

Refactor wisdom

Diffstat:
Mcmd/wisdom/wisdom.go | 17++++++++++++-----
Mpkg/wisdom/quote/quote.go | 14++++++--------
Mpkg/wisdom/wisdom.go | 68+++++++++++++++++++++++++++++++++++++++++++++++++-------------------
3 files changed, 67 insertions(+), 32 deletions(-)

diff --git a/cmd/wisdom/wisdom.go b/cmd/wisdom/wisdom.go @@ -6,13 +6,10 @@ import ( "path/filepath" "code.dwrz.net/src/pkg/log" + "code.dwrz.net/src/pkg/terminal" "code.dwrz.net/src/pkg/wisdom" ) -var ( - wrap = flag.Int("w", 72, "word wrap; disabled if negative") -) - func main() { var l = log.New(os.Stderr) @@ -23,10 +20,20 @@ func main() { l.Error.Fatalf("failed to get user config dir: %v", err) } + terminal, err := terminal.New(os.Stdin.Fd()) + if err != nil { + l.Error.Fatalf("failed to create terminal: %v", err) + } + + size, err := terminal.Size() + if err != nil { + l.Error.Fatalf("failed to get terminal size: %v", err) + } + w, err := wisdom.New(wisdom.Parameters{ Log: l, Path: filepath.Join(dir, "wisdom"), - Wrap: *wrap, + Size: size, }) if err := w.Command(flag.CommandLine.Args()); err != nil { diff --git a/pkg/wisdom/quote/quote.go b/pkg/wisdom/quote/quote.go @@ -2,8 +2,6 @@ package quote import ( "strings" - - "code.dwrz.net/src/pkg/text" ) type Quote struct { @@ -14,26 +12,26 @@ type Quote struct { Text string `json:"text"` } -func (q *Quote) Render(width int) string { +func (q *Quote) Render() string { var str strings.Builder - str.WriteString(text.Wrap(q.Text, width)) + str.WriteString(q.Text) if q.Author != "" || q.Source != "" { str.WriteString("\n\n") } if q.Author != "" { - str.WriteString(text.Wrap(q.Author, width)) + str.WriteString(q.Author) } if q.Author != "" && q.Source != "" { str.WriteString(", ") } if q.Source != "" { - str.WriteString(text.Wrap(q.Source, width)) + str.WriteString(q.Source) } if q.Comment != "" { str.WriteString("\n\n") - str.WriteString(text.Wrap(q.Comment, width)) + str.WriteString(q.Comment) } if len(q.Tags) > 0 { str.WriteString("\nTags: ") @@ -41,7 +39,7 @@ func (q *Quote) Render(width int) string { for tag := range q.Tags { tags += tag + " " } - str.WriteString(text.Wrap(tags, width)) + str.WriteString(tags) } return str.String() diff --git a/pkg/wisdom/wisdom.go b/pkg/wisdom/wisdom.go @@ -9,13 +9,14 @@ import ( "os/exec" "path/filepath" "strings" - "text/tabwriter" "unicode" "github.com/google/uuid" + "github.com/mattn/go-runewidth" "code.dwrz.net/src/pkg/log" "code.dwrz.net/src/pkg/store" + "code.dwrz.net/src/pkg/terminal" "code.dwrz.net/src/pkg/text" "code.dwrz.net/src/pkg/wisdom/quote" ) @@ -25,13 +26,13 @@ const coll = "data" type Parameters struct { Log *log.Logger Path string - Wrap int + Size *terminal.Size } type Wisdom struct { log *log.Logger store *store.Store - wrap int + size *terminal.Size } func New(p Parameters) (*Wisdom, error) { @@ -50,7 +51,7 @@ func New(p Parameters) (*Wisdom, error) { return &Wisdom{ log: p.Log, store: store, - wrap: p.Wrap, + size: p.Size, }, nil } @@ -69,7 +70,7 @@ func (w *Wisdom) Command(args []string) error { ) } - fmt.Println(q.Render(w.wrap)) + fmt.Println(q.Render()) return nil } @@ -258,8 +259,8 @@ func (w *Wisdom) list() error { return fmt.Errorf("failed to load quotes: %v", err) } - tw := tabwriter.NewWriter(os.Stdout, 1, 1, 1, ' ', 0) - fmt.Fprintln(tw, "Id\tText\tAuthor\tSource\t") + var output strings.Builder + output.WriteString("id,author,source,text\n") for _, d := range docs { var q = &quote.Quote{} @@ -271,20 +272,49 @@ func (w *Wisdom) list() error { continue } - var t = q.Text - if w.wrap > 0 { - t = text.Truncate(q.Text, w.wrap-1) + "…" + var ( + line strings.Builder + // Account for the final newline. + space = int(w.size.Columns) + ) + // Id + line.WriteString(text.Truncate(d.Id, space)) + space -= runewidth.StringWidth(d.Id) + line.WriteByte(',') + space -= 1 + + // Author + line.WriteString(text.Truncate(q.Author, space)) + space -= runewidth.StringWidth(q.Author) + line.WriteByte(',') + space -= 1 + + // Source + line.WriteString(text.Truncate(q.Source, space)) + space -= runewidth.StringWidth(q.Source) + line.WriteByte(',') + space -= 1 + + // Text + t := strings.ReplaceAll(q.Text, "\n", " ") + switch { + case space < 1: + // Don't output text. + case len(t) > space: + line.WriteString(text.Truncate( + t, + space-runewidth.RuneWidth('…'), + )) + line.WriteRune('…') + default: + line.WriteString(t) } + line.WriteByte('\n') - fmt.Fprintf( - tw, "%s\t%s\t%s\t%s\t\n", - d.Id, - strings.ReplaceAll(t, "\n", " "), - q.Author, - q.Source, - ) + output.WriteString(line.String()) } - tw.Flush() + + fmt.Println(output.String()) return nil } @@ -318,7 +348,7 @@ func (w *Wisdom) show(args []string) error { ) } - fmt.Println(q.Render(w.wrap)) + fmt.Println(q.Render()) } return nil