mirror of
https://github.com/charmbracelet/gum
synced 2024-05-04 15:33:14 +02:00
feat(pager): gum pager for scrolling through long documents
This commit is contained in:
parent
bdd86d5fbc
commit
430ab459d7
20
file/hidden_windows.go
Normal file
20
file/hidden_windows.go
Normal file
|
@ -0,0 +1,20 @@
|
|||
//go:build windows
|
||||
|
||||
package file
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// IsHidden reports whether a file is hidden or not.
|
||||
func IsHidden(file string) (bool, error) {
|
||||
pointer, err := syscall.UTF16PtrFromString(file)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
attributes, err := syscall.GetFileAttributes(pointer)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return attributes&syscall.FILE_ATTRIBUTE_HIDDEN != 0, nil
|
||||
}
|
14
main.go
14
main.go
|
@ -52,12 +52,14 @@ func main() {
|
|||
Summary: false,
|
||||
}),
|
||||
kong.Vars{
|
||||
"version": version,
|
||||
"defaultBackground": "",
|
||||
"defaultForeground": "",
|
||||
"defaultMargin": "0 0",
|
||||
"defaultPadding": "0 0",
|
||||
"defaultUnderline": "false",
|
||||
"version": version,
|
||||
"defaultBorder": "none",
|
||||
"defaultBorderForeground": "",
|
||||
"defaultBackground": "",
|
||||
"defaultForeground": "",
|
||||
"defaultMargin": "0 0",
|
||||
"defaultPadding": "0 0",
|
||||
"defaultUnderline": "false",
|
||||
},
|
||||
)
|
||||
if err := ctx.Run(); err != nil {
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
package pager
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/charmbracelet/bubbles/viewport"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/charmbracelet/glamour"
|
||||
"github.com/charmbracelet/gum/internal/stdin"
|
||||
)
|
||||
|
||||
|
@ -15,24 +16,23 @@ func (o Options) Run() error {
|
|||
var err error
|
||||
|
||||
if o.Content == "" {
|
||||
o.Content, err = stdin.Read()
|
||||
stdin, err := stdin.Read()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if stdin != "" {
|
||||
o.Content = stdin
|
||||
} else {
|
||||
return fmt.Errorf("provide some content to display")
|
||||
}
|
||||
}
|
||||
|
||||
renderer, err := glamour.NewTermRenderer(
|
||||
glamour.WithWordWrap(80),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
md, err := renderer.Render(o.Content)
|
||||
vp.SetContent(md)
|
||||
|
||||
model := model{
|
||||
viewport: vp,
|
||||
helpStyle: o.HelpStyle.ToLipgloss(),
|
||||
viewport: vp,
|
||||
helpStyle: o.HelpStyle.ToLipgloss(),
|
||||
content: o.Content,
|
||||
showLineNumbers: o.ShowLineNumbers,
|
||||
lineNumberStyle: o.LineNumberStyle.ToLipgloss(),
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -4,7 +4,9 @@ import "github.com/charmbracelet/gum/style"
|
|||
|
||||
// Options are the options for the pager.
|
||||
type Options struct {
|
||||
Style style.Styles `embed:"" help:"Style the pager" envprefix:"GUM_PAGER_"`
|
||||
HelpStyle style.Styles `embed:"" prefix:"help." help:"Style the help text" set:"defaultForeground=241" envprefix:"GUM_PAGER_HELP_"`
|
||||
Content string `arg:"" optional:"" help:"Display content to scroll"`
|
||||
Style style.Styles `embed:"" help:"Style the pager" set:"defaultBorder=rounded" set:"defaultPadding=0 1" set:"defaultBorderForeground=212" envprefix:"GUM_PAGER_"`
|
||||
HelpStyle style.Styles `embed:"" prefix:"help." help:"Style the help text" set:"defaultForeground=241" envprefix:"GUM_PAGER_HELP_"`
|
||||
Content string `arg:"" optional:"" help:"Display content to scroll"`
|
||||
ShowLineNumbers bool `help:"Show line numbers" default:"true"`
|
||||
LineNumberStyle style.Styles `embed:"" prefix:"line-number." help:"Style the line numbers" set:"defaultForeground=237" envprefix:"GUM_PAGER_LINE_NUMBER_"`
|
||||
}
|
||||
|
|
|
@ -4,14 +4,21 @@
|
|||
package pager
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/charmbracelet/bubbles/viewport"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"github.com/mattn/go-runewidth"
|
||||
)
|
||||
|
||||
type model struct {
|
||||
viewport viewport.Model
|
||||
helpStyle lipgloss.Style
|
||||
content string
|
||||
viewport viewport.Model
|
||||
helpStyle lipgloss.Style
|
||||
showLineNumbers bool
|
||||
lineNumberStyle lipgloss.Style
|
||||
}
|
||||
|
||||
func (m model) Init() tea.Cmd {
|
||||
|
@ -21,10 +28,31 @@ func (m model) Init() tea.Cmd {
|
|||
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
switch msg := msg.(type) {
|
||||
case tea.WindowSizeMsg:
|
||||
m.viewport.Height = msg.Height - 2
|
||||
m.viewport.Width = msg.Width
|
||||
m.viewport.Height = msg.Height - 1
|
||||
textStyle := lipgloss.NewStyle().Width(m.viewport.Width)
|
||||
var text strings.Builder
|
||||
for i, line := range strings.Split(m.content, "\n") {
|
||||
line = strings.ReplaceAll(line, "\t", " ")
|
||||
if m.showLineNumbers {
|
||||
text.WriteString(m.lineNumberStyle.Render(fmt.Sprintf("%4d │ ", i+1)))
|
||||
}
|
||||
text.WriteString(textStyle.Render(runewidth.Truncate(line, m.viewport.Width, "")))
|
||||
text.WriteString("\n")
|
||||
}
|
||||
|
||||
diffHeight := m.viewport.Height - lipgloss.Height(text.String())
|
||||
if diffHeight > 0 && m.showLineNumbers {
|
||||
remainingLines := " ~ │ " + strings.Repeat("\n ~ │ ", diffHeight-1)
|
||||
text.WriteString(m.lineNumberStyle.Render(remainingLines))
|
||||
}
|
||||
m.viewport.SetContent(text.String())
|
||||
case tea.KeyMsg:
|
||||
switch msg.String() {
|
||||
case "g":
|
||||
m.viewport.GotoTop()
|
||||
case "G":
|
||||
m.viewport.GotoBottom()
|
||||
case "q", "ctrl+c", "esc":
|
||||
return m, tea.Quit
|
||||
}
|
||||
|
@ -35,5 +63,5 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||
}
|
||||
|
||||
func (m model) View() string {
|
||||
return m.viewport.View() + "\n" + m.helpStyle.Render("↑/↓: Navigate • q: Quit")
|
||||
return m.viewport.View() + m.helpStyle.Render("\n ↑/↓: Navigate • q: Quit")
|
||||
}
|
||||
|
|
|
@ -22,9 +22,9 @@ type Styles struct {
|
|||
Foreground string `help:"Foreground Color" default:"${defaultForeground}" group:"Style Flags" env:"FOREGROUND"`
|
||||
|
||||
// Border
|
||||
Border string `help:"Border Style" enum:"none,hidden,normal,rounded,thick,double" default:"none" group:"Style Flags" env:"BORDER"`
|
||||
Border string `help:"Border Style" enum:"none,hidden,normal,rounded,thick,double" default:"${defaultBorder}" group:"Style Flags" env:"BORDER"`
|
||||
BorderBackground string `help:"Border Background Color" group:"Style Flags" env:"BORDER_BACKGROUND"`
|
||||
BorderForeground string `help:"Border Foreground Color" group:"Style Flags" env:"BORDER_FOREGROUND"`
|
||||
BorderForeground string `help:"Border Foreground Color" group:"Style Flags" default:"${defaultBorderForeground}" env:"BORDER_FOREGROUND"`
|
||||
|
||||
// Layout
|
||||
Align string `help:"Text Alignment" enum:"left,center,right,bottom,middle,top" default:"left" group:"Style Flags" env:"ALIGN"`
|
||||
|
|
Loading…
Reference in a new issue