Compare commits

..

1 Commits

Author SHA1 Message Date
Sebastian Lohff 237900e362 Broken search 2019-02-25 02:00:57 +01:00
3 changed files with 34 additions and 103 deletions

View File

@ -1,12 +1,11 @@
# 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 clintermission.climenu import CliMenu, CliMenuStyle, CliMenuCursor, CliMenuTheme, cli_select_item from clintermission.climenu import CliMenu, CliMenuStyle, CliMenuCursor, CliMenuTheme
__all__ = [ __all__ = [
CliMenu, CliMenu,
CliMenuStyle, CliMenuStyle,
CliMenuCursor, CliMenuCursor,
CliMenuTheme, CliMenuTheme,
cli_select_item,
] ]

View File

@ -4,11 +4,11 @@ from prompt_toolkit.application import Application
from prompt_toolkit.buffer import Buffer from prompt_toolkit.buffer import Buffer
from prompt_toolkit.document import Document from prompt_toolkit.document import Document
from prompt_toolkit.filters import is_searching from prompt_toolkit.filters import is_searching
from prompt_toolkit.filters.base import Condition
from prompt_toolkit.key_binding import KeyBindings 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.layout.controls import BufferControl from prompt_toolkit.layout.controls import BufferControl
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 from prompt_toolkit.widgets import SearchToolbar
@ -68,11 +68,16 @@ class CliMenuTheme:
CYAN = CliMenuStyle('cyan', 'lightcyan', 'cyan') CYAN = CliMenuStyle('cyan', 'lightcyan', 'cyan')
BLUE = CliMenuStyle('ansiblue', 'ansired', 'ansiblue') BLUE = CliMenuStyle('ansiblue', 'ansired', 'ansiblue')
ANSI_CYAN = CliMenuStyle('ansicyan', 'ansibrightcyan', 'ansicyan') ANSI_CYAN = CliMenuStyle('ansicyan', 'ansibrightcyan', 'ansicyan')
BOLD_HIGHLIGHT = CliMenuStyle(header_style='bold', highlight_style='bold fg:black bg:white')
@Condition
def is_not_searching():
print("CALLED IT")
return not is_searching()
class CliMenu: class CliMenu:
default_style = CliMenuTheme.BASIC default_stye = CliMenuTheme.BASIC
default_cursor = CliMenuCursor.TRIANGLE default_cursor = CliMenuCursor.TRIANGLE
def __init__(self, options=None, header=None, cursor=None, style=None, def __init__(self, options=None, header=None, cursor=None, style=None,
@ -92,17 +97,17 @@ class CliMenu:
self._style = style self._style = style
if not self._style: if not self._style:
self._style = self.default_style self._style = self.default_stye
if header: if header:
self.add_header(header, indent=False) self.add_header(header, indent=False)
if options: if options:
for option in options: for option in options:
if isinstance(option, tuple) and len(option) == 2: if isinstance(option, tuple):
self.add_option(*option) self.add_option(*option)
else: else:
self.add_option(option, option) self.add_option(option)
def add_header(self, title, indent=True): def add_header(self, title, indent=True):
for text in title.split('\n'): for text in title.split('\n'):
@ -119,13 +124,6 @@ class CliMenu:
return self._success return self._success
def get_options(self):
return [_item for _item in self._items if isinstance(_item, CliMenuOption)]
@property
def num_options(self):
return self._item_num
def get_selection(self): def get_selection(self):
if self.success: if self.success:
item = self._items[self._pos] item = self._items[self._pos]
@ -189,38 +187,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):
@ -229,47 +195,43 @@ 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('n')
@self._kb.add('n', filter=~is_searching)
def search_inc(event, filter=is_searching): def search_inc(event, filter=is_searching):
if not self._bufctrl.search_state.text: print(self._bufctrl.search_state.text)
return print("curr pos", self._buf.get_search_position(self._bufctrl.search_state))
# search_state.direction = search.SearchDirection.BACKWARD
next10 = []
for i in range(10):
p = self._buf.get_search_position(self._bufctrl.search_state, count=i + 1, include_current_position=False)
next10.append(p)
search_dir = 1 if event.data == 'n' else -1 print("next 10 pos are", next10)
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) #search.do_incremental_search(search.SearchDirection.FORWARD)
@self._kb.add('right', filter=~is_searching)
@self._kb.add('c-space', filter=~is_searching) @self._kb.add('right')
#@self._kb.add('c-m')
@self._kb.add('c-space')
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) self._searchbar = SearchToolbar(text_if_not_searching=[('class:not-searching', 'NOOT NOOT')], ignore_case=True)
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)
@ -284,7 +246,8 @@ class CliMenu:
self._searchbar]) 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,
@ -293,18 +256,3 @@ class CliMenu:
app.run() app.run()
self._ran = True self._ran = True
def cli_select_item(options, header=None, abort_exc=ValueError, abort_text="Selection aborted.", style=None,
return_single=True):
"""Helper function to quickly get a selection with just a few arguments"""
menu = CliMenu(header=header, options=options, style=style)
if return_single and menu.num_options == 1:
item = menu.get_options()[0]
return item.num, item.item
if not menu.success:
raise abort_exc(abort_text)
return menu.get_selection()

View File

@ -1,16 +0,0 @@
#!/usr/bin/env python3
from clintermission import CliMenu, CliMenuTheme
def main():
q = ["Foo", "Bar", "Baz baz baz baz baz"]
m = CliMenu(q, "Time to choose:\n", style=CliMenuTheme.BOLD_HIGHLIGHT)
if m.success:
print("You selected", m.get_selection())
else:
print("You aborted the selection")
if __name__ == '__main__':
main()