mirror of
https://github.com/charmbracelet/gum
synced 2024-06-08 00:32:17 +02:00
feat(file): gum file to pick files
This commit is contained in:
parent
430ab459d7
commit
2bea4dc030
58
file/command.go
Normal file
58
file/command.go
Normal file
|
@ -0,0 +1,58 @@
|
|||
package file
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/charmbracelet/gum/internal/stack"
|
||||
)
|
||||
|
||||
// Run is the interface to picking a file.
|
||||
func (o Options) Run() error {
|
||||
if o.Path == "" {
|
||||
o.Path = "."
|
||||
}
|
||||
|
||||
path, err := filepath.Abs(o.Path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m := model{
|
||||
path: path,
|
||||
cursor: o.Cursor,
|
||||
selected: 0,
|
||||
showHidden: o.All,
|
||||
autoHeight: o.Height == 0,
|
||||
height: o.Height,
|
||||
max: 0,
|
||||
min: 0,
|
||||
selectedStack: stack.NewStack(),
|
||||
minStack: stack.NewStack(),
|
||||
maxStack: stack.NewStack(),
|
||||
cursorStyle: o.CursorStyle.ToLipgloss(),
|
||||
symlinkStyle: o.SymlinkStyle.ToLipgloss(),
|
||||
directoryStyle: o.DirectoryStyle.ToLipgloss(),
|
||||
fileStyle: o.FileStyle.ToLipgloss(),
|
||||
permissionStyle: o.PermissionsStyle.ToLipgloss(),
|
||||
selectedStyle: o.SelectedStyle.ToLipgloss(),
|
||||
fileSizeStyle: o.FileSizeStyle.ToLipgloss(),
|
||||
}
|
||||
|
||||
tm, err := tea.NewProgram(&m, tea.WithOutput(os.Stderr)).StartReturningModel()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m = tm.(model)
|
||||
|
||||
if m.path == "" {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Println(m.path)
|
||||
|
||||
return nil
|
||||
}
|
226
file/file.go
Normal file
226
file/file.go
Normal file
|
@ -0,0 +1,226 @@
|
|||
// Package file provides an interface to pick a file from a folder (tree).
|
||||
// The user is provided a file manager-like interface to navigate, to
|
||||
// select a file.
|
||||
//
|
||||
// Let's pick a file from the current directory:
|
||||
//
|
||||
// $ gum file
|
||||
// $ gum file .
|
||||
//
|
||||
// Let's pick a file from the home directory:
|
||||
//
|
||||
// $ gum file $HOME
|
||||
package file
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/charmbracelet/gum/internal/stack"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"github.com/dustin/go-humanize"
|
||||
)
|
||||
|
||||
const marginBottom = 5
|
||||
|
||||
type model struct {
|
||||
quitting bool
|
||||
path string
|
||||
files []os.DirEntry
|
||||
showHidden bool
|
||||
|
||||
selected int
|
||||
selectedStack stack.Stack
|
||||
|
||||
min int
|
||||
max int
|
||||
maxStack stack.Stack
|
||||
minStack stack.Stack
|
||||
height int
|
||||
autoHeight bool
|
||||
|
||||
cursor string
|
||||
cursorStyle lipgloss.Style
|
||||
symlinkStyle lipgloss.Style
|
||||
directoryStyle lipgloss.Style
|
||||
fileStyle lipgloss.Style
|
||||
permissionStyle lipgloss.Style
|
||||
selectedStyle lipgloss.Style
|
||||
fileSizeStyle lipgloss.Style
|
||||
}
|
||||
|
||||
type readDirMsg []os.DirEntry
|
||||
|
||||
func readDir(path string, showHidden bool) tea.Cmd {
|
||||
return func() tea.Msg {
|
||||
dirEntries, err := os.ReadDir(path)
|
||||
if err != nil {
|
||||
return tea.Quit
|
||||
}
|
||||
|
||||
sort.Slice(dirEntries, func(i, j int) bool {
|
||||
if dirEntries[i].IsDir() == dirEntries[j].IsDir() {
|
||||
return dirEntries[i].Name() < dirEntries[j].Name()
|
||||
}
|
||||
return dirEntries[i].IsDir()
|
||||
})
|
||||
|
||||
if showHidden {
|
||||
return readDirMsg(dirEntries)
|
||||
}
|
||||
|
||||
var sanitizedDirEntries []fs.DirEntry
|
||||
for _, dirEntry := range dirEntries {
|
||||
isHidden, _ := IsHidden(dirEntry.Name())
|
||||
if isHidden {
|
||||
continue
|
||||
}
|
||||
sanitizedDirEntries = append(sanitizedDirEntries, dirEntry)
|
||||
}
|
||||
return readDirMsg(sanitizedDirEntries)
|
||||
}
|
||||
}
|
||||
|
||||
func (m model) Init() tea.Cmd {
|
||||
return readDir(m.path, m.showHidden)
|
||||
}
|
||||
|
||||
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
switch msg := msg.(type) {
|
||||
case readDirMsg:
|
||||
m.files = msg
|
||||
case tea.WindowSizeMsg:
|
||||
if m.autoHeight {
|
||||
m.height = msg.Height - marginBottom
|
||||
}
|
||||
m.max = m.height
|
||||
case tea.KeyMsg:
|
||||
switch msg.String() {
|
||||
case "g":
|
||||
m.selected = 0
|
||||
m.min = 0
|
||||
m.max = m.height - 1
|
||||
case "G":
|
||||
m.selected = len(m.files) - 1
|
||||
m.min = len(m.files) - m.height
|
||||
m.max = len(m.files) - 1
|
||||
case "j", "down":
|
||||
m.selected++
|
||||
if m.selected >= len(m.files) {
|
||||
m.selected = len(m.files) - 1
|
||||
}
|
||||
if m.selected > m.max {
|
||||
m.min++
|
||||
m.max++
|
||||
}
|
||||
case "k", "up":
|
||||
m.selected--
|
||||
if m.selected < 0 {
|
||||
m.selected = 0
|
||||
}
|
||||
if m.selected < m.min {
|
||||
m.min--
|
||||
m.max--
|
||||
}
|
||||
case "ctrl+c", "q":
|
||||
m.path = ""
|
||||
m.quitting = true
|
||||
return m, tea.Quit
|
||||
case "backspace", "h", "left":
|
||||
m.path = filepath.Dir(m.path)
|
||||
if m.selectedStack.Length() > 0 {
|
||||
m.selected, m.min, m.max = m.popView()
|
||||
} else {
|
||||
m.selected = 0
|
||||
m.min = 0
|
||||
m.max = m.height - 1
|
||||
}
|
||||
return m, readDir(m.path, m.showHidden)
|
||||
case "l", "right", "enter":
|
||||
if len(m.files) == 0 {
|
||||
break
|
||||
}
|
||||
if !m.files[m.selected].IsDir() {
|
||||
if msg.String() == "enter" {
|
||||
m.path = filepath.Join(m.path, m.files[m.selected].Name())
|
||||
m.quitting = true
|
||||
return m, tea.Quit
|
||||
}
|
||||
break
|
||||
}
|
||||
m.path = filepath.Join(m.path, m.files[m.selected].Name())
|
||||
m.pushView()
|
||||
m.selected = 0
|
||||
m.min = 0
|
||||
m.max = m.height - 1
|
||||
return m, readDir(m.path, m.showHidden)
|
||||
}
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (m model) pushView() {
|
||||
m.minStack.Push(m.min)
|
||||
m.maxStack.Push(m.max)
|
||||
m.selectedStack.Push(m.selected)
|
||||
}
|
||||
|
||||
func (m model) popView() (int, int, int) {
|
||||
return m.selectedStack.Pop(), m.minStack.Pop(), m.maxStack.Pop()
|
||||
}
|
||||
|
||||
func (m model) View() string {
|
||||
if m.quitting {
|
||||
return ""
|
||||
}
|
||||
if len(m.files) == 0 {
|
||||
return "Bummer. No files found."
|
||||
}
|
||||
var s strings.Builder
|
||||
|
||||
for i, f := range m.files {
|
||||
if i < m.min {
|
||||
continue
|
||||
}
|
||||
if i > m.max {
|
||||
break
|
||||
}
|
||||
|
||||
var symlinkPath string
|
||||
info, _ := f.Info()
|
||||
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.WriteString("\n")
|
||||
}
|
||||
|
||||
return s.String()
|
||||
}
|
10
file/hidden_unix.go
Normal file
10
file/hidden_unix.go
Normal file
|
@ -0,0 +1,10 @@
|
|||
//go:build !windows
|
||||
|
||||
package file
|
||||
|
||||
import "strings"
|
||||
|
||||
// IsHidden reports whether a file is hidden or not
|
||||
func IsHidden(file string) (bool, error) {
|
||||
return strings.HasPrefix(file, "."), nil
|
||||
}
|
21
file/options.go
Normal file
21
file/options.go
Normal file
|
@ -0,0 +1,21 @@
|
|||
package file
|
||||
|
||||
import "github.com/charmbracelet/gum/style"
|
||||
|
||||
// Options are the options for the file command.
|
||||
type Options struct {
|
||||
// Path is the path to the folder / directory to begin traversing.
|
||||
Path string `arg:"" optional:"" name:"path" help:"The path to the folder to begin traversing"`
|
||||
// Cursor is the character to display in front of the current selected items.
|
||||
Cursor string `short:"c" help:"The cursor character" default:">"`
|
||||
All bool `short:"a" help:"Show hidden and 'dot' files" default:"true"`
|
||||
|
||||
Height int `help:"Maximum number of files to display" default:"0"`
|
||||
CursorStyle style.Styles `embed:"" prefix:"cursor." help:"The cursor style" set:"defaultForeground=212" envprefix:"GUM_FILE_CURSOR_"`
|
||||
SymlinkStyle style.Styles `embed:"" prefix:"symlink." help:"The style to use for symlinks" set:"defaultForeground=36" envprefix:"GUM_FILE_SYMLINK_"`
|
||||
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_"`
|
||||
}
|
3
go.mod
3
go.mod
|
@ -8,7 +8,8 @@ require (
|
|||
github.com/charmbracelet/bubbles v0.14.1-0.20221006154229-d1775121146a
|
||||
github.com/charmbracelet/bubbletea v0.22.2-0.20221007181357-2696b2f3399f
|
||||
github.com/charmbracelet/glamour v0.5.1-0.20220727184942-e70ff2d969da
|
||||
github.com/charmbracelet/lipgloss v0.6.0
|
||||
github.com/charmbracelet/lipgloss v0.6.1-0.20220930064401-ae7c84f7b158
|
||||
github.com/dustin/go-humanize v1.0.0
|
||||
github.com/mattn/go-runewidth v0.0.14
|
||||
github.com/muesli/roff v0.1.0
|
||||
github.com/muesli/termenv v0.13.0
|
||||
|
|
26
go.sum
26
go.sum
|
@ -13,16 +13,25 @@ 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.1-0.20221006154229-d1775121146a h1:/prXWlDbR4CWT1FaTvkU8WhLfpZv3eOrN9PtL8oDdDU=
|
||||
github.com/charmbracelet/bubbles v0.14.1-0.20221006154229-d1775121146a/go.mod h1:5rZgJTHmgWISQnxnzzIJtQt3GC1bfJfNmr4SEtRDtTQ=
|
||||
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/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.6.0 h1:1StyZB9vBSOyuZxQUcUwGr17JmojPNm87inij9N3wJY=
|
||||
github.com/charmbracelet/lipgloss v0.6.0/go.mod h1:tHh2wr34xcHjC2HCXIlGSG1jaDF0S0atAUvBMP6Ppuk=
|
||||
github.com/charmbracelet/lipgloss v0.5.0/go.mod h1:EZLha/HbzEt7cYqdFPovlqy5FZPj0xFhg5SaqxScmgs=
|
||||
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=
|
||||
github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
|
@ -30,6 +39,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
|
|||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E=
|
||||
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
|
||||
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
|
||||
github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
|
||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||
|
@ -51,6 +62,7 @@ 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=
|
||||
|
@ -76,9 +88,12 @@ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ
|
|||
github.com/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI=
|
||||
github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
|
||||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.4.4 h1:zNWRjYUW32G9KirMXYHQHVNFkXvMI7LpgNW2AgYAoIs=
|
||||
github.com/yuin/goldmark v1.4.4/go.mod h1:rmuwmfZ0+bvzB24eSC//bk1R1Zp3hM0OXYv/G2LIilg=
|
||||
|
@ -92,6 +107,7 @@ 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=
|
||||
|
|
28
gum.go
28
gum.go
|
@ -6,6 +6,7 @@ import (
|
|||
"github.com/charmbracelet/gum/choose"
|
||||
"github.com/charmbracelet/gum/completion"
|
||||
"github.com/charmbracelet/gum/confirm"
|
||||
"github.com/charmbracelet/gum/file"
|
||||
"github.com/charmbracelet/gum/filter"
|
||||
"github.com/charmbracelet/gum/format"
|
||||
"github.com/charmbracelet/gum/input"
|
||||
|
@ -56,6 +57,20 @@ type Gum struct {
|
|||
//
|
||||
Confirm confirm.Options `cmd:"" help:"Ask a user to confirm an action"`
|
||||
|
||||
// File provides an interface to pick a file from a folder (tree).
|
||||
// The user is provided a file manager-like interface to navigate, to
|
||||
// select a file.
|
||||
//
|
||||
// Let's pick a file from the current directory:
|
||||
//
|
||||
// $ gum file
|
||||
// $ gum file .
|
||||
//
|
||||
// Let's pick a file from the home directory:
|
||||
//
|
||||
// $ gum file $HOME
|
||||
File file.Options `cmd:"" help:"Pick a file from a folder"`
|
||||
|
||||
// Filter provides a fuzzy searching text input to allow filtering a list of
|
||||
// options to select one option.
|
||||
//
|
||||
|
@ -106,6 +121,19 @@ type Gum struct {
|
|||
// https://github.com/charmbracelet/bubbles/tree/master/viewport
|
||||
//
|
||||
// It allows the user to scroll through content like a pager.
|
||||
//
|
||||
// ╭────────────────────────────────────────────────╮
|
||||
// │ 1 │ Gum Pager │
|
||||
// │ 2 │ ========= │
|
||||
// │ 3 │ │
|
||||
// │ 4 │ ``` │
|
||||
// │ 5 │ gum pager --height 10 --width 25 < text │
|
||||
// │ 6 │ ``` │
|
||||
// │ 7 │ │
|
||||
// │ 8 │ │
|
||||
// ╰────────────────────────────────────────────────╯
|
||||
// ↑/↓: Navigate • q: Quit
|
||||
//
|
||||
Pager pager.Options `cmd:"" help:"Scroll through a file"`
|
||||
|
||||
// Spin provides a shell script interface for the spinner bubble.
|
||||
|
|
26
internal/stack/stack.go
Normal file
26
internal/stack/stack.go
Normal file
|
@ -0,0 +1,26 @@
|
|||
package stack
|
||||
|
||||
// Stack is a stack interface for integers.
|
||||
type Stack struct {
|
||||
Push func(int)
|
||||
Pop func() int
|
||||
Length func() int
|
||||
}
|
||||
|
||||
// NewStack returns a new stack of integers
|
||||
func NewStack() Stack {
|
||||
slice := make([]int, 0)
|
||||
return Stack{
|
||||
Push: func(i int) {
|
||||
slice = append(slice, i)
|
||||
},
|
||||
Pop: func() int {
|
||||
res := slice[len(slice)-1]
|
||||
slice = slice[:len(slice)-1]
|
||||
return res
|
||||
},
|
||||
Length: func() int {
|
||||
return len(slice)
|
||||
},
|
||||
}
|
||||
}
|
8
main.go
8
main.go
|
@ -53,13 +53,21 @@ func main() {
|
|||
}),
|
||||
kong.Vars{
|
||||
"version": version,
|
||||
"defaultHeight": "0",
|
||||
"defaultWidth": "0",
|
||||
"defaultAlign": "left",
|
||||
"defaultBorder": "none",
|
||||
"defaultBorderForeground": "",
|
||||
"defaultBorderBackground": "",
|
||||
"defaultBackground": "",
|
||||
"defaultForeground": "",
|
||||
"defaultMargin": "0 0",
|
||||
"defaultPadding": "0 0",
|
||||
"defaultUnderline": "false",
|
||||
"defaultBold": "false",
|
||||
"defaultFaint": "false",
|
||||
"defaultItalic": "false",
|
||||
"defaultStrikethrough": "false",
|
||||
},
|
||||
)
|
||||
if err := ctx.Run(); err != nil {
|
||||
|
|
|
@ -23,20 +23,20 @@ type Styles struct {
|
|||
|
||||
// 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"`
|
||||
BorderBackground string `help:"Border Background Color" group:"Style Flags" default:"${defaultBorderBackground}" env:"BORDER_BACKGROUND"`
|
||||
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"`
|
||||
Height int `help:"Text height" group:"Style Flags" env:"HEIGHT"`
|
||||
Width int `help:"Text width" group:"Style Flags" env:"WIDTH"`
|
||||
Align string `help:"Text Alignment" enum:"left,center,right,bottom,middle,top" default:"${defaultAlign}" group:"Style Flags" env:"ALIGN"`
|
||||
Height int `help:"Text height" default:"${defaultHeight}" group:"Style Flags" env:"HEIGHT"`
|
||||
Width int `help:"Text width" default:"${defaultWidth}" group:"Style Flags" env:"WIDTH"`
|
||||
Margin string `help:"Text margin" default:"${defaultMargin}" group:"Style Flags" env:"MARGIN"`
|
||||
Padding string `help:"Text padding" default:"${defaultPadding}" group:"Style Flags" env:"PADDING"`
|
||||
|
||||
// Format
|
||||
Bold bool `help:"Bold text" group:"Style Flags" env:"BOLD"`
|
||||
Faint bool `help:"Faint text" group:"Style Flags" env:"FAINT"`
|
||||
Italic bool `help:"Italicize text" group:"Style Flags" env:"ITALIC"`
|
||||
Strikethrough bool `help:"Strikethrough text" group:"Style Flags" env:"STRIKETHROUGH"`
|
||||
Bold bool `help:"Bold text" default:"${defaultBold}" group:"Style Flags" env:"BOLD"`
|
||||
Faint bool `help:"Faint text" default:"${defaultFaint}" group:"Style Flags" env:"FAINT"`
|
||||
Italic bool `help:"Italicize text" default:"${defaultItalic}" group:"Style Flags" env:"ITALIC"`
|
||||
Strikethrough bool `help:"Strikethrough text" default:"${defaultStrikethrough}" group:"Style Flags" env:"STRIKETHROUGH"`
|
||||
Underline bool `help:"Underline text" default:"${defaultUnderline}" group:"Style Flags" env:"UNDERLINE"`
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue