src

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

commit 3b7bfee9afa33983ed6c09dfdf1c31b4f41dc5be
parent b4cb819fe26aa013fa744e8b859d01c991733805
Author: dwrz <dwrz@dwrz.net>
Date:   Sun, 22 Mar 2026 12:55:16 +0000

Remove wisdom

Diffstat:
Dcmd/wisdom/wisdom.go | 50--------------------------------------------------
Dpkg/wisdom/quote/quote.go | 46----------------------------------------------
Dpkg/wisdom/wisdom.go | 355-------------------------------------------------------------------------------
3 files changed, 0 insertions(+), 451 deletions(-)

diff --git a/cmd/wisdom/wisdom.go b/cmd/wisdom/wisdom.go @@ -1,50 +0,0 @@ -package main - -import ( - "flag" - "os" - "path/filepath" - - "code.dwrz.net/src/pkg/log" - "code.dwrz.net/src/pkg/terminal" - "code.dwrz.net/src/pkg/wisdom" -) - -func main() { - var l = log.New(os.Stderr) - - flag.Parse() - - dir, err := os.UserConfigDir() - if err != nil { - l.Error.Fatalf("failed to get user config dir: %v", err) - } - - var params = wisdom.Parameters{ - Log: l, - Path: filepath.Join(dir, "wisdom"), - } - - terminal, err := terminal.New(os.Stdin.Fd()) - if err != nil { - l.Error.Printf("failed to create terminal: %v", err) - } - - if terminal != nil { - size, err := terminal.Size() - if err != nil { - l.Error.Printf("failed to get terminal size: %v", err) - } - - params.Size = *size - } - - w, err := wisdom.New(params) - if err != nil { - l.Error.Fatalf("failed to create command: %v", err) - } - - if err := w.Command(flag.CommandLine.Args()); err != nil { - l.Error.Fatal(err) - } -} diff --git a/pkg/wisdom/quote/quote.go b/pkg/wisdom/quote/quote.go @@ -1,46 +0,0 @@ -package quote - -import ( - "strings" -) - -type Quote struct { - Author string `json:"author"` - Comment string `json:"comment"` - Source string `json:"source"` - Tags map[string]struct{} `json:"tags"` - Text string `json:"text"` -} - -func (q *Quote) Render() string { - var str strings.Builder - - str.WriteString(q.Text) - - if q.Author != "" || q.Source != "" { - str.WriteString("\n\n") - } - if q.Author != "" { - str.WriteString(q.Author) - } - if q.Author != "" && q.Source != "" { - str.WriteString(", ") - } - if q.Source != "" { - str.WriteString(q.Source) - } - if q.Comment != "" { - str.WriteString("\n\n") - str.WriteString(q.Comment) - } - if len(q.Tags) > 0 { - str.WriteString("\nTags: ") - var tags string - for tag := range q.Tags { - tags += tag + " " - } - str.WriteString(tags) - } - - return str.String() -} diff --git a/pkg/wisdom/wisdom.go b/pkg/wisdom/wisdom.go @@ -1,355 +0,0 @@ -package wisdom - -import ( - "bufio" - "encoding/json" - "fmt" - "io" - "os" - "os/exec" - "path/filepath" - "strings" - "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" -) - -const coll = "data" - -type Parameters struct { - Log *log.Logger - Path string - Size terminal.Size -} - -type Wisdom struct { - log *log.Logger - store *store.Store - size terminal.Size -} - -func New(p Parameters) (*Wisdom, error) { - store, err := store.New(store.Parameters{ - Log: p.Log, - Path: p.Path, - }) - if err != nil { - return nil, fmt.Errorf("failed to create store: %v", err) - } - - if err := store.NewCollection(coll); err != nil { - return nil, fmt.Errorf("failed to create collection: %v", err) - } - - return &Wisdom{ - log: p.Log, - store: store, - size: p.Size, - }, nil -} - -func (w *Wisdom) Command(args []string) error { - // Show a random quote by default. - if len(args) == 0 { - d, err := w.store.Collection(coll).Random() - if err != nil { - return fmt.Errorf("failed to load quote: %v", err) - } - - var q quote.Quote - if err := d.Unmarshal(&q); err != nil { - return fmt.Errorf( - "failed to unmarshal document: %v", err, - ) - } - - fmt.Println(q.Render()) - - return nil - } - - command, rest := args[0], args[1:] - switch command { - case "add": - if err := w.add(); err != nil { - return fmt.Errorf("failed to add quote: %v", err) - } - - case "edit": - if err := w.edit(rest); err != nil { - return fmt.Errorf("failed to edit quote: %v", err) - } - - case "show": - if err := w.show(rest); err != nil { - return fmt.Errorf("failed to show quote: %v", err) - } - - case "list": - if err := w.list(); err != nil { - return fmt.Errorf("failed to list quotes: %v", err) - } - - case "remove": - if err := w.remove(rest); err != nil { - return fmt.Errorf("failed to remove quote: %v", err) - } - - default: - return fmt.Errorf("unrecognized command: %v", command) - } - - return nil -} - -func (w *Wisdom) add() error { - var ( - in = bufio.NewReader(os.Stdin) - str strings.Builder - q = quote.Quote{ - Tags: map[string]struct{}{}, - } - ) - - // Text - fmt.Print("Text (Ctrl-D for EOF):") - if _, err := io.Copy(&str, os.Stdin); err != nil { - if err != io.EOF { - return fmt.Errorf("failed to read: %v", err) - } - } - q.Text = strings.TrimRightFunc(str.String(), unicode.IsSpace) - if q.Text == "" { - return fmt.Errorf("missing text") - } - str.Reset() - - // Author - fmt.Print("Author: ") - line, err := in.ReadString('\n') - if err != nil { - return fmt.Errorf("failed to read: %v", err) - } - q.Author = strings.TrimSpace(line) - - // Source - fmt.Print("Source: ") - line, err = in.ReadString('\n') - if err != nil { - return fmt.Errorf("failed to read: %v", err) - } - q.Source = strings.TrimSpace(line) - - // Tags - fmt.Print("Tags (comma delimited): ") - line, err = in.ReadString('\n') - if err != nil { - return fmt.Errorf("failed to read: %v", err) - } - for _, t := range strings.Split(strings.TrimSpace(line), ",") { - if t == "" { - continue - } - q.Tags[t] = struct{}{} - } - - // Comment - fmt.Print("Comment (Ctrl-D for EOF): ") - if _, err := io.Copy(&str, os.Stdin); err != nil { - if err != io.EOF { - return fmt.Errorf("failed to read: %v", err) - } - } - q.Comment = strings.TrimSpace(str.String()) - str.Reset() - - if _, err := w.store.Collection(coll).Create( - uuid.NewString(), q, - ); err != nil { - return fmt.Errorf("failed to create: %v", err) - } - - return nil -} - -func (w *Wisdom) edit(args []string) error { - if len(args) == 0 { - return fmt.Errorf("missing id") - } - - editor := strings.Split(os.Getenv("EDITOR"), " ") - if len(editor) == 0 { - return fmt.Errorf("missing $EDITOR") - } - - path, err := exec.LookPath(editor[0]) - if err != nil { - return fmt.Errorf( - "failed to find $EDITOR %s: %w", editor, err, - ) - } - - for _, id := range args { - d, err := w.store.Collection(coll).FindId(id) - if err != nil { - return fmt.Errorf("failed to load quote: %v", err) - } - - temp := filepath.Join(os.TempDir(), "wisdom", id) - if err := os.WriteFile(temp, d.Data, 0600); err != nil { - return err - } - - cmd := exec.Cmd{ - Path: path, - Args: append(editor, temp), - Stdin: os.Stdin, - Stdout: os.Stdout, - Stderr: os.Stderr, - } - if err := cmd.Run(); err != nil { - return err - } - - data, err := os.ReadFile(temp) - if err != nil { - return fmt.Errorf( - "failed to read file %s: %w", temp, err, - ) - } - - var q = &quote.Quote{} - if err := json.Unmarshal(data, q); err != nil { - return fmt.Errorf( - "failed to json unmarshal %s: %w", temp, err, - ) - } - - if err := os.Remove(temp); err != nil { - return fmt.Errorf("failed to remove temp file: %v", err) - } - - d, err = w.store.Collection(coll).Create(uuid.NewString(), q) - if err != nil { - return fmt.Errorf( - "failed to create new document: %v", err, - ) - } - - if err := w.store.Collection(coll).Delete(id); err != nil { - return fmt.Errorf( - "failed to delete original document: %v", err, - ) - } - } - - return nil -} - -func (w *Wisdom) list() error { - docs, err := w.store.Collection(coll).All() - if err != nil { - return fmt.Errorf("failed to load quotes: %v", err) - } - - var output strings.Builder - output.WriteString("id,author,source,text\n") - for _, d := range docs { - var q = &quote.Quote{} - - if err := d.Unmarshal(q); err != nil { - w.log.Error.Printf( - "failed to unmarshal document %s: %v", - d.Id, err, - ) - continue - } - - 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') - - output.WriteString(line.String()) - } - - fmt.Println(output.String()) - - return nil -} - -func (w *Wisdom) remove(args []string) error { - if len(args) == 0 { - return fmt.Errorf("missing quote filename") - } - - for _, name := range args { - if err := w.store.Collection(coll).Delete(name); err != nil { - return fmt.Errorf("failed to delete %s: %v", name, err) - } - } - - return nil -} - -func (w *Wisdom) show(args []string) error { - for _, id := range args { - d, err := w.store.Collection(coll).FindId(id) - if err != nil { - return fmt.Errorf("failed to load quotes: %v", err) - } - - var q = &quote.Quote{} - if err := d.Unmarshal(q); err != nil { - return fmt.Errorf( - "failed to unmarshal document %s: %v", - d.Id, err, - ) - } - - fmt.Println(q.Render()) - } - - return nil -}