Implement searching in the themes kitten

This commit is contained in:
Kovid Goyal 2021-08-07 11:17:32 +05:30
parent ca1b2454bd
commit 2c96727c45
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
2 changed files with 85 additions and 20 deletions

View file

@ -22,6 +22,9 @@
from ..choose.match import match
MARK_BEFORE = '\033[33m'
MARK_AFTER = '\033[39m'
def set_comment_in_zip_file(path: str, data: str) -> None:
with zipfile.ZipFile(path, 'a') as zf:
@ -265,15 +268,21 @@ def copy(self) -> 'Themes':
return ans
def apply_search(
self, expression: str, mark_before: str = '\033[33m', mark_after: str = '\033[39m'
self, expression: str, mark_before: str = MARK_BEFORE, mark_after: str = MARK_AFTER
) -> Iterator[str]:
for k, v in tuple(self.themes.items()):
result = match(v.name, expression, mark_before=mark_before, mark_after=mark_after)
if result and result[0]:
yield result[0]
else:
del self.themes[k]
self.index_map = tuple(x for x in self.index_map if x != k)
raw = '\n'.join(self.themes)
results = match(raw, expression, positions=True, level1=' ')
themes: Dict[str, Theme] = {}
for r in results:
pos, k = r.split(':', 1)
positions = tuple(map(int, pos.split(',')))
text = k
for p in reversed(positions):
text = text[:p] + mark_before + text[p] + mark_after + text[p+1:]
themes[k] = self.themes[k]
yield text
self.themes = themes
self.index_map = tuple(self.themes)
def load_themes() -> Themes:

View file

@ -19,9 +19,10 @@
from kitty.utils import ScreenSize
from ..tui.handler import Handler
from ..tui.line_edit import LineEdit
from ..tui.loop import Loop
from ..tui.operations import styled
from .collection import Theme, Themes, load_themes
from ..tui.operations import color_code, styled
from .collection import MARK_AFTER, Theme, Themes, load_themes
separator = ''
@ -107,11 +108,12 @@ def update_themes(self, themes: Themes) -> None:
self.max_width = max(self.widths) if self.widths else 0
self.current_idx = 0
def update_search(self, search: str = '') -> None:
def update_search(self, search: str = '') -> bool:
if search == self.current_search:
return
return False
self.current_search = search
self.update_themes(self.all_themes)
return True
def lines(self, num_rows: int) -> Iterator[Tuple[str, int, bool]]:
if num_rows < 1:
@ -139,6 +141,7 @@ def __init__(self, cached_values: Dict[str, Any]) -> None:
}
self.themes_list = ThemesList()
self.colors_set_once = False
self.line_edit = LineEdit()
self.tabs = tuple('all dark light recent'.split())
def enforce_cursor_state(self) -> None:
@ -245,12 +248,18 @@ def draw_tab(text: str, name: str, acc: str) -> None:
self.print()
def draw_bottom_bar(self) -> None:
self.cmd.set_cursor_position(0, self.screen_size.rows)
self.print(styled(' ' * self.screen_size.cols, reverse=True), end='\r')
for t in ('search', 'accept'):
text = mark_shortcut(t.capitalize(), t[0])
for (t, sc) in (('search (/)', 's'), ('accept (⏎)', 'c')):
text = mark_shortcut(t.capitalize(), sc)
self.cmd.styled(f' {text} ', reverse=True)
self.cmd.sgr('0')
def draw_search_bar(self) -> None:
self.cmd.set_cursor_position(0, self.screen_size.rows)
self.cmd.clear_to_eol()
self.line_edit.write(self.write)
def draw_theme_demo(self) -> None:
theme = self.themes_list.current_theme
xstart = self.themes_list.max_width + 3
@ -312,14 +321,52 @@ def draw_browsing_screen(self) -> None:
mw = self.themes_list.max_width + 1
for line, width, is_current in self.themes_list.lines(num_rows):
num_rows -= 1
if is_current:
line = line.replace(MARK_AFTER, '\033[' + color_code('green') + 'm')
self.cmd.styled('>' if is_current else ' ', fg='green')
self.cmd.styled(line, bold=is_current, fg='green' if is_current else None)
self.cmd.move_cursor_by(mw - width, 'right')
self.print(separator)
if self.themes_list:
self.draw_theme_demo()
self.cmd.set_cursor_position(0, self.screen_size.rows)
if self.state is State.browsing:
self.draw_bottom_bar() if self.state is State.browsing else self.draw_search_bar()
def on_searching_key_event(self, key_event: KeyEventType, in_bracketed_paste: bool = False) -> None:
if key_event.matches('enter'):
self.state = State.browsing
self.draw_bottom_bar()
return
if key_event.matches('esc'):
self.state = State.browsing
self.themes_list.update_search('')
self.set_colors_to_current_theme()
return self.draw_screen()
if key_event.text:
self.line_edit.on_text(key_event.text, in_bracketed_paste)
else:
if not self.line_edit.on_key(key_event):
if key_event.matches('left') or key_event.matches('shift+tab'):
return self.next_category(-1)
if key_event.matches('right') or key_event.matches('tab'):
return self.next_category(1)
if key_event.matches('down'):
return self.next(delta=1)
if key_event.matches('up'):
return self.next(delta=-1)
if key_event.matches('page_down'):
return self.next(delta=self.screen_size.rows - 3, allow_wrapping=False)
if key_event.matches('page_up'):
return self.next(delta=3 - self.screen_size.rows, allow_wrapping=False)
return
if self.line_edit.current_input:
q = self.line_edit.current_input[1:]
if self.themes_list.update_search(q):
self.set_colors_to_current_theme()
self.draw_screen()
else:
self.draw_search_bar()
else:
self.state = State.browsing
self.draw_bottom_bar()
def on_browsing_key_event(self, key_event: KeyEventType, in_bracketed_paste: bool = False) -> None:
@ -327,8 +374,10 @@ def on_browsing_key_event(self, key_event: KeyEventType, in_bracketed_paste: boo
return self.quit_loop(0)
for cat in 'all dark light recent'.split():
if key_event.matches(cat[0]) or key_event.matches(f'alt+{cat[0]}'):
self.current_category = cat
return self.redraw_after_category_change()
if cat != self.current_category:
self.current_category = cat
self.redraw_after_category_change()
return
if key_event.matches('left') or key_event.matches('shift+tab'):
return self.next_category(-1)
if key_event.matches('right') or key_event.matches('tab'):
@ -342,8 +391,13 @@ def on_browsing_key_event(self, key_event: KeyEventType, in_bracketed_paste: boo
if key_event.matches('page_up'):
return self.next(delta=3 - self.screen_size.rows, allow_wrapping=False)
if key_event.matches('s') or key_event.matches('/'):
self.state = State.searching
return self.draw_screen()
return self.start_search()
def start_search(self) -> None:
self.line_edit.clear()
self.line_edit.add_text('/' + self.themes_list.current_search)
self.state = State.searching
self.draw_screen()
def next_category(self, delta: int = 1) -> None:
idx = self.tabs.index(self.current_category) + delta + len(self.tabs)
@ -363,6 +417,8 @@ def on_key_event(self, key_event: KeyEventType, in_bracketed_paste: bool = False
self.on_fetching_key_event(key_event, in_bracketed_paste)
elif self.state is State.browsing:
self.on_browsing_key_event(key_event, in_bracketed_paste)
elif self.state is State.searching:
self.on_searching_key_event(key_event, in_bracketed_paste)
def draw_screen(self) -> None:
with self.pending_update():