def apply_transformation(self, transformation_input): buffer_control, document, lineno, source_to_display, fragments, _, _ = transformation_input.unpack() # When the application is in the 'done' state, don't highlight. if get_app().is_done: return Transformation(fragments) # Get the highlight positions. key = (get_app().render_counter, document.text, document.cursor_position) positions = self._positions_cache.get( key, lambda: self._get_positions_to_highlight(document)) # Apply if positions were found at this line. if positions: for row, col in positions: if row == lineno: col = source_to_display(col) fragments = explode_text_fragments(fragments) style, text = fragments[col] if col == document.cursor_position_col: style += ' class:matching-bracket.cursor ' else: style += ' class:matching-bracket.other ' fragments[col] = (style, text) return Transformation(fragments)
def _get_menu_fragments(self): focused = get_app().layout.has_focus(self.window) # This is called during the rendering. When we discover that this # widget doesn't have the focus anymore. Reset menu state. if not focused: self.selected_menu = [0] # Generate text fragments for the main menu. def one_item(i, item): def mouse_handler(mouse_event): if mouse_event.event_type == MouseEventType.MOUSE_UP: # Toggle focus. app = get_app() if app.layout.has_focus(self.window): if self.selected_menu == [i]: app.layout.focus_last() else: app.layout.focus(self.window) self.selected_menu = [i] yield ('class:menu-bar', ' ', mouse_handler) if i == self.selected_menu[0] and focused: yield ('[SetMenuPosition]', '', mouse_handler) style = 'class:menu-bar.selected-item' else: style = 'class:menu-bar' yield style, item.text, mouse_handler result = [] for i, item in enumerate(self.menu_items): result.extend(one_item(i, item)) return result
def _get_main_buffer(self, buffer_control): from polymorph.deps.prompt_toolkit.layout.controls import BufferControl prev_control = get_app().layout.search_target_buffer_control if isinstance(prev_control, BufferControl) and \ prev_control.search_buffer_control == buffer_control: return prev_control return None
def control_is_searchable(): " When the current UIControl is searchable. " from polymorph.deps.prompt_toolkit.layout.controls import BufferControl control = get_app().layout.current_control return (isinstance(control, BufferControl) and control.search_buffer_control is not None)
def emacs_insert_mode(): app = get_app() if (app.editing_mode != EditingMode.EMACS or app.current_buffer.selection_state or app.current_buffer.read_only()): return False return True
def vi_recording_macro(): " When recording a Vi macro. " app = get_app() if app.editing_mode != EditingMode.VI: return False return app.vi_state.recording_register is not None
def _start_timeout(self): """ Start auto flush timeout. Similar to Vim's `timeoutlen` option. Start a background thread with a timer. When this timeout expires and no key was pressed in the meantime, we flush all data in the queue and call the appropriate key binding handlers. """ timeout = get_app().timeoutlen if timeout is None: return counter = self._keys_pressed def wait(): " Wait for timeout. " time.sleep(timeout) if len(self.key_buffer) > 0 and counter == self._keys_pressed: # (No keys pressed in the meantime.) call_from_executor(flush_keys) def flush_keys(): " Flush keys. " self.feed(_Flush) self.process_keys() # Automatically flush keys. # (_daemon needs to be set, otherwise, this will hang the # application for .5 seconds before exiting.) run_in_executor(wait, _daemon=True)
def create_content(self, width, height): """ Create a UIContent object for this control. """ complete_state = get_app().current_buffer.complete_state if complete_state: completions = complete_state.completions index = complete_state.complete_index # Can be None! # Calculate width of completions menu. menu_width = self._get_menu_width(width, complete_state) menu_meta_width = self._get_menu_meta_width( width - menu_width, complete_state) show_meta = self._show_meta(complete_state) def get_line(i): c = completions[i] is_current_completion = (i == index) result = self._get_menu_item_fragments(c, is_current_completion, menu_width) if show_meta: result += self._get_menu_item_meta_fragments( c, is_current_completion, menu_meta_width) return result return UIContent(get_line=get_line, cursor_position=Point(x=0, y=index or 0), line_count=len(completions)) return UIContent()
def completion_is_selected(): """ True when the user selected a completion. """ complete_state = get_app().current_buffer.complete_state return (complete_state is not None and complete_state.current_completion is not None)
def _get_text_fragments(self): style = 'class:completion-menu.multi-column-meta' state = get_app().current_buffer.complete_state if state and state.current_completion and state.current_completion.display_meta: return [(style, ' %s ' % state.current_completion.display_meta)] return []
def preferred_width(self, max_available_width): complete_state = get_app().current_buffer.complete_state if complete_state: menu_width = self._get_menu_width(500, complete_state) menu_meta_width = self._get_menu_meta_width(500, complete_state) return menu_width + menu_meta_width else: return 0
def test(): # Consider focused when any window inside this container is # focused. current_window = get_app().layout.current_window for c in walk(value): if isinstance(c, Window) and c == current_window: return True return False
def create_content(self, width, height): complete_state = get_app().current_buffer.complete_state if complete_state: completions = complete_state.completions index = complete_state.complete_index # Can be None! # Width of the completions without the left/right arrows in the margins. content_width = width - 6 # Booleans indicating whether we stripped from the left/right cut_left = False cut_right = False # Create Menu content. fragments = [] for i, c in enumerate(completions): # When there is no more place for the next completion if fragment_list_len(fragments) + len( c.display) >= content_width: # If the current one was not yet displayed, page to the next sequence. if i <= (index or 0): fragments = [] cut_left = True # If the current one is visible, stop here. else: cut_right = True break fragments.append( ('class:completion-toolbar.completion.current' if i == index else 'class:completion-toolbar.completion', c.display)) fragments.append(('', ' ')) # Extend/strip until the content width. fragments.append( ('', ' ' * (content_width - fragment_list_len(fragments)))) fragments = fragments[:content_width] # Return fragments all_fragments = [ ('', ' '), ('class:completion-toolbar.arrow', '<' if cut_left else ' '), ('', ' '), ] + fragments + [ ('', ' '), ('class:completion-toolbar.arrow', '>' if cut_right else ' '), ('', ' '), ] else: all_fragments = [] def get_line(i): return all_fragments return UIContent(get_line=get_line, line_count=1)
def get_formatted_text(): arg = get_app().key_processor.arg or '' if arg == '-': arg = '-1' return [ ('class:arg-toolbar', 'Repeat: '), ('class:arg-toolbar.text', arg), ]
def preferred_height(self, width, max_available_height, wrap_lines): """ Preferred height: as much as needed in order to display all the completions. """ complete_state = get_app().current_buffer.complete_state column_width = self._get_column_width(complete_state) column_count = max(1, (width - self._required_margin) // column_width) return int( math.ceil(len(complete_state.completions) / float(column_count)))
def mouse_handler(mouse_event): if mouse_event.event_type == MouseEventType.MOUSE_UP: # Toggle focus. app = get_app() if app.layout.has_focus(self.window): if self.selected_menu == [i]: app.layout.focus_last() else: app.layout.focus(self.window) self.selected_menu = [i]
def vi_replace_mode(): from polymorph.deps.prompt_toolkit.key_binding.vi_state import InputMode app = get_app() if (app.editing_mode != EditingMode.VI or app.vi_state.operator_func or app.vi_state.waiting_for_digraph or app.current_buffer.selection_state or app.current_buffer.read_only()): return False return app.vi_state.input_mode == InputMode.REPLACE
def renderer_height_is_known(): """ Only True when the renderer knows it's real height. (On VT100 terminals, we have to wait for a CPR response, before we can be sure of the available height between the cursor position and the bottom of the terminal. And usually it's nicer to wait with drawing bottom toolbars until we receive the height, in order to avoid flickering -- first drawing somewhere in the middle, and then again at the bottom.) """ return get_app().renderer.height_is_known
def _get_text_fragments(self): app = get_app() if app.key_processor.arg is None: return [] else: arg = app.key_processor.arg return [ ('class:prompt.arg', '(arg: '), ('class:prompt.arg.text', str(arg)), ('class:prompt.arg', ') '), ]
def mouse_handler(mouse_event): if mouse_event.event_type == MouseEventType.MOUSE_UP: app = get_app() if item.handler: app.layout.focus_last() item.handler() else: self.selected_menu = self.selected_menu[:level + 1] + [ i ]
def vi_navigation_mode(): " Active when the set for Vi navigation key bindings are active. " from polymorph.deps.prompt_toolkit.key_binding.vi_state import InputMode app = get_app() if (app.editing_mode != EditingMode.VI or app.vi_state.operator_func or app.vi_state.waiting_for_digraph or app.current_buffer.selection_state): return False return (app.vi_state.input_mode == InputMode.NAVIGATION or app.current_buffer.read_only())
def filter(): " Only handle key bindings if this menu is visible. " app = get_app() complete_state = app.current_buffer.complete_state # There need to be completions, and one needs to be selected. if complete_state is None or complete_state.complete_index is None: return False # This menu needs to be visible. return any(window.content == self for window in app.layout.visible_windows)
def preferred_width(self, max_available_width): """ Report the width of the longest meta text as the preferred width of this control. It could be that we use less width, but this way, we're sure that the layout doesn't change when we select another completion (E.g. that completions are suddenly shown in more or fewer columns.) """ app = get_app() if app.current_buffer.complete_state: state = app.current_buffer.complete_state return 2 + max( get_cwidth(c.display_meta) for c in state.completions) else: return 0
def move(right=False): buff = get_app().current_buffer complete_state = buff.complete_state if complete_state is not None and \ buff.complete_state.complete_index is not None: # Calculate new complete index. new_index = buff.complete_state.complete_index if right: new_index += self._rendered_rows else: new_index -= self._rendered_rows if 0 <= new_index < len(complete_state.completions): buff.go_to_completion(new_index)
def __init__(self, key_processor_ref, arg=None, key_sequence=None, previous_key_sequence=None, is_repeat=False): self._key_processor_ref = key_processor_ref self.key_sequence = key_sequence self.previous_key_sequence = previous_key_sequence #: True when the previous key sequence was handled by the same handler. self.is_repeat = is_repeat self._arg = arg self._app = get_app()
def get_formatted_text(): buff = get_app().current_buffer if buff.validation_error: row, column = buff.document.translate_index_to_position( buff.validation_error.cursor_position) if show_position: text = '%s (line=%s column=%s)' % ( buff.validation_error.message, row + 1, column + 1) else: text = buff.validation_error.message return [('class:validation-toolbar', text)] else: return []
def _fix_vi_cursor_position(self, event): """ After every command, make sure that if we are in Vi navigation mode, we never put the cursor after the last character of a line. (Unless it's an empty line.) """ app = get_app() buff = app.current_buffer preferred_column = buff.preferred_column if (vi_navigation_mode() and buff.document.is_cursor_at_the_end_of_line and len(buff.document.current_line) > 0): buff.cursor_position -= 1 # Set the preferred_column for arrow up/down again. # (This was cleared after changing the cursor position.) buff.preferred_column = preferred_column
def preferred_width(self, max_available_width): """ Preferred width: prefer to use at least min_rows, but otherwise as much as possible horizontally. """ complete_state = get_app().current_buffer.complete_state column_width = self._get_column_width(complete_state) result = int( column_width * math.ceil(len(complete_state.completions) / float(self.min_rows))) # When the desired width is still more than the maximum available, # reduce by removing columns until we are less than the available # width. while result > column_width and result > max_available_width - self._required_margin: result -= column_width return result + self._required_margin
def mouse_handler(self, mouse_event): """ Handle mouse events: clicking and scrolling. """ b = get_app().current_buffer if mouse_event.event_type == MouseEventType.MOUSE_UP: # Select completion. b.go_to_completion(mouse_event.position.y) b.complete_state = None elif mouse_event.event_type == MouseEventType.SCROLL_DOWN: # Scroll up. b.complete_next(count=3, disable_wrap_around=True) elif mouse_event.event_type == MouseEventType.SCROLL_UP: # Scroll down. b.complete_previous(count=3, disable_wrap_around=True)
def get_default_output(): """ Get the output class to be used by default. Called when creating a new Application(), when no `Output` has been passed. """ try: value = _default_output.get() except TaskLocalNotSetError: # If an application is already running, take the output from there. # (This is important for the "ENTER for continue" prompts after # executing system commands and displaying readline-style completions.) app = get_app(return_none=True) if app: return app.output return create_output() else: return value