feat: add regex search with n/N to repeat forward/backward

This commit is contained in:
lohhiiccc 2026-07-02 20:53:59 +02:00
parent a00381a2c2
commit 4dc693a9a4
4 changed files with 74 additions and 0 deletions

View file

@ -1,4 +1,5 @@
from __future__ import annotations
import re
from typing import TYPE_CHECKING
from ..items.Folder import Folder
from ..core.Prompt import Prompt
@ -26,6 +27,9 @@ class Input:
"new_folder": self._new_folder,
"delete_folder": self._delete_folder,
"new_file": self._new_file,
"search": self._search,
"search_next": self._search_next,
"search_previous": self._search_previous,
}
def handle(self, key: str) -> bool:
@ -156,6 +160,39 @@ class Input:
self.app.open_prompt(Prompt("New file name: ", "text", on_submit))
return True
def _search(self) -> bool:
navigator = self.app.navigator
def on_submit(pattern: str) -> None:
if not pattern:
return
try:
regex = re.compile(pattern)
except re.error as e:
self.app.open_prompt(Prompt.error(f"Invalid regex: {e}"))
return
if not navigator.search(regex):
self.app.open_prompt(Prompt.error(f"No match: {pattern}"))
self.app.open_prompt(Prompt("Search: ", "text", on_submit))
return True
def _search_next(self) -> bool:
navigator = self.app.navigator
if navigator.last_pattern is None:
return True
if not navigator.search_next():
self.app.open_prompt(Prompt.error(f"No match: {navigator.last_pattern}"))
return True
def _search_previous(self) -> bool:
navigator = self.app.navigator
if navigator.last_pattern is None:
return True
if not navigator.search_previous():
self.app.open_prompt(Prompt.error(f"No match: {navigator.last_pattern}"))
return True
@property
def app(self) -> App:
return self._app

View file

@ -18,6 +18,9 @@ DEFAULT_KEYBINDS: dict[str, list[str]] = {
"new_folder": ["d"],
"delete_folder": ["D"],
"new_file": ["%"],
"search": ["/"],
"search_next": ["n"],
"search_previous": ["N"],
}
DEFAULT_CURSOR_RESET = "top"

View file

@ -9,6 +9,9 @@ class Cursor:
def clamp(self, count: int) -> None:
self._pos = min(self._pos, max(count - 1, 0))
def set(self, pos: int) -> None:
self._pos = pos
def up(self) -> None:
self._pos -= 1 if self.pos >= 1 else 0

View file

@ -1,4 +1,5 @@
import os
import re
from pathlib import Path
from ..items.AItems import AItem
from ..items.Folder import Folder
@ -19,6 +20,7 @@ class Navigator:
self._current: Folder | None = None
self._items: list[AItem] = []
self._error: str | None = None
self._last_regex: re.Pattern | None = None
self._load()
def _load(self) -> None:
@ -49,6 +51,35 @@ class Navigator:
self._sort_grouping = Sort.next_grouping(self._sort_grouping)
self._resort()
def search(self, regex: re.Pattern) -> bool:
self._last_regex = regex
return self._find(regex, 1)
def search_next(self) -> bool:
if self._last_regex is None:
return False
return self._find(self._last_regex, 1)
def search_previous(self) -> bool:
if self._last_regex is None:
return False
return self._find(self._last_regex, -1)
def _find(self, regex: re.Pattern, direction: int) -> bool:
count = len(self._items)
if count == 0:
return False
for step in range(1, count + 1):
index = (self._cursor.pos + direction * step) % count
if regex.search(self._items[index].name):
self._cursor.set(index)
return True
return False
@property
def last_pattern(self) -> str | None:
return self._last_regex.pattern if self._last_regex else None
def _reset_cursor(self) -> None:
if self._config.cursor_reset == "keep":
self._cursor.clamp(len(self._items))