dict @ b7ca1117b18e228b84dd62a677a0a2ca52b3c549

  1package ui
  2
  3import (
  4	"context"
  5	"fmt"
  6	"log/slog"
  7	"sync"
  8
  9	"github.com/gdamore/tcell/v2"
 10	"github.com/rivo/tview"
 11	"github.com/urfave/cli/v2"
 12
 13	"git.gabrielgio.me/dict/db"
 14)
 15
 16const (
 17	memory = ":memory:"
 18)
 19
 20var UICommand = &cli.Command{
 21	Name:  "ui",
 22	Usage: "interactive dictionary",
 23	Flags: []cli.Flag{
 24		&cli.StringFlag{
 25			Name:  "database",
 26			Value: "main.dict",
 27			Usage: "Dictionary database location",
 28		},
 29	},
 30	Action: func(cCtx *cli.Context) error {
 31		name := cCtx.String("database")
 32		return Run(context.Background(), name)
 33	},
 34}
 35
 36func Run(ctx context.Context, name string) error {
 37	db, err := db.Open(memory)
 38	if err != nil {
 39		return err
 40	}
 41
 42	err = db.Restore(ctx, name)
 43	if err != nil {
 44		return err
 45	}
 46
 47	textView := tview.NewTextView().
 48		SetDynamicColors(true).
 49		SetRegions(true)
 50
 51	app := tview.NewApplication()
 52
 53	search := ""
 54	tx := sync.Mutex{}
 55
 56	input := tview.NewInputField().
 57		SetChangedFunc(func(v string) {
 58
 59			tx.Lock()
 60			defer tx.Unlock()
 61			search = v
 62
 63			go func(v string) {
 64				words, err := db.SelectDict(ctx, v, 100)
 65				if err != nil {
 66					return
 67				}
 68
 69				tx.Lock()
 70				if search != v {
 71					tx.Unlock()
 72					return
 73				}
 74				tx.Unlock()
 75
 76				textView.Clear()
 77				lastWord := ""
 78				for _, w := range words {
 79					w.Word = tview.Escape(w.Word)
 80					w.Line = tview.Escape(w.Line)
 81
 82					if lastWord == w.Word {
 83						fmt.Fprintf(textView, "%s\n", w.Line)
 84					} else if lastWord == "" {
 85						fmt.Fprintf(textView, "[::bu]%s[-:-:-]\n", w.Word)
 86						fmt.Fprintf(textView, "%s\n", w.Line)
 87					} else {
 88						fmt.Fprintf(textView, "\n[::bu]%s[-:-:-]\n", w.Word)
 89						fmt.Fprintf(textView, "%s\n", w.Line)
 90					}
 91
 92					lastWord = w.Word
 93				}
 94
 95				app.Draw()
 96			}(v)
 97		}).
 98		SetAutocompleteFunc(func(v string) []string {
 99			if len(v) == 0 {
100				return []string{}
101			}
102
103			vs, err := db.SelectSpell(ctx, v)
104			if err != nil {
105				slog.Error("Error select spelling", "error", err)
106				return []string{}
107			}
108
109			return vs
110		})
111
112	input.SetDoneFunc(func(key tcell.Key) {
113		if key == tcell.KeyEscape {
114			textView.Clear()
115			input.SetText("")
116		}
117	})
118
119	grid := tview.NewGrid().
120		SetRows(1, 0, 3).
121		AddItem(input, 0, 0, 1, 3, 0, 0, false).
122		AddItem(textView, 1, 0, 1, 3, 0, 0, false)
123
124	return app.
125		SetRoot(grid, true).
126		SetFocus(input).
127		Run()
128}