feat: add regex search with n/N to repeat forward/backward
This commit is contained in:
parent
a00381a2c2
commit
4dc693a9a4
4 changed files with 74 additions and 0 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue