colors, ../ och -a

This commit is contained in:
Joakim
2026-10-12 22:07:53 +02:00
parent f196983af0
commit 8deac25f00
3 changed files with 28 additions and 6 deletions

View File

@@ -23,3 +23,8 @@
- Navigation is limited to the directory containing the applicable `.tui` file.
- Added `ls --color`-style colors for directories, symlinks, executables, archives and common image files.
- Marked paths remain visible as marked when returning to their directory.
### v2 – cursor and block selection update
- Cursor can now move to the empty line immediately below the last object.
- `Ctrl+K K` now behaves like joe: the block end is the row immediately above the cursor.
- On the bottom empty line, `Ctrl+K K` therefore selects through the last object.

View File

@@ -227,3 +227,9 @@ tui
```
The example configuration is in `tui/example.tui`.
### Cursor and block selection
There is an empty cursor position immediately below the last object in a directory. This makes range selection behave like a text editor.
`Ctrl+K K` follows joe-style semantics: the end of the selection is the row immediately above the cursor. Thus, when the cursor is on the empty line below the final object, `Ctrl+K K` includes the final object.

View File

@@ -179,7 +179,7 @@ class FileBrowser:
self.entries = entries
# Cursor 0 is always the synthetic parent entry.
self.cursor = min(self.cursor, len(self.entries))
self.cursor = min(self.cursor, len(self.entries) + 1)
# Marks are global absolute paths, so they survive directory changes.
# Drop marks only for objects that no longer exist.
@@ -237,15 +237,20 @@ class FileBrowser:
if not self.entries:
return
if self.cursor == 0:
# Like joe's Ctrl-K K, the end of the block is the line immediately
# above the cursor. The bottom empty line therefore selects the last
# object in the directory, while standing on an object selects the
# object immediately above it.
end = self.cursor - 2
if end < 0:
return
# K sets/replaces only the end endpoint. The start endpoint is kept.
self.selection_end = self.current_entry_index()
self.selection_end = end
self._update_selection()
def move(self, delta):
self.cursor = max(0, min(len(self.entries), self.cursor + delta))
self.cursor = max(0, min(len(self.entries) + 1, self.cursor + delta))
def enter(self):
if self.cursor == 0:
@@ -421,7 +426,7 @@ def draw(stdscr, browser, status=""):
for row in range(visible):
index = first + row
if index > len(browser.entries):
if index > len(browser.entries) + 1:
break
if index == 0:
@@ -429,13 +434,19 @@ def draw(stdscr, browser, status=""):
text = "../" if entry is not None else "./"
attrs = entry_color(entry) | curses.A_BOLD
is_marked = False
else:
elif index <= len(browser.entries):
entry = browser.entries[index - 1]
is_marked = entry.resolve() in browser.marked
attrs = entry_color(entry)
if is_marked:
attrs |= curses.A_REVERSE
text = entry.name + ("/" if entry.is_dir() else "")
else:
# One empty line after the final object, matching the cursor range.
entry = None
is_marked = False
attrs = curses.A_NORMAL
text = ""
if index == browser.cursor:
attrs |= curses.A_UNDERLINE