Skip to content

Commit

Permalink
feat: add ability to move cursor in search mode
Browse files Browse the repository at this point in the history
- The default keymap of bubbles/textinput has been reset as some keys
  clash with the cursor navigation keys. We should support customization
  of the textinput keymap in the future.
  • Loading branch information
kencx committed Jun 2, 2023
1 parent 3cba5b8 commit 55dd7ad
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 12 deletions.
31 changes: 20 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ Prefixes are useful for applications with a common leading hotkey like tmux.

Refer to the `examples` for more examples.

>Multiline fields are not supported at the moment.
>Multiline fields are not supported!
### Quick Add

Expand Down Expand Up @@ -175,12 +175,15 @@ By default, the following options are included.
| `padding` | `1` | Space between border and text |
| `border` | `"hidden"` | Border style: `normal, rounded, double, thick, hidden`|

> If set, `XDG_CONFIG_HOME` will be used in Unix and Darwin systems. Otherwise, keyb
> will fall back to the default OS config directory:
>
>- Unix: `$XDG_CONFIG_HOME/keyb/keyb.yml`,
>- MacOS or Darwin: `$HOME/Library/Application Support/keyb/keyb.yml`,
>- Windows: `%Appdata%\keyb\keyb.yml`
#### keyb Configuration Path

If `XDG_CONFIG_HOME` is set, it will be prioritized and used in Unix and Darwin
systems. Otherwise, keyb will fall back to the default OS config directory
defined as such:

- Unix: `$XDG_CONFIG_HOME/keyb/keyb.yml`,
- MacOS/Darwin: `$HOME/Library/Application Support/keyb/keyb.yml`,
- Windows: `%Appdata%\keyb\keyb.yml`

#### Color
Both ANSI and hex color codes are supported.
Expand All @@ -204,21 +207,27 @@ Multiple keys may be set for a single binding, separated by commas.
| Hotkey | Default | Description |
| ----------------------- | -------------------------- | ---------------- |
| `up`, `down` | <kbd>j, k / Up, Down</kbd> | Move cursor |
| `half_up, half_down` | <kbd>Ctrl + u, d</kbd> | Move half window |
| `full_up, full_down` | <kbd>Ctrl + b, f</kbd> | Move full window |
| `up_focus`, `down_focus`| <kbd>Ctrl + j, ctrl + k </kbd> | Move cursor in search mode |
| `half_up, half_down` | <kbd>Ctrl + u, d</kbd> | Move half window (also works in search mode) |
| `full_up, full_down` | <kbd>Ctrl + b, f</kbd> | Move full window (also works in search mode) |
| `top, middle, bottom` | <kbd>H, M, L</kbd> | Go to top, middle, bottom of screen |
| `first_line, last_line` | <kbd>g, G</kbd> | Go to first, last line |
| `search` | <kbd>/</kbd> | Enter search mode |
| `clear_search` | <kbd>Alt + d</kbd> | Clear current search (remains in search mode) |
| `normal` | <kbd>Esc</kbd> | Exit search mode |
| `quit` | <kbd>Ctrl + c, q</kbd> | Quit |

