feat: add configurable sort strategies with cycle key
This commit is contained in:
parent
c0ff8ae70b
commit
0c1d14bcb1
4 changed files with 61 additions and 3 deletions
|
|
@ -15,6 +15,7 @@ class Input:
|
|||
"enter": self._enter,
|
||||
"back": self._back,
|
||||
"parent": self._parent,
|
||||
"sort": self._sort,
|
||||
}
|
||||
|
||||
def handle(self, key: str) -> bool:
|
||||
|
|
@ -49,6 +50,10 @@ class Input:
|
|||
self.app.navigator.up()
|
||||
return True
|
||||
|
||||
def _sort(self) -> bool:
|
||||
self.app.navigator.cycle_sort()
|
||||
return True
|
||||
|
||||
@property
|
||||
def app(self) -> App:
|
||||
return self._app
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import os
|
|||
import sys
|
||||
import tomllib
|
||||
from pathlib import Path
|
||||
from . import Sort
|
||||
|
||||
DEFAULT_KEYBINDS: dict[str, list[str]] = {
|
||||
"quit": ["q"],
|
||||
|
|
@ -11,15 +12,18 @@ DEFAULT_KEYBINDS: dict[str, list[str]] = {
|
|||
"enter": ["l", "KEY_RIGHT", "\n", "KEY_ENTER"],
|
||||
"back": ["h", "KEY_LEFT", "KEY_BACKSPACE", "\x7f", "\x08"],
|
||||
"parent": ["-"],
|
||||
"sort": ["i"],
|
||||
}
|
||||
|
||||
DEFAULT_CURSOR_RESET = "top"
|
||||
|
||||
|
||||
class Config:
|
||||
def __init__(self, keybinds: dict[str, list[str]], cursor_reset: str) -> None:
|
||||
def __init__(self, keybinds: dict[str, list[str]], cursor_reset: str,
|
||||
sort_mode: str) -> None:
|
||||
self._keybinds = keybinds
|
||||
self._cursor_reset = cursor_reset
|
||||
self._sort_mode = sort_mode
|
||||
self._key_to_action: dict[str, str] = {
|
||||
key: action
|
||||
for action, keys in keybinds.items()
|
||||
|
|
@ -42,7 +46,12 @@ class Config:
|
|||
keybinds = dict(DEFAULT_KEYBINDS)
|
||||
keybinds.update(data.get("keybinds", {}))
|
||||
cursor_reset = data.get("cursor", {}).get("reset", DEFAULT_CURSOR_RESET)
|
||||
return cls(keybinds, cursor_reset)
|
||||
sort_mode = data.get("sort", {}).get("mode", Sort.DEFAULT_MODE)
|
||||
if sort_mode not in Sort.MODES:
|
||||
print(f"pyexplorer: unknown sort mode {sort_mode!r}, "
|
||||
f"falling back to {Sort.DEFAULT_MODE!r}", file=sys.stderr)
|
||||
sort_mode = Sort.DEFAULT_MODE
|
||||
return cls(keybinds, cursor_reset, sort_mode)
|
||||
|
||||
@staticmethod
|
||||
def _default_path() -> Path:
|
||||
|
|
@ -58,3 +67,7 @@ class Config:
|
|||
@property
|
||||
def cursor_reset(self) -> str:
|
||||
return self._cursor_reset
|
||||
|
||||
@property
|
||||
def sort_mode(self) -> str:
|
||||
return self._sort_mode
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ from pathlib import Path
|
|||
from ..items.AItems import AItem
|
||||
from ..items.Folder import Folder
|
||||
from ..items.Symlink import Symlink
|
||||
from . import Sort
|
||||
from .Config import Config
|
||||
from .Cursor import Cursor
|
||||
|
||||
|
|
@ -10,6 +11,7 @@ class Navigator:
|
|||
|
||||
def __init__(self, path: Path, config: Config) -> None:
|
||||
self._config = config
|
||||
self._sort_mode = config.sort_mode
|
||||
self._history = [path]
|
||||
self._cursor = Cursor()
|
||||
self._current: Folder | None = None
|
||||
|
|
@ -21,7 +23,8 @@ class Navigator:
|
|||
self._error = None
|
||||
try:
|
||||
self._current = Folder(self._history[-1])
|
||||
self._items = self._current.children()
|
||||
self._items = Sort.sort_items(self._current.children(),
|
||||
self._sort_mode)
|
||||
except FileNotFoundError:
|
||||
self._items = []
|
||||
except PermissionError:
|
||||
|
|
@ -31,6 +34,10 @@ class Navigator:
|
|||
def refresh(self) -> None:
|
||||
self._load()
|
||||
|
||||
def cycle_sort(self) -> None:
|
||||
self._sort_mode = Sort.next_mode(self._sort_mode)
|
||||
self._items = Sort.sort_items(self._items, self._sort_mode)
|
||||
|
||||
def _reset_cursor(self) -> None:
|
||||
if self._config.cursor_reset == "keep":
|
||||
self._cursor.clamp(len(self._items))
|
||||
|
|
|
|||
33
src/core/Sort.py
Normal file
33
src/core/Sort.py
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
from ..items.AItems import AItem
|
||||
|
||||
MODES = [
|
||||
"name_asc",
|
||||
"name_desc",
|
||||
"dirs_first_asc",
|
||||
"files_first_asc",
|
||||
"dirs_first_desc",
|
||||
"files_first_desc",
|
||||
]
|
||||
|
||||
DEFAULT_MODE = "name_asc"
|
||||
|
||||
_DESC_MODES = ("name_desc", "dirs_first_desc", "files_first_desc")
|
||||
_DIRS_FIRST_MODES = ("dirs_first_asc", "dirs_first_desc")
|
||||
_FILES_FIRST_MODES = ("files_first_asc", "files_first_desc")
|
||||
|
||||
|
||||
def sort_items(items: list[AItem], mode: str) -> list[AItem]:
|
||||
items = sorted(items, key=lambda item: item.name, reverse=mode in _DESC_MODES)
|
||||
if mode in _DIRS_FIRST_MODES:
|
||||
items = sorted(items, key=lambda item: not item.is_navigable())
|
||||
elif mode in _FILES_FIRST_MODES:
|
||||
items = sorted(items, key=lambda item: item.is_navigable())
|
||||
return items
|
||||
|
||||
|
||||
def next_mode(mode: str) -> str:
|
||||
try:
|
||||
i = MODES.index(mode)
|
||||
except ValueError:
|
||||
return DEFAULT_MODE
|
||||
return MODES[(i + 1) % len(MODES)]
|
||||
Loading…
Add table
Reference in a new issue