dict @ master

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