class SearchBox(urwid.Pile): def __init__(self, controller: Any) -> None: self.controller = controller super(SearchBox, self).__init__(self.main_view()) def main_view(self) -> Any: self.text_box = ReadlineEdit(u"Search: ") self.w = urwid.LineBox(self.text_box) return [self.w] def keypress(self, size: Tuple[int, int], key: str) -> str: if key == 'esc': self.text_box.set_edit_text("") self.controller.editor_mode = False self.controller.view.middle_column.set_focus('body') return key elif key == 'enter': self.controller.editor_mode = False self.controller.model.index['search'] = set() self.controller.search_messages(self.text_box.edit_text) self.controller.view.middle_column.set_focus('body') return key key = super(SearchBox, self).keypress(size, key) return key
class SearchBox(urwid.Pile): def __init__(self, controller: Any) -> None: self.controller = controller super().__init__(self.main_view()) def main_view(self) -> Any: search_text = ("Search [" + ", ".join(keys_for_command("SEARCH_MESSAGES")) + "]: ") self.text_box = ReadlineEdit(search_text + " ") # Add some text so that when packing, # urwid doesn't hide the widget. self.conversation_focus = urwid.Text(" ") self.search_bar = urwid.Columns([ ('pack', self.conversation_focus), ('pack', urwid.Text(" ")), self.text_box, ]) self.msg_narrow = urwid.Text("DONT HIDE") self.recipient_bar = urwid.LineBox(self.msg_narrow, title="Current message recipients", tline='─', lline='', trcorner='─', tlcorner='─', blcorner='─', rline='', bline='─', brcorner='─') return [self.search_bar, self.recipient_bar] def keypress(self, size: urwid_Size, key: str) -> Optional[str]: if ((is_command_key('ENTER', key) and self.text_box.edit_text == '') or is_command_key('GO_BACK', key)): self.text_box.set_edit_text("") self.controller.exit_editor_mode() self.controller.view.middle_column.set_focus('body') return key elif is_command_key('ENTER', key): self.controller.exit_editor_mode() self.controller.search_messages(self.text_box.edit_text) self.controller.view.middle_column.set_focus('body') return key key = super().keypress(size, key) return key
class SearchBox(urwid.Pile): def __init__(self, controller: Any) -> None: self.controller = controller super(SearchBox, self).__init__(self.main_view()) def main_view(self) -> Any: self.text_box = ReadlineEdit(u"Search: ") # Add some text so that when packing, # urwid doesn't hide the widget. self.msg_narrow = urwid.Text("DONT HIDE") w = urwid.Columns([ ('pack', self.msg_narrow), ('pack', urwid.Text(" ")), self.text_box, ]) self.w = urwid.LineBox(w, tlcorner=u'', tline=u'', lline=u'', trcorner=u'', blcorner=u'─', rline=u'', bline=u'─', brcorner=u'─') return [self.w] def keypress(self, size: Tuple[int, int], key: str) -> str: if is_command_key('GO_BACK', key): self.text_box.set_edit_text("") self.controller.editor_mode = False self.controller.view.middle_column.set_focus('body') return key elif is_command_key('ENTER', key): self.controller.editor_mode = False self.controller.model.index['search'] = set() self.controller.search_messages(self.text_box.edit_text) self.controller.view.middle_column.set_focus('body') return key key = super(SearchBox, self).keypress(size, key) return key
class FuzzyInput(urwid.ListBox): signals = ["accept"] def __init__( self, plugin: PluginBase, main_loop: urwid.MainLoop, is_tag_used: Callable[[str], bool], ) -> None: self._plugin = plugin self._main_loop = main_loop self._is_tag_used = is_tag_used self._focus = -1 self._matches: List[Tuple[str, int]] = [] self._update_id = 0 self._update_alarm = None self._input_box = ReadlineEdit("", wrap=urwid.CLIP) urwid.signals.connect_signal( self._input_box, "change", self._on_text_change ) super().__init__(urwid.SimpleListWalker([])) self._update_widgets() def selectable(self) -> bool: return True def keypress(self, size: Tuple[int, int], key: str) -> Optional[str]: keymap: Dict[str, Callable[[Tuple[int, int]], None]] = { "enter": self._accept, "tab": self._select_prev, "shift tab": self._select_next, } if key in keymap: keymap[key](size) return None return self._input_box.keypress((size[0],), key) def _accept(self, _size: Tuple[int, int]) -> None: text = self._input_box.text.strip() if not text: return self._input_box.set_edit_text("") self._matches = [] self._focus = -1 self._update_widgets() urwid.signals.emit_signal(self, "accept", self, text) self._invalidate() def _select_next(self, _size: Tuple[int, int]) -> None: if self._focus > 0: self._focus -= 1 self._on_results_focus_change() self._update_widgets() def _select_prev(self, size: Tuple[int, int]) -> None: if self._focus + 1 < min(len(self._matches), size[1] - 1): self._focus += 1 self._on_results_focus_change() self._update_widgets() def _on_text_change(self, *_args: Any, **_kwargs: Any) -> None: if self._update_alarm: self._main_loop.remove_alarm(self._update_alarm) self._update_alarm = self._main_loop.set_alarm_in( 0.05, lambda *_: self._schedule_update_matches() ) def _on_results_focus_change(self, *_args: Any, **_kwargs: Any) -> None: urwid.signals.disconnect_signal( self._input_box, "change", self._on_text_change ) self._input_box.set_edit_text( common.box_to_ui(self._matches[self._focus][0]) ) self._input_box.set_edit_pos(len(self._input_box.text)) urwid.signals.connect_signal( self._input_box, "change", self._on_text_change ) def _schedule_update_matches(self) -> None: asyncio.ensure_future(self._update_matches()) async def _update_matches(self) -> None: text = common.unbox_from_ui(self._input_box.text) self._update_id += 1 update_id = self._update_id tag_names = await self._plugin.find_tags(text) if self._update_id > update_id: return matches = [] for tag_name in tag_names: tag_usage_count = await self._plugin.get_tag_usage_count(tag_name) matches.append((tag_name, tag_usage_count)) self._matches = matches self._focus = util.clamp(self._focus, -1, len(self._matches) - 1) self._update_widgets() def _update_widgets(self) -> None: new_list: List[urwid.Widget] = [self._input_box] for i, (tag_name, tag_usage_count) in enumerate(self._matches): attr_name = "match" if self._is_tag_used(tag_name): attr_name = "e-" + attr_name if i == self._focus: attr_name = "f-" + attr_name columns_widget = urwid.Columns( [ ( urwid.Text( common.box_to_ui(tag_name), align=urwid.LEFT, wrap=urwid.CLIP, layout=EllipsisTextLayout(), ) ), (urwid.PACK, urwid.Text(str(tag_usage_count))), ], dividechars=1, ) new_list.append(urwid.AttrWrap(columns_widget, attr_name)) list.clear(self.body) self.body.extend(new_list) self.body.set_focus(0)