dict @ b7ca1117b18e228b84dd62a677a0a2ca52b3c549

feat: Add async request
diff --git a/cmd/ui/ui.go b/cmd/ui/ui.go
index b5f2f2fca941082410826eb92820fcb5b44172f8..50b854328935a0a51ff79a78d5e66c0c66b60b82 100644
--- a/cmd/ui/ui.go
+++ b/cmd/ui/ui.go
@@ -4,6 +4,7 @@ import (
 	"context"
 	"fmt"
 	"log/slog"
+	"sync"
 
 	"github.com/gdamore/tcell/v2"
 	"github.com/rivo/tview"
@@ -47,30 +48,52 @@ 	textView := tview.NewTextView().
 		SetDynamicColors(true).
 		SetRegions(true)
 
+	app := tview.NewApplication()
+
+	search := ""
+	tx := sync.Mutex{}
+
 	input := tview.NewInputField().
 		SetChangedFunc(func(v string) {
-			textView.Clear()
+
+			tx.Lock()
+			defer tx.Unlock()
+			search = v
 
-			words, err := db.SelectDict(ctx, v, 100)
-			if err != nil {
-				return
-			}
+			go func(v string) {
+				words, err := db.SelectDict(ctx, v, 100)
+				if err != nil {
+					return
+				}
+
+				tx.Lock()
+				if search != v {
+					tx.Unlock()
+					return
+				}
+				tx.Unlock()
+
+				textView.Clear()
+				lastWord := ""
+				for _, w := range words {
+					w.Word = tview.Escape(w.Word)
+					w.Line = tview.Escape(w.Line)
 
-			lastWord := ""
-			for _, w := range words {
+					if lastWord == w.Word {
+						fmt.Fprintf(textView, "%s\n", w.Line)
+					} else if lastWord == "" {
+						fmt.Fprintf(textView, "[::bu]%s[-:-:-]\n", w.Word)
+						fmt.Fprintf(textView, "%s\n", w.Line)
+					} else {
+						fmt.Fprintf(textView, "\n[::bu]%s[-:-:-]\n", w.Word)
+						fmt.Fprintf(textView, "%s\n", w.Line)
+					}
 
-				if lastWord == w.Word {
-					fmt.Fprintf(textView, "%s\n", w.Line)
-				} else if lastWord == "" {
-					fmt.Fprintf(textView, "[bold]%s[normal]\n", w.Word)
-					fmt.Fprintf(textView, "%s\n", w.Line)
-				} else {
-					fmt.Fprintf(textView, "\n[bold]%s[normal]\n", w.Word)
-					fmt.Fprintf(textView, "%s\n", w.Line)
+					lastWord = w.Word
 				}
 
-				lastWord = w.Word
-			}
+				app.Draw()
+			}(v)
 		}).
 		SetAutocompleteFunc(func(v string) []string {
 			if len(v) == 0 {
@@ -98,10 +121,8 @@ 		SetRows(1, 0, 3).
 		AddItem(input, 0, 0, 1, 3, 0, 0, false).
 		AddItem(textView, 1, 0, 1, 3, 0, 0, false)
 
-	err = tview.NewApplication().
+	return app.
 		SetRoot(grid, true).
 		SetFocus(input).
 		Run()
-
-	return err
 }