feat: huh file picker (#523)

Use `huh` for `gum file`.
This commit is contained in:
Maas Lalani 2024-03-28 16:19:06 -04:00 committed by GitHub
parent f7572e387e
commit 3a717104a9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 32 additions and 115 deletions

View file

@ -3,13 +3,10 @@ package file
import (
"errors"
"fmt"
"os"
"path/filepath"
"github.com/charmbracelet/gum/internal/exit"
"github.com/charmbracelet/bubbles/filepicker"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/huh"
"github.com/charmbracelet/lipgloss"
)
// Run is the interface to picking a file.
@ -27,46 +24,36 @@ func (o Options) Run() error {
return fmt.Errorf("file not found: %w", err)
}
fp := filepicker.New()
fp.CurrentDirectory = path
fp.Path = path
fp.Height = o.Height
fp.AutoHeight = o.Height == 0
fp.Cursor = o.Cursor
fp.DirAllowed = o.Directory
fp.FileAllowed = o.File
fp.ShowHidden = o.All
fp.Styles = filepicker.DefaultStyles()
fp.Styles.Cursor = o.CursorStyle.ToLipgloss()
fp.Styles.Symlink = o.SymlinkStyle.ToLipgloss()
fp.Styles.Directory = o.DirectoryStyle.ToLipgloss()
fp.Styles.File = o.FileStyle.ToLipgloss()
fp.Styles.Permission = o.PermissionsStyle.ToLipgloss()
fp.Styles.Selected = o.SelectedStyle.ToLipgloss()
fp.Styles.FileSize = o.FileSizeStyle.ToLipgloss()
theme := huh.ThemeCharm()
theme.Focused.Base = lipgloss.NewStyle()
theme.Focused.File = o.FileStyle.ToLipgloss()
theme.Focused.Directory = o.DirectoryStyle.ToLipgloss()
theme.Focused.SelectedOption = o.SelectedStyle.ToLipgloss()
m := model{
filepicker: fp,
timeout: o.Timeout,
hasTimeout: o.Timeout > 0,
aborted: false,
}
// XXX: These should be file selected specific.
theme.Focused.TextInput.Placeholder = o.PermissionsStyle.ToLipgloss()
theme.Focused.TextInput.Prompt = o.CursorStyle.ToLipgloss()
err = huh.NewForm(
huh.NewGroup(
huh.NewFilePicker().
Picking(true).
CurrentDirectory(path).
DirAllowed(o.Directory).
FileAllowed(o.File).
Height(o.Height).
ShowHidden(o.All).
Value(&path),
),
).
WithShowHelp(false).
WithTheme(theme).
Run()
tm, err := tea.NewProgram(&m, tea.WithOutput(os.Stderr)).Run()
if err != nil {
return fmt.Errorf("unable to pick selection: %w", err)
return err
}
m = tm.(model)
if m.aborted {
return exit.ErrAborted
}
if m.selectedPath == "" {
os.Exit(1)
}
fmt.Println(m.selectedPath)
fmt.Println(path)
return nil
}

View file

@ -1,72 +0,0 @@
// 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 (
"time"
"github.com/charmbracelet/bubbles/filepicker"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/gum/timeout"
)
type model struct {
filepicker filepicker.Model
selectedPath string
aborted bool
quitting bool
timeout time.Duration
hasTimeout bool
}
func (m model) Init() tea.Cmd {
return tea.Batch(
timeout.Init(m.timeout, nil),
m.filepicker.Init(),
)
}
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.KeyMsg:
switch msg.String() {
case "ctrl+c", "q", "esc":
m.aborted = true
m.quitting = true
return m, tea.Quit
}
case timeout.TickTimeoutMsg:
if msg.TimeoutValue <= 0 {
m.quitting = true
m.aborted = true
return m, tea.Quit
}
m.timeout = msg.TimeoutValue
return m, timeout.Tick(msg.TimeoutValue, msg.Data)
}
var cmd tea.Cmd
m.filepicker, cmd = m.filepicker.Update(msg)
if didSelect, path := m.filepicker.DidSelectFile(msg); didSelect {
m.selectedPath = path
m.quitting = true
return m, tea.Quit
}
return m, cmd
}
func (m model) View() string {
if m.quitting {
return ""
}
return m.filepicker.View()
}

View file

@ -16,7 +16,7 @@ type Options struct {
File bool `help:"Allow files selection" default:"true" env:"GUM_FILE_FILE"`
Directory bool `help:"Allow directories selection" default:"false" env:"GUM_FILE_DIRECTORY"`
Height int `help:"Maximum number of files to display" default:"0" env:"GUM_FILE_HEIGHT"`
Height int `help:"Maximum number of files to display" default:"10" env:"GUM_FILE_HEIGHT"`
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_"`

2
go.mod
View file

@ -8,7 +8,7 @@ require (
github.com/charmbracelet/bubbles v0.18.0
github.com/charmbracelet/bubbletea v0.25.0
github.com/charmbracelet/glamour v0.7.0
github.com/charmbracelet/huh v0.3.1-0.20240327025511-ec643317aa10
github.com/charmbracelet/huh v0.3.1-0.20240328185852-590ecabc34b9
github.com/charmbracelet/lipgloss v0.10.0
github.com/charmbracelet/log v0.4.0
github.com/mattn/go-isatty v0.0.20

2
go.sum
View file

@ -29,6 +29,8 @@ github.com/charmbracelet/huh v0.3.0 h1:CxPplWkgW2yUTDDG0Z4S5HH8SJOosWHd4LxCvi0Xs
github.com/charmbracelet/huh v0.3.0/go.mod h1:fujUdKX8tC45CCSaRQdw789O6uaCRwx8l2NDyKfC4jA=
github.com/charmbracelet/huh v0.3.1-0.20240327025511-ec643317aa10 h1:779PmXc9Zt/Hxa0yg4I8sQk/1Nfa5TQisXaHZEW60Yk=
github.com/charmbracelet/huh v0.3.1-0.20240327025511-ec643317aa10/go.mod h1:x0rYoA1kpsaefXhRJZuxLM+qP4CYyEFE67T3ZGl7zPU=
github.com/charmbracelet/huh v0.3.1-0.20240328185852-590ecabc34b9 h1:Izr4MC+shs9PpR4MWz/OFA4+ywbKutvPv0eSHJwfn60=
github.com/charmbracelet/huh v0.3.1-0.20240328185852-590ecabc34b9/go.mod h1:x0rYoA1kpsaefXhRJZuxLM+qP4CYyEFE67T3ZGl7zPU=
github.com/charmbracelet/lipgloss v0.10.0 h1:KWeXFSexGcfahHX+54URiZGkBFazf70JNMtwg/AFW3s=
github.com/charmbracelet/lipgloss v0.10.0/go.mod h1:Wig9DSfvANsxqkRsqj6x87irdy123SR4dOXlKa91ciE=
github.com/charmbracelet/log v0.3.1 h1:TjuY4OBNbxmHWSwO3tosgqs5I3biyY8sQPny/eCMTYw=