feat: add support for sort orders

This commit is contained in:
2026-08-22 17:03:47 +03:00
parent b078184f2f
commit 346af4bdbb
+50
View File
@@ -9,6 +9,7 @@ Here's an example usage:
import pathlib
import random
from collections.abc import Callable
from typing import ClassVar, cast, final, override
import typed_argparse as tap
@@ -30,6 +31,36 @@ from random_file_picker.openers import (
GEEQIE_AVAILABLE = is_geeqie_available()
# Map valid sort keys to the function that extracts the comparison value
SORT_KEYS: dict[str, Callable[[pathlib.Path], float | int | str]] = {
"name": lambda p: p.name.lower(),
"date": lambda p: p.stat().st_mtime,
"size": lambda p: p.stat().st_size,
}
# Map valid order strings to their `reverse` boolean flag (True = descending)
SORT_ORDERS: dict[str, bool] = {
"a": False, "asc": False, "ascending": False,
"d": True, "desc": True, "descending": True,
}
def parse_and_sort_files(files: list[pathlib.Path], sort_args: list[str]) -> None:
"""Sort files in place and raise ValueError on invalid rules."""
rules: list[str] = []
for arg in sort_args:
rules.extend(r.strip() for r in arg.split(",") if r.strip())
for rule in reversed(rules):
parts = rule.split(":")
key_str = parts[0].strip().lower()
order_str = parts[1].strip().lower() if len(parts) > 1 else "a"
if key_str not in SORT_KEYS:
raise ValueError(f"Invalid sort key '{key_str}'. Valid options: {', '.join(SORT_KEYS.keys())}")
if order_str not in SORT_ORDERS:
raise ValueError(f"Invalid sort order '{order_str}'. Valid options: {', '.join(SORT_ORDERS.keys())}")
files.sort(key=SORT_KEYS[key_str], reverse=SORT_ORDERS[order_str])
class Args(tap.TypedArgs):
file_size: int = tap.arg("-s", default=10, help="Maximum file size in MB")
directory: str = tap.arg("-d", default=".", help="Directory to search for files")
@@ -37,6 +68,7 @@ class Args(tap.TypedArgs):
use_geeqie: bool = tap.arg("--use-geeqie", default=False, help="Whether to use Geeqie as the image viewer")
no_trash: bool = tap.arg("--no-trash", default=False, help="Delete files immediately without moving to trash")
no_random: bool = tap.arg("--no-random", default=False, help="Do not randomize the order of files")
sort: list[str] | None = tap.arg("--sort", nargs="*", help="Sort rules (e.g. 'date:d, name:a'). Keys: name, date, size. Orders: a, d.")
blacklist: list[str] | None = tap.arg("--blacklist", nargs="*", help="List of glob patterns to blacklist files")
whitelist: list[str] | None = tap.arg("--whitelist", nargs="*", help="List of glob patterns to whitelist files")
@@ -105,6 +137,7 @@ class MenuApp(App[None]):
use_geeqie: bool = False,
use_trash: bool = True,
no_random: bool = False,
sort: list[str] | None = None,
):
super().__init__()
self.directory: pathlib.Path = pathlib.Path(directory)
@@ -115,6 +148,7 @@ class MenuApp(App[None]):
self.use_geeqie: bool = use_geeqie
self.use_trash: bool = use_trash
self.no_random: bool = no_random
self.sort_rules: list[str] = sort or []
self.usable_files: list[pathlib.Path] = []
self.current_index: int = 0
self.current_file: pathlib.Path | None = None
@@ -189,6 +223,13 @@ class MenuApp(App[None]):
if event.state == WorkerState.SUCCESS:
files = worker.result or []
self.usable_files = list(files)
if self.sort_rules:
try:
parse_and_sort_files(self.usable_files, self.sort_rules)
except ValueError as e:
status.update(f"❌ Sorting error: {e}")
return
if not self.no_random:
random.shuffle(self.usable_files)
@@ -376,6 +417,14 @@ def main_with_tap(args: Args) -> None:
print("❌ Geeqie is not available on this system. Please install it or run without --use-geeqie.")
return
# Validate sort arguments before launching the TUI
if args.sort:
try:
parse_and_sort_files([], args.sort)
except ValueError as e:
print(f"❌ Sorting error: {e}")
return
app = MenuApp(
directory=args.directory,
file_limit=args.file_size,
@@ -385,6 +434,7 @@ def main_with_tap(args: Args) -> None:
use_geeqie=args.use_geeqie,
use_trash=not args.no_trash,
no_random=args.no_random,
sort=args.sort or [], # default filesystem order if no sort rules are provided
)
app.run()