summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Schlachter <t480-debian-git@schlachter.ca>2026-01-08 01:26:15 -0500
committerDavid Schlachter <t480-debian-git@schlachter.ca>2026-01-08 01:26:15 -0500
commitbfa6f9641a59e1c388b33d1bc1be2bbe9e4d3a86 (patch)
tree5a2936eb159de765c7dd98e4aa8cb995fbd84b0a
parent6d3623e3295ceacf7e1200d05790a9c662b69960 (diff)
Prettier view
-rw-r--r--go.mod1
-rw-r--r--go.sum4
-rw-r--r--main.go30
3 files changed, 34 insertions, 1 deletions
diff --git a/go.mod b/go.mod
index 3bf4820..23bf6a6 100644
--- a/go.mod
+++ b/go.mod
@@ -8,6 +8,7 @@ require (
github.com/goccy/go-json v0.10.5
github.com/mattn/go-sqlite3 v1.14.33
github.com/microcosm-cc/bluemonday v1.0.27
+ github.com/muesli/reflow v0.3.0
)
require (
diff --git a/go.sum b/go.sum
index 2c916fa..56d7dbb 100644
--- a/go.sum
+++ b/go.sum
@@ -30,6 +30,7 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
+github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-sqlite3 v1.14.33 h1:A5blZ5ulQo2AtayQ9/limgHEkFreKj1Dv226a1K73s0=
@@ -40,8 +41,11 @@ github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
+github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
+github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
+github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
diff --git a/main.go b/main.go
index 235be18..ef4e7ad 100644
--- a/main.go
+++ b/main.go
@@ -7,12 +7,16 @@ import (
"fmt"
"log"
"net/http"
+ "regexp"
+ "strings"
"time"
"github.com/charmbracelet/bubbles/textinput"
+ "github.com/charmbracelet/bubbles/viewport"
tea "github.com/charmbracelet/bubbletea"
_ "github.com/mattn/go-sqlite3"
"github.com/microcosm-cc/bluemonday"
+ "github.com/muesli/reflow/wordwrap"
)
const (
@@ -33,6 +37,7 @@ type model struct {
c *http.Client
wordAddStatus string
p bluemonday.Policy
+ vp viewport.Model
}
type (
@@ -47,6 +52,7 @@ func initialModel(c *http.Client, db *sql.DB) model {
ti.Focus()
ti.CharLimit = 156
ti.Width = 36
+ vp := viewport.New(80, 30)
return model{
wordInput: ti,
@@ -55,6 +61,7 @@ func initialModel(c *http.Client, db *sql.DB) model {
c: c,
wordAddStatus: "(Press 'Enter' to add this word and its definition to Anki)",
p: *bluemonday.StrictPolicy(),
+ vp: vp,
}
}
@@ -82,6 +89,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case definitionMsg:
m.currentDefinition = string(msg)
+ m.vp.SetContent(formatDefinitionForDisplay(m.p, m.currentDefinition))
return m, nil
case wordAddedMsg:
m.wordAddStatus = fmt.Sprintf("✅ Added '%s' to Anki", string(msg))
@@ -103,11 +111,17 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
textPickerLongerCmds = append(textPickerLongerCmds, lookupWord(m.db, m.currentWord))
}
+ var vpCmd tea.Cmd
+ m.vp, vpCmd = m.vp.Update(msg)
+ textPickerLongerCmds = append(textPickerLongerCmds, vpCmd)
+
m.wordInput, cmd = m.wordInput.Update(msg)
textPickerLongerCmds = append(textPickerLongerCmds, cmd)
return m, tea.Batch(textPickerLongerCmds...)
}
+var whitespaceTrimmerRe = regexp.MustCompile(`^[ \t]*$`)
+
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",
@@ -115,10 +129,24 @@ func (m model) View() string {
m.wordAddStatus,
"(esc to quit)",
"Current definition:\n",
- m.p.Sanitize(m.currentDefinition),
+ m.vp.View(),
) + "\n"
}
+func formatDefinitionForDisplay(policy bluemonday.Policy, definition string) string {
+ return wordwrap.String(
+ strings.ReplaceAll(
+ whitespaceTrimmerRe.ReplaceAllLiteralString(
+ policy.Sanitize(definition),
+ "",
+ ),
+ "\n\n",
+ "\n",
+ ),
+ 72,
+ )
+}
+
func main() {
db, err := setupDatabase()
if err != nil {