Compare commits

..

No commits in common. "f0e5b7bb5832feb5ed30cf5f3b6367b8260a2cbc" and "6a128e13a6bbee5ae210a053893c04d3543873c8" have entirely different histories.

1 changed files with 15 additions and 76 deletions

View File

@ -1,15 +1,12 @@
# Written by Sebastian Lohff <seba@someserver.de> # Written by Sebastian Lohff <seba@someserver.de>
# Licensed under Apache License 2.0 # Licensed under Apache License 2.0
from prompt_toolkit.application import Application from prompt_toolkit.application import Application
from prompt_toolkit.buffer import Buffer
from prompt_toolkit.document import Document
from prompt_toolkit.filters import is_searching
from prompt_toolkit.key_binding import KeyBindings
from prompt_toolkit.layout import Layout, Window, HSplit from prompt_toolkit.layout import Layout, Window, HSplit
from prompt_toolkit.buffer import Buffer
from prompt_toolkit.layout.controls import BufferControl from prompt_toolkit.layout.controls import BufferControl
from prompt_toolkit.key_binding import KeyBindings
from prompt_toolkit.document import Document
from prompt_toolkit.layout.processors import Processor, Transformation from prompt_toolkit.layout.processors import Processor, Transformation
from prompt_toolkit import search
from prompt_toolkit.widgets import SearchToolbar
class CliMenuHeader: class CliMenuHeader:
@ -141,8 +138,6 @@ class CliMenu:
return ' ' * (len(self._cursor) + 1 * self._dedent_selection) return ' ' * (len(self._cursor) + 1 * self._dedent_selection)
def _transform_line(self, ti): def _transform_line(self, ti):
if len(list(ti.fragments)) == 0:
return Transformation(ti.fragments)
style, text = list(ti.fragments)[0] style, text = list(ti.fragments)[0]
item = self._items[ti.lineno] item = self._items[ti.lineno]
s = self._style s = self._style
@ -164,9 +159,7 @@ class CliMenu:
indent += ' ' * (self._header_indent + len(self._cursor) + 1) indent += ' ' * (self._header_indent + len(self._cursor) + 1)
style = s.header_style style = s.header_style
items = [(s if s else style, t) for s, t in ti.fragments] return Transformation([('', indent), (style, prefix + text)])
return Transformation([('', indent), (style, prefix)] + items)
def next_item(self, direction): def next_item(self, direction):
if not any(item.focusable for item in self._items): if not any(item.focusable for item in self._items):
@ -181,38 +174,6 @@ class CliMenu:
if self._items[self._pos].focusable: if self._items[self._pos].focusable:
break break
def sync_cursor_to_line(self, line, sync_dir=1):
"""Sync cursor to next fousable item starting on `line`"""
assert sync_dir in (1, -1)
self._pos = line
while not self._items[self._pos].focusable:
self._pos = (self._pos + sync_dir) % len(self._items)
self._buf.cursor_position = self._doc.translate_row_col_to_index(self._pos, 0)
def _get_search_result_lines(self):
"""Get a list of all lines that have a match with the current search result"""
if not self._bufctrl.search_state.text:
return []
idx_list = []
i = 1
while True:
next_idx = self._buf.get_search_position(self._bufctrl.search_state, count=i,
include_current_position=False)
if next_idx in idx_list:
break
idx_list.append(next_idx)
i += 1
lines = []
for idx in idx_list:
line, _ = self._doc.translate_index_to_position(idx)
if line not in lines:
lines.append(line)
return lines
def _run(self): def _run(self):
class MenuColorizer(Processor): class MenuColorizer(Processor):
def apply_transformation(_self, ti): def apply_transformation(_self, ti):
@ -221,62 +182,40 @@ class CliMenu:
# keybindings # keybindings
self._kb = KeyBindings() self._kb = KeyBindings()
@self._kb.add('q', filter=~is_searching) @self._kb.add('q')
@self._kb.add('c-c') @self._kb.add('c-c')
def quit(event): def quit(event):
event.app.exit() event.app.exit()
@self._kb.add('down', filter=~is_searching) @self._kb.add('down')
@self._kb.add('j', filter=~is_searching) @self._kb.add('j')
def down(event): def down(event):
self.next_item(1) self.next_item(1)
@self._kb.add('up', filter=~is_searching) @self._kb.add('up')
@self._kb.add('k', filter=~is_searching) @self._kb.add('k')
def up(event): def up(event):
self.next_item(-1) self.next_item(-1)
@self._kb.add('N', filter=~is_searching) @self._kb.add('right')
@self._kb.add('n', filter=~is_searching) @self._kb.add('c-m')
def search_inc(event, filter=is_searching): @self._kb.add('c-space')
if not self._bufctrl.search_state.text:
return
search_dir = 1 if event.data == 'n' else -1
sr_lines = self._get_search_result_lines()
if sr_lines:
line = sr_lines[search_dir] if len(sr_lines) > 1 else sr_lines[0]
self.sync_cursor_to_line(line, search_dir)
@self._kb.add('c-m', filter=~is_searching)
@self._kb.add('right', filter=~is_searching)
@self._kb.add('c-space', filter=~is_searching)
def accept(event): def accept(event):
self._success = True self._success = True
event.app.exit() event.app.exit()
@self._kb.add('c-m', filter=is_searching)
def accept_search(event):
search.accept_search()
new_line, _ = self._doc.translate_index_to_position(self._buf.cursor_position)
self.sync_cursor_to_line(new_line)
self._searchbar = SearchToolbar(ignore_case=True)
text = '\n'.join(map(lambda _x: _x.text, self._items)) text = '\n'.join(map(lambda _x: _x.text, self._items))
self._doc = Document(text, cursor_position=self._pos) self._doc = Document(text, cursor_position=self._pos)
self._buf = Buffer(read_only=True, document=self._doc) self._buf = Buffer(read_only=True, document=self._doc)
self._bufctrl = BufferControl(self._buf, self._bufctrl = BufferControl(self._buf,
search_buffer_control=self._searchbar.control,
preview_search=True,
input_processors=[MenuColorizer()]) input_processors=[MenuColorizer()])
split = HSplit([Window(self._bufctrl, split = HSplit([Window(self._bufctrl,
wrap_lines=True, wrap_lines=True,
always_hide_cursor=True), always_hide_cursor=True)])
self._searchbar])
# set initial pos # set initial pos
self.sync_cursor_to_line(0) if not self._items[self._pos].focusable:
self.next_item(1)
app = Application(layout=Layout(split), app = Application(layout=Layout(split),
key_bindings=self._kb, key_bindings=self._kb,