summaryrefslogtreecommitdiff
path: root/main.go
diff options
context:
space:
mode:
Diffstat (limited to 'main.go')
-rw-r--r--main.go135
1 files changed, 93 insertions, 42 deletions
diff --git a/main.go b/main.go
index ea0f382..235be18 100644
--- a/main.go
+++ b/main.go
@@ -3,12 +3,16 @@
package main
import (
+ "database/sql"
+ "fmt"
"log"
"net/http"
- "os"
"time"
+ "github.com/charmbracelet/bubbles/textinput"
+ tea "github.com/charmbracelet/bubbletea"
_ "github.com/mattn/go-sqlite3"
+ "github.com/microcosm-cc/bluemonday"
)
const (
@@ -20,32 +24,99 @@ const (
modelName = "Basic-830ae"
)
-type addNote struct {
- Action string `json:"action"`
- Version int `json:"version"`
- Params addNoteParams `json:"params"`
+type model struct {
+ wordInput textinput.Model
+ err error
+ currentWord string
+ currentDefinition string
+ db *sql.DB
+ c *http.Client
+ wordAddStatus string
+ p bluemonday.Policy
}
-type addNoteParams struct {
- Note note `json:"note"`
+type (
+ errMsg error
+ definitionMsg string
+ wordAddedMsg string
+)
+
+func initialModel(c *http.Client, db *sql.DB) model {
+ ti := textinput.New()
+ ti.Placeholder = ""
+ ti.Focus()
+ ti.CharLimit = 156
+ ti.Width = 36
+
+ return model{
+ wordInput: ti,
+ err: nil,
+ db: db,
+ c: c,
+ wordAddStatus: "(Press 'Enter' to add this word and its definition to Anki)",
+ p: *bluemonday.StrictPolicy(),
+ }
}
-type note struct {
- DeckName string `json:"deckName"`
- ModelName string `json:"modelName"`
- // Fields will not be trivial to generalize
- Fields fields `json:"fields"`
- Options options `json:"options"`
+func (m model) Init() tea.Cmd {
+ return textinput.Blink
}
-type fields struct {
- Front string `json:"Front"`
- Back string `json:"Back"`
+func lookupWord(db *sql.DB, word string) tea.Cmd {
+ return func() tea.Msg {
+ var definition string
+ row := db.QueryRow(`select definition from words where word = ? limit 1`, word)
+ err := row.Scan(&definition)
+ if err != nil {
+ return errMsg(fmt.Errorf("looking up '%s': %s", word, err))
+ }
+ return definitionMsg(definition)
+ }
}
-type options struct {
- AllowDuplicate bool `json:"allowDuplicate"`
- DuplicateScope string `json:"duplicateScope"`
+func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
+ var cmd tea.Cmd
+
+ var textPickerLongerCmds []tea.Cmd
+
+ switch msg := msg.(type) {
+ case definitionMsg:
+ m.currentDefinition = string(msg)
+ return m, nil
+ case wordAddedMsg:
+ m.wordAddStatus = fmt.Sprintf("✅ Added '%s' to Anki", string(msg))
+ case tea.KeyMsg:
+ switch msg.Type {
+ case tea.KeyCtrlC, tea.KeyEsc:
+ return m, tea.Quit
+ case tea.KeyEnter:
+ return m, addCard(m.c, m.currentWord, m.currentDefinition)
+ }
+
+ case errMsg:
+ m.err = msg
+ return m, nil
+ }
+
+ if m.wordInput.Value() != m.currentWord {
+ m.currentWord = m.wordInput.Value()
+ textPickerLongerCmds = append(textPickerLongerCmds, lookupWord(m.db, m.currentWord))
+ }
+
+ m.wordInput, cmd = m.wordInput.Update(msg)
+ textPickerLongerCmds = append(textPickerLongerCmds, cmd)
+ return m, tea.Batch(textPickerLongerCmds...)
+}
+
+func (m model) View() string {
+ return fmt.Sprintf(
+ "Look up a word:\n\n%s\n\n%s\n%s\n\n%s\n%s",
+ m.wordInput.View(),
+ m.wordAddStatus,
+ "(esc to quit)",
+ "Current definition:\n",
+ m.p.Sanitize(m.currentDefinition),
+ ) + "\n"
}
func main() {
@@ -55,31 +126,11 @@ func main() {
}
defer db.Close()
- // We're going to start this app very simply! The first iteration will take
- // a word as its first command-line argument. We will search for the word in
- // the dictionary and create a new Anki card using the first exact match.
- //
- // In the future, we may make it easy for the user to edit cards (flag?),
- // and possibly implement a TUI to choose definitions more interactively as
- // well (e.g. search with partial matches).
- //
- // I would also like to make more things less hard-coded.
- if len(os.Args) < 2 {
- log.Fatalf("no word was provided")
- }
- word := os.Args[1]
-
- var definition string
- row := db.QueryRow(`select definition from words where word = ? limit 1`, word)
- err = row.Scan(&definition)
- if err != nil {
- log.Fatalf("looking up '%s': %s", word, err)
- }
-
c := http.DefaultClient
c.Timeout = 5 * time.Second
- if err := addCard(c, word, definition); err != nil {
- log.Fatalf("creating card: %s", err)
+ p := tea.NewProgram(initialModel(c, db))
+ if _, err := p.Run(); err != nil {
+ log.Fatal(err)
}
}