Skip to content

Commit dbb3431

Browse files
committed
✨ keypad keybindings
1 parent 4d4eecb commit dbb3431

File tree

6 files changed

+115
-59
lines changed

6 files changed

+115
-59
lines changed

browsr/browsr.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ CurrentFileInfoBar {
4646

4747
/* -- WindowSwitcher -- */
4848

49-
VimScroll {
49+
KeyBindScroll {
5050
overflow: auto scroll;
5151
min-width: 100%;
5252
}

browsr/widgets/code_browser.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,12 @@ def bind_keys(self) -> None:
132132
self.app.bind(
133133
keys="x", action="download_file", description="Download File", show=True
134134
)
135+
self.app.bind(
136+
keys="kp_up", action="cursor_up", description="Cursor Up", show=False
137+
)
138+
self.app.bind(
139+
keys="kp_down", action="cursor_down", description="Cursor Down", show=False
140+
)
135141

136142
def watch_show_tree(self, show_tree: bool) -> None:
137143
"""
@@ -169,7 +175,7 @@ def handle_table_view_display_toggle(
169175
Handle the table view display toggle.
170176
"""
171177
self.datatable_window.display = self.table_view_status
172-
self.window_switcher.vim_scroll.display = self.static_window_status
178+
self.window_switcher.keybind_scroll.display = self.static_window_status
173179

174180
@on(DirectoryTree.FileSelected)
175181
def handle_file_selected(self, message: DirectoryTree.FileSelected) -> None:
@@ -247,9 +253,9 @@ def download_file_workflow(self) -> None:
247253
self.confirmation.download_message.update(Markdown(prompt_message))
248254
self.confirmation.refresh()
249255
self.table_view_status = self.datatable_window.display
250-
self.static_window_status = self.window_switcher.vim_scroll.display
256+
self.static_window_status = self.window_switcher.keybind_scroll.display
251257
self.datatable_window.display = False
252-
self.window_switcher.vim_scroll.display = False
258+
self.window_switcher.keybind_scroll.display = False
253259
self.confirmation_window.display = True
254260

255261
@work(thread=True)

browsr/widgets/keys.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
from __future__ import annotations
2+
3+
from typing import ClassVar
4+
5+
from textual.binding import Binding, BindingType
6+
from textual.containers import VerticalScroll
7+
from textual.widgets import DataTable
8+
9+
vim_scroll_bindings = [
10+
Binding(key="k", action="scroll_up", description="Scroll Up", show=False),
11+
Binding(key="j", action="scroll_down", description="Scroll Down", show=False),
12+
Binding(key="h", action="scroll_left", description="Scroll Left", show=False),
13+
Binding(key="l", action="scroll_right", description="Scroll Right", show=False),
14+
]
15+
vim_cursor_bindings = [
16+
Binding(key="k", action="cursor_up", description="Cursor Up", show=False),
17+
Binding(key="j", action="cursor_down", description="Cursor Down", show=False),
18+
Binding(key="h", action="cursor_left", description="Cursor Left", show=False),
19+
Binding(key="l", action="cursor_right", description="Cursor Right", show=False),
20+
]
21+
keypad_scroll_bindings = [
22+
Binding(key="kp_up", action="scroll_up", description="Scroll Up", show=False),
23+
Binding(key="kp_down", action="scroll_down", description="Scroll Down", show=False),
24+
Binding(key="kp_left", action="scroll_left", description="Scroll Left", show=False),
25+
Binding(key="kp_right", action="scroll_right", description="Scroll Right", show=False),
26+
Binding(key="kp_page_up", action="page_up", description="Page Up", show=False),
27+
Binding(key="kp_page_down", action="page_down", description="Page Down", show=False),
28+
Binding(key="kp_home", action="scroll_home", description="Scroll Home", show=False),
29+
Binding(key="kp_end", action="scroll_end", description="Scroll End", show=False),
30+
]
31+
keypad_cursor_bindings = [
32+
Binding(key="kp_up", action="cursor_up", description="Cursor Up", show=False),
33+
Binding(key="kp_down", action="cursor_down", description="Cursor Down", show=False),
34+
Binding(key="kp_left", action="cursor_left", description="Cursor Left", show=False),
35+
Binding(key="kp_right", action="cursor_right", description="Cursor Right", show=False),
36+
Binding(key="kp_page_up", action="page_up", description="Page Up", show=False),
37+
Binding(key="kp_page_down", action="page_down", description="Page Down", show=False),
38+
Binding(key="kp_home", action="scroll_home", description="Scroll Home", show=False),
39+
Binding(key="kp_end", action="scroll_end", description="Scroll End", show=False),
40+
Binding(key="kp_enter", action="select_cursor", description="Select Item", show=False),
41+
]
42+
43+
44+
class KeyBindScroll(VerticalScroll):
45+
"""
46+
A VerticalScroll with Vim and Keypad Keybindings
47+
"""
48+
49+
BINDINGS: ClassVar[list[BindingType]] = [
50+
*VerticalScroll.BINDINGS,
51+
*vim_scroll_bindings,
52+
*keypad_scroll_bindings,
53+
]
54+
55+
56+
class KeyBindDataTable(DataTable[str]):
57+
"""
58+
A DataTable with Vim and Keypad Keybindings
59+
"""
60+
61+
BINDINGS: ClassVar[list[BindingType]] = [
62+
*DataTable.BINDINGS,
63+
*vim_cursor_bindings,
64+
*keypad_cursor_bindings,
65+
]

browsr/widgets/universal_directory_tree.py

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@
66

77
from typing import ClassVar, Iterable
88

9-
from textual.binding import BindingType
9+
from textual.binding import Binding, BindingType
1010
from textual.widgets._directory_tree import DirEntry
1111
from textual.widgets._tree import TreeNode
1212
from textual_universal_directorytree import UniversalDirectoryTree, UPath
1313

1414
from browsr.widgets.double_click_directory_tree import DoubleClickDirectoryTree
15-
from browsr.widgets.vim import vim_cursor_bindings
15+
from browsr.widgets.keys import vim_cursor_bindings, keypad_cursor_bindings
1616

1717

1818
class BrowsrDirectoryTree(DoubleClickDirectoryTree, UniversalDirectoryTree):
@@ -23,6 +23,9 @@ class BrowsrDirectoryTree(DoubleClickDirectoryTree, UniversalDirectoryTree):
2323
BINDINGS: ClassVar[list[BindingType]] = [
2424
*UniversalDirectoryTree.BINDINGS,
2525
*vim_cursor_bindings,
26+
*keypad_cursor_bindings,
27+
Binding(key="h,left,kp_left", action="collapse_parent", description="Collapse (Parent) Directory", show=False),
28+
Binding(key="l,right,kp_right", action="expand_or_select", description="Expand Directory or Select File", show=False),
2629
]
2730

2831
@classmethod
@@ -64,3 +67,27 @@ def _populate_node(
6467
allow_expand=self._safe_is_dir(path),
6568
)
6669
node.expand()
70+
71+
def action_collapse_parent(self) -> None:
72+
cursor_node = self.cursor_node
73+
cursor_path = cursor_node.data.path
74+
collapse_parent = False
75+
if self._safe_is_dir(cursor_path):
76+
if cursor_node.is_expanded:
77+
cursor_node.collapse()
78+
elif not cursor_node.is_root:
79+
collapse_parent = True
80+
else:
81+
collapse_parent = True
82+
if collapse_parent:
83+
self.action_cursor_parent()
84+
cursor_node.parent.collapse()
85+
86+
def action_expand_or_select(self) -> None:
87+
cursor_node = self.cursor_node
88+
cursor_path = cursor_node.data.path
89+
if self._safe_is_dir(cursor_path):
90+
if not cursor_node.is_expanded:
91+
cursor_node.expand()
92+
else:
93+
self.action_select_cursor()

browsr/widgets/vim.py

Lines changed: 0 additions & 42 deletions
This file was deleted.

browsr/widgets/windows.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
FileInfo,
3131
open_image,
3232
)
33-
from browsr.widgets.vim import VimDataTable, VimScroll
33+
from browsr.widgets.keys import KeyBindDataTable, KeyBindScroll
3434

3535

3636
class BaseCodeWindow(Widget):
@@ -226,7 +226,7 @@ def next_theme(self) -> str | None:
226226
return next_theme
227227

228228

229-
class DataTableWindow(VimDataTable, BaseCodeWindow):
229+
class DataTableWindow(KeyBindDataTable, BaseCodeWindow):
230230
"""
231231
A DataTable widget for displaying code.
232232
"""
@@ -311,22 +311,22 @@ def __init__(
311311
zebra_stripes=True, show_header=True, show_cursor=True, id="table-view"
312312
)
313313
self.datatable_window.display = False
314-
self.vim_scroll = VimScroll(self.static_window)
314+
self.keybind_scroll = KeyBindScroll(self.static_window)
315315
self.rendered_file: UPath | None = None
316316

317317
def compose(self) -> ComposeResult:
318318
"""
319319
Compose the widget
320320
"""
321-
yield self.vim_scroll
321+
yield self.keybind_scroll
322322
yield self.datatable_window
323323

324324
def get_active_widget(self) -> Widget:
325325
"""
326326
Get the active widget
327327
"""
328-
if self.vim_scroll.display:
329-
return self.vim_scroll
328+
if self.keybind_scroll.display:
329+
return self.keybind_scroll
330330
elif self.datatable_window.display:
331331
return self.datatable_window
332332

@@ -335,7 +335,7 @@ def switch_window(self, window: BaseCodeWindow) -> None:
335335
Switch to the window
336336
"""
337337
screens: dict[Widget, Widget] = {
338-
self.static_window: self.vim_scroll,
338+
self.static_window: self.keybind_scroll,
339339
self.datatable_window: self.datatable_window,
340340
}
341341
for window_screen in screens:
@@ -382,11 +382,11 @@ def render_file(self, file_path: UPath, scroll_home: bool = True) -> None:
382382
self.switch_window(switch_window)
383383
active_widget = self.get_active_widget()
384384
if scroll_home:
385-
if active_widget is self.vim_scroll:
386-
self.vim_scroll.scroll_home(animate=False)
385+
if active_widget is self.keybind_scroll:
386+
self.keybind_scroll.scroll_home(animate=False)
387387
else:
388388
switch_window.scroll_home(animate=False)
389-
if active_widget is self.vim_scroll:
389+
if active_widget is self.keybind_scroll:
390390
self.app.sub_title = str(file_path) + f" [{self.static_window.theme}]"
391391
else:
392392
self.app.sub_title = str(file_path)
@@ -396,7 +396,7 @@ def next_theme(self) -> str | None:
396396
"""
397397
Switch to the next theme
398398
"""
399-
if self.get_active_widget() is not self.vim_scroll:
399+
if self.get_active_widget() is not self.keybind_scroll:
400400
return None
401401
current_index = favorite_themes.index(self.static_window.theme)
402402
next_theme = favorite_themes[(current_index + 1) % len(favorite_themes)]

0 commit comments

Comments
 (0)