Skip to content

Commit

Permalink
support external keymap, add API for current file
Browse files Browse the repository at this point in the history
  • Loading branch information
ardnew committed Jan 8, 2024
1 parent 1b2c707 commit be5c416
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 99 deletions.
121 changes: 62 additions & 59 deletions keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,67 +2,70 @@ package walk

import "github.com/charmbracelet/bubbles/key"

type keyMap struct {
forceQuit key.Binding
quit key.Binding
quitQ key.Binding
open key.Binding
back key.Binding
up key.Binding
down key.Binding
left key.Binding
right key.Binding
top key.Binding
bottom key.Binding
leftmost key.Binding
rightmost key.Binding
pageUp key.Binding
pageDown key.Binding
home key.Binding
end key.Binding
vimUp key.Binding
vimDown key.Binding
vimLeft key.Binding
vimRight key.Binding
vimTop key.Binding
vimBottom key.Binding
search key.Binding
preview key.Binding
delete key.Binding
undo key.Binding
yank key.Binding
type KeyMap struct {
ForceQuit key.Binding
Quit key.Binding
QuitQ key.Binding
Open key.Binding
Back key.Binding
Up key.Binding
Down key.Binding
Left key.Binding
Right key.Binding
Top key.Binding
Bottom key.Binding
Leftmost key.Binding
Rightmost key.Binding
PageUp key.Binding
PageDown key.Binding
Home key.Binding
End key.Binding
VimUp key.Binding
VimDown key.Binding
VimLeft key.Binding
VimRight key.Binding
VimTop key.Binding
VimBottom key.Binding
Search key.Binding
Preview key.Binding
Delete key.Binding
Undo key.Binding
Yank key.Binding
}

func newKeyMap() *keyMap { return new(keyMap).init() }
func NewKeyMap() *KeyMap { return new(KeyMap).Default() }

func (k *keyMap) init() *keyMap {
k.forceQuit = key.NewBinding(key.WithKeys("ctrl+c"))
k.quit = key.NewBinding(key.WithKeys("esc"))
k.quitQ = key.NewBinding(key.WithKeys("q"))
k.open = key.NewBinding(key.WithKeys("enter"))
k.back = key.NewBinding(key.WithKeys("backspace"))
k.up = key.NewBinding(key.WithKeys("up"))
k.down = key.NewBinding(key.WithKeys("down"))
k.left = key.NewBinding(key.WithKeys("left"))
k.right = key.NewBinding(key.WithKeys("right"))
k.top = key.NewBinding(key.WithKeys("shift+up"))
k.bottom = key.NewBinding(key.WithKeys("shift+down"))
k.leftmost = key.NewBinding(key.WithKeys("shift+left"))
k.rightmost = key.NewBinding(key.WithKeys("shift+right"))
k.pageUp = key.NewBinding(key.WithKeys("pgup"))
k.pageDown = key.NewBinding(key.WithKeys("pgdown"))
k.home = key.NewBinding(key.WithKeys("home"))
k.end = key.NewBinding(key.WithKeys("end"))
k.vimUp = key.NewBinding(key.WithKeys("k"))
k.vimDown = key.NewBinding(key.WithKeys("j"))
k.vimLeft = key.NewBinding(key.WithKeys("h"))
k.vimRight = key.NewBinding(key.WithKeys("l"))
k.vimTop = key.NewBinding(key.WithKeys("g"))
k.vimBottom = key.NewBinding(key.WithKeys("G"))
k.search = key.NewBinding(key.WithKeys("/"))
k.preview = key.NewBinding(key.WithKeys(" "))
k.delete = key.NewBinding(key.WithKeys("d"))
k.undo = key.NewBinding(key.WithKeys("u"))
k.yank = key.NewBinding(key.WithKeys("y"))
func (k *KeyMap) Default() *KeyMap {
if k == nil {
k = new(KeyMap)
}
k.ForceQuit = key.NewBinding(key.WithKeys("ctrl+c"))
k.Quit = key.NewBinding(key.WithKeys("esc"))
k.QuitQ = key.NewBinding(key.WithKeys("q"))
k.Open = key.NewBinding(key.WithKeys("enter"))
k.Back = key.NewBinding(key.WithKeys("backspace"))
k.Up = key.NewBinding(key.WithKeys("up"))
k.Down = key.NewBinding(key.WithKeys("down"))
k.Left = key.NewBinding(key.WithKeys("left"))
k.Right = key.NewBinding(key.WithKeys("right"))
k.Top = key.NewBinding(key.WithKeys("shift+up"))
k.Bottom = key.NewBinding(key.WithKeys("shift+down"))
k.Leftmost = key.NewBinding(key.WithKeys("shift+left"))
k.Rightmost = key.NewBinding(key.WithKeys("shift+right"))
k.PageUp = key.NewBinding(key.WithKeys("pgup"))
k.PageDown = key.NewBinding(key.WithKeys("pgdown"))
k.Home = key.NewBinding(key.WithKeys("home"))
k.End = key.NewBinding(key.WithKeys("end"))
k.VimUp = key.NewBinding(key.WithKeys("k"))
k.VimDown = key.NewBinding(key.WithKeys("j"))
k.VimLeft = key.NewBinding(key.WithKeys("h"))
k.VimRight = key.NewBinding(key.WithKeys("l"))
k.VimTop = key.NewBinding(key.WithKeys("g"))
k.VimBottom = key.NewBinding(key.WithKeys("G"))
k.Search = key.NewBinding(key.WithKeys("/"))
k.Preview = key.NewBinding(key.WithKeys(" "))
k.Delete = key.NewBinding(key.WithKeys("d"))
k.Undo = key.NewBinding(key.WithKeys("u"))
k.Yank = key.NewBinding(key.WithKeys("y"))
return k
}
98 changes: 58 additions & 40 deletions walk.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import (
"github.com/sahilm/fuzzy"
)

var version = "v2.1.0"
var version = "v2.2.0"

func Version() string { return version }

Expand All @@ -35,22 +35,26 @@ type Styles struct {
Warning, Preview, Cursor, Bar, Search, Danger lipgloss.Style
}

func DefaultStyle() *Styles {
return &Styles{
Warning: lipgloss.NewStyle().Border(lipgloss.RoundedBorder()).PaddingLeft(1).PaddingRight(1),
Preview: lipgloss.NewStyle().PaddingLeft(2),
Cursor: lipgloss.NewStyle().Background(lipgloss.Color("#825DF2")).Foreground(lipgloss.Color("#FFFFFF")),
Bar: lipgloss.NewStyle().Background(lipgloss.Color("#5C5C5C")).Foreground(lipgloss.Color("#FFFFFF")),
Search: lipgloss.NewStyle().Background(lipgloss.Color("#499F1C")).Foreground(lipgloss.Color("#FFFFFF")),
Danger: lipgloss.NewStyle().Background(lipgloss.Color("#FF0000")).Foreground(lipgloss.Color("#FFFFFF")),
func NewStyles() *Styles { return new(Styles).Default() }

func (s *Styles) Default() *Styles {
if s == nil {
s = new(Styles)
}
s.Warning = lipgloss.NewStyle().Border(lipgloss.RoundedBorder()).PaddingLeft(1).PaddingRight(1)
s.Preview = lipgloss.NewStyle().PaddingLeft(2)
s.Cursor = lipgloss.NewStyle().Background(lipgloss.Color("#825DF2")).Foreground(lipgloss.Color("#FFFFFF"))
s.Bar = lipgloss.NewStyle().Background(lipgloss.Color("#5C5C5C")).Foreground(lipgloss.Color("#FFFFFF"))
s.Search = lipgloss.NewStyle().Background(lipgloss.Color("#499F1C")).Foreground(lipgloss.Color("#FFFFFF"))
s.Danger = lipgloss.NewStyle().Background(lipgloss.Color("#FF0000")).Foreground(lipgloss.Color("#FFFFFF"))
return s
}

type Model struct {
path string // Current dir path we are looking at.
files []fs.DirEntry // Files we are looking at.
err error // Error while listing files.
kb *keyMap // Key bindings.
kb *KeyMap // Key bindings.
st *Styles // Rendering attributes.
cmdline []string // Command line to open files.
c, r int // Selector position in columns and rows.
Expand Down Expand Up @@ -136,14 +140,23 @@ func (m *Model) WithStyle(styles *Styles) *Model {
return m
}

func Keys(keys *KeyMap) Option {
return func(m *Model) *Model { return m.WithKeys(keys) }
}

func (m *Model) WithKeys(keys *KeyMap) *Model {
m.kb = keys
return m
}

func New(options ...Option) *Model {
m := (&Model{
kb: newKeyMap(),
positions: make(map[string]position),
}).With(options...)
m := (&Model{ positions: make(map[string]position) }).With(options...)

if m.kb == nil {
m.kb = m.kb.Default()
}
if m.st == nil {
m.st = DefaultStyle()
m.st = m.st.Default()
}
return m
}
Expand Down Expand Up @@ -191,10 +204,10 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {

case tea.KeyMsg:
if m.searchMode {
if key.Matches(msg, m.kb.search) {
if key.Matches(msg, m.kb.Search) {
m.searchMode = false
return m, nil
} else if key.Matches(msg, m.kb.back) {
} else if key.Matches(msg, m.kb.Back) {
if len(m.search) > 0 {
m.search = m.search[:len(m.search)-1]
return m, nil
Expand Down Expand Up @@ -224,20 +237,20 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}

switch {
case key.Matches(msg, m.kb.forceQuit):
case key.Matches(msg, m.kb.ForceQuit):
_, _ = fmt.Fprintln(os.Stderr) // Keep last item visible after prompt.
m.exitCode = 2
m.dontDoPendingDeletions()
return m, tea.Quit

case key.Matches(msg, m.kb.quit, m.kb.quitQ):
case key.Matches(msg, m.kb.Quit, m.kb.QuitQ):
_, _ = fmt.Fprintln(os.Stderr) // Keep last item visible after prompt.
fmt.Println(m.path) // Write to cd.
m.exitCode = 0
m.performPendingDeletions()
return m, tea.Quit

case key.Matches(msg, m.kb.open):
case key.Matches(msg, m.kb.Open):
m.searchMode = false
filePath, ok := m.filePath()
if !ok {
Expand All @@ -261,7 +274,7 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return m, m.openCommand()
}

case key.Matches(msg, m.kb.back):
case key.Matches(msg, m.kb.Back):
m.searchMode = false
m.prevName = filepath.Base(m.path)
m.path = filepath.Join(m.path, "..")
Expand All @@ -275,62 +288,62 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.list()
return m, nil

case key.Matches(msg, m.kb.up):
case key.Matches(msg, m.kb.Up):
m.moveUp()

case key.Matches(msg, m.kb.top, m.kb.pageUp, m.kb.vimTop):
case key.Matches(msg, m.kb.Top, m.kb.PageUp, m.kb.VimTop):
m.moveTop()

case key.Matches(msg, m.kb.bottom, m.kb.pageDown, m.kb.vimBottom):
case key.Matches(msg, m.kb.Bottom, m.kb.PageDown, m.kb.VimBottom):
m.moveBottom()

case key.Matches(msg, m.kb.leftmost):
case key.Matches(msg, m.kb.Leftmost):
m.moveLeftmost()

case key.Matches(msg, m.kb.rightmost):
case key.Matches(msg, m.kb.Rightmost):
m.moveRightmost()

case key.Matches(msg, m.kb.home):
case key.Matches(msg, m.kb.Home):
m.moveStart()

case key.Matches(msg, m.kb.end):
case key.Matches(msg, m.kb.End):
m.moveEnd()

case key.Matches(msg, m.kb.vimUp):
case key.Matches(msg, m.kb.VimUp):
if !m.searchMode {
m.moveUp()
}

case key.Matches(msg, m.kb.down):
case key.Matches(msg, m.kb.Down):
m.moveDown()

case key.Matches(msg, m.kb.vimDown):
case key.Matches(msg, m.kb.VimDown):
if !m.searchMode {
m.moveDown()
}

case key.Matches(msg, m.kb.left):
case key.Matches(msg, m.kb.Left):
m.moveLeft()

case key.Matches(msg, m.kb.vimLeft):
case key.Matches(msg, m.kb.VimLeft):
if !m.searchMode {
m.moveLeft()
}

case key.Matches(msg, m.kb.right):
case key.Matches(msg, m.kb.Right):
m.moveRight()

case key.Matches(msg, m.kb.vimRight):
case key.Matches(msg, m.kb.VimRight):
if !m.searchMode {
m.moveRight()
}

case key.Matches(msg, m.kb.search):
case key.Matches(msg, m.kb.Search):
m.searchMode = true
m.searchId++
m.search = ""

case key.Matches(msg, m.kb.preview):
case key.Matches(msg, m.kb.Preview):
m.previewMode = !m.previewMode
// Reset position history as c&r changes.
m.positions = make(map[string]position)
Expand All @@ -348,7 +361,7 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.previewContent = ""
return m, tea.ExitAltScreen

case key.Matches(msg, m.kb.delete):
case key.Matches(msg, m.kb.Delete):
filePathToDelete, ok := m.filePath()
if ok {
if m.deleteCurrentFile {
Expand All @@ -367,14 +380,14 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}
return m, nil

case key.Matches(msg, m.kb.undo):
case key.Matches(msg, m.kb.Undo):
if len(m.toBeDeleted) > 0 {
m.toBeDeleted = m.toBeDeleted[:len(m.toBeDeleted)-1]
m.list()
m.previewContent = ""
return m, nil
}
case key.Matches(msg, m.kb.yank):
case key.Matches(msg, m.kb.Yank):
// copy path to clipboard
clipboard.WriteAll(m.path)
m.yankSuccess = true
Expand Down Expand Up @@ -535,6 +548,11 @@ func (m *Model) View() string {
return main
}

func (m *Model) Value() string {
path, _ := m.filePath()
return path
}

func (m *Model) moveUp() {
m.r--
if m.r < 0 {
Expand Down

0 comments on commit be5c416

Please sign in to comment.