aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/controls.py
diff options
context:
space:
mode:
authorNikita Slyusarev <nslus@yandex-team.com>2022-02-10 16:46:52 +0300
committerDaniil Cherednik <dcherednik@yandex-team.ru>2022-02-10 16:46:52 +0300
commitcd77cecfc03a3eaf87816af28a33067c4f0cdb59 (patch)
tree1308e0bae862d52e0020d881fe758080437fe389 /contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/controls.py
parentcdae02d225fb5b3afbb28990e79a7ac6c9125327 (diff)
downloadydb-cd77cecfc03a3eaf87816af28a33067c4f0cdb59.tar.gz
Restoring authorship annotation for Nikita Slyusarev <nslus@yandex-team.com>. Commit 1 of 2.
Diffstat (limited to 'contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/controls.py')
-rw-r--r--contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/controls.py726
1 files changed, 363 insertions, 363 deletions
diff --git a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/controls.py b/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/controls.py
index ca74931dbc2..951110f82be 100644
--- a/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/controls.py
+++ b/contrib/python/prompt-toolkit/py2/prompt_toolkit/layout/controls.py
@@ -4,34 +4,34 @@ User interface Controls for the layout.
from __future__ import unicode_literals
from abc import ABCMeta, abstractmethod
-from collections import namedtuple
+from collections import namedtuple
from six import with_metaclass
-from six.moves import range
+from six.moves import range
-from prompt_toolkit.cache import SimpleCache
+from prompt_toolkit.cache import SimpleCache
from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER
from prompt_toolkit.filters import to_cli_filter
-from prompt_toolkit.mouse_events import MouseEventType
+from prompt_toolkit.mouse_events import MouseEventType
from prompt_toolkit.search_state import SearchState
from prompt_toolkit.selection import SelectionType
-from prompt_toolkit.token import Token
-from prompt_toolkit.utils import get_cwidth
+from prompt_toolkit.token import Token
+from prompt_toolkit.utils import get_cwidth
from .lexers import Lexer, SimpleLexer
-from .processors import Processor
-from .screen import Char, Point
-from .utils import token_list_width, split_lines, token_list_to_text
+from .processors import Processor
+from .screen import Char, Point
+from .utils import token_list_width, split_lines, token_list_to_text
-import six
+import six
import time
-
+
__all__ = (
'BufferControl',
'FillControl',
'TokenListControl',
'UIControl',
- 'UIContent',
+ 'UIContent',
)
@@ -46,7 +46,7 @@ class UIControl(with_metaclass(ABCMeta, object)):
def preferred_width(self, cli, max_available_width):
return None
- def preferred_height(self, cli, width, max_available_height, wrap_lines):
+ def preferred_height(self, cli, width, max_available_height, wrap_lines):
return None
def has_focus(self, cli):
@@ -54,18 +54,18 @@ class UIControl(with_metaclass(ABCMeta, object)):
Return ``True`` when this user control has the focus.
If so, the cursor will be displayed according to the cursor position
- reported by :meth:`.UIControl.create_content`. If the created content
- has the property ``show_cursor=False``, the cursor will be hidden from
- the output.
+ reported by :meth:`.UIControl.create_content`. If the created content
+ has the property ``show_cursor=False``, the cursor will be hidden from
+ the output.
"""
return False
@abstractmethod
- def create_content(self, cli, width, height):
+ def create_content(self, cli, width, height):
"""
- Generate the content for this user control.
+ Generate the content for this user control.
- Returns a :class:`.UIContent` instance.
+ Returns a :class:`.UIContent` instance.
"""
def mouse_handler(self, cli, mouse_event):
@@ -94,78 +94,78 @@ class UIControl(with_metaclass(ABCMeta, object)):
"""
-class UIContent(object):
- """
- Content generated by a user control. This content consists of a list of
- lines.
-
- :param get_line: Callable that returns the current line. This is a list of
- (Token, text) tuples.
- :param line_count: The number of lines.
- :param cursor_position: a :class:`.Point` for the cursor position.
- :param menu_position: a :class:`.Point` for the menu position.
- :param show_cursor: Make the cursor visible.
- :param default_char: The default :class:`.Char` for filling the background.
- """
- def __init__(self, get_line=None, line_count=0,
- cursor_position=None, menu_position=None, show_cursor=True,
- default_char=None):
- assert callable(get_line)
- assert isinstance(line_count, six.integer_types)
- assert cursor_position is None or isinstance(cursor_position, Point)
- assert menu_position is None or isinstance(menu_position, Point)
- assert default_char is None or isinstance(default_char, Char)
-
- self.get_line = get_line
- self.line_count = line_count
- self.cursor_position = cursor_position or Point(0, 0)
- self.menu_position = menu_position
- self.show_cursor = show_cursor
- self.default_char = default_char
-
- # Cache for line heights. Maps (lineno, width) -> height.
- self._line_heights = {}
-
- def __getitem__(self, lineno):
- " Make it iterable (iterate line by line). "
- if lineno < self.line_count:
- return self.get_line(lineno)
- else:
- raise IndexError
-
- def get_height_for_line(self, lineno, width):
- """
- Return the height that a given line would need if it is rendered in a
- space with the given width.
- """
- try:
- return self._line_heights[lineno, width]
- except KeyError:
- text = token_list_to_text(self.get_line(lineno))
- result = self.get_height_for_text(text, width)
-
- # Cache and return
- self._line_heights[lineno, width] = result
- return result
-
- @staticmethod
- def get_height_for_text(text, width):
- # Get text width for this line.
- line_width = get_cwidth(text)
-
- # Calculate height.
- try:
- quotient, remainder = divmod(line_width, width)
- except ZeroDivisionError:
- # Return something very big.
- # (This can happen, when the Window gets very small.)
- return 10 ** 10
- else:
- if remainder:
- quotient += 1 # Like math.ceil.
- return max(1, quotient)
-
-
+class UIContent(object):
+ """
+ Content generated by a user control. This content consists of a list of
+ lines.
+
+ :param get_line: Callable that returns the current line. This is a list of
+ (Token, text) tuples.
+ :param line_count: The number of lines.
+ :param cursor_position: a :class:`.Point` for the cursor position.
+ :param menu_position: a :class:`.Point` for the menu position.
+ :param show_cursor: Make the cursor visible.
+ :param default_char: The default :class:`.Char` for filling the background.
+ """
+ def __init__(self, get_line=None, line_count=0,
+ cursor_position=None, menu_position=None, show_cursor=True,
+ default_char=None):
+ assert callable(get_line)
+ assert isinstance(line_count, six.integer_types)
+ assert cursor_position is None or isinstance(cursor_position, Point)
+ assert menu_position is None or isinstance(menu_position, Point)
+ assert default_char is None or isinstance(default_char, Char)
+
+ self.get_line = get_line
+ self.line_count = line_count
+ self.cursor_position = cursor_position or Point(0, 0)
+ self.menu_position = menu_position
+ self.show_cursor = show_cursor
+ self.default_char = default_char
+
+ # Cache for line heights. Maps (lineno, width) -> height.
+ self._line_heights = {}
+
+ def __getitem__(self, lineno):
+ " Make it iterable (iterate line by line). "
+ if lineno < self.line_count:
+ return self.get_line(lineno)
+ else:
+ raise IndexError
+
+ def get_height_for_line(self, lineno, width):
+ """
+ Return the height that a given line would need if it is rendered in a
+ space with the given width.
+ """
+ try:
+ return self._line_heights[lineno, width]
+ except KeyError:
+ text = token_list_to_text(self.get_line(lineno))
+ result = self.get_height_for_text(text, width)
+
+ # Cache and return
+ self._line_heights[lineno, width] = result
+ return result
+
+ @staticmethod
+ def get_height_for_text(text, width):
+ # Get text width for this line.
+ line_width = get_cwidth(text)
+
+ # Calculate height.
+ try:
+ quotient, remainder = divmod(line_width, width)
+ except ZeroDivisionError:
+ # Return something very big.
+ # (This can happen, when the Window gets very small.)
+ return 10 ** 10
+ else:
+ if remainder:
+ quotient += 1 # Like math.ceil.
+ return max(1, quotient)
+
+
class TokenListControl(UIControl):
"""
Control that displays a list of (Token, text) tuples.
@@ -195,8 +195,8 @@ class TokenListControl(UIControl):
cursor will be shown there.
"""
def __init__(self, get_tokens, default_char=None, get_default_char=None,
- align_right=False, align_center=False, has_focus=False):
- assert callable(get_tokens)
+ align_right=False, align_center=False, has_focus=False):
+ assert callable(get_tokens)
assert default_char is None or isinstance(default_char, Char)
assert get_default_char is None or callable(get_default_char)
assert not (default_char and get_default_char)
@@ -211,21 +211,21 @@ class TokenListControl(UIControl):
if default_char:
get_default_char = lambda _: default_char
elif not get_default_char:
- get_default_char = lambda _: Char(' ', Token.Transparent)
+ get_default_char = lambda _: Char(' ', Token.Transparent)
self.get_default_char = get_default_char
- #: Cache for the content.
- self._content_cache = SimpleCache(maxsize=18)
- self._token_cache = SimpleCache(maxsize=1)
+ #: Cache for the content.
+ self._content_cache = SimpleCache(maxsize=18)
+ self._token_cache = SimpleCache(maxsize=1)
# Only cache one token list. We don't need the previous item.
# Render info for the mouse support.
- self._tokens = None
-
- def reset(self):
- self._tokens = None
+ self._tokens = None
+ def reset(self):
+ self._tokens = None
+
def __repr__(self):
return '%s(%r)' % (self.__class__.__name__, self.get_tokens)
@@ -235,7 +235,7 @@ class TokenListControl(UIControl):
(This function is called several times during one rendering, because
we also need those for calculating the dimensions.)
"""
- return self._token_cache.get(
+ return self._token_cache.get(
cli.render_counter, lambda: self.get_tokens(cli))
def has_focus(self, cli):
@@ -246,15 +246,15 @@ class TokenListControl(UIControl):
Return the preferred width for this control.
That is the width of the longest line.
"""
- text = token_list_to_text(self._get_tokens_cached(cli))
+ text = token_list_to_text(self._get_tokens_cached(cli))
line_lengths = [get_cwidth(l) for l in text.split('\n')]
return max(line_lengths)
- def preferred_height(self, cli, width, max_available_height, wrap_lines):
- content = self.create_content(cli, width, None)
- return content.line_count
+ def preferred_height(self, cli, width, max_available_height, wrap_lines):
+ content = self.create_content(cli, width, None)
+ return content.line_count
- def create_content(self, cli, width, height):
+ def create_content(self, cli, width, height):
# Get tokens
tokens_with_mouse_handlers = self._get_tokens_cached(cli)
@@ -270,51 +270,51 @@ class TokenListControl(UIControl):
padding = width - used_width
if center:
padding = int(padding / 2)
- return [(default_char.token, default_char.char * padding)] + line
+ return [(default_char.token, default_char.char * padding)] + line
if right or center:
- token_lines_with_mouse_handlers = []
-
+ token_lines_with_mouse_handlers = []
+
for line in split_lines(tokens_with_mouse_handlers):
- token_lines_with_mouse_handlers.append(process_line(line))
- else:
- token_lines_with_mouse_handlers = list(split_lines(tokens_with_mouse_handlers))
+ token_lines_with_mouse_handlers.append(process_line(line))
+ else:
+ token_lines_with_mouse_handlers = list(split_lines(tokens_with_mouse_handlers))
# Strip mouse handlers from tokens.
- token_lines = [
- [tuple(item[:2]) for item in line]
- for line in token_lines_with_mouse_handlers
- ]
+ token_lines = [
+ [tuple(item[:2]) for item in line]
+ for line in token_lines_with_mouse_handlers
+ ]
- # Keep track of the tokens with mouse handler, for later use in
- # `mouse_handler`.
+ # Keep track of the tokens with mouse handler, for later use in
+ # `mouse_handler`.
self._tokens = tokens_with_mouse_handlers
- # If there is a `Token.SetCursorPosition` in the token list, set the
- # cursor position here.
- def get_cursor_position():
- SetCursorPosition = Token.SetCursorPosition
-
- for y, line in enumerate(token_lines):
- x = 0
- for token, text in line:
- if token == SetCursorPosition:
- return Point(x=x, y=y)
- x += len(text)
- return None
-
- # Create content, or take it from the cache.
- key = (default_char.char, default_char.token,
- tuple(tokens_with_mouse_handlers), width, right, center)
-
- def get_content():
- return UIContent(get_line=lambda i: token_lines[i],
- line_count=len(token_lines),
- default_char=default_char,
- cursor_position=get_cursor_position())
-
- return self._content_cache.get(key, get_content)
-
+ # If there is a `Token.SetCursorPosition` in the token list, set the
+ # cursor position here.
+ def get_cursor_position():
+ SetCursorPosition = Token.SetCursorPosition
+
+ for y, line in enumerate(token_lines):
+ x = 0
+ for token, text in line:
+ if token == SetCursorPosition:
+ return Point(x=x, y=y)
+ x += len(text)
+ return None
+
+ # Create content, or take it from the cache.
+ key = (default_char.char, default_char.token,
+ tuple(tokens_with_mouse_handlers), width, right, center)
+
+ def get_content():
+ return UIContent(get_line=lambda i: token_lines[i],
+ line_count=len(token_lines),
+ default_char=default_char,
+ cursor_position=get_cursor_position())
+
+ return self._content_cache.get(key, get_content)
+
@classmethod
def static(cls, tokens):
def get_static_tokens(cli):
@@ -330,29 +330,29 @@ class TokenListControl(UIControl):
return `NotImplemented` in case we want the `Window` to handle this
particular event.)
"""
- if self._tokens:
- # Read the generator.
- tokens_for_line = list(split_lines(self._tokens))
-
- try:
- tokens = tokens_for_line[mouse_event.position.y]
- except IndexError:
- return NotImplemented
- else:
- # Find position in the token list.
- xpos = mouse_event.position.x
-
+ if self._tokens:
+ # Read the generator.
+ tokens_for_line = list(split_lines(self._tokens))
+
+ try:
+ tokens = tokens_for_line[mouse_event.position.y]
+ except IndexError:
+ return NotImplemented
+ else:
+ # Find position in the token list.
+ xpos = mouse_event.position.x
+
# Find mouse handler for this character.
count = 0
- for item in tokens:
+ for item in tokens:
count += len(item[1])
- if count >= xpos:
+ if count >= xpos:
if len(item) >= 3:
# Handler found. Call it.
- # (Handler can return NotImplemented, so return
- # that result.)
+ # (Handler can return NotImplemented, so return
+ # that result.)
handler = item[2]
- return handler(cli, mouse_event)
+ return handler(cli, mouse_event)
else:
break
@@ -364,38 +364,38 @@ class FillControl(UIControl):
"""
Fill whole control with characters with this token.
(Also helpful for debugging.)
-
- :param char: :class:`.Char` instance to use for filling.
- :param get_char: A callable that takes a CommandLineInterface and returns a
- :class:`.Char` object.
+
+ :param char: :class:`.Char` instance to use for filling.
+ :param get_char: A callable that takes a CommandLineInterface and returns a
+ :class:`.Char` object.
"""
- def __init__(self, character=None, token=Token, char=None, get_char=None): # 'character' and 'token' parameters are deprecated.
- assert char is None or isinstance(char, Char)
- assert get_char is None or callable(get_char)
- assert not (char and get_char)
-
- self.char = char
-
- if character:
- # Passing (character=' ', token=token) is deprecated.
- self.character = character
- self.token = token
-
- self.get_char = lambda cli: Char(character, token)
- elif get_char:
- # When 'get_char' is given.
- self.get_char = get_char
- else:
- # When 'char' is given.
- self.char = self.char or Char()
- self.get_char = lambda cli: self.char
- self.char = char
-
+ def __init__(self, character=None, token=Token, char=None, get_char=None): # 'character' and 'token' parameters are deprecated.
+ assert char is None or isinstance(char, Char)
+ assert get_char is None or callable(get_char)
+ assert not (char and get_char)
+
+ self.char = char
+
+ if character:
+ # Passing (character=' ', token=token) is deprecated.
+ self.character = character
+ self.token = token
+
+ self.get_char = lambda cli: Char(character, token)
+ elif get_char:
+ # When 'get_char' is given.
+ self.get_char = get_char
+ else:
+ # When 'char' is given.
+ self.char = self.char or Char()
+ self.get_char = lambda cli: self.char
+ self.char = char
+
def __repr__(self):
- if self.char:
- return '%s(char=%r)' % (self.__class__.__name__, self.char)
- else:
- return '%s(get_char=%r)' % (self.__class__.__name__, self.get_char)
+ if self.char:
+ return '%s(char=%r)' % (self.__class__.__name__, self.char)
+ else:
+ return '%s(get_char=%r)' % (self.__class__.__name__, self.get_char)
def reset(self):
pass
@@ -403,19 +403,19 @@ class FillControl(UIControl):
def has_focus(self, cli):
return False
- def create_content(self, cli, width, height):
- def get_line(i):
- return []
-
- return UIContent(
- get_line=get_line,
- line_count=100 ** 100, # Something very big.
- default_char=self.get_char(cli))
-
-
-_ProcessedLine = namedtuple('_ProcessedLine', 'tokens source_to_display display_to_source')
+ def create_content(self, cli, width, height):
+ def get_line(i):
+ return []
+ return UIContent(
+ get_line=get_line,
+ line_count=100 ** 100, # Something very big.
+ default_char=self.get_char(cli))
+
+_ProcessedLine = namedtuple('_ProcessedLine', 'tokens source_to_display display_to_source')
+
+
class BufferControl(UIControl):
"""
Control for visualising the content of a `Buffer`.
@@ -444,7 +444,7 @@ class BufferControl(UIControl):
assert menu_position is None or callable(menu_position)
assert lexer is None or isinstance(lexer, Lexer)
assert get_search_state is None or callable(get_search_state)
- assert default_char is None or isinstance(default_char, Char)
+ assert default_char is None or isinstance(default_char, Char)
self.preview_search = to_cli_filter(preview_search)
self.get_search_state = get_search_state
@@ -457,15 +457,15 @@ class BufferControl(UIControl):
self.default_char = default_char or Char(token=Token.Transparent)
self.search_buffer_name = search_buffer_name
- #: Cache for the lexer.
+ #: Cache for the lexer.
#: Often, due to cursor movement, undo/redo and window resizing
#: operations, it happens that a short time, the same document has to be
#: lexed. This is a faily easy way to cache such an expensive operation.
- self._token_cache = SimpleCache(maxsize=8)
+ self._token_cache = SimpleCache(maxsize=8)
self._xy_to_cursor_position = None
self._last_click_timestamp = None
- self._last_get_processed_line = None
+ self._last_get_processed_line = None
def _buffer(self, cli):
"""
@@ -483,114 +483,114 @@ class BufferControl(UIControl):
any(i.has_focus(cli) for i in self.input_processors)
def preferred_width(self, cli, max_available_width):
+ """
+ This should return the preferred width.
+
+ Note: We don't specify a preferred width according to the content,
+ because it would be too expensive. Calculating the preferred
+ width can be done by calculating the longest line, but this would
+ require applying all the processors to each line. This is
+ unfeasible for a larger document, and doing it for small
+ documents only would result in inconsistent behaviour.
"""
- This should return the preferred width.
-
- Note: We don't specify a preferred width according to the content,
- because it would be too expensive. Calculating the preferred
- width can be done by calculating the longest line, but this would
- require applying all the processors to each line. This is
- unfeasible for a larger document, and doing it for small
- documents only would result in inconsistent behaviour.
- """
- return None
-
- def preferred_height(self, cli, width, max_available_height, wrap_lines):
- # Calculate the content height, if it was drawn on a screen with the
- # given width.
- height = 0
- content = self.create_content(cli, width, None)
-
- # When line wrapping is off, the height should be equal to the amount
- # of lines.
- if not wrap_lines:
- return content.line_count
-
- # When the number of lines exceeds the max_available_height, just
- # return max_available_height. No need to calculate anything.
- if content.line_count >= max_available_height:
- return max_available_height
-
- for i in range(content.line_count):
- height += content.get_height_for_line(i, width)
-
- if height >= max_available_height:
- return max_available_height
-
- return height
-
- def _get_tokens_for_line_func(self, cli, document):
- """
- Create a function that returns the tokens for a given line.
+ return None
+
+ def preferred_height(self, cli, width, max_available_height, wrap_lines):
+ # Calculate the content height, if it was drawn on a screen with the
+ # given width.
+ height = 0
+ content = self.create_content(cli, width, None)
+
+ # When line wrapping is off, the height should be equal to the amount
+ # of lines.
+ if not wrap_lines:
+ return content.line_count
+
+ # When the number of lines exceeds the max_available_height, just
+ # return max_available_height. No need to calculate anything.
+ if content.line_count >= max_available_height:
+ return max_available_height
+
+ for i in range(content.line_count):
+ height += content.get_height_for_line(i, width)
+
+ if height >= max_available_height:
+ return max_available_height
+
+ return height
+
+ def _get_tokens_for_line_func(self, cli, document):
"""
- # Cache using `document.text`.
- def get_tokens_for_line():
- return self.lexer.lex_document(cli, document)
-
- return self._token_cache.get(document.text, get_tokens_for_line)
-
- def _create_get_processed_line_func(self, cli, document):
- """
- Create a function that takes a line number of the current document and
- returns a _ProcessedLine(processed_tokens, source_to_display, display_to_source)
- tuple.
- """
- def transform(lineno, tokens):
- " Transform the tokens for a given line number. "
+ Create a function that returns the tokens for a given line.
+ """
+ # Cache using `document.text`.
+ def get_tokens_for_line():
+ return self.lexer.lex_document(cli, document)
+
+ return self._token_cache.get(document.text, get_tokens_for_line)
+
+ def _create_get_processed_line_func(self, cli, document):
+ """
+ Create a function that takes a line number of the current document and
+ returns a _ProcessedLine(processed_tokens, source_to_display, display_to_source)
+ tuple.
+ """
+ def transform(lineno, tokens):
+ " Transform the tokens for a given line number. "
source_to_display_functions = []
display_to_source_functions = []
- # Get cursor position at this line.
- if document.cursor_position_row == lineno:
- cursor_column = document.cursor_position_col
- else:
- cursor_column = None
-
- def source_to_display(i):
- """ Translate x position from the buffer to the x position in the
- processed token list. """
- for f in source_to_display_functions:
- i = f(i)
- return i
-
- # Apply each processor.
+ # Get cursor position at this line.
+ if document.cursor_position_row == lineno:
+ cursor_column = document.cursor_position_col
+ else:
+ cursor_column = None
+
+ def source_to_display(i):
+ """ Translate x position from the buffer to the x position in the
+ processed token list. """
+ for f in source_to_display_functions:
+ i = f(i)
+ return i
+
+ # Apply each processor.
for p in self.input_processors:
- transformation = p.apply_transformation(
- cli, document, lineno, source_to_display, tokens)
+ transformation = p.apply_transformation(
+ cli, document, lineno, source_to_display, tokens)
tokens = transformation.tokens
- if cursor_column:
- cursor_column = transformation.source_to_display(cursor_column)
+ if cursor_column:
+ cursor_column = transformation.source_to_display(cursor_column)
- display_to_source_functions.append(transformation.display_to_source)
- source_to_display_functions.append(transformation.source_to_display)
+ display_to_source_functions.append(transformation.display_to_source)
+ source_to_display_functions.append(transformation.source_to_display)
- def display_to_source(i):
+ def display_to_source(i):
for f in reversed(display_to_source_functions):
- i = f(i)
- return i
-
- return _ProcessedLine(tokens, source_to_display, display_to_source)
-
- def create_func():
- get_line = self._get_tokens_for_line_func(cli, document)
- cache = {}
-
- def get_processed_line(i):
- try:
- return cache[i]
- except KeyError:
- processed_line = transform(i, get_line(i))
- cache[i] = processed_line
- return processed_line
- return get_processed_line
-
- return create_func()
-
- def create_content(self, cli, width, height):
- """
- Create a UIContent.
- """
+ i = f(i)
+ return i
+
+ return _ProcessedLine(tokens, source_to_display, display_to_source)
+
+ def create_func():
+ get_line = self._get_tokens_for_line_func(cli, document)
+ cache = {}
+
+ def get_processed_line(i):
+ try:
+ return cache[i]
+ except KeyError:
+ processed_line = transform(i, get_line(i))
+ cache[i] = processed_line
+ return processed_line
+ return get_processed_line
+
+ return create_func()
+
+ def create_content(self, cli, width, height):
+ """
+ Create a UIContent.
+ """
buffer = self._buffer(cli)
# Get the document to be shown. If we are currently searching (the
@@ -615,31 +615,31 @@ class BufferControl(UIControl):
else:
document = buffer.document
- get_processed_line = self._create_get_processed_line_func(cli, document)
- self._last_get_processed_line = get_processed_line
+ get_processed_line = self._create_get_processed_line_func(cli, document)
+ self._last_get_processed_line = get_processed_line
- def translate_rowcol(row, col):
- " Return the content column for this coordinate. "
- return Point(y=row, x=get_processed_line(row).source_to_display(col))
+ def translate_rowcol(row, col):
+ " Return the content column for this coordinate. "
+ return Point(y=row, x=get_processed_line(row).source_to_display(col))
- def get_line(i):
- " Return the tokens for a given line number. "
- tokens = get_processed_line(i).tokens
+ def get_line(i):
+ " Return the tokens for a given line number. "
+ tokens = get_processed_line(i).tokens
- # Add a space at the end, because that is a possible cursor
- # position. (When inserting after the input.) We should do this on
- # all the lines, not just the line containing the cursor. (Because
- # otherwise, line wrapping/scrolling could change when moving the
- # cursor around.)
- tokens = tokens + [(self.default_char.token, ' ')]
- return tokens
+ # Add a space at the end, because that is a possible cursor
+ # position. (When inserting after the input.) We should do this on
+ # all the lines, not just the line containing the cursor. (Because
+ # otherwise, line wrapping/scrolling could change when moving the
+ # cursor around.)
+ tokens = tokens + [(self.default_char.token, ' ')]
+ return tokens
- content = UIContent(
- get_line=get_line,
- line_count=document.line_count,
- cursor_position=translate_rowcol(document.cursor_position_row,
- document.cursor_position_col),
- default_char=self.default_char)
+ content = UIContent(
+ get_line=get_line,
+ line_count=document.line_count,
+ cursor_position=translate_rowcol(document.cursor_position_row,
+ document.cursor_position_col),
+ default_char=self.default_char)
# If there is an auto completion going on, use that start point for a
# pop-up menu position. (But only when this buffer has the focus --
@@ -648,22 +648,22 @@ class BufferControl(UIControl):
menu_position = self.menu_position(cli) if self.menu_position else None
if menu_position is not None:
assert isinstance(menu_position, int)
- menu_row, menu_col = buffer.document.translate_index_to_position(menu_position)
- content.menu_position = translate_rowcol(menu_row, menu_col)
+ menu_row, menu_col = buffer.document.translate_index_to_position(menu_position)
+ content.menu_position = translate_rowcol(menu_row, menu_col)
elif buffer.complete_state:
# Position for completion menu.
# Note: We use 'min', because the original cursor position could be
# behind the input string when the actual completion is for
# some reason shorter than the text we had before. (A completion
# can change and shorten the input.)
- menu_row, menu_col = buffer.document.translate_index_to_position(
+ menu_row, menu_col = buffer.document.translate_index_to_position(
min(buffer.cursor_position,
buffer.complete_state.original_document.cursor_position))
- content.menu_position = translate_rowcol(menu_row, menu_col)
+ content.menu_position = translate_rowcol(menu_row, menu_col)
else:
- content.menu_position = None
+ content.menu_position = None
- return content
+ return content
def mouse_handler(self, cli, mouse_event):
"""
@@ -674,46 +674,46 @@ class BufferControl(UIControl):
# Focus buffer when clicked.
if self.has_focus(cli):
- if self._last_get_processed_line:
- processed_line = self._last_get_processed_line(position.y)
-
+ if self._last_get_processed_line:
+ processed_line = self._last_get_processed_line(position.y)
+
# Translate coordinates back to the cursor position of the
# original input.
- xpos = processed_line.display_to_source(position.x)
- index = buffer.document.translate_row_col_to_index(position.y, xpos)
+ xpos = processed_line.display_to_source(position.x)
+ index = buffer.document.translate_row_col_to_index(position.y, xpos)
# Set the cursor position.
- if mouse_event.event_type == MouseEventType.MOUSE_DOWN:
- buffer.exit_selection()
- buffer.cursor_position = index
-
- elif mouse_event.event_type == MouseEventType.MOUSE_UP:
- # When the cursor was moved to another place, select the text.
- # (The >1 is actually a small but acceptable workaround for
- # selecting text in Vi navigation mode. In navigation mode,
- # the cursor can never be after the text, so the cursor
- # will be repositioned automatically.)
- if abs(buffer.cursor_position - index) > 1:
- buffer.start_selection(selection_type=SelectionType.CHARACTERS)
- buffer.cursor_position = index
-
- # Select word around cursor on double click.
- # Two MOUSE_UP events in a short timespan are considered a double click.
- double_click = self._last_click_timestamp and time.time() - self._last_click_timestamp < .3
- self._last_click_timestamp = time.time()
-
- if double_click:
- start, end = buffer.document.find_boundaries_of_current_word()
- buffer.cursor_position += start
- buffer.start_selection(selection_type=SelectionType.CHARACTERS)
- buffer.cursor_position += end - start
- else:
- # Don't handle scroll events here.
- return NotImplemented
+ if mouse_event.event_type == MouseEventType.MOUSE_DOWN:
+ buffer.exit_selection()
+ buffer.cursor_position = index
+
+ elif mouse_event.event_type == MouseEventType.MOUSE_UP:
+ # When the cursor was moved to another place, select the text.
+ # (The >1 is actually a small but acceptable workaround for
+ # selecting text in Vi navigation mode. In navigation mode,
+ # the cursor can never be after the text, so the cursor
+ # will be repositioned automatically.)
+ if abs(buffer.cursor_position - index) > 1:
+ buffer.start_selection(selection_type=SelectionType.CHARACTERS)
+ buffer.cursor_position = index
+
+ # Select word around cursor on double click.
+ # Two MOUSE_UP events in a short timespan are considered a double click.
+ double_click = self._last_click_timestamp and time.time() - self._last_click_timestamp < .3
+ self._last_click_timestamp = time.time()
+
+ if double_click:
+ start, end = buffer.document.find_boundaries_of_current_word()
+ buffer.cursor_position += start
+ buffer.start_selection(selection_type=SelectionType.CHARACTERS)
+ buffer.cursor_position += end - start
+ else:
+ # Don't handle scroll events here.
+ return NotImplemented
# Not focussed, but focussing on click events.
else:
- if self.focus_on_click(cli) and mouse_event.event_type == MouseEventType.MOUSE_UP:
+ if self.focus_on_click(cli) and mouse_event.event_type == MouseEventType.MOUSE_UP:
# Focus happens on mouseup. (If we did this on mousedown, the
# up event will be received at the point where this widget is
# focussed and be handled anyway.)