docs: document gum table, file, pager

This commit documents `gum table`, `gum file`, and `gum pager` with
demonstration GIFs and sample scripts.
This commit is contained in:
Maas Lalani 2022-10-02 15:55:14 -04:00
parent 2bea4dc030
commit 995bd04e38
12 changed files with 86 additions and 49 deletions

View File

@ -289,6 +289,34 @@ gum confirm && rm file.txt || echo "File not removed"
<img src="https://stuff.charm.sh/gum/confirm_2.gif" alt="Shell running gum confirm" />
</picture>
#### File
Prompt the user to select a file from the file tree.
```bash
EDITOR $(gum file $HOME)
```
<picture>
<source media="(max-width: 600px)" srcset="https://stuff.charm.sh/gum/file.gif">
<source media="(min-width: 600px)" width="600" srcset="https://stuff.charm.sh/gum/file.gif">
<img src="https://stuff.charm.sh/gum/file.gif" alt="Shell running gum file" />
</picture>
#### Pager
Scroll through a long document with line numbers and a fully customizable viewport.
```bash
gum pager < README.md
```
<picture>
<source media="(max-width: 600px)" srcset="https://stuff.charm.sh/gum/pager.gif">
<source media="(min-width: 600px)" width="600" srcset="https://stuff.charm.sh/gum/pager.gif">
<img src="https://stuff.charm.sh/gum/pager.gif" alt="Shell running gum pager" />
</picture>
#### Spin
Display a spinner while running a script or command. The spinner will
@ -306,6 +334,20 @@ gum spin --spinner dot --title "Buying Bubble Gum..." -- sleep 5
Available spinner types include: `line`, `dot`, `minidot`, `jump`, `pulse`, `points`, `globe`, `moon`, `monkey`, `meter`, `hamburger`.
#### Table
Select a row from some tabular data.
```bash
gum table < flavors.csv | cut -d ',' -f 1
```
<picture>
<source media="(max-width: 600px)" srcset="https://stuff.charm.sh/gum/table.gif">
<source media="(min-width: 600px)" width="600" srcset="https://stuff.charm.sh/gum/table.gif">
<img src="https://stuff.charm.sh/gum/table.gif" alt="Shell running gum table" />
</picture>
## Styling
#### Style

View File

@ -17,7 +17,7 @@ func (o Options) Run() error {
path, err := filepath.Abs(o.Path)
if err != nil {
return err
return fmt.Errorf("file not found: %w", err)
}
m := model{
@ -43,7 +43,7 @@ func (o Options) Run() error {
tm, err := tea.NewProgram(&m, tea.WithOutput(os.Stderr)).StartReturningModel()
if err != nil {
return err
return fmt.Errorf("unable to pick selection: %w", err)
}
m = tm.(model)

View File

@ -196,30 +196,34 @@ func (m model) View() string {
isSymlink := info.Mode()&fs.ModeSymlink != 0
size := humanize.Bytes(uint64(info.Size()))
name := f.Name()
if isSymlink {
symlinkPath, _ = filepath.EvalSymlinks(filepath.Join(m.path, name))
}
if m.selected == i {
selected := fmt.Sprintf(" %s %"+fmt.Sprint(m.fileSizeStyle.GetWidth())+"s %s", info.Mode().String(), size, name)
if isSymlink {
selected = fmt.Sprintf("%s → %s", selected, symlinkPath)
}
s.WriteString(m.cursorStyle.Render(m.cursor) + m.selectedStyle.Render(selected))
} else {
var style = m.fileStyle
if f.IsDir() {
style = m.directoryStyle
} else if isSymlink {
style = m.symlinkStyle
}
fileName := style.Render(name)
if isSymlink {
fileName = fmt.Sprintf("%s → %s", fileName, symlinkPath)
}
s.WriteString(fmt.Sprintf(" %s %s %s", m.permissionStyle.Render(info.Mode().String()), m.fileSizeStyle.Render(size), fileName))
s.WriteRune('\n')
continue
}
s.WriteString("\n")
var style = m.fileStyle
if f.IsDir() {
style = m.directoryStyle
} else if isSymlink {
style = m.symlinkStyle
}
fileName := style.Render(name)
if isSymlink {
fileName = fmt.Sprintf("%s → %s", fileName, symlinkPath)
}
s.WriteString(fmt.Sprintf(" %s %s %s", m.permissionStyle.Render(info.Mode().String()), m.fileSizeStyle.Render(size), fileName))
s.WriteRune('\n')
}
return s.String()

View File

@ -4,7 +4,7 @@ package file
import "strings"
// IsHidden reports whether a file is hidden or not
// IsHidden reports whether a file is hidden or not.
func IsHidden(file string) (bool, error) {
return strings.HasPrefix(file, "."), nil
}

View File

@ -16,6 +16,8 @@ type Options struct {
DirectoryStyle style.Styles `embed:"" prefix:"directory." help:"The style to use for directories" set:"defaultForeground=99" envprefix:"GUM_FILE_DIRECTORY_"`
FileStyle style.Styles `embed:"" prefix:"file." help:"The style to use for files" envprefix:"GUM_FILE_FILE_"`
PermissionsStyle style.Styles `embed:"" prefix:"permissions." help:"The style to use for permissions" set:"defaultForeground=244" envprefix:"GUM_FILE_PERMISSIONS_"`
SelectedStyle style.Styles `embed:"" prefix:"selected." help:"The style to use for the selected item" set:"defaultBold=true" set:"defaultForeground=212" envprefix:"GUM_FILE_SELECTED_"`
FileSizeStyle style.Styles `embed:"" prefix:"file-size." help:"The style to use for file sizes" set:"defaultWidth=8" set:"defaultAlign=right" set:"defaultForeground=240" envprefix:"GUM_FILE_FILE_SIZE_"`
//nolint:staticcheck
SelectedStyle style.Styles `embed:"" prefix:"selected." help:"The style to use for the selected item" set:"defaultBold=true" set:"defaultForeground=212" envprefix:"GUM_FILE_SELECTED_"`
//nolint:staticcheck
FileSizeStyle style.Styles `embed:"" prefix:"file-size." help:"The style to use for file sizes" set:"defaultWidth=8" set:"defaultAlign=right" set:"defaultForeground=240" envprefix:"GUM_FILE_FILE_SIZE_"`
}

16
go.sum
View File

@ -13,23 +13,15 @@ github.com/aymanbagabas/go-osc52 v1.0.3 h1:DTwqENW7X9arYimJrPeGZcV0ln14sGMt3pHZs
github.com/aymanbagabas/go-osc52 v1.0.3/go.mod h1:zT8H+Rk4VSabYN90pWyugflM3ZhpTZNC7cASDfUCdT4=
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
github.com/charmbracelet/bubbles v0.14.0 h1:DJfCwnARfWjZLvMglhSQzo76UZ2gucuHPy9jLWX45Og=
github.com/charmbracelet/bubbles v0.14.0/go.mod h1:bbeTiXwPww4M031aGi8UK2HT9RDWoiNibae+1yCMtcc=
github.com/charmbracelet/bubbletea v0.21.0/go.mod h1:GgmJMec61d08zXsOhqRC/AiOx4K4pmz+VIcRIm1FKr4=
github.com/charmbracelet/bubbletea v0.22.1 h1:z66q0LWdJNOWEH9zadiAIXp2GN1AWrwNXU8obVY9X24=
github.com/charmbracelet/bubbles v0.14.1-0.20221006154229-d1775121146a h1:/prXWlDbR4CWT1FaTvkU8WhLfpZv3eOrN9PtL8oDdDU=
github.com/charmbracelet/bubbles v0.14.1-0.20221006154229-d1775121146a/go.mod h1:5rZgJTHmgWISQnxnzzIJtQt3GC1bfJfNmr4SEtRDtTQ=
github.com/charmbracelet/bubbletea v0.22.1/go.mod h1:8/7hVvbPN6ZZPkczLiB8YpLkLJ0n7DMho5Wvfd2X1C0=
<<<<<<< HEAD
github.com/charmbracelet/bubbletea v0.22.2-0.20221007181357-2696b2f3399f h1:mbSd0Sdm2wXUWtXJ81o86G9V+9IhddX0qQcGK6bMbKo=
github.com/charmbracelet/bubbletea v0.22.2-0.20221007181357-2696b2f3399f/go.mod h1:JAfGK/3/pPKHTnAS8JIE2u9f61BjWTQY57RbT25aMXU=
||||||| parent of c5917c0 (feat(file): gum file to pick files)
github.com/charmbracelet/bubbletea v0.22.2-0.20221006105051-f406999cba69 h1:GpZktjqyEQjuvFtFb0UlMlbZCOwOhk/bpKb6+quLz+E=
github.com/charmbracelet/bubbletea v0.22.2-0.20221006105051-f406999cba69/go.mod h1:JAfGK/3/pPKHTnAS8JIE2u9f61BjWTQY57RbT25aMXU=
=======
>>>>>>> c5917c0 (feat(file): gum file to pick files)
github.com/charmbracelet/glamour v0.5.1-0.20220727184942-e70ff2d969da h1:FGz53GWQRiKQ/5xUsoCCkewSQIC7u81Scaxx2nUy3nM=
github.com/charmbracelet/glamour v0.5.1-0.20220727184942-e70ff2d969da/go.mod h1:HXz79SMFnF9arKxqeoHWxmo1BhplAH7wehlRhKQIL94=
github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao=
github.com/charmbracelet/lipgloss v0.5.0/go.mod h1:EZLha/HbzEt7cYqdFPovlqy5FZPj0xFhg5SaqxScmgs=
github.com/charmbracelet/lipgloss v0.6.0/go.mod h1:tHh2wr34xcHjC2HCXIlGSG1jaDF0S0atAUvBMP6Ppuk=
github.com/charmbracelet/lipgloss v0.6.1-0.20220930064401-ae7c84f7b158 h1:uuY3ti70rfEiLw3rHKSRiJ+cWfq4KWScgjxhoVRf0eE=
github.com/charmbracelet/lipgloss v0.6.1-0.20220930064401-ae7c84f7b158/go.mod h1:5EY1dcRQX7kPSA5ssoYjq2qEDhpS4cdtmdYY1OlAdMs=
github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw=
@ -62,7 +54,6 @@ github.com/microcosm-cc/bluemonday v1.0.19 h1:OI7hoF5FY4pFz2VA//RN8TfM0YJ2dJcl4P
github.com/microcosm-cc/bluemonday v1.0.19/go.mod h1:QNzV2UbLK2/53oIIwTOyLUSABMkjZ4tqiyC1g/DyqxE=
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.0/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
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/mango v0.1.1-0.20220205060214-77e2058169ab h1:m7QFONkzLK0fVXCjwX5tANcnj1yXxTnYQtnfJiY3tcA=
@ -107,7 +98,6 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=

View File

@ -7,7 +7,7 @@ type Stack struct {
Length func() int
}
// NewStack returns a new stack of integers
// NewStack returns a new stack of integers.
func NewStack() Stack {
slice := make([]int, 0)
return Stack{

View File

@ -13,12 +13,11 @@ import (
func (o Options) Run() error {
vp := viewport.New(o.Style.Width, o.Style.Height)
vp.Style = o.Style.ToLipgloss()
var err error
if o.Content == "" {
stdin, err := stdin.Read()
if err != nil {
return err
return fmt.Errorf("unable to read stdin")
}
if stdin != "" {
o.Content = stdin
@ -34,9 +33,9 @@ func (o Options) Run() error {
showLineNumbers: o.ShowLineNumbers,
lineNumberStyle: o.LineNumberStyle.ToLipgloss(),
}
err := tea.NewProgram(model, tea.WithAltScreen()).Start()
if err != nil {
return err
return fmt.Errorf("unable to start program: %w", err)
}
return tea.NewProgram(model, tea.WithAltScreen()).Start()
return nil
}

View File

@ -4,6 +4,7 @@ import "github.com/charmbracelet/gum/style"
// Options are the options for the pager.
type Options struct {
//nolint:staticcheck
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"`

View File

@ -28,7 +28,7 @@ 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.Height = msg.Height - lipgloss.Height(m.helpStyle.Render("?")) - 1
m.viewport.Width = msg.Width
textStyle := lipgloss.NewStyle().Width(m.viewport.Width)
var text strings.Builder

View File

@ -15,11 +15,11 @@ import (
"github.com/charmbracelet/gum/style"
)
// Run provides a shell script interface for rendering tabular data (CSV)
// Run provides a shell script interface for rendering tabular data (CSV).
func (o Options) Run() error {
var reader *csv.Reader
if o.File != "" {
file, err := os.OpenFile(o.File, os.O_RDONLY, 0600)
file, err := os.Open(o.File)
if err != nil {
return fmt.Errorf("could not find file at path %s", o.File)
}
@ -54,7 +54,7 @@ func (o Options) Run() error {
if err != nil {
return fmt.Errorf("invalid data provided")
}
var columns []table.Column
var columns = make([]table.Column, 0, len(columnNames))
for i, title := range columnNames {
width := runewidth.StringWidth(title)
@ -75,7 +75,7 @@ func (o Options) Run() error {
Selected: defaultStyles.Selected.Inherit(o.SelectedStyle.ToLipgloss()),
}
var rows []table.Row
var rows = make([]table.Row, 0, len(data))
for _, row := range data {
rows = append(rows, table.Row(row))
}
@ -99,7 +99,7 @@ func (o Options) Run() error {
}
m := tm.(model)
fmt.Println(strings.Join([]string(m.selected), string(o.Separator)))
fmt.Println(strings.Join([]string(m.selected), o.Separator))
return nil
}

View File

@ -8,11 +8,10 @@
//
// $ gum table <<< "Flavor,Price\nStrawberry,$0.50\nBanana,$0.99\nCherry,$0.75"
//
// Flavor Price
// Strawberry $0.50
// Banana $0.99
// Cherry $0.75
//
// Flavor Price
// Strawberry $0.50
// Banana $0.99
// Cherry $0.75
package table
import (