From f5ba95650c875e916f144aff689cc7e30917b367 Mon Sep 17 00:00:00 2001 From: Thomas Ballinger Date: Fri, 5 Aug 2016 18:11:58 -0400 Subject: [PATCH 1/4] test existing suggestion box behavior --- bpython/curtsiesfrontend/repl.py | 3 +- bpython/test/test_curtsies_painting.py | 163 ++++++++++++++++++++++--- 2 files changed, 151 insertions(+), 15 deletions(-) diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py index 98aa59d24..0bf0342bf 100644 --- a/bpython/curtsiesfrontend/repl.py +++ b/bpython/curtsiesfrontend/repl.py @@ -1260,7 +1260,7 @@ def paint(self, about_to_exit=False, user_quit=False): the idea is that we don't need to worry about that here, instead every frame is completely redrawn because less state is cool! """ - # The hairiest function in the curtsies - a cleanup would be great. + # The hairiest function in the curtsies if about_to_exit: # exception to not changing state! self.clean_up_current_line_for_exit() @@ -1501,6 +1501,7 @@ def _set_current_line(self, line, update_completion=True, if clear_special_mode: self.special_mode = None self.unhighlight_paren() + current_line = property(_get_current_line, _set_current_line, None, "The current line") diff --git a/bpython/test/test_curtsies_painting.py b/bpython/test/test_curtsies_painting.py index 87af5be62..a70daee6a 100644 --- a/bpython/test/test_curtsies_painting.py +++ b/bpython/test/test_curtsies_painting.py @@ -1,7 +1,9 @@ # coding: utf8 from __future__ import unicode_literals -import sys +import itertools +import string import os +import sys from contextlib import contextmanager from curtsies.formatstringarray import FormatStringTest, fsarray @@ -21,6 +23,7 @@ def setup_config(): config_struct = config.Struct() config.loadini(config_struct, os.devnull) + config_struct.cli_suggestion_width = 1 return config_struct @@ -48,13 +51,18 @@ def _request_refresh(inner_self): self.repl.rl_history = History() self.repl.height, self.repl.width = (5, 10) + @property + def locals(self): + return self.repl.coderunner.interp.locals + def assert_paint(self, screen, cursor_row_col): array, cursor_pos = self.repl.paint() self.assertFSArraysEqual(array, screen) self.assertEqual(cursor_pos, cursor_row_col) - def assert_paint_ignoring_formatting(self, screen, cursor_row_col=None): - array, cursor_pos = self.repl.paint() + def assert_paint_ignoring_formatting(self, screen, cursor_row_col=None, + **paint_kwargs): + array, cursor_pos = self.repl.paint(**paint_kwargs) self.assertFSArraysEqualIgnoringFormatting(array, screen) if cursor_row_col is not None: self.assertEqual(cursor_pos, cursor_row_col) @@ -96,15 +104,15 @@ def test_completion(self): self.cursor_offset = 2 if config.supports_box_chars(): screen = ['>>> an', - '┌───────────────────────┐', - '│ and any( │', - '└───────────────────────┘', + '┌──────────────────────────────┐', + '│ and any( │', + '└──────────────────────────────┘', 'Welcome to bpython! Press f'] else: screen = ['>>> an', - '+-----------------------+', - '| and any( |', - '+-----------------------+', + '+------------------------------+', + '| and any( |', + '+------------------------------+', 'Welcome to bpython! Press f'] self.assert_paint_ignoring_formatting(screen, (0, 4)) @@ -155,7 +163,7 @@ def output_to_repl(repl): sys.stdout, sys.stderr = old_out, old_err -class TestCurtsiesRewindRedraw(CurtsiesPaintingTest): +class HigherLevelCurtsiesPaintingTest(CurtsiesPaintingTest): def refresh(self): self.refresh_requests.append(RefreshRequestEvent()) @@ -194,6 +202,12 @@ def _request_refresh(inner_self): self.repl.rl_history = History() self.repl.height, self.repl.width = (5, 32) + def send_key(self, key): + self.repl.process_event('' if key == ' ' else key) + self.repl.paint() # has some side effects we need to be wary of + + +class TestCurtsiesRewindRedraw(HigherLevelCurtsiesPaintingTest): def test_rewind(self): self.repl.current_line = '1 + 1' self.enter() @@ -564,10 +578,6 @@ def test_unhighlight_paren_bugs(self): green("... ") + yellow(')') + bold(cyan(" "))]) self.assert_paint(screen, (1, 6)) - def send_key(self, key): - self.repl.process_event('' if key == ' ' else key) - self.repl.paint() # has some side effects we need to be wary of - def test_472(self): [self.send_key(c) for c in "(1, 2, 3)"] with output_to_repl(self.repl): @@ -586,3 +596,128 @@ def test_472(self): '(1, 4, 3)', '>>> '] self.assert_paint_ignoring_formatting(screen, (4, 4)) + + +def completion_target(num_names, chars_in_first_name=1): + class Class(object): + pass + + if chars_in_first_name < 1: + raise ValueError('need at least one char in each name') + elif chars_in_first_name == 1 and num_names > len(string.ascii_letters): + raise ValueError('need more chars to make so many names') + + names = gen_names() + if num_names > 0: + setattr(Class, 'a' * chars_in_first_name, 1) + next(names) # use the above instead of first name + for _, name in zip(range(num_names - 1), names): + setattr(Class, name, 0) + + return Class() + + +def gen_names(): + for letters in itertools.chain( + itertools.combinations_with_replacement(string.ascii_letters, 1), + itertools.combinations_with_replacement(string.ascii_letters, 2)): + yield ''.join(letters) + + +class TestCompletionHelpers(TestCase): + def test_gen_names(self): + self.assertEqual(list(zip([1, 2, 3], gen_names())), + [(1, 'a'), (2, 'b'), (3, 'c')]) + + def test_completion_target(self): + target = completion_target(14) + self.assertEqual(len([x for x in dir(target) + if not x.startswith('_')]), + 14) + + +class TestCurtsiesInfoboxPaint(HigherLevelCurtsiesPaintingTest): + def test_simple(self): + self.repl.width, self.repl.height = (20, 30) + self.locals['abc'] = completion_target(3, 50) + self.repl.current_line = 'abc' + self.repl.cursor_offset = 3 + self.repl.process_event('.') + screen = ['>>> abc.', + '+------------------+', + '| aaaaaaaaaaaaaaaa |', + '| b |', + '| c |', + '+------------------+'] + self.assert_paint_ignoring_formatting(screen, (0, 8)) + + def test_fill_screen(self): + self.repl.width, self.repl.height = (20, 15) + self.locals['abc'] = completion_target(20, 100) + self.repl.current_line = 'abc' + self.repl.cursor_offset = 3 + self.repl.process_event('.') + screen = ['>>> abc.', + '+------------------+', + '| aaaaaaaaaaaaaaaa |', + '| b |', + '| c |', + '| d |', + '| e |', + '| f |', + '| g |', + '| h |', + '| i |', + '| j |', + '| k |', + '| l |', + '+------------------+'] + self.assert_paint_ignoring_formatting(screen, (0, 8)) + + def test_lower_on_screen(self): + self.repl.get_top_usable_line = lambda: 10 # halfway down terminal + self.repl.width, self.repl.height = (20, 15) + self.locals['abc'] = completion_target(20, 100) + self.repl.current_line = 'abc' + self.repl.cursor_offset = 3 + self.repl.process_event('.') + screen = ['>>> abc.', + '+------------------+', + '| aaaaaaaaaaaaaaaa |', + '| b |', + '| c |', + '| d |', + '| e |', + '| f |', + '| g |', + '| h |', + '| i |', + '| j |', + '| k |', + '| l |', + '+------------------+'] + self.assert_paint_ignoring_formatting(screen, (0, 8)) + + def test_at_bottom_of_screen(self): + self.repl.get_top_usable_line = lambda: 17 # two lines from bottom + self.repl.width, self.repl.height = (20, 15) + self.locals['abc'] = completion_target(20, 100) + self.repl.current_line = 'abc' + self.repl.cursor_offset = 3 + self.repl.process_event('.') + screen = ['>>> abc.', + '+------------------+', + '| aaaaaaaaaaaaaaaa |', + '| b |', + '| c |', + '| d |', + '| e |', + '| f |', + '| g |', + '| h |', + '| i |', + '| j |', + '| k |', + '| l |', + '+------------------+'] + self.assert_paint_ignoring_formatting(screen, (0, 8)) From 9a371d7d19bab1d21ce23e8b4c8275aec791bee7 Mon Sep 17 00:00:00 2001 From: Thomas Ballinger Date: Mon, 6 Jun 2016 20:09:59 -0400 Subject: [PATCH 2/4] choose completion box size based on screen size --- bpython/curtsiesfrontend/repl.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py index 0bf0342bf..e99f13edf 100644 --- a/bpython/curtsiesfrontend/repl.py +++ b/bpython/curtsiesfrontend/repl.py @@ -1410,10 +1410,21 @@ def move_screen_up(current_line_start_row): if self.config.curtsies_list_above: info_max_rows = max(visible_space_above, visible_space_below) else: + # Logic for determining size of completion box # smallest allowed over-full completion box - minimum_possible_height = 20 + minimum_possible_height = 4 + # smallest amount of history that must be visible + try_preserve_history_height = 40 + preferred_height = max( + # always make infobox at least this height + minimum_possible_height, + + # there's so much space that we can preserve + # this much history and still expand the infobox + min_height - try_preserve_history_height) + info_max_rows = min(max(visible_space_below, - minimum_possible_height), + preferred_height), min_height - current_line_height - 1) infobox = paint.paint_infobox( info_max_rows, From 66c5771711b8b4707b820ed513df293d08b679cc Mon Sep 17 00:00:00 2001 From: Thomas Ballinger Date: Thu, 4 Aug 2016 15:38:42 -0400 Subject: [PATCH 3/4] move new variables to parameters --- bpython/curtsiesfrontend/repl.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py index e99f13edf..e8f57551d 100644 --- a/bpython/curtsiesfrontend/repl.py +++ b/bpython/curtsiesfrontend/repl.py @@ -1251,7 +1251,9 @@ def current_output_line(self, value): self.current_stdouterr_line = '' self.stdin.current_line = '\n' - def paint(self, about_to_exit=False, user_quit=False): + def paint(self, about_to_exit=False, user_quit=False, + try_preserve_history_height=40, + min_infobox_height=4): """Returns an array of min_height or more rows and width columns, plus cursor position @@ -1259,6 +1261,10 @@ def paint(self, about_to_exit=False, user_quit=False): a diff and only write to the screen in portions that have changed, but the idea is that we don't need to worry about that here, instead every frame is completely redrawn because less state is cool! + + try_preserve_history_height is the the number of rows of content that + must be visible before the suggestion box scrolls the terminal in order + to display more than min_infobox_height rows of suggestions, docs etc. """ # The hairiest function in the curtsies if about_to_exit: @@ -1412,15 +1418,12 @@ def move_screen_up(current_line_start_row): else: # Logic for determining size of completion box # smallest allowed over-full completion box - minimum_possible_height = 4 - # smallest amount of history that must be visible - try_preserve_history_height = 40 preferred_height = max( # always make infobox at least this height - minimum_possible_height, + min_infobox_height, - # there's so much space that we can preserve - # this much history and still expand the infobox + # use this value if there's so much space that we can + # preserve this try_preserve_history_height rows history min_height - try_preserve_history_height) info_max_rows = min(max(visible_space_below, From aa4ff4273736fed0a6bbbc3ec9414032be7ecc42 Mon Sep 17 00:00:00 2001 From: Thomas Ballinger Date: Fri, 5 Aug 2016 18:46:21 -0400 Subject: [PATCH 4/4] Test suggestion box behavior before/after #466. --- bpython/curtsiesfrontend/repl.py | 4 ++-- bpython/test/test_curtsies_painting.py | 28 ++++++++++++++++++++++++-- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py index e8f57551d..f8739d778 100644 --- a/bpython/curtsiesfrontend/repl.py +++ b/bpython/curtsiesfrontend/repl.py @@ -1252,8 +1252,8 @@ def current_output_line(self, value): self.stdin.current_line = '\n' def paint(self, about_to_exit=False, user_quit=False, - try_preserve_history_height=40, - min_infobox_height=4): + try_preserve_history_height=30, + min_infobox_height=5): """Returns an array of min_height or more rows and width columns, plus cursor position diff --git a/bpython/test/test_curtsies_painting.py b/bpython/test/test_curtsies_painting.py index a70daee6a..2a324e591 100644 --- a/bpython/test/test_curtsies_painting.py +++ b/bpython/test/test_curtsies_painting.py @@ -696,7 +696,19 @@ def test_lower_on_screen(self): '| k |', '| l |', '+------------------+'] - self.assert_paint_ignoring_formatting(screen, (0, 8)) + # behavior before issue #466 + self.assert_paint_ignoring_formatting( + screen, try_preserve_history_height=0) + self.assert_paint_ignoring_formatting( + screen, min_infobox_height=100) + # behavior after issue #466 + screen = ['>>> abc.', + '+------------------+', + '| aaaaaaaaaaaaaaaa |', + '| b |', + '| c |', + '+------------------+'] + self.assert_paint_ignoring_formatting(screen) def test_at_bottom_of_screen(self): self.repl.get_top_usable_line = lambda: 17 # two lines from bottom @@ -720,4 +732,16 @@ def test_at_bottom_of_screen(self): '| k |', '| l |', '+------------------+'] - self.assert_paint_ignoring_formatting(screen, (0, 8)) + # behavior before issue #466 + self.assert_paint_ignoring_formatting( + screen, try_preserve_history_height=0) + self.assert_paint_ignoring_formatting( + screen, min_infobox_height=100) + # behavior after issue #466 + screen = ['>>> abc.', + '+------------------+', + '| aaaaaaaaaaaaaaaa |', + '| b |', + '| c |', + '+------------------+'] + self.assert_paint_ignoring_formatting(screen) pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy