def _get_positions_to_highlight(self, document): """ Return a list of (row, col) tuples that need to be highlighted. """ # Try for the character under the cursor. if document.current_char and document.current_char in self.chars: pos = document.find_matching_bracket_position( start_pos=document.cursor_position - self.max_cursor_distance, end_pos=document.cursor_position + self.max_cursor_distance) # Try for the character before the cursor. elif (document.char_before_cursor and document.char_before_cursor in self._closing_braces and document.char_before_cursor in self.chars): document = Document(document.text, document.cursor_position - 1) pos = document.find_matching_bracket_position( start_pos=document.cursor_position - self.max_cursor_distance, end_pos=document.cursor_position + self.max_cursor_distance) else: pos = None # Return a list of (row, col) tuples that need to be highlighted. if pos: pos += document.cursor_position # pos is relative. row, col = document.translate_index_to_position(pos) return [(row, col), (document.cursor_position_row, document.cursor_position_col)] else: return []
def create_copy_document(self): """ Create a Document instance and token list that can be used in copy mode. """ data_buffer = self.screen.pt_screen.data_buffer text = [] token_list = [] first_row = min(data_buffer.keys()) last_row = max(data_buffer.keys()) def token_has_no_background(token): try: # Token looks like ('C', color, bgcolor, bold, underline, ...) return token[2] is None except IndexError: return True for row_index in range(first_row, last_row + 1): row = data_buffer[row_index] max_column = max(row.keys()) if row else 0 # Remove trailing whitespace. (If the background is transparent.) row_data = [row[x] for x in range(0, max_column + 1)] while (row_data and row_data[-1].char.isspace() and token_has_no_background(row_data[-1].token)): row_data.pop() # Walk through row. char_iter = iter(range(len(row_data))) for x in char_iter: c = row[x] text.append(c.char) token_list.append((c.token, c.char)) # Skip next cell when this is a double width character. if c.width == 2: next(char_iter) # Add newline. text.append('\n') token_list.append((Token, '\n')) # Remove newlines at the end. while text and text[-1] == '\n': text.pop() token_list.pop() # Calculate cursor position. d = Document(text=''.join(text)) return Document(text=d.text, cursor_position=d.translate_row_col_to_index( row=self.screen.pt_screen.cursor_position.y, col=self.screen.pt_screen.cursor_position.x)), token_list
class DocumentTest(unittest.TestCase): def setUp(self): self.document = Document( 'line 1\n' + 'line 2\n' + 'line 3\n' + 'line 4\n', len('line 1\n' + 'lin') ) def test_current_char(self): self.assertEqual(self.document.current_char, 'e') def test_text_before_cursor(self): self.assertEqual(self.document.text_before_cursor, 'line 1\nlin') def test_text_after_cursor(self): self.assertEqual(self.document.text_after_cursor, 'e 2\n' + 'line 3\n' + 'line 4\n') def test_lines(self): self.assertEqual(self.document.lines, [ 'line 1', 'line 2', 'line 3', 'line 4', '']) def test_line_count(self): self.assertEqual(self.document.line_count, 5) def test_current_line_before_cursor(self): self.assertEqual(self.document.current_line_before_cursor, 'lin') def test_current_line_after_cursor(self): self.assertEqual(self.document.current_line_after_cursor, 'e 2') def test_current_line(self): self.assertEqual(self.document.current_line, 'line 2') def test_cursor_position(self): self.assertEqual(self.document.cursor_position_row, 1) self.assertEqual(self.document.cursor_position_col, 3) d = Document('', 0) self.assertEqual(d.cursor_position_row, 0) self.assertEqual(d.cursor_position_col, 0) def test_translate_index_to_position(self): pos = self.document.translate_index_to_position( len('line 1\nline 2\nlin')) self.assertEqual(pos[0], 2) self.assertEqual(pos[1], 3) pos = self.document.translate_index_to_position(0) self.assertEqual(pos, (0, 0))
def _get_source_code_document(self, filename): """ Return source code around current line as string. """ source_code = ''.join(linecache.getlines(filename)) document = Document(source_code) return Document(document.text, document.translate_row_col_to_index( row=self.curframe.f_lineno - 1, col=0))
def setUp(self): self.document = Document( 'line 1\n' + 'line 2\n' + 'line 3\n' + 'line 4\n', len('line 1\n' + 'lin') )
def __init__(self, python_input, original_document): """ Create an `Application` for the history screen. This has to be run as a sub application of `python_input`. When this application runs and returns, it retuns the selected lines. """ self.python_input = python_input history_mapping = HistoryMapping(self, python_input.history, original_document) self.history_mapping = history_mapping document = Document(history_mapping.concatenated_history) document = Document( document.text, cursor_position=document.cursor_position + document.get_start_of_line_position()) self.history_buffer = Buffer( document=document, on_cursor_position_changed=self._history_buffer_pos_changed, accept_handler=( lambda buff: get_app().exit(result=self.default_buffer.text)), read_only=True) self.default_buffer = Buffer( name=DEFAULT_BUFFER, document=history_mapping.get_new_document(), on_cursor_position_changed=self._default_buffer_pos_changed, read_only=True) self.help_buffer = Buffer( document=Document(HELP_TEXT, 0), read_only=True ) self.history_layout = HistoryLayout(self) self.app = Application( layout=self.history_layout.layout, full_screen=True, style=python_input._current_style, mouse_support=Condition(lambda: python_input.enable_mouse_support), key_bindings=create_key_bindings(self, python_input, history_mapping) )
def _get_fuzzy_completions( self, document: Document, complete_event: CompleteEvent) -> Iterable[Completion]: word_before_cursor = document.get_word_before_cursor( pattern=re.compile(self._get_pattern())) # Get completions document2 = Document( text=document.text[:document.cursor_position - len(word_before_cursor)], cursor_position=document.cursor_position - len(word_before_cursor)) completions = list(self.completer.get_completions(document2, complete_event)) fuzzy_matches: List[_FuzzyMatch] = [] pat = '.*?'.join(map(re.escape, word_before_cursor)) pat = '(?=({0}))'.format(pat) # lookahead regex to manage overlapping matches regex = re.compile(pat, re.IGNORECASE) for compl in completions: matches = list(regex.finditer(compl.text)) if matches: # Prefer the match, closest to the left, then shortest. best = min(matches, key=lambda m: (m.start(), len(m.group(1)))) fuzzy_matches.append(_FuzzyMatch(len(best.group(1)), best.start(), compl)) def sort_key(fuzzy_match: '_FuzzyMatch') -> Tuple[int, int]: " Sort by start position, then by the length of the match. " return fuzzy_match.start_pos, fuzzy_match.match_length fuzzy_matches = sorted(fuzzy_matches, key=sort_key) for match in fuzzy_matches: # Include these completions, but set the correct `display` # attribute and `start_position`. yield Completion( match.completion.text, start_position=match.completion.start_position - len(word_before_cursor), display_meta=match.completion.display_meta, display=self._get_display(match, word_before_cursor), style=match.completion.style)
def get_completions(self, document: Document, _complete_event: CompleteEvent = None) -> Sequence[Completion]: """ Returns a sequence of completions for given command line. """ incomplete_cmd = '' if document.text.strip(): incomplete_cmd = document.text.strip().split(maxsplit=1)[0] start, end = document.find_boundaries_of_current_word(WORD=True) start += document.cursor_position end += document.cursor_position current_word = document.text[start:end] current_word_is_command = (document.text[:start].strip() == '') if current_word_is_command: return self._complete_commands(incomplete_cmd) try: cmd = self._cmds.choose(incomplete_cmd) except ValueError: # invalid command return [] incomplete_param = current_word if '=' not in incomplete_param: return self._complete_params(cmd, incomplete_param) param_name, incomplete_value = incomplete_param.split('=', maxsplit=1) param = cmd.parameters.get(param_name) if not param: return [] # TODO: would be cool to exclude existing params return self._complete_value(param.type, incomplete_value)
def test_substring_completion(self): self.init4() doc = Document(u'create') gen = self.completer.get_completions(doc, None) self.assertEqual(six.next(gen), Completion( "createmore", -6))
def get_path_matches(self, _, word_before_cursor): completer = PathCompleter(expanduser=True) document = Document(text=word_before_cursor, cursor_position=len(word_before_cursor)) for c in completer.get_completions(document, None): yield Match(completion=c, priority=None)
def test_builtin_function_name_completion(completer, complete_event): text = 'SELECT MA' position = len('SELECT MA') result = completer.get_completions( Document(text=text, cursor_position=position), complete_event) assert set(result) == set([Completion(text='MAX', start_position=-2)])
def text(self, value): self.buffer.set_document(Document(value, 0), bypass_readonly=True)
def assertPromptValidate(self, prompt_mock, value): validator = prompt_mock.call_args[1]['validator'] validator.validate(Document(text=six.text_type(value)))
def __send_to_output(self, message): new_text = self.output_buffer.text + "{}\n".format(message) self.output_buffer.document = Document(text=new_text, cursor_position=len(new_text))
def validate(self, document): document = Document(text=self.isp.transform_cell(document.text)) super(IPythonValidator, self).validate(document)
def sync_cursor(source_buffer, target_buffer): old_target_text = target_buffer.document.text source_row = source_buffer.document.cursor_position_row target_buffer.set_document(Document(old_target_text, 0), True) if source_row > 0: target_buffer.cursor_down(count=source_row)
def set_prompt(self, prompt_command="", position=0): """ writes the prompt line """ self.description_docs = u'{}'.format(prompt_command) self.cli.current_buffer.reset(initial_document=Document( self.description_docs, cursor_position=position)) self.cli.request_redraw()
fragments += ti.fragments[1:] else: fragments = ti.fragments source_to_display = lambda i: i display_to_source = lambda i: i return Transformation(fragments, source_to_display=source_to_display, display_to_source=display_to_source) def __repr__(self) -> str: return 'AddStyleToDiff(%r, %r)' % (self.text, self.style) local_file_buffer = Buffer(document=Document("".join(a), 0), read_only=True) # Editable buffer. local_file_buffer_control = BufferControl(buffer=local_file_buffer, input_processors=[ AddStyleToDiff("bg:#222222") ]) # Editable buffer. remote_file_buffer = Buffer(document=Document("".join(b), 0), read_only=True) # Editable buffer. def sync_cursor(source_buffer, target_buffer): old_target_text = target_buffer.document.text source_row = source_buffer.document.cursor_position_row target_buffer.set_document(Document(old_target_text, 0), True) if source_row > 0:
def msg_out(self, text: str) -> None: new_text = self.msg_field.text + f'\n{text}' self.msg_field.buffer.document = \ Document(text=new_text, cursor_position=len(new_text))
def update_status(self): self.status_field.buffer.document = Document(text=self.status)
def text(self, value: str) -> None: self.document = Document(value, 0)
def source(self, event): """ Show and modify source of the object under cursor. """ source_is_already_open = False for tab in self.session.tabs: if tab.name == 'Source': source_is_already_open = True if not source_is_already_open: cursor_row_index = self.python_code_buffer.document.cursor_position_row cursor_col_index = self.python_code_buffer.document.cursor_position_col current_row = self.python_code_buffer.document.lines[ cursor_row_index] text_before_cursor = current_row[:cursor_col_index] self.inspected_class_object, self.inspected_method_object, source_code = inspect_code( text_before_cursor, self.interface) self.source_code_original = source_code self.source_code_buffer = Buffer() self.source_code_buffer.document = Document(text=source_code) formatted_text = BufferControl(buffer=self.source_code_buffer, lexer=PythonLexer( self.source_code_buffer)) source_window = Window(formatted_text, width=120, wrap_lines=True) tab_index = self.session.add_tab(Tab("Source", source_window)) self.tabs_container.set_selected_tab(tab_index) # Source float is already exist, so saving the modified version of the source and closing the float. else: # Source code modifications only works on method right now. # so it only works if source code inspector return both class ans method object. if self.inspected_class_object and \ self.inspected_method_object and \ self.source_code_original != self.source_code_buffer.document.text: # Only modify the method object if the code has actually changed try: # Should be method definition source = self.source_code_buffer.document.text # Evaluting the method object (with the original name) exec(source, self.interface) method_name = self.inspected_method_object.__name__ # The moment we evaluated the new method in the exec above, # we can get a pointer to that method using its name in the local context(scope) new_method_object = eval(method_name, self.interface) setattr( self.inspected_class_object, method_name, new_method_object.__get__( self.inspected_class_object, type(self.inspected_class_object))) # setattr(class_object, method_name, eval(method_name)) except Exception as e: self.__send_to_output("Exception: {}".format(e)) self.session.remove_tab_by_name("Source") self.tabs_container.update_selected_tab()
def test_special_name_completion(completer, complete_event): text = '\\d' position = len('\\d') result = completer.get_completions( Document(text=text, cursor_position=position), complete_event) assert result == [Completion(text='\\dt', start_position=-2)]
def test_non_empty_text_validator_with_valid_input(user_input): validator = io_utils.not_empty_validator("error message") document = Document(user_input) # If there is input there shouldn't be an exception assert validator.validate(document) is None
def __init__(self, text='', multiline=True, password=False, lexer=None, auto_suggest=None, completer=None, complete_while_typing=True, accept_handler=None, history=None, focusable=True, focus_on_click=False, wrap_lines=True, read_only=False, width=None, height=None, dont_extend_height=False, dont_extend_width=False, line_numbers=False, get_line_prefix=None, scrollbar=False, style='', search_field=None, preview_search=True, prompt='', input_processors=None): assert isinstance(text, six.text_type) assert search_field is None or isinstance(search_field, SearchToolbar) if search_field is None: search_control = None elif isinstance(search_field, SearchToolbar): search_control = search_field.control if input_processors is None: input_processors = [] # Writeable attributes. self.completer = completer self.complete_while_typing = complete_while_typing self.lexer = lexer self.auto_suggest = auto_suggest self.read_only = read_only self.wrap_lines = wrap_lines self.buffer = Buffer( document=Document(text, 0), multiline=multiline, read_only=Condition(lambda: is_true(self.read_only)), completer=DynamicCompleter(lambda: self.completer), complete_while_typing=Condition( lambda: is_true(self.complete_while_typing)), auto_suggest=DynamicAutoSuggest(lambda: self.auto_suggest), accept_handler=accept_handler, history=history) self.control = BufferControl( buffer=self.buffer, lexer=DynamicLexer(lambda: self.lexer), input_processors=[ ConditionalProcessor( AppendAutoSuggestion(), has_focus(self.buffer) & ~is_done), ConditionalProcessor( processor=PasswordProcessor(), filter=to_filter(password) ), BeforeInput(prompt, style='class:text-area.prompt'), ] + input_processors, search_buffer_control=search_control, preview_search=preview_search, focusable=focusable, focus_on_click=focus_on_click) if multiline: if scrollbar: right_margins = [ScrollbarMargin(display_arrows=True)] else: right_margins = [] if line_numbers: left_margins = [NumberedMargin()] else: left_margins = [] else: height = D.exact(1) left_margins = [] right_margins = [] style = 'class:text-area ' + style self.window = Window( height=height, width=width, dont_extend_height=dont_extend_height, dont_extend_width=dont_extend_width, content=self.control, style=style, wrap_lines=Condition(lambda: is_true(self.wrap_lines)), left_margins=left_margins, right_margins=right_margins, get_line_prefix=get_line_prefix)
def search_once(working_index, document): """ Do search one time. Return (working_index, document) or `None` """ if direction == SearchDirection.FORWARD: # Try find at the current input. new_index = document.find( text, include_current_position=include_current_position, ignore_case=ignore_case) if new_index is not None: return (working_index, Document(document.text, document.cursor_position + new_index)) else: # No match, go forward in the history. (Include len+1 to wrap around.) # (Here we should always include all cursor positions, because # it's a different line.) for i in range(working_index + 1, len(self._working_lines) + 1): i %= len(self._working_lines) # modified by rtichoke if not no_duplicates or self._working_lines[ i] not in self.search_history: document = Document(self._working_lines[i], 0) new_index = document.find( text, include_current_position=True, ignore_case=ignore_case) if new_index is not None: return (i, Document(document.text, new_index)) else: # Try find at the current input. new_index = document.find_backwards(text, ignore_case=ignore_case) if new_index is not None: return (working_index, Document(document.text, document.cursor_position + new_index)) else: # No match, go back in the history. (Include -1 to wrap around.) for i in range(working_index - 1, -2, -1): i %= len(self._working_lines) # modified by rtichoke if not no_duplicates or self._working_lines[ i] not in self.search_history: document = Document(self._working_lines[i], len(self._working_lines[i])) new_index = document.find_backwards( text, ignore_case=ignore_case) if new_index is not None: return (i, Document( document.text, len(document.text) + new_index))
def document(): return Document('line 1\n' + 'line 2\n' + 'line 3\n' + 'line 4\n', len('line 1\n' + 'lin'))
def get_completions(self, text, cursor_positition): with self._completer_lock: return self.completer.get_completions( Document(text=text, cursor_position=cursor_positition), None)
def get_completions(self, document : Document, complete_event : CompleteEvent) -> Completion: for cmd, color in zip((MyCompleter.CMD + MyCompleter.OTHER), (('bg:ansiblack fg:ansired',) * len(MyCompleter.CMD)) + (('bg:ansiyellow fg:ansiblack',) * len(MyCompleter.OTHER))): last_word = document.get_word_under_cursor() if cmd.startswith(last_word) and not last_word == '': yield Completion(cmd, start_position=-len(last_word), style=color)
def info(self, string): """Output given string as info, which is a right justified text element.""" width = click.get_terminal_size()[0] output = string.rjust(width) output = self.output.text + '\n' + output self.output.document = Document(text=output, cursor_position=len(output))
def test_select_keyword_completion(completer, complete_event): text = 'SEL' position = len('SEL') result = completer.get_completions( Document(text=text, cursor_position=position), complete_event) assert set(result) == set([Completion(text='SELECT', start_position=-3)])
def autocomplete( message: str, choices: List[str], default: str = "", qmark: str = DEFAULT_QUESTION_PREFIX, completer: Optional[Completer] = None, meta_information: Optional[Dict[str, Any]] = None, ignore_case: bool = True, match_middle: bool = True, complete_style: CompleteStyle = CompleteStyle.COLUMN, validate: Any = None, style: Optional[Style] = None, **kwargs: Any, ) -> Question: """Prompt the user to enter a message with autocomplete help. Example: >>> import questionary >>> questionary.autocomplete( ... 'Choose ant specie', ... choices=[ ... 'Camponotus pennsylvanicus', ... 'Linepithema humile', ... 'Eciton burchellii', ... "Atta colombica", ... 'Polyergus lucidus', ... 'Polyergus rufescens', ... ]).ask() ? Choose ant specie Atta colombica 'Atta colombica' .. image:: ../images/autocomplete.gif This is just a really basic example, the prompt can be customised using the parameters. Args: message: Question text choices: Items shown in the selection, this contains items as strings default: Default return value (single value). qmark: Question prefix displayed in front of the question. By default this is a ``?`` completer: A prompt_toolkit :class:`prompt_toolkit.completion.Completion` implementation. If not set, a questionary completer implementation will be used. meta_information: A dictionary with information/anything about choices. ignore_case: If true autocomplete would ignore case. match_middle: If true autocomplete would search in every string position not only in string begin. complete_style: How autocomplete menu would be shown, it could be ``COLUMN`` ``MULTI_COLUMN`` or ``READLINE_LIKE`` from :class:`prompt_toolkit.shortcuts.CompleteStyle`. validate: Require the entered value to pass a validation. The value can not be submitted until the validator accepts it (e.g. to check minimum password length). This can either be a function accepting the input and returning a boolean, or an class reference to a subclass of the prompt toolkit Validator class. style: A custom color and style for the question parts. You can configure colors as well as font types for different elements. Returns: :class:`Question`: Question instance, ready to be prompted (using ``.ask()``). """ merged_style = merge_styles([DEFAULT_STYLE, style]) def get_prompt_tokens() -> List[Tuple[str, str]]: return [("class:qmark", qmark), ("class:question", " {} ".format(message))] def get_meta_style( meta: Optional[Dict[str, Any]]) -> Optional[Dict[str, Any]]: if meta: for key in meta: meta[key] = HTML("<text>{}</text>").format(meta[key]) return meta validator = build_validator(validate) if completer is None: if not choices: raise ValueError( "No choices is given, you should use Text question.") # use the default completer completer = WordCompleter( choices, ignore_case=ignore_case, meta_information=get_meta_style(meta_information), match_middle=match_middle, ) p = PromptSession( get_prompt_tokens, lexer=SimpleLexer("class:answer"), style=merged_style, completer=completer, validator=validator, complete_style=complete_style, **kwargs, ) p.default_buffer.reset(Document(default)) return Question(p.app)
def __init__( self, text: str = "", multiline: FilterOrBool = True, password: FilterOrBool = False, lexer: Optional[Lexer] = None, auto_suggest: Optional[AutoSuggest] = None, completer: Optional[Completer] = None, complete_while_typing: FilterOrBool = True, validator: Optional[Validator] = None, accept_handler: Optional[BufferAcceptHandler] = None, history: Optional[History] = None, focusable: FilterOrBool = True, focus_on_click: FilterOrBool = False, wrap_lines: FilterOrBool = True, read_only: FilterOrBool = False, width: AnyDimension = None, height: AnyDimension = None, dont_extend_height: FilterOrBool = False, dont_extend_width: FilterOrBool = False, line_numbers: bool = False, get_line_prefix: Optional[GetLinePrefixCallable] = None, scrollbar: bool = False, style: str = "", search_field: Optional[SearchToolbar] = None, preview_search: FilterOrBool = True, prompt: AnyFormattedText = "", input_processors: Optional[List[Processor]] = None, ) -> None: if search_field is None: search_control = None elif isinstance(search_field, SearchToolbar): search_control = search_field.control if input_processors is None: input_processors = [] # Writeable attributes. self.completer = completer self.complete_while_typing = complete_while_typing self.lexer = lexer self.auto_suggest = auto_suggest self.read_only = read_only self.wrap_lines = wrap_lines self.validator = validator self.buffer = Buffer( document=Document(text, 0), multiline=multiline, read_only=Condition(lambda: is_true(self.read_only)), completer=DynamicCompleter(lambda: self.completer), complete_while_typing=Condition( lambda: is_true(self.complete_while_typing)), validator=DynamicValidator(lambda: self.validator), auto_suggest=DynamicAutoSuggest(lambda: self.auto_suggest), accept_handler=accept_handler, history=history, ) self.control = BufferControl( buffer=self.buffer, lexer=DynamicLexer(lambda: self.lexer), input_processors=[ ConditionalProcessor(AppendAutoSuggestion(), has_focus(self.buffer) & ~is_done), ConditionalProcessor(processor=PasswordProcessor(), filter=to_filter(password)), BeforeInput(prompt, style="class:text-area.prompt"), ] + input_processors, search_buffer_control=search_control, preview_search=preview_search, focusable=focusable, focus_on_click=focus_on_click, ) if multiline: if scrollbar: right_margins = [ScrollbarMargin(display_arrows=True)] else: right_margins = [] if line_numbers: left_margins = [NumberedMargin()] else: left_margins = [] else: height = D.exact(1) left_margins = [] right_margins = [] style = "class:text-area " + style self.window = Window( height=height, width=width, dont_extend_height=dont_extend_height, dont_extend_width=dont_extend_width, content=self.control, style=style, wrap_lines=Condition(lambda: is_true(self.wrap_lines)), left_margins=left_margins, right_margins=right_margins, get_line_prefix=get_line_prefix, )
def _print(field, st): s = field.text + st.replace('\r', '') field.buffer.document = Document(text=s, cursor_position=len(s))
def find_completions(self, document: Document) -> dict: """ Find tab completions from the commands repository. Completions are returned based on tokens extracted from the command text received by prompt_toolkit. A dictionary is then walked, matching a token to a nested dictionary until no more dictionaries are available. The resultant dictionary then becomes the suggestions for tab completion. Some commands may have 'dynamic' completions, such as file system related commands. They are defined with a 'dynamic' key, and the method defined as the value for this key is executed to get completions. :param document: :return: """ # extract tokens from the document similar to # how a shell invocation would have been done tokens = get_tokens(document.text) # start with the current suggestions dictionary being # all commands current_suggestions = self.COMMANDS # when the tokens are extracted, we are expecting something in # the format of: # command sub_command sub_sub_command # so, lets use that and serach the the COMMAND dictionary for # the last dictionary with a correct suggestion for token in tokens: candidate = token.lower() if candidate in list(current_suggestions.keys()): # if there are sub commands, grab them if 'commands' in current_suggestions[candidate]: current_suggestions = current_suggestions[candidate]['commands'] # dynamic commands change based on the current status of the # environment, so, call the method defined elif 'dynamic' in current_suggestions[candidate]: current_suggestions = current_suggestions[candidate]['dynamic']() # in this case, there are probably no sub commands, so return # an empty dictionary else: return {} suggestions = {} # once we have the deepest suggestions dictionary in the # current_suggestions variable, loop through and check for # 'sorta' matched versions if current_suggestions and len(current_suggestions) > 0: for k, _ in current_suggestions.items(): # fuzzy-ish matching when part of a word is in a suggestion if document.get_word_before_cursor().lower() in k.lower(): suggestions[k] = current_suggestions[k] return suggestions
def set_doc(): self.pt_cli.application.buffer.document = Document(s)
def setUp(self): self.document = Document()
def _run(self): class MenuColorizer(Processor): def apply_transformation(_self, ti): return self._transform_line(ti) # keybindings self._kb = KeyBindings() @self._kb.add('q', filter=~is_searching) @self._kb.add('c-c') def quit(event): event.app.exit() @self._kb.add('down', filter=~is_searching) @self._kb.add('j', filter=~is_searching) def down(event): self.next_item(1) @self._kb.add('up', filter=~is_searching) @self._kb.add('k', filter=~is_searching) def up(event): self.next_item(-1) @self._kb.add('N', filter=~is_searching) @self._kb.add('n', filter=~is_searching) def search_inc(event, filter=is_searching): 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) def accept(event): self._success = True 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._register_extra_kb_cbs(self._kb) self._searchbar = SearchToolbar(ignore_case=True) text = '\n'.join(map(lambda _x: _x.text, self._items)) self._doc = Document(text, cursor_position=self._pos) self._buf = Buffer(read_only=True, document=self._doc) self._bufctrl = BufferControl( self._buf, search_buffer_control=self._searchbar.control, preview_search=True, input_processors=[MenuColorizer()]) split = HSplit([ Window(self._bufctrl, wrap_lines=True, always_hide_cursor=True), self._searchbar ]) # set initial pos self.sync_cursor_to_line(0) app = Application(layout=Layout(split), key_bindings=self._kb, full_screen=False, mouse_support=False) app.run() self._ran = True