Printer abstraction
This commit is contained in:
parent
dd2a06c1e1
commit
865c6dc230
43
actions.go
43
actions.go
|
@ -559,43 +559,20 @@ func parseURL(str string, state *BrowserState, defaultScheme string) (*url.URL,
|
|||
}
|
||||
|
||||
func print(state *BrowserState) error {
|
||||
if state.Modal != nil {
|
||||
defer func() { state.Modal = nil }()
|
||||
return state.Printer.PrintModal(state, state.Modal)
|
||||
}
|
||||
|
||||
if state.Body == nil {
|
||||
return ErrMustBeOnAPage
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
if state.Modal != nil || state.Pager == "never" {
|
||||
_, err := os.Stdout.Write(out)
|
||||
return err
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
return errors.New("invalid 'pager' value in configuration")
|
||||
return state.Printer.PrintPage(state, state.Formatted)
|
||||
}
|
||||
|
||||
func Print(state *BrowserState) error {
|
||||
|
|
6
go.mod
6
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
|
||||
)
|
||||
|
|
8
go.sum
8
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=
|
||||
|
|
20
main.go
20
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()
|
||||
|
|
45
state.go
45
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")
|
||||
}
|
||||
}
|
||||
|
|
65
tui.go
65
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
|
||||
}
|
||||
|
||||
var cmd tea.Cmd
|
||||
model.Viewport, cmd = model.Viewport.Update(msg)
|
||||
|
||||
return model, cmd
|
||||
}
|
||||
|
||||
func (model *TUIModel) View() string {
|
||||
return model.Viewport.View()
|
||||
}
|
||||
|
||||
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())
|
||||
}
|
||||
}
|
||||
|
||||
return model, nil
|
||||
}
|
||||
|
||||
func (model TUIModel) View() string {
|
||||
return "pardon our dust"
|
||||
}
|
||||
|
||||
func runTUI(state *BrowserState) {
|
||||
p := tea.NewProgram(NewTUIModel(state))
|
||||
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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue