diff --git a/README.md b/README.md
index 33f0af7..29f1dd2 100644
--- a/README.md
+++ b/README.md
@@ -289,6 +289,34 @@ gum confirm && rm file.txt || echo "File not removed"
+#### File
+
+Prompt the user to select a file from the file tree.
+
+```bash
+EDITOR $(gum file $HOME)
+```
+
+
+
+#### Pager
+
+Scroll through a long document with line numbers and a fully customizable viewport.
+
+```bash
+gum pager < README.md
+```
+
+
+
#### 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
+```
+
+
+
## Styling
#### Style
diff --git a/file/command.go b/file/command.go
index bdade02..fd6df01 100644
--- a/file/command.go
+++ b/file/command.go
@@ -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)
diff --git a/file/file.go b/file/file.go
index 06e0e10..d1db75a 100644
--- a/file/file.go
+++ b/file/file.go
@@ -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()
diff --git a/file/hidden_unix.go b/file/hidden_unix.go
index ada959b..a3e2cb1 100644
--- a/file/hidden_unix.go
+++ b/file/hidden_unix.go
@@ -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
}
diff --git a/file/options.go b/file/options.go
index 415fbf4..91228f5 100644
--- a/file/options.go
+++ b/file/options.go
@@ -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_"`
}
diff --git a/go.sum b/go.sum
index 4f1b376..88c563a 100644
--- a/go.sum
+++ b/go.sum
@@ -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=
diff --git a/internal/stack/stack.go b/internal/stack/stack.go
index af90413..b28fedb 100644
--- a/internal/stack/stack.go
+++ b/internal/stack/stack.go
@@ -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{
diff --git a/pager/command.go b/pager/command.go
index 77da6ba..ec9c1b6 100644
--- a/pager/command.go
+++ b/pager/command.go
@@ -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
}
diff --git a/pager/options.go b/pager/options.go
index 9900d82..f8da7ce 100644
--- a/pager/options.go
+++ b/pager/options.go
@@ -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"`
diff --git a/pager/pager.go b/pager/pager.go
index f359a0e..f920074 100644
--- a/pager/pager.go
+++ b/pager/pager.go
@@ -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
diff --git a/table/command.go b/table/command.go
index 364fa83..1fe4106 100644
--- a/table/command.go
+++ b/table/command.go
@@ -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
}
diff --git a/table/table.go b/table/table.go
index 4c5929a..ce55616 100644
--- a/table/table.go
+++ b/table/table.go
@@ -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 (