>The
>[default](https://github.com/charmbracelet/bubbles/blob/afd7868712d4a4f817829dc7e1868c337c5e5cff/textinput/textinput.go#L61)
>key bindings for the search bar have been reset temporarily. Customization of
>these key bindings are coming soon.
## Roadmap

- [x] Ability to customize keyb hotkeys
- [ ] Export to additional file formats (`json, toml, conf/ini` etc.)
- [x] `a, add` subcommand to quickly add a single hotkey entry from the CLI
- [ ] Automatic parsing from online cheatsheet repos (eg. `cheat/cheatsheets`)
- [ ] Export to additional file formats (`json, toml, conf/ini` etc.)
- [ ] Allow customization of search bar key bindings

## Contributing

Expand Down
4 changes: 4 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ type Keys struct {
Quit string
Up string
Down string
UpFocus string `yaml:"up_focus"`
DownFocus string `yaml:"down_focus"`
HalfUp string `yaml:"half_up"`
HalfDown string `yaml:"half_down"`
FullUp string `yaml:"full_up"`
Expand Down Expand Up @@ -188,6 +190,8 @@ func generateDefaultConfig() (*Config, error) {
Quit: "q, ctrl+c",
Up: "k, up",
Down: "j, down",
UpFocus: "ctrl+k",
DownFocus: "ctrl+j",
HalfUp: "ctrl+u",
HalfDown: "ctrl+d",
FullUp: "ctrl+b",
Expand Down
2 changes: 2 additions & 0 deletions config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ func TestParse(t *testing.T) {
Quit: "q, ctrl+c",
Up: "k, up",
Down: "j, down",
UpFocus: "ctrl+k",
DownFocus: "ctrl+j",
HalfUp: "ctrl+u",
HalfDown: "ctrl+d",
FullUp: "ctrl+b",
Expand Down
4 changes: 4 additions & 0 deletions ui/list/keymap.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ type KeyMap struct {
HalfDown key.Binding
FullUp key.Binding
FullDown key.Binding
UpFocus key.Binding
DownFocus key.Binding
GoToFirstLine key.Binding
GoToLastLine key.Binding
GoToTop key.Binding
Expand All @@ -38,6 +40,8 @@ func CreateKeyMap(keys config.Keys) KeyMap {
HalfDown: SetKey(keys.HalfDown),
FullUp: SetKey(keys.FullUp),
FullDown: SetKey(keys.FullDown),
UpFocus: SetKey(keys.UpFocus),
DownFocus: SetKey(keys.DownFocus),
GoToFirstLine: SetKey(keys.GoToFirstLine),
GoToLastLine: SetKey(keys.GoToLastLine),
GoToTop: SetKey(keys.GoToTop),
Expand Down
8 changes: 8 additions & 0 deletions ui/list/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ func (m *Model) configure(c *config.Config) {
Foreground(lipgloss.Color(c.PromptColor))
m.searchBar.Placeholder = c.Placeholder

// temp measure: clear default keymap
// TODO allow customization of text input keymap
m.searchBar.KeyMap = textinput.KeyMap{}

if c.PlaceholderFg != "" || c.PlaceholderBg != "" {
m.searchBar.PlaceholderStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color(c.PlaceholderFg)).
Expand Down Expand Up @@ -171,6 +175,10 @@ func (m *Model) SyncContent(table *table.Model) {
return
}

if m.cursor > table.LineCount {
m.cursor = table.LineCount - 1
}

for i, row := range table.Rows {
if i == m.cursor {
row.IsSelected = true
Expand Down
73 changes: 72 additions & 1 deletion ui/list/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,17 @@ func (m *Model) handleNormal(msg tea.Msg) tea.Cmd {
m.viewport.LineDown(1)
}

case key.Matches(msg, m.keys.UpFocus):
m.cursor--
if m.cursorPastViewTop() {
m.viewport.LineUp(1)
}
case key.Matches(msg, m.keys.DownFocus):
m.cursor++
if m.cursorPastViewBottom() {
m.viewport.LineDown(1)
}

case key.Matches(msg, m.keys.HalfUp):
m.cursor -= m.viewport.Height / 2
if m.cursorPastViewTop() {
Expand Down Expand Up @@ -186,6 +197,67 @@ func (m *Model) handleSearch(msg tea.Msg) tea.Cmd {
m.searchBar.Reset()
return m.startSearch()

// scrolling in search mode
case key.Matches(msg, m.keys.UpFocus):
m.cursor--
if m.cursorPastViewTop() {
m.viewport.LineUp(1)
}
return nil
case key.Matches(msg, m.keys.DownFocus):
m.cursor++
if m.cursorPastViewBottom() {
m.viewport.LineDown(1)
}
return nil

case key.Matches(msg, m.keys.HalfUp):
m.cursor -= m.viewport.Height / 2
if m.cursorPastViewTop() {
m.viewport.HalfViewUp()
}

// don't loop around
if m.cursorPastBeginning() {
m.cursorToBeginning()
m.viewport.GotoTop()
}
case key.Matches(msg, m.keys.HalfDown):
m.cursor += m.viewport.Height / 2
if m.cursorPastViewBottom() {
m.viewport.HalfViewDown()
}

// don't loop around
if m.cursorPastEnd() {
m.cursorToEnd()
m.viewport.GotoBottom()
}

case key.Matches(msg, m.keys.FullUp):
m.cursor -= m.viewport.Height
if m.cursorPastViewTop() {
m.viewport.ViewUp()
}

// don't loop around
if m.cursorPastBeginning() {
m.cursorToBeginning()
m.viewport.GotoTop()
}

case key.Matches(msg, m.keys.FullDown):
m.cursor += m.viewport.Height
if m.cursorPastViewBottom() {
m.viewport.ViewDown()
}

// don't loop around
if m.cursorPastEnd() {
m.cursorToEnd()
m.viewport.GotoBottom()
}

case key.Matches(msg, m.keys.Normal):
m.search = false
m.searchBar.Blur()
Expand All @@ -207,7 +279,6 @@ func (m *Model) handleSearch(msg tea.Msg) tea.Cmd {
} else {
matchRows(m)
}
m.cursorToBeginning()

// reset if search input is empty regardless of filterState
if m.searchBar.Value() == "" {
Expand Down

0 comments on commit 55dd7ad

Please sign in to comment.