summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortjp <tjp@ctrl-c.club>2024-01-23 22:42:18 -0700
committertjp <tjp@ctrl-c.club>2024-01-23 22:42:18 -0700
commit865c6dc23099e129cb3ba9709b2926734144e605 (patch)
tree6824a2de82e842ea79554b581ceb0db328235c46
parentdd2a06c1e1391fe6242015330b7c61fa37fd67cc (diff)
Printer abstraction
-rw-r--r--actions.go37
-rw-r--r--go.mod6
-rw-r--r--go.sum8
-rw-r--r--main.go20
-rw-r--r--state.go45
-rw-r--r--tui.go57
6 files changed, 122 insertions, 51 deletions
diff --git a/actions.go b/actions.go
index c11e677..c80445b 100644
--- a/actions.go
+++ b/actions.go
@@ -559,43 +559,20 @@ func parseURL(str string, state *BrowserState, defaultScheme string) (*url.URL,
}
func print(state *BrowserState) error {
- if state.Quiet {
- return nil
- }
-
- defer func() { state.Modal = nil }()
-
- if state.Body == nil && state.Modal == nil {
- return ErrMustBeOnAPage
- }
- out := []byte(state.Formatted)
if state.Modal != nil {
- out = state.Modal
+ defer func() { state.Modal = nil }()
+ return state.Printer.PrintModal(state, state.Modal)
}
- if state.Modal != nil || state.Pager == "never" {
- _, err := os.Stdout.Write(out)
- return err
+ if state.Body == nil {
+ return ErrMustBeOnAPage
}
- lessarg := []string{}
- switch state.Pager {
- case "auto":
- lessarg = []string{"-F"}
- fallthrough
- case "always":
- less, err := exec.LookPath("less")
- if err != nil {
- return err
- }
- cmd := exec.Command(less, lessarg...)
- cmd.Stdin = bytes.NewBuffer(out)
- cmd.Stdout = os.Stdout
- cmd.Stderr = os.Stderr
- return cmd.Run()
+ if state.Quiet {
+ return nil
}
- return errors.New("invalid 'pager' value in configuration")
+ return state.Printer.PrintPage(state, state.Formatted)
}
func Print(state *BrowserState) error {
diff --git a/go.mod b/go.mod
index 5a3ef25..99ae622 100644
--- a/go.mod
+++ b/go.mod
@@ -10,21 +10,23 @@ require (
require (
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
+ github.com/charmbracelet/bubbles v0.17.1 // indirect
github.com/charmbracelet/bubbletea v0.25.0 // indirect
+ github.com/charmbracelet/lipgloss v0.9.1 // indirect
github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect
github.com/go-kit/log v0.2.1 // indirect
github.com/go-logfmt/logfmt v0.5.1 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/mattn/go-isatty v0.0.18 // indirect
github.com/mattn/go-localereader v0.0.1 // indirect
- github.com/mattn/go-runewidth v0.0.14 // indirect
+ github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b // indirect
github.com/muesli/cancelreader v0.2.2 // indirect
github.com/muesli/reflow v0.3.0 // indirect
github.com/muesli/termenv v0.15.2 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
golang.org/x/sync v0.1.0 // indirect
- golang.org/x/sys v0.7.0 // indirect
+ golang.org/x/sys v0.12.0 // indirect
golang.org/x/term v0.6.0 // indirect
golang.org/x/text v0.3.8 // indirect
)
diff --git a/go.sum b/go.sum
index 8cebcc5..868664e 100644
--- a/go.sum
+++ b/go.sum
@@ -2,8 +2,12 @@ github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
+github.com/charmbracelet/bubbles v0.17.1 h1:0SIyjOnkrsfDo88YvPgAWvZMwXe26TP6drRvmkjyUu4=
+github.com/charmbracelet/bubbles v0.17.1/go.mod h1:9HxZWlkCqz2PRwsCbYl7a3KXvGzFaDHpYbSYMJ+nE3o=
github.com/charmbracelet/bubbletea v0.25.0 h1:bAfwk7jRz7FKFl9RzlIULPkStffg5k6pNt5dywy4TcM=
github.com/charmbracelet/bubbletea v0.25.0/go.mod h1:EN3QDR1T5ZdWmdfDzYcqOCAps45+QIJbLOBxmVNWNNg=
+github.com/charmbracelet/lipgloss v0.9.1 h1:PNyd3jvaJbg4jRHKWXnCj1akQm4rh8dbEzN1p/u1KWg=
+github.com/charmbracelet/lipgloss v0.9.1/go.mod h1:1mPmG4cxScwUQALAAnacHaigiiHB9Pmr+v1VEawJl6I=
github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM=
github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ=
github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI=
@@ -27,6 +31,8 @@ github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+Ei
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
+github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
+github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b h1:1XF24mVaiu7u+CFywTdcDo2ie1pzzhwjt6RHqzpMU34=
github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho=
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
@@ -50,6 +56,8 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
+golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY=
diff --git a/main.go b/main.go
index b2f5d98..695a8fc 100644
--- a/main.go
+++ b/main.go
@@ -44,14 +44,8 @@ func main() {
state.Quiet = true
}
- if urls := flag.Args(); len(urls) > 0 {
- if err := Go(state, urls[0]); err != nil {
- writeError(err.Error())
- }
- }
-
- // runInteractivePrompt(state)
- runTUI(state)
+ runInteractivePrompt(state, flag.Args())
+ // runTUI(state, flag.Args())
}
func buildReadline(prompt string, conf *Config) (*readline.Instance, error) {
@@ -106,7 +100,15 @@ func buildInitialState() (*BrowserState, error) {
return state, nil
}
-func runInteractivePrompt(state *BrowserState) {
+func runInteractivePrompt(state *BrowserState, args []string) {
+ state.Printer = PromptPrinter{}
+
+ if len(args) > 0 {
+ if err := Go(state, args[0]); err != nil {
+ writeError(err.Error())
+ }
+ }
+
for {
state.Readline.SetPrompt(Prompt)
line, err := state.Readline.Readline()
diff --git a/state.go b/state.go
index 57767a8..918346f 100644
--- a/state.go
+++ b/state.go
@@ -1,7 +1,11 @@
package main
import (
+ "bytes"
+ "errors"
"net/url"
+ "os"
+ "os/exec"
"github.com/chzyer/readline"
)
@@ -21,6 +25,7 @@ type BrowserState struct {
CurrentTour *Tour
Readline *readline.Instance
+ Printer Printer
}
type History struct {
@@ -60,3 +65,43 @@ func NewBrowserState(conf *Config) *BrowserState {
state.CurrentTour = &state.DefaultTour
return state
}
+
+type Printer interface {
+ PrintModal(*BrowserState, []byte) error
+ PrintPage(*BrowserState, string) error
+}
+
+type PromptPrinter struct{}
+
+func (_ PromptPrinter) PrintModal(state *BrowserState, contents []byte) error {
+ _, err := os.Stdout.Write(contents)
+ return err
+}
+
+func (_ PromptPrinter) PrintPage(state *BrowserState, body string) error {
+ if state.Quiet {
+ return nil
+ }
+
+ lessarg := []string{}
+ switch state.Pager {
+ case "auto":
+ lessarg = []string{"-F"}
+ fallthrough
+ case "always":
+ less, err := exec.LookPath("less")
+ if err != nil {
+ return err
+ }
+ cmd := exec.Command(less, lessarg...)
+ cmd.Stdin = bytes.NewBufferString(body)
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ return cmd.Run()
+ case "never":
+ _, err := os.Stdout.WriteString(body)
+ return err
+ default:
+ return errors.New("invalid 'pager' value in configuration")
+ }
+}
diff --git a/tui.go b/tui.go
index 12bb665..c131110 100644
--- a/tui.go
+++ b/tui.go
@@ -4,40 +4,77 @@ import (
"os"
tea "github.com/charmbracelet/bubbletea"
+ "github.com/charmbracelet/bubbles/viewport"
)
type TUIModel struct {
State *BrowserState
+ Viewport viewport.Model
+ inited bool
}
-func NewTUIModel(state *BrowserState) TUIModel {
- return TUIModel{State: state}
+func NewTUIModel(state *BrowserState) *TUIModel {
+ return &TUIModel{State: state}
}
-func (model TUIModel) Init() tea.Cmd {
+func (model *TUIModel) Init() tea.Cmd {
return nil
}
-func (model TUIModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
+func (model *TUIModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.KeyMsg:
switch msg.String() {
- case "ctrl+c", "ctrl+d", "q":
+ case "ctrl+c", "q":
return model, tea.Quit
+ case "g":
+ model.Viewport.GotoTop()
+ return model, nil
+ case "G":
+ model.Viewport.GotoBottom()
+ return model, nil
}
+ case tea.WindowSizeMsg:
+ model.inited = true
+ model.Viewport.Width = msg.Width
+ model.Viewport.Height = msg.Height - 1
}
- return model, nil
+ var cmd tea.Cmd
+ model.Viewport, cmd = model.Viewport.Update(msg)
+
+ return model, cmd
}
-func (model TUIModel) View() string {
- return "pardon our dust"
+func (model *TUIModel) View() string {
+ return model.Viewport.View()
}
-func runTUI(state *BrowserState) {
- p := tea.NewProgram(NewTUIModel(state))
+func runTUI(state *BrowserState, args []string) {
+ model := NewTUIModel(state)
+ state.Printer = (*TUIPrinter)(model)
+
+ if len(args) > 0 {
+ if err := Go(state, args[0]); err != nil {
+ writeError(err.Error())
+ }
+ }
+
+ p := tea.NewProgram(model, tea.WithAltScreen())
if _, err := p.Run(); err != nil {
writeError(err.Error())
os.Exit(1)
}
}
+
+type TUIPrinter TUIModel
+
+func (p *TUIPrinter) PrintModal(state *BrowserState, contents []byte) error {
+ (*TUIModel)(p).Viewport.SetContent(string(contents))
+ return nil
+}
+
+func (p *TUIPrinter) PrintPage(state *BrowserState, body string) error {
+ (*TUIModel)(p).Viewport.SetContent(body)
+ return nil
+}