From 4603a22d7e73972079a01b201f7b3656212b1891 Mon Sep 17 00:00:00 2001 From: samuelgregorovic Date: Wed, 6 Oct 2021 20:34:21 +0200 Subject: [PATCH 01/31] basic parentheses and quote closing on key events --- bpython/curtsiesfrontend/repl.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py index 30fbbb14..9fc24c38 100644 --- a/bpython/curtsiesfrontend/repl.py +++ b/bpython/curtsiesfrontend/repl.py @@ -789,9 +789,21 @@ def process_key_event(self, e): self.incr_search_mode = None elif e in ("",): self.add_normal_character(" ") + elif e in ["(", "{", '"', "'", "["]: + self.insert_char_pair(e) else: self.add_normal_character(e) + def insert_char_pair(self, e): + closing_char = self.get_closing_char(e) + self.add_normal_character(e) + self.add_normal_character(closing_char) + self.cursor_offset = len(self.current_line) - 1 + + def get_closing_char(self, e): + closing_char_map = {"(": ")", "{": "}", "[": "]", '"': '"', "'": "'"} + return closing_char_map[e] + def get_last_word(self): previous_word = _last_word(self.rl_history.entry) From 594a4686880cb0cd8341dd3732cca8f070473206 Mon Sep 17 00:00:00 2001 From: samuelgregorovic Date: Wed, 6 Oct 2021 21:53:51 +0200 Subject: [PATCH 02/31] basic pair deletion for common pairs --- bpython/curtsiesfrontend/manual_readline.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/bpython/curtsiesfrontend/manual_readline.py b/bpython/curtsiesfrontend/manual_readline.py index afeb5553..2b2c58cb 100644 --- a/bpython/curtsiesfrontend/manual_readline.py +++ b/bpython/curtsiesfrontend/manual_readline.py @@ -231,6 +231,17 @@ def delete(cursor_offset, line): return (cursor_offset, line[:cursor_offset] + line[cursor_offset + 1 :]) +def cursor_on_closing_char_pair(cursor_offset, line): + closing_char_map = {"(": ")", "{": "}", "[": "]", '"': '"', "'": "'"} + if cursor_offset < len(line): + cur_char = line[cursor_offset] + prev_char = line[cursor_offset - 1] + if prev_char in closing_char_map.keys(): + if cur_char == closing_char_map[prev_char]: + return True + return False + + @edit_keys.on("") @edit_keys.on(config="backspace_key") def backspace(cursor_offset, line): @@ -244,6 +255,12 @@ def backspace(cursor_offset, line): cursor_offset - to_delete, line[: cursor_offset - to_delete] + line[cursor_offset:], ) + if cursor_on_closing_char_pair(cursor_offset, line): + return ( + cursor_offset - 1, + line[: cursor_offset - 1] + line[cursor_offset + 1 :], + ) + return (cursor_offset - 1, line[: cursor_offset - 1] + line[cursor_offset:]) From 691def45083cc4757b4054567ec348d51c167163 Mon Sep 17 00:00:00 2001 From: samuelgregorovic Date: Wed, 6 Oct 2021 22:46:34 +0200 Subject: [PATCH 03/31] jump behind closing paren/quote on TAB --- bpython/curtsiesfrontend/repl.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py index 9fc24c38..07700cd5 100644 --- a/bpython/curtsiesfrontend/repl.py +++ b/bpython/curtsiesfrontend/repl.py @@ -42,7 +42,7 @@ Interp, code_finished_will_parse, ) -from .manual_readline import edit_keys +from .manual_readline import edit_keys, cursor_on_closing_char_pair from .parse import parse as bpythonparse, func_for_letter, color_for_letter from .preprocess import preprocess from .. import __version__ @@ -925,6 +925,8 @@ def only_whitespace_left_of_cursor(): self._cursor_offset, self._current_line = cursor_and_line # using _current_line so we don't trigger a completion reset self.list_win_visible = True + if cursor_on_closing_char_pair(self._cursor_offset, self._current_line): + self._cursor_offset += 2 def on_control_d(self): if self.current_line == "": From ee98f16ad2cbe2cd8ff12fe9a246d9055e4d6e14 Mon Sep 17 00:00:00 2001 From: samuelgregorovic Date: Sat, 30 Oct 2021 10:51:39 +0200 Subject: [PATCH 04/31] jump on tab even with content in parens --- bpython/curtsiesfrontend/manual_readline.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/bpython/curtsiesfrontend/manual_readline.py b/bpython/curtsiesfrontend/manual_readline.py index 2b2c58cb..60b3398b 100644 --- a/bpython/curtsiesfrontend/manual_readline.py +++ b/bpython/curtsiesfrontend/manual_readline.py @@ -236,9 +236,8 @@ def cursor_on_closing_char_pair(cursor_offset, line): if cursor_offset < len(line): cur_char = line[cursor_offset] prev_char = line[cursor_offset - 1] - if prev_char in closing_char_map.keys(): - if cur_char == closing_char_map[prev_char]: - return True + if cur_char in closing_char_map.values(): + return True return False From a59daed786cbcd4f344b278c560eae904bb292e9 Mon Sep 17 00:00:00 2001 From: samuelgregorovic Date: Sat, 30 Oct 2021 11:18:21 +0200 Subject: [PATCH 05/31] move cursor on closing paren ovrwrite --- bpython/curtsiesfrontend/repl.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py index 07700cd5..405d80c2 100644 --- a/bpython/curtsiesfrontend/repl.py +++ b/bpython/curtsiesfrontend/repl.py @@ -791,6 +791,8 @@ def process_key_event(self, e): self.add_normal_character(" ") elif e in ["(", "{", '"', "'", "["]: self.insert_char_pair(e) + elif e in [")", "}", '"', "'", "["]: + self.insert_char_pair_end(e) else: self.add_normal_character(e) @@ -800,6 +802,11 @@ def insert_char_pair(self, e): self.add_normal_character(closing_char) self.cursor_offset = len(self.current_line) - 1 + def insert_char_pair_end(self, e): + if self.current_line[self.cursor_offset] != e: + self.add_normal_character(e) + self.cursor_offset = len(self.current_line) + 2 + def get_closing_char(self, e): closing_char_map = {"(": ")", "{": "}", "[": "]", '"': '"', "'": "'"} return closing_char_map[e] From 920640363e6e3b9f1822700bd0f93c529579a0e1 Mon Sep 17 00:00:00 2001 From: samuelgregorovic Date: Sat, 30 Oct 2021 12:06:21 +0200 Subject: [PATCH 06/31] removed quotes completion + fixed bad cursor bug --- bpython/curtsiesfrontend/manual_readline.py | 4 +++- bpython/curtsiesfrontend/repl.py | 15 +++++++++------ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/bpython/curtsiesfrontend/manual_readline.py b/bpython/curtsiesfrontend/manual_readline.py index 60b3398b..cec2e04c 100644 --- a/bpython/curtsiesfrontend/manual_readline.py +++ b/bpython/curtsiesfrontend/manual_readline.py @@ -232,7 +232,9 @@ def delete(cursor_offset, line): def cursor_on_closing_char_pair(cursor_offset, line): - closing_char_map = {"(": ")", "{": "}", "[": "]", '"': '"', "'": "'"} + closing_char_map = {"(": ")", "{": "}", "[": "]"} + if line is None: + return False if cursor_offset < len(line): cur_char = line[cursor_offset] prev_char = line[cursor_offset - 1] diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py index 405d80c2..dbafa271 100644 --- a/bpython/curtsiesfrontend/repl.py +++ b/bpython/curtsiesfrontend/repl.py @@ -789,9 +789,9 @@ def process_key_event(self, e): self.incr_search_mode = None elif e in ("",): self.add_normal_character(" ") - elif e in ["(", "{", '"', "'", "["]: + elif e in ["(", "{", "["]: self.insert_char_pair(e) - elif e in [")", "}", '"', "'", "["]: + elif e in [")", "}", "]"]: self.insert_char_pair_end(e) else: self.add_normal_character(e) @@ -803,12 +803,15 @@ def insert_char_pair(self, e): self.cursor_offset = len(self.current_line) - 1 def insert_char_pair_end(self, e): - if self.current_line[self.cursor_offset] != e: - self.add_normal_character(e) - self.cursor_offset = len(self.current_line) + 2 + logger.debug(f"{len(self.current_line)} o:{self.cursor_offset}\n") + if self.cursor_offset < len(self.current_line): + if self.current_line[self.cursor_offset] == e: + self.cursor_offset = len(self.current_line) + 1 + return + self.add_normal_character(e) def get_closing_char(self, e): - closing_char_map = {"(": ")", "{": "}", "[": "]", '"': '"', "'": "'"} + closing_char_map = {"(": ")", "{": "}", "[": "]"} return closing_char_map[e] def get_last_word(self): From 82a32e6bac5e32e0235eb01e6d2b4d51ed0de96a Mon Sep 17 00:00:00 2001 From: samuelgregorovic Date: Sat, 30 Oct 2021 12:54:21 +0200 Subject: [PATCH 07/31] nested tabbing/ovewriting brackets working --- bpython/curtsiesfrontend/repl.py | 30 +++- test.txt | 250 +++++++++++++++++++++++++++++++ 2 files changed, 274 insertions(+), 6 deletions(-) create mode 100644 test.txt diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py index dbafa271..19b8b530 100644 --- a/bpython/curtsiesfrontend/repl.py +++ b/bpython/curtsiesfrontend/repl.py @@ -798,15 +798,33 @@ def process_key_event(self, e): def insert_char_pair(self, e): closing_char = self.get_closing_char(e) - self.add_normal_character(e) - self.add_normal_character(closing_char) - self.cursor_offset = len(self.current_line) - 1 + self._set_current_line( + ( + self.current_line[: self.cursor_offset] + + e + + self.current_line[self.cursor_offset :] + ), + update_completion=False, + reset_rl_history=False, + clear_special_mode=False, + ) + self.cursor_offset += 1 + + self._set_current_line( + ( + self.current_line[: self.cursor_offset] + + closing_char + + self.current_line[self.cursor_offset :] + ), + update_completion=False, + reset_rl_history=False, + clear_special_mode=False, + ) def insert_char_pair_end(self, e): - logger.debug(f"{len(self.current_line)} o:{self.cursor_offset}\n") if self.cursor_offset < len(self.current_line): if self.current_line[self.cursor_offset] == e: - self.cursor_offset = len(self.current_line) + 1 + self.cursor_offset += 1 return self.add_normal_character(e) @@ -936,7 +954,7 @@ def only_whitespace_left_of_cursor(): # using _current_line so we don't trigger a completion reset self.list_win_visible = True if cursor_on_closing_char_pair(self._cursor_offset, self._current_line): - self._cursor_offset += 2 + self._cursor_offset += 1 def on_control_d(self): if self.current_line == "": diff --git a/test.txt b/test.txt new file mode 100644 index 00000000..e2e2e9c2 --- /dev/null +++ b/test.txt @@ -0,0 +1,250 @@ +2021-10-30 12:46:27,154: bpython.args: INFO: Starting bpython 0.22.dev114 +2021-10-30 12:46:27,154: bpython.args: INFO: Python /home/administrator/github/personal/bpython-dev/bin/python3: sys.version_info(major=3, minor=8, micro=10, releaselevel='final', serial=0) +2021-10-30 12:46:27,155: bpython.args: INFO: curtsies: 0.3.7 +2021-10-30 12:46:27,155: bpython.args: INFO: cwcwidth: 0.1.4 +2021-10-30 12:46:27,155: bpython.args: INFO: greenlet: 1.1.2 +2021-10-30 12:46:27,155: bpython.args: INFO: pygments: 2.10.0 +2021-10-30 12:46:27,155: bpython.args: INFO: requests: 2.26.0 +2021-10-30 12:46:27,155: bpython.args: INFO: environment: +LANG: en_US.UTF-8 +LC_ADDRESS: sk_SK.UTF-8 +LC_IDENTIFICATION: sk_SK.UTF-8 +LC_MEASUREMENT: sk_SK.UTF-8 +LC_MONETARY: sk_SK.UTF-8 +LC_NAME: sk_SK.UTF-8 +LC_NUMERIC: sk_SK.UTF-8 +LC_PAPER: sk_SK.UTF-8 +LC_TELEPHONE: sk_SK.UTF-8 +LC_TIME: sk_SK.UTF-8 +TERM: xterm-256color +2021-10-30 12:46:27,156: curtsies.window: DEBUG: -------initializing Window object ------ +2021-10-30 12:46:27,157: bpython.curtsiesfrontend.repl: DEBUG: starting init +2021-10-30 12:46:27,157: bpython.curtsiesfrontend.repl: DEBUG: starting parent init +2021-10-30 12:46:27,168: curtsies.window: DEBUG: initial top_usable_row: 71 +2021-10-30 12:46:27,168: curtsies.window: DEBUG: running BaseWindow.__enter__ +2021-10-30 12:46:27,170: bpython.curtsiesfrontend.repl: DEBUG: processing event +2021-10-30 12:46:27,218: bpython.curtsiesfrontend.repl: DEBUG: Display line '' -> +2021-10-30 12:46:27,218: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ') +2021-10-30 12:46:27,218: bpython.curtsiesfrontend.repl: DEBUG: no history issues. start 0 +2021-10-30 12:46:27,218: curtsies.formatstringarray: DEBUG: slice: (slice(None, 0, None), slice(None, 140, None)) +2021-10-30 12:46:27,218: curtsies.formatstringarray: DEBUG: num columns: 140 +2021-10-30 12:46:27,218: curtsies.formatstringarray: DEBUG: colslice: slice(None, 140, None) +2021-10-30 12:46:27,219: bpython.curtsiesfrontend.repl: DEBUG: ---current line row slice 0, 1 +2021-10-30 12:46:27,219: bpython.curtsiesfrontend.repl: DEBUG: ---current line col slice 0, 140 +2021-10-30 12:46:27,219: curtsies.formatstringarray: DEBUG: slice: (slice(0, 1, None), slice(0, 140, None)) +2021-10-30 12:46:27,219: curtsies.formatstringarray: DEBUG: num columns: 140 +2021-10-30 12:46:27,219: curtsies.formatstringarray: DEBUG: colslice: slice(0, 140, None) +2021-10-30 12:46:27,219: bpython.curtsiesfrontend.repl: DEBUG: Display line '' -> +2021-10-30 12:46:27,219: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ') +2021-10-30 12:46:27,219: bpython.curtsiesfrontend.repl: DEBUG: Display line '' -> +2021-10-30 12:46:27,220: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ') +2021-10-30 12:46:27,220: bpython.curtsiesfrontend.repl: DEBUG: Display line '' -> +2021-10-30 12:46:27,220: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ') +2021-10-30 12:46:27,220: bpython.curtsiesfrontend.repl: DEBUG: Display line '' -> +2021-10-30 12:46:27,220: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ') +2021-10-30 12:46:27,220: bpython.curtsiesfrontend.repl: DEBUG: about to exit: False +2021-10-30 12:46:27,220: curtsies.formatstringarray: DEBUG: slice: (1, slice(None, None, None)) +2021-10-30 12:46:27,220: curtsies.formatstringarray: DEBUG: num columns: 140 +2021-10-30 12:46:27,220: curtsies.formatstringarray: DEBUG: colslice: slice(None, None, None) +2021-10-30 12:46:27,221: bpython.curtsiesfrontend.repl: DEBUG: returning arr of size (2, 140) +2021-10-30 12:46:27,221: bpython.curtsiesfrontend.repl: DEBUG: cursor pos: (0, 4) +2021-10-30 12:46:27,221: curtsies.window: DEBUG: sending scroll down message w/ cursor on bottom line +2021-10-30 12:46:27,221: curtsies.window: DEBUG: new top_usable_row: 70 +2021-10-30 12:46:27,221: curtsies.window: DEBUG: lines in last lines by row: dict_keys([]) +2021-10-30 12:46:27,221: curtsies.window: DEBUG: lines in current lines by row: dict_keys([70, 71]) +2021-10-30 12:46:28,486: bpython.curtsiesfrontend.repl: DEBUG: processing event '(' +2021-10-30 12:46:28,492: bpython.curtsiesfrontend.repl: DEBUG: Display line '()' -> on_magenta(bold(red('(')))+bold(yellow(')')) +2021-10-30 12:46:28,493: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ')+on_magenta(bold(red('(')))+bold(yellow(')')) +2021-10-30 12:46:28,493: bpython.curtsiesfrontend.repl: DEBUG: no history issues. start 0 +2021-10-30 12:46:28,493: curtsies.formatstringarray: DEBUG: slice: (slice(None, 0, None), slice(None, 140, None)) +2021-10-30 12:46:28,493: curtsies.formatstringarray: DEBUG: num columns: 140 +2021-10-30 12:46:28,493: curtsies.formatstringarray: DEBUG: colslice: slice(None, 140, None) +2021-10-30 12:46:28,493: bpython.curtsiesfrontend.repl: DEBUG: ---current line row slice 0, 1 +2021-10-30 12:46:28,493: bpython.curtsiesfrontend.repl: DEBUG: ---current line col slice 0, 140 +2021-10-30 12:46:28,493: curtsies.formatstringarray: DEBUG: slice: (slice(0, 1, None), slice(0, 140, None)) +2021-10-30 12:46:28,493: curtsies.formatstringarray: DEBUG: num columns: 140 +2021-10-30 12:46:28,493: curtsies.formatstringarray: DEBUG: colslice: slice(0, 140, None) +2021-10-30 12:46:28,494: bpython.curtsiesfrontend.repl: DEBUG: Display line '()' -> on_magenta(bold(red('(')))+bold(yellow(')')) +2021-10-30 12:46:28,494: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ')+on_magenta(bold(red('(')))+bold(yellow(')')) +2021-10-30 12:46:28,494: bpython.curtsiesfrontend.repl: DEBUG: Display line '()' -> on_magenta(bold(red('(')))+bold(yellow(')')) +2021-10-30 12:46:28,494: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ')+on_magenta(bold(red('(')))+bold(yellow(')')) +2021-10-30 12:46:28,495: bpython.curtsiesfrontend.repl: DEBUG: Display line '()' -> on_magenta(bold(red('(')))+bold(yellow(')')) +2021-10-30 12:46:28,495: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ')+on_magenta(bold(red('(')))+bold(yellow(')')) +2021-10-30 12:46:28,495: bpython.curtsiesfrontend.repl: DEBUG: Display line '()' -> on_magenta(bold(red('(')))+bold(yellow(')')) +2021-10-30 12:46:28,495: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ')+on_magenta(bold(red('(')))+bold(yellow(')')) +2021-10-30 12:46:28,495: bpython.curtsiesfrontend.repl: DEBUG: about to exit: False +2021-10-30 12:46:28,495: curtsies.formatstringarray: DEBUG: slice: (1, slice(None, None, None)) +2021-10-30 12:46:28,495: curtsies.formatstringarray: DEBUG: num columns: 140 +2021-10-30 12:46:28,495: curtsies.formatstringarray: DEBUG: colslice: slice(None, None, None) +2021-10-30 12:46:28,496: bpython.curtsiesfrontend.repl: DEBUG: returning arr of size (2, 140) +2021-10-30 12:46:28,496: bpython.curtsiesfrontend.repl: DEBUG: cursor pos: (0, 5) +2021-10-30 12:46:28,496: curtsies.window: DEBUG: lines in last lines by row: dict_keys([70, 71]) +2021-10-30 12:46:28,496: curtsies.window: DEBUG: lines in current lines by row: dict_keys([70, 71]) +2021-10-30 12:46:29,836: bpython.curtsiesfrontend.repl: DEBUG: processing event '(' +2021-10-30 12:46:29,839: bpython.curtsiesfrontend.repl: DEBUG: Display line '(())' -> on_magenta(bold(red('(')))+yellow('(')+yellow(')')+bold(yellow(')')) +2021-10-30 12:46:29,841: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ')+on_magenta(bold(red('(')))+yellow('(')+yellow(')')+bold(yellow(')')) +2021-10-30 12:46:29,843: bpython.curtsiesfrontend.repl: DEBUG: no history issues. start 0 +2021-10-30 12:46:29,843: curtsies.formatstringarray: DEBUG: slice: (slice(None, 0, None), slice(None, 140, None)) +2021-10-30 12:46:29,843: curtsies.formatstringarray: DEBUG: num columns: 140 +2021-10-30 12:46:29,843: curtsies.formatstringarray: DEBUG: colslice: slice(None, 140, None) +2021-10-30 12:46:29,844: bpython.curtsiesfrontend.repl: DEBUG: ---current line row slice 0, 1 +2021-10-30 12:46:29,844: bpython.curtsiesfrontend.repl: DEBUG: ---current line col slice 0, 140 +2021-10-30 12:46:29,844: curtsies.formatstringarray: DEBUG: slice: (slice(0, 1, None), slice(0, 140, None)) +2021-10-30 12:46:29,844: curtsies.formatstringarray: DEBUG: num columns: 140 +2021-10-30 12:46:29,845: curtsies.formatstringarray: DEBUG: colslice: slice(0, 140, None) +2021-10-30 12:46:29,846: bpython.curtsiesfrontend.repl: DEBUG: Display line '(())' -> on_magenta(bold(red('(')))+yellow('(')+yellow(')')+bold(yellow(')')) +2021-10-30 12:46:29,846: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ')+on_magenta(bold(red('(')))+yellow('(')+yellow(')')+bold(yellow(')')) +2021-10-30 12:46:29,848: bpython.curtsiesfrontend.repl: DEBUG: Display line '(())' -> on_magenta(bold(red('(')))+yellow('(')+yellow(')')+bold(yellow(')')) +2021-10-30 12:46:29,849: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ')+on_magenta(bold(red('(')))+yellow('(')+yellow(')')+bold(yellow(')')) +2021-10-30 12:46:29,850: bpython.curtsiesfrontend.repl: DEBUG: Display line '(())' -> on_magenta(bold(red('(')))+yellow('(')+yellow(')')+bold(yellow(')')) +2021-10-30 12:46:29,850: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ')+on_magenta(bold(red('(')))+yellow('(')+yellow(')')+bold(yellow(')')) +2021-10-30 12:46:29,851: bpython.curtsiesfrontend.repl: DEBUG: Display line '(())' -> on_magenta(bold(red('(')))+yellow('(')+yellow(')')+bold(yellow(')')) +2021-10-30 12:46:29,852: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ')+on_magenta(bold(red('(')))+yellow('(')+yellow(')')+bold(yellow(')')) +2021-10-30 12:46:29,852: bpython.curtsiesfrontend.repl: DEBUG: about to exit: False +2021-10-30 12:46:29,853: curtsies.formatstringarray: DEBUG: slice: (1, slice(None, None, None)) +2021-10-30 12:46:29,853: curtsies.formatstringarray: DEBUG: num columns: 140 +2021-10-30 12:46:29,853: curtsies.formatstringarray: DEBUG: colslice: slice(None, None, None) +2021-10-30 12:46:29,854: bpython.curtsiesfrontend.repl: DEBUG: returning arr of size (2, 140) +2021-10-30 12:46:29,854: bpython.curtsiesfrontend.repl: DEBUG: cursor pos: (0, 7) +2021-10-30 12:46:29,855: curtsies.window: DEBUG: lines in last lines by row: dict_keys([70, 71]) +2021-10-30 12:46:29,855: curtsies.window: DEBUG: lines in current lines by row: dict_keys([70, 71]) +2021-10-30 12:46:30,159: curtsies.input: DEBUG: popping an event! (1635590790.1589813, ) [] +2021-10-30 12:46:30,160: bpython.curtsiesfrontend.repl: DEBUG: processing event +2021-10-30 12:46:30,162: bpython.curtsiesfrontend.repl: DEBUG: Display line '(())' -> on_magenta(bold(red('(')))+yellow('(')+yellow(')')+bold(yellow(')')) +2021-10-30 12:46:30,162: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ')+on_magenta(bold(red('(')))+yellow('(')+yellow(')')+bold(yellow(')')) +2021-10-30 12:46:30,163: bpython.curtsiesfrontend.repl: DEBUG: no history issues. start 0 +2021-10-30 12:46:30,164: curtsies.formatstringarray: DEBUG: slice: (slice(None, 0, None), slice(None, 140, None)) +2021-10-30 12:46:30,164: curtsies.formatstringarray: DEBUG: num columns: 140 +2021-10-30 12:46:30,164: curtsies.formatstringarray: DEBUG: colslice: slice(None, 140, None) +2021-10-30 12:46:30,164: bpython.curtsiesfrontend.repl: DEBUG: ---current line row slice 0, 1 +2021-10-30 12:46:30,165: bpython.curtsiesfrontend.repl: DEBUG: ---current line col slice 0, 140 +2021-10-30 12:46:30,165: curtsies.formatstringarray: DEBUG: slice: (slice(0, 1, None), slice(0, 140, None)) +2021-10-30 12:46:30,165: curtsies.formatstringarray: DEBUG: num columns: 140 +2021-10-30 12:46:30,165: curtsies.formatstringarray: DEBUG: colslice: slice(0, 140, None) +2021-10-30 12:46:30,167: bpython.curtsiesfrontend.repl: DEBUG: Display line '(())' -> on_magenta(bold(red('(')))+yellow('(')+yellow(')')+bold(yellow(')')) +2021-10-30 12:46:30,167: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ')+on_magenta(bold(red('(')))+yellow('(')+yellow(')')+bold(yellow(')')) +2021-10-30 12:46:30,169: bpython.curtsiesfrontend.repl: DEBUG: Display line '(())' -> on_magenta(bold(red('(')))+yellow('(')+yellow(')')+bold(yellow(')')) +2021-10-30 12:46:30,170: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ')+on_magenta(bold(red('(')))+yellow('(')+yellow(')')+bold(yellow(')')) +2021-10-30 12:46:30,171: bpython.curtsiesfrontend.repl: DEBUG: Display line '(())' -> on_magenta(bold(red('(')))+yellow('(')+yellow(')')+bold(yellow(')')) +2021-10-30 12:46:30,171: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ')+on_magenta(bold(red('(')))+yellow('(')+yellow(')')+bold(yellow(')')) +2021-10-30 12:46:30,172: bpython.curtsiesfrontend.repl: DEBUG: Display line '(())' -> on_magenta(bold(red('(')))+yellow('(')+yellow(')')+bold(yellow(')')) +2021-10-30 12:46:30,173: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ')+on_magenta(bold(red('(')))+yellow('(')+yellow(')')+bold(yellow(')')) +2021-10-30 12:46:30,173: bpython.curtsiesfrontend.repl: DEBUG: about to exit: False +2021-10-30 12:46:30,174: bpython.curtsiesfrontend.repl: DEBUG: returning arr of size (1, 140) +2021-10-30 12:46:30,174: bpython.curtsiesfrontend.repl: DEBUG: cursor pos: (0, 7) +2021-10-30 12:46:30,174: curtsies.window: DEBUG: lines in last lines by row: dict_keys([70, 71]) +2021-10-30 12:46:30,175: curtsies.window: DEBUG: lines in current lines by row: dict_keys([70, 71]) +2021-10-30 12:46:31,990: bpython.curtsiesfrontend.repl: DEBUG: processing event '' +2021-10-30 12:46:31,992: bpython.curtsiesfrontend.repl: DEBUG: Display line '(()' -> yellow('(')+on_magenta(bold(red('(')))+on_magenta(bold(red(')'))) +2021-10-30 12:46:31,993: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ')+yellow('(')+on_magenta(bold(red('(')))+on_magenta(bold(red(')'))) +2021-10-30 12:46:31,994: bpython.curtsiesfrontend.repl: DEBUG: no history issues. start 0 +2021-10-30 12:46:31,994: curtsies.formatstringarray: DEBUG: slice: (slice(None, 0, None), slice(None, 140, None)) +2021-10-30 12:46:31,994: curtsies.formatstringarray: DEBUG: num columns: 140 +2021-10-30 12:46:31,994: curtsies.formatstringarray: DEBUG: colslice: slice(None, 140, None) +2021-10-30 12:46:31,994: bpython.curtsiesfrontend.repl: DEBUG: ---current line row slice 0, 1 +2021-10-30 12:46:31,994: bpython.curtsiesfrontend.repl: DEBUG: ---current line col slice 0, 140 +2021-10-30 12:46:31,994: curtsies.formatstringarray: DEBUG: slice: (slice(0, 1, None), slice(0, 140, None)) +2021-10-30 12:46:31,994: curtsies.formatstringarray: DEBUG: num columns: 140 +2021-10-30 12:46:31,994: curtsies.formatstringarray: DEBUG: colslice: slice(0, 140, None) +2021-10-30 12:46:31,995: bpython.curtsiesfrontend.repl: DEBUG: Display line '(()' -> yellow('(')+on_magenta(bold(red('(')))+on_magenta(bold(red(')'))) +2021-10-30 12:46:31,995: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ')+yellow('(')+on_magenta(bold(red('(')))+on_magenta(bold(red(')'))) +2021-10-30 12:46:31,996: bpython.curtsiesfrontend.repl: DEBUG: Display line '(()' -> yellow('(')+on_magenta(bold(red('(')))+on_magenta(bold(red(')'))) +2021-10-30 12:46:31,996: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ')+yellow('(')+on_magenta(bold(red('(')))+on_magenta(bold(red(')'))) +2021-10-30 12:46:31,996: bpython.curtsiesfrontend.repl: DEBUG: Display line '(()' -> yellow('(')+on_magenta(bold(red('(')))+on_magenta(bold(red(')'))) +2021-10-30 12:46:31,996: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ')+yellow('(')+on_magenta(bold(red('(')))+on_magenta(bold(red(')'))) +2021-10-30 12:46:31,997: bpython.curtsiesfrontend.repl: DEBUG: Display line '(()' -> yellow('(')+on_magenta(bold(red('(')))+on_magenta(bold(red(')'))) +2021-10-30 12:46:31,997: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ')+yellow('(')+on_magenta(bold(red('(')))+on_magenta(bold(red(')'))) +2021-10-30 12:46:31,997: bpython.curtsiesfrontend.repl: DEBUG: about to exit: False +2021-10-30 12:46:31,997: bpython.curtsiesfrontend.repl: DEBUG: returning arr of size (1, 140) +2021-10-30 12:46:31,997: bpython.curtsiesfrontend.repl: DEBUG: cursor pos: (0, 7) +2021-10-30 12:46:32,613: curtsies.window: DEBUG: lines in last lines by row: dict_keys([70, 71]) +2021-10-30 12:46:32,613: curtsies.window: DEBUG: lines in current lines by row: dict_keys([70, 71]) +2021-10-30 12:46:32,614: bpython.curtsiesfrontend.repl: DEBUG: processing event +2021-10-30 12:46:32,614: bpython.curtsiesfrontend.repl: DEBUG: received sigint event +2021-10-30 12:46:32,615: bpython.curtsiesfrontend.repl: DEBUG: Display line '(()' -> yellow('(')+yellow('(')+yellow(')') +2021-10-30 12:46:32,616: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ')+yellow('(')+yellow('(')+yellow(')') +2021-10-30 12:46:32,618: bpython.curtsiesfrontend.repl: DEBUG: Display line '' -> +2021-10-30 12:46:32,618: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ') +2021-10-30 12:46:32,619: bpython.curtsiesfrontend.repl: DEBUG: no history issues. start 2 +2021-10-30 12:46:32,619: curtsies.formatstringarray: DEBUG: slice: (slice(None, 2, None), slice(None, 140, None)) +2021-10-30 12:46:32,620: curtsies.formatstringarray: DEBUG: num columns: 140 +2021-10-30 12:46:32,620: curtsies.formatstringarray: DEBUG: colslice: slice(None, 140, None) +2021-10-30 12:46:32,620: bpython.curtsiesfrontend.repl: DEBUG: ---current line row slice 2, 3 +2021-10-30 12:46:32,620: bpython.curtsiesfrontend.repl: DEBUG: ---current line col slice 0, 140 +2021-10-30 12:46:32,620: curtsies.formatstringarray: DEBUG: slice: (slice(2, 3, None), slice(0, 140, None)) +2021-10-30 12:46:32,621: curtsies.formatstringarray: DEBUG: num columns: 140 +2021-10-30 12:46:32,621: curtsies.formatstringarray: DEBUG: colslice: slice(0, 140, None) +2021-10-30 12:46:32,621: bpython.curtsiesfrontend.repl: DEBUG: Display line '' -> +2021-10-30 12:46:32,621: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ') +2021-10-30 12:46:32,621: bpython.curtsiesfrontend.repl: DEBUG: Display line '' -> +2021-10-30 12:46:32,621: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ') +2021-10-30 12:46:32,622: bpython.curtsiesfrontend.repl: DEBUG: Display line '' -> +2021-10-30 12:46:32,622: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ') +2021-10-30 12:46:32,622: bpython.curtsiesfrontend.repl: DEBUG: Display line '' -> +2021-10-30 12:46:32,622: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ') +2021-10-30 12:46:32,622: bpython.curtsiesfrontend.repl: DEBUG: about to exit: False +2021-10-30 12:46:32,622: bpython.curtsiesfrontend.repl: DEBUG: returning arr of size (3, 140) +2021-10-30 12:46:32,622: bpython.curtsiesfrontend.repl: DEBUG: cursor pos: (2, 4) +2021-10-30 12:46:32,622: curtsies.window: DEBUG: sending scroll down message w/ cursor on bottom line +2021-10-30 12:46:32,622: curtsies.window: DEBUG: new top_usable_row: 69 +2021-10-30 12:46:32,623: curtsies.window: DEBUG: lines in last lines by row: dict_keys([70, 71]) +2021-10-30 12:46:32,623: curtsies.window: DEBUG: lines in current lines by row: dict_keys([69, 70, 71]) +2021-10-30 12:46:33,256: bpython.curtsiesfrontend.repl: DEBUG: processing event +2021-10-30 12:46:33,256: bpython.curtsiesfrontend.repl: DEBUG: received sigint event +2021-10-30 12:46:33,256: bpython.curtsiesfrontend.repl: DEBUG: Display line '' -> +2021-10-30 12:46:33,256: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ') +2021-10-30 12:46:33,257: bpython.curtsiesfrontend.repl: DEBUG: Display line '' -> +2021-10-30 12:46:33,257: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ') +2021-10-30 12:46:33,257: bpython.curtsiesfrontend.repl: DEBUG: no history issues. start 4 +2021-10-30 12:46:33,257: curtsies.formatstringarray: DEBUG: slice: (slice(None, 4, None), slice(None, 140, None)) +2021-10-30 12:46:33,257: curtsies.formatstringarray: DEBUG: num columns: 140 +2021-10-30 12:46:33,258: curtsies.formatstringarray: DEBUG: colslice: slice(None, 140, None) +2021-10-30 12:46:33,258: bpython.curtsiesfrontend.repl: DEBUG: ---current line row slice 4, 5 +2021-10-30 12:46:33,258: bpython.curtsiesfrontend.repl: DEBUG: ---current line col slice 0, 140 +2021-10-30 12:46:33,258: curtsies.formatstringarray: DEBUG: slice: (slice(4, 5, None), slice(0, 140, None)) +2021-10-30 12:46:33,258: curtsies.formatstringarray: DEBUG: num columns: 140 +2021-10-30 12:46:33,258: curtsies.formatstringarray: DEBUG: colslice: slice(0, 140, None) +2021-10-30 12:46:33,258: bpython.curtsiesfrontend.repl: DEBUG: Display line '' -> +2021-10-30 12:46:33,258: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ') +2021-10-30 12:46:33,259: bpython.curtsiesfrontend.repl: DEBUG: Display line '' -> +2021-10-30 12:46:33,259: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ') +2021-10-30 12:46:33,259: bpython.curtsiesfrontend.repl: DEBUG: Display line '' -> +2021-10-30 12:46:33,259: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ') +2021-10-30 12:46:33,259: bpython.curtsiesfrontend.repl: DEBUG: Display line '' -> +2021-10-30 12:46:33,259: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ') +2021-10-30 12:46:33,259: bpython.curtsiesfrontend.repl: DEBUG: about to exit: False +2021-10-30 12:46:33,259: bpython.curtsiesfrontend.repl: DEBUG: returning arr of size (5, 140) +2021-10-30 12:46:33,259: bpython.curtsiesfrontend.repl: DEBUG: cursor pos: (4, 4) +2021-10-30 12:46:33,260: curtsies.window: DEBUG: sending scroll down message w/ cursor on bottom line +2021-10-30 12:46:33,260: curtsies.window: DEBUG: new top_usable_row: 68 +2021-10-30 12:46:33,260: curtsies.window: DEBUG: sending scroll down message w/ cursor on bottom line +2021-10-30 12:46:33,260: curtsies.window: DEBUG: new top_usable_row: 67 +2021-10-30 12:46:33,260: curtsies.window: DEBUG: lines in last lines by row: dict_keys([69, 70, 71]) +2021-10-30 12:46:33,260: curtsies.window: DEBUG: lines in current lines by row: dict_keys([67, 68, 69, 70, 71]) +2021-10-30 12:46:33,622: bpython.curtsiesfrontend.repl: DEBUG: processing event '' +2021-10-30 12:46:33,622: bpython.curtsiesfrontend.repl: DEBUG: unhighlighting paren for exit +2021-10-30 12:46:33,624: bpython.curtsiesfrontend.repl: DEBUG: Display line '' -> +2021-10-30 12:46:33,624: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ') +2021-10-30 12:46:33,625: bpython.curtsiesfrontend.repl: DEBUG: no history issues. start 4 +2021-10-30 12:46:33,626: curtsies.formatstringarray: DEBUG: slice: (slice(None, 4, None), slice(None, 140, None)) +2021-10-30 12:46:33,626: curtsies.formatstringarray: DEBUG: num columns: 140 +2021-10-30 12:46:33,627: curtsies.formatstringarray: DEBUG: colslice: slice(None, 140, None) +2021-10-30 12:46:33,627: bpython.curtsiesfrontend.repl: DEBUG: ---current line row slice 4, 5 +2021-10-30 12:46:33,627: bpython.curtsiesfrontend.repl: DEBUG: ---current line col slice 0, 140 +2021-10-30 12:46:33,627: curtsies.formatstringarray: DEBUG: slice: (slice(4, 5, None), slice(0, 140, None)) +2021-10-30 12:46:33,627: curtsies.formatstringarray: DEBUG: num columns: 140 +2021-10-30 12:46:33,627: curtsies.formatstringarray: DEBUG: colslice: slice(0, 140, None) +2021-10-30 12:46:33,627: bpython.curtsiesfrontend.repl: DEBUG: Display line '' -> +2021-10-30 12:46:33,628: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ') +2021-10-30 12:46:33,628: bpython.curtsiesfrontend.repl: DEBUG: Display line '' -> +2021-10-30 12:46:33,628: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ') +2021-10-30 12:46:33,628: bpython.curtsiesfrontend.repl: DEBUG: Display line '' -> +2021-10-30 12:46:33,628: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ') +2021-10-30 12:46:33,628: bpython.curtsiesfrontend.repl: DEBUG: Display line '' -> +2021-10-30 12:46:33,628: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ') +2021-10-30 12:46:33,629: bpython.curtsiesfrontend.repl: DEBUG: about to exit: True +2021-10-30 12:46:33,629: bpython.curtsiesfrontend.repl: DEBUG: returning arr of size (5, 140) +2021-10-30 12:46:33,629: bpython.curtsiesfrontend.repl: DEBUG: cursor pos: (4, 4) +2021-10-30 12:46:33,629: curtsies.window: DEBUG: lines in last lines by row: dict_keys([67, 68, 69, 70, 71]) +2021-10-30 12:46:33,629: curtsies.window: DEBUG: lines in current lines by row: dict_keys([67, 68, 69, 70, 71]) +2021-10-30 12:46:33,629: curtsies.window: DEBUG: running BaseWindow.__exit__ From e00f87b6e34070907d5355860337e0565293cea2 Mon Sep 17 00:00:00 2001 From: samuelgregorovic Date: Sat, 30 Oct 2021 13:04:09 +0200 Subject: [PATCH 08/31] fixed backspace event when cursor on closing paren --- bpython/curtsiesfrontend/manual_readline.py | 15 +++++++++++---- bpython/curtsiesfrontend/repl.py | 5 ++++- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/bpython/curtsiesfrontend/manual_readline.py b/bpython/curtsiesfrontend/manual_readline.py index cec2e04c..6f24b539 100644 --- a/bpython/curtsiesfrontend/manual_readline.py +++ b/bpython/curtsiesfrontend/manual_readline.py @@ -233,14 +233,18 @@ def delete(cursor_offset, line): def cursor_on_closing_char_pair(cursor_offset, line): closing_char_map = {"(": ")", "{": "}", "[": "]"} + on_closing_char, pair_close = False, False if line is None: - return False + return on_closing_char, pair_close if cursor_offset < len(line): cur_char = line[cursor_offset] prev_char = line[cursor_offset - 1] if cur_char in closing_char_map.values(): - return True - return False + on_closing_char = True + if prev_char in closing_char_map: + if closing_char_map[prev_char] == cur_char: + pair_close = True + return on_closing_char, pair_close @edit_keys.on("") @@ -256,7 +260,10 @@ def backspace(cursor_offset, line): cursor_offset - to_delete, line[: cursor_offset - to_delete] + line[cursor_offset:], ) - if cursor_on_closing_char_pair(cursor_offset, line): + on_closing_char, pair_close = cursor_on_closing_char_pair( + cursor_offset, line + ) + if on_closing_char and pair_close: return ( cursor_offset - 1, line[: cursor_offset - 1] + line[cursor_offset + 1 :], diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py index 19b8b530..205d29e5 100644 --- a/bpython/curtsiesfrontend/repl.py +++ b/bpython/curtsiesfrontend/repl.py @@ -953,7 +953,10 @@ def only_whitespace_left_of_cursor(): self._cursor_offset, self._current_line = cursor_and_line # using _current_line so we don't trigger a completion reset self.list_win_visible = True - if cursor_on_closing_char_pair(self._cursor_offset, self._current_line): + on_closing_char, _ = cursor_on_closing_char_pair( + self._cursor_offset, self._current_line + ) + if on_closing_char: self._cursor_offset += 1 def on_control_d(self): From a902deb1b2094fbc885750643fca4bc6941368a1 Mon Sep 17 00:00:00 2001 From: samuelgregorovic Date: Sat, 30 Oct 2021 14:11:26 +0200 Subject: [PATCH 09/31] added quote completion + autocomplete compatibility --- bpython/curtsiesfrontend/manual_readline.py | 2 +- bpython/curtsiesfrontend/repl.py | 37 +++++++++++++++------ 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/bpython/curtsiesfrontend/manual_readline.py b/bpython/curtsiesfrontend/manual_readline.py index 6f24b539..5cd8be36 100644 --- a/bpython/curtsiesfrontend/manual_readline.py +++ b/bpython/curtsiesfrontend/manual_readline.py @@ -232,7 +232,7 @@ def delete(cursor_offset, line): def cursor_on_closing_char_pair(cursor_offset, line): - closing_char_map = {"(": ")", "{": "}", "[": "]"} + closing_char_map = {"(": ")", "{": "}", "[": "]", "'": "'", '"': '"'} on_closing_char, pair_close = False, False if line is None: return on_closing_char, pair_close diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py index 205d29e5..96aee7a8 100644 --- a/bpython/curtsiesfrontend/repl.py +++ b/bpython/curtsiesfrontend/repl.py @@ -789,9 +789,9 @@ def process_key_event(self, e): self.incr_search_mode = None elif e in ("",): self.add_normal_character(" ") - elif e in ["(", "{", "["]: + elif e in ["(", "{", "[", "'", '"']: self.insert_char_pair(e) - elif e in [")", "}", "]"]: + elif e in [")", "}", "]", "'", '"']: self.insert_char_pair_end(e) else: self.add_normal_character(e) @@ -829,7 +829,7 @@ def insert_char_pair_end(self, e): self.add_normal_character(e) def get_closing_char(self, e): - closing_char_map = {"(": ")", "{": "}", "[": "]"} + closing_char_map = {"(": ")", "{": "}", "[": "]", "'": "'", '"': '"'} return closing_char_map[e] def get_last_word(self): @@ -932,7 +932,11 @@ def only_whitespace_left_of_cursor(): for unused in range(to_add): self.add_normal_character(" ") return - + on_closing_char, _ = cursor_on_closing_char_pair( + self._cursor_offset, self._current_line + ) + if on_closing_char: + self._cursor_offset += 1 # run complete() if we don't already have matches if len(self.matches_iter.matches) == 0: self.list_win_visible = self.complete(tab=True) @@ -941,23 +945,36 @@ def only_whitespace_left_of_cursor(): if self.matches_iter.is_cseq(): cursor_and_line = self.matches_iter.substitute_cseq() self._cursor_offset, self._current_line = cursor_and_line + if self.is_completion_callable(self._current_line): + self._current_line = self.append_closing_bracket( + self._current_line + ) # using _current_line so we don't trigger a completion reset if not self.matches_iter.matches: self.list_win_visible = self.complete() - elif self.matches_iter.matches: self.current_match = ( back and self.matches_iter.previous() or next(self.matches_iter) ) cursor_and_line = self.matches_iter.cur_line() self._cursor_offset, self._current_line = cursor_and_line + if self.is_completion_callable(self._current_line): + self._current_line = self.append_closing_bracket( + self._current_line + ) # using _current_line so we don't trigger a completion reset self.list_win_visible = True - on_closing_char, _ = cursor_on_closing_char_pair( - self._cursor_offset, self._current_line - ) - if on_closing_char: - self._cursor_offset += 1 + + def is_completion_callable(self, completion): + closing_char_map = {"(": ")", "{": "}", "[": "]", "'": "'", '"': '"'} + completion_end = completion[-1] + return completion_end in closing_char_map + + def append_closing_bracket(self, completion): + closing_char_map = {"(": ")", "{": "}", "[": "]", "'": "'", '"': '"'} + if completion[-1] in closing_char_map: + completion = f"{completion}{closing_char_map[completion[-1]]}" + return completion def on_control_d(self): if self.current_line == "": From c11b5fc6a57abd4208a1a0080a81003234b7e228 Mon Sep 17 00:00:00 2001 From: samuelgregorovic Date: Sat, 30 Oct 2021 14:23:41 +0200 Subject: [PATCH 10/31] added cmd argument + update manpage help --- bpython/args.py | 5 +++++ doc/sphinx/source/man-bpython.rst | 1 + 2 files changed, 6 insertions(+) diff --git a/bpython/args.py b/bpython/args.py index 79ddcc67..0fd0e7dd 100644 --- a/bpython/args.py +++ b/bpython/args.py @@ -144,6 +144,11 @@ def callback(group): "-L", help=_("Log output file"), ) + parser.add_argument( + "--brackets-completion", + "-B", + help=_("Enable brackets auto-completion"), + ) if extras is not None: extras_group = parser.add_argument_group(extras[0], extras[1]) diff --git a/doc/sphinx/source/man-bpython.rst b/doc/sphinx/source/man-bpython.rst index fe37a25f..61ea00a4 100644 --- a/doc/sphinx/source/man-bpython.rst +++ b/doc/sphinx/source/man-bpython.rst @@ -59,6 +59,7 @@ The following options are supported by all frontends: -V, --version Print :program:`bpython`'s version and exit. -l , --log-level= Set logging level -L , --log-output= Set log output file +-B, --brackets-completion Enable brackets auto-completion In addition to the above options, :program:`bpython` also supports the following options: From a55830cf3730514a59e49dfca67a28911059a464 Mon Sep 17 00:00:00 2001 From: samuelgregorovic Date: Sat, 30 Oct 2021 15:09:45 +0200 Subject: [PATCH 11/31] added config option + updated sample config --- bpython/config.py | 4 ++++ bpython/sample-config | 1 + 2 files changed, 5 insertions(+) diff --git a/bpython/config.py b/bpython/config.py index 48686610..e19f9ee9 100644 --- a/bpython/config.py +++ b/bpython/config.py @@ -152,6 +152,7 @@ class Config: "syntax": True, "tab_length": 4, "unicode_box": True, + "brackets_completion": False, }, "keyboard": { "backspace": "C-h", @@ -358,6 +359,9 @@ def get_key_no_doublebind(command: str) -> str: if self.unicode_box and supports_box_chars() else ("|", "|", "-", "-", "+", "+", "+", "+") ) + self.brackets_completion = config.getboolean( + "general", "brackets_completion" + ) def load_theme( diff --git a/bpython/sample-config b/bpython/sample-config index 287e8a2f..c07a7e11 100644 --- a/bpython/sample-config +++ b/bpython/sample-config @@ -61,6 +61,7 @@ # Enable autoreload feature by default (default: False). # default_autoreload = False +# brackets_completion = True [keyboard] From 49c98df485c982122ab5dd175e4886c5461da1ad Mon Sep 17 00:00:00 2001 From: samuelgregorovic Date: Sat, 30 Oct 2021 15:37:29 +0200 Subject: [PATCH 12/31] obey config option + docstrings --- bpython/curtsiesfrontend/manual_readline.py | 6 + bpython/curtsiesfrontend/repl.py | 66 +++--- test.txt | 250 -------------------- 3 files changed, 38 insertions(+), 284 deletions(-) delete mode 100644 test.txt diff --git a/bpython/curtsiesfrontend/manual_readline.py b/bpython/curtsiesfrontend/manual_readline.py index 5cd8be36..b028cca5 100644 --- a/bpython/curtsiesfrontend/manual_readline.py +++ b/bpython/curtsiesfrontend/manual_readline.py @@ -232,6 +232,9 @@ def delete(cursor_offset, line): def cursor_on_closing_char_pair(cursor_offset, line): + """Checks if cursor sits on closing character of a pair + and whether its pair character is directly behind it + """ closing_char_map = {"(": ")", "{": "}", "[": "]", "'": "'", '"': '"'} on_closing_char, pair_close = False, False if line is None: @@ -260,6 +263,9 @@ def backspace(cursor_offset, line): cursor_offset - to_delete, line[: cursor_offset - to_delete] + line[cursor_offset:], ) + # removes opening bracket along with closing bracket + # if there is nothing between them + # TODO: could not get config value here, works even without -B option on_closing_char, pair_close = cursor_on_closing_char_pair( cursor_offset, line ) diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py index 96aee7a8..ae12991f 100644 --- a/bpython/curtsiesfrontend/repl.py +++ b/bpython/curtsiesfrontend/repl.py @@ -306,6 +306,8 @@ class BaseRepl(Repl): Subclasses are responsible for implementing several methods. """ + PAIR_CHAR_MAP = {"(": ")", "{": "}", "[": "]", "'": "'", '"': '"'} + def __init__( self, config, @@ -789,49 +791,45 @@ def process_key_event(self, e): self.incr_search_mode = None elif e in ("",): self.add_normal_character(" ") - elif e in ["(", "{", "[", "'", '"']: - self.insert_char_pair(e) - elif e in [")", "}", "]", "'", '"']: + elif e in self.__class__.PAIR_CHAR_MAP.keys(): + self.insert_char_pair_start(e) + elif e in self.__class__.PAIR_CHAR_MAP.values(): self.insert_char_pair_end(e) else: self.add_normal_character(e) - def insert_char_pair(self, e): - closing_char = self.get_closing_char(e) - self._set_current_line( - ( - self.current_line[: self.cursor_offset] - + e - + self.current_line[self.cursor_offset :] - ), - update_completion=False, - reset_rl_history=False, - clear_special_mode=False, - ) - self.cursor_offset += 1 + def insert_char_pair_start(self, e): + """Accepts character which is a part of CHARACTER_PAIRS + like brackets and quotes, and appends it to the line with + an appropriate pair end - self._set_current_line( - ( - self.current_line[: self.cursor_offset] - + closing_char - + self.current_line[self.cursor_offset :] - ), - update_completion=False, - reset_rl_history=False, - clear_special_mode=False, - ) + e.x. if you type "(" (lparen) , this will insert "()" + into the line + """ + self.add_normal_character(e) + if self.config.brackets_completion: + closing_char = self.__class__.PAIR_CHAR_MAP[e] + self.add_normal_character(closing_char) + self.cursor_offset -= 1 def insert_char_pair_end(self, e): - if self.cursor_offset < len(self.current_line): - if self.current_line[self.cursor_offset] == e: - self.cursor_offset += 1 - return + """Accepts character which is a part of CHARACTER_PAIRS + like brackets and quotes, and checks whether it should be + inserted to the line or overwritten + + e.x. if you type ")" (rparen) , and your cursor is directly + above another ")" (rparen) in the cmd, this will just skip + it and move the cursor. + If there is no same character underneath the cursor, the + character will be printed/appended to the line + """ + if self.config.brackets_completion: + if self.cursor_offset < len(self.current_line): + if self.current_line[self.cursor_offset] == e: + self.cursor_offset += 1 + return self.add_normal_character(e) - def get_closing_char(self, e): - closing_char_map = {"(": ")", "{": "}", "[": "]", "'": "'", '"': '"'} - return closing_char_map[e] - def get_last_word(self): previous_word = _last_word(self.rl_history.entry) diff --git a/test.txt b/test.txt deleted file mode 100644 index e2e2e9c2..00000000 --- a/test.txt +++ /dev/null @@ -1,250 +0,0 @@ -2021-10-30 12:46:27,154: bpython.args: INFO: Starting bpython 0.22.dev114 -2021-10-30 12:46:27,154: bpython.args: INFO: Python /home/administrator/github/personal/bpython-dev/bin/python3: sys.version_info(major=3, minor=8, micro=10, releaselevel='final', serial=0) -2021-10-30 12:46:27,155: bpython.args: INFO: curtsies: 0.3.7 -2021-10-30 12:46:27,155: bpython.args: INFO: cwcwidth: 0.1.4 -2021-10-30 12:46:27,155: bpython.args: INFO: greenlet: 1.1.2 -2021-10-30 12:46:27,155: bpython.args: INFO: pygments: 2.10.0 -2021-10-30 12:46:27,155: bpython.args: INFO: requests: 2.26.0 -2021-10-30 12:46:27,155: bpython.args: INFO: environment: -LANG: en_US.UTF-8 -LC_ADDRESS: sk_SK.UTF-8 -LC_IDENTIFICATION: sk_SK.UTF-8 -LC_MEASUREMENT: sk_SK.UTF-8 -LC_MONETARY: sk_SK.UTF-8 -LC_NAME: sk_SK.UTF-8 -LC_NUMERIC: sk_SK.UTF-8 -LC_PAPER: sk_SK.UTF-8 -LC_TELEPHONE: sk_SK.UTF-8 -LC_TIME: sk_SK.UTF-8 -TERM: xterm-256color -2021-10-30 12:46:27,156: curtsies.window: DEBUG: -------initializing Window object ------ -2021-10-30 12:46:27,157: bpython.curtsiesfrontend.repl: DEBUG: starting init -2021-10-30 12:46:27,157: bpython.curtsiesfrontend.repl: DEBUG: starting parent init -2021-10-30 12:46:27,168: curtsies.window: DEBUG: initial top_usable_row: 71 -2021-10-30 12:46:27,168: curtsies.window: DEBUG: running BaseWindow.__enter__ -2021-10-30 12:46:27,170: bpython.curtsiesfrontend.repl: DEBUG: processing event -2021-10-30 12:46:27,218: bpython.curtsiesfrontend.repl: DEBUG: Display line '' -> -2021-10-30 12:46:27,218: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ') -2021-10-30 12:46:27,218: bpython.curtsiesfrontend.repl: DEBUG: no history issues. start 0 -2021-10-30 12:46:27,218: curtsies.formatstringarray: DEBUG: slice: (slice(None, 0, None), slice(None, 140, None)) -2021-10-30 12:46:27,218: curtsies.formatstringarray: DEBUG: num columns: 140 -2021-10-30 12:46:27,218: curtsies.formatstringarray: DEBUG: colslice: slice(None, 140, None) -2021-10-30 12:46:27,219: bpython.curtsiesfrontend.repl: DEBUG: ---current line row slice 0, 1 -2021-10-30 12:46:27,219: bpython.curtsiesfrontend.repl: DEBUG: ---current line col slice 0, 140 -2021-10-30 12:46:27,219: curtsies.formatstringarray: DEBUG: slice: (slice(0, 1, None), slice(0, 140, None)) -2021-10-30 12:46:27,219: curtsies.formatstringarray: DEBUG: num columns: 140 -2021-10-30 12:46:27,219: curtsies.formatstringarray: DEBUG: colslice: slice(0, 140, None) -2021-10-30 12:46:27,219: bpython.curtsiesfrontend.repl: DEBUG: Display line '' -> -2021-10-30 12:46:27,219: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ') -2021-10-30 12:46:27,219: bpython.curtsiesfrontend.repl: DEBUG: Display line '' -> -2021-10-30 12:46:27,220: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ') -2021-10-30 12:46:27,220: bpython.curtsiesfrontend.repl: DEBUG: Display line '' -> -2021-10-30 12:46:27,220: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ') -2021-10-30 12:46:27,220: bpython.curtsiesfrontend.repl: DEBUG: Display line '' -> -2021-10-30 12:46:27,220: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ') -2021-10-30 12:46:27,220: bpython.curtsiesfrontend.repl: DEBUG: about to exit: False -2021-10-30 12:46:27,220: curtsies.formatstringarray: DEBUG: slice: (1, slice(None, None, None)) -2021-10-30 12:46:27,220: curtsies.formatstringarray: DEBUG: num columns: 140 -2021-10-30 12:46:27,220: curtsies.formatstringarray: DEBUG: colslice: slice(None, None, None) -2021-10-30 12:46:27,221: bpython.curtsiesfrontend.repl: DEBUG: returning arr of size (2, 140) -2021-10-30 12:46:27,221: bpython.curtsiesfrontend.repl: DEBUG: cursor pos: (0, 4) -2021-10-30 12:46:27,221: curtsies.window: DEBUG: sending scroll down message w/ cursor on bottom line -2021-10-30 12:46:27,221: curtsies.window: DEBUG: new top_usable_row: 70 -2021-10-30 12:46:27,221: curtsies.window: DEBUG: lines in last lines by row: dict_keys([]) -2021-10-30 12:46:27,221: curtsies.window: DEBUG: lines in current lines by row: dict_keys([70, 71]) -2021-10-30 12:46:28,486: bpython.curtsiesfrontend.repl: DEBUG: processing event '(' -2021-10-30 12:46:28,492: bpython.curtsiesfrontend.repl: DEBUG: Display line '()' -> on_magenta(bold(red('(')))+bold(yellow(')')) -2021-10-30 12:46:28,493: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ')+on_magenta(bold(red('(')))+bold(yellow(')')) -2021-10-30 12:46:28,493: bpython.curtsiesfrontend.repl: DEBUG: no history issues. start 0 -2021-10-30 12:46:28,493: curtsies.formatstringarray: DEBUG: slice: (slice(None, 0, None), slice(None, 140, None)) -2021-10-30 12:46:28,493: curtsies.formatstringarray: DEBUG: num columns: 140 -2021-10-30 12:46:28,493: curtsies.formatstringarray: DEBUG: colslice: slice(None, 140, None) -2021-10-30 12:46:28,493: bpython.curtsiesfrontend.repl: DEBUG: ---current line row slice 0, 1 -2021-10-30 12:46:28,493: bpython.curtsiesfrontend.repl: DEBUG: ---current line col slice 0, 140 -2021-10-30 12:46:28,493: curtsies.formatstringarray: DEBUG: slice: (slice(0, 1, None), slice(0, 140, None)) -2021-10-30 12:46:28,493: curtsies.formatstringarray: DEBUG: num columns: 140 -2021-10-30 12:46:28,493: curtsies.formatstringarray: DEBUG: colslice: slice(0, 140, None) -2021-10-30 12:46:28,494: bpython.curtsiesfrontend.repl: DEBUG: Display line '()' -> on_magenta(bold(red('(')))+bold(yellow(')')) -2021-10-30 12:46:28,494: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ')+on_magenta(bold(red('(')))+bold(yellow(')')) -2021-10-30 12:46:28,494: bpython.curtsiesfrontend.repl: DEBUG: Display line '()' -> on_magenta(bold(red('(')))+bold(yellow(')')) -2021-10-30 12:46:28,494: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ')+on_magenta(bold(red('(')))+bold(yellow(')')) -2021-10-30 12:46:28,495: bpython.curtsiesfrontend.repl: DEBUG: Display line '()' -> on_magenta(bold(red('(')))+bold(yellow(')')) -2021-10-30 12:46:28,495: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ')+on_magenta(bold(red('(')))+bold(yellow(')')) -2021-10-30 12:46:28,495: bpython.curtsiesfrontend.repl: DEBUG: Display line '()' -> on_magenta(bold(red('(')))+bold(yellow(')')) -2021-10-30 12:46:28,495: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ')+on_magenta(bold(red('(')))+bold(yellow(')')) -2021-10-30 12:46:28,495: bpython.curtsiesfrontend.repl: DEBUG: about to exit: False -2021-10-30 12:46:28,495: curtsies.formatstringarray: DEBUG: slice: (1, slice(None, None, None)) -2021-10-30 12:46:28,495: curtsies.formatstringarray: DEBUG: num columns: 140 -2021-10-30 12:46:28,495: curtsies.formatstringarray: DEBUG: colslice: slice(None, None, None) -2021-10-30 12:46:28,496: bpython.curtsiesfrontend.repl: DEBUG: returning arr of size (2, 140) -2021-10-30 12:46:28,496: bpython.curtsiesfrontend.repl: DEBUG: cursor pos: (0, 5) -2021-10-30 12:46:28,496: curtsies.window: DEBUG: lines in last lines by row: dict_keys([70, 71]) -2021-10-30 12:46:28,496: curtsies.window: DEBUG: lines in current lines by row: dict_keys([70, 71]) -2021-10-30 12:46:29,836: bpython.curtsiesfrontend.repl: DEBUG: processing event '(' -2021-10-30 12:46:29,839: bpython.curtsiesfrontend.repl: DEBUG: Display line '(())' -> on_magenta(bold(red('(')))+yellow('(')+yellow(')')+bold(yellow(')')) -2021-10-30 12:46:29,841: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ')+on_magenta(bold(red('(')))+yellow('(')+yellow(')')+bold(yellow(')')) -2021-10-30 12:46:29,843: bpython.curtsiesfrontend.repl: DEBUG: no history issues. start 0 -2021-10-30 12:46:29,843: curtsies.formatstringarray: DEBUG: slice: (slice(None, 0, None), slice(None, 140, None)) -2021-10-30 12:46:29,843: curtsies.formatstringarray: DEBUG: num columns: 140 -2021-10-30 12:46:29,843: curtsies.formatstringarray: DEBUG: colslice: slice(None, 140, None) -2021-10-30 12:46:29,844: bpython.curtsiesfrontend.repl: DEBUG: ---current line row slice 0, 1 -2021-10-30 12:46:29,844: bpython.curtsiesfrontend.repl: DEBUG: ---current line col slice 0, 140 -2021-10-30 12:46:29,844: curtsies.formatstringarray: DEBUG: slice: (slice(0, 1, None), slice(0, 140, None)) -2021-10-30 12:46:29,844: curtsies.formatstringarray: DEBUG: num columns: 140 -2021-10-30 12:46:29,845: curtsies.formatstringarray: DEBUG: colslice: slice(0, 140, None) -2021-10-30 12:46:29,846: bpython.curtsiesfrontend.repl: DEBUG: Display line '(())' -> on_magenta(bold(red('(')))+yellow('(')+yellow(')')+bold(yellow(')')) -2021-10-30 12:46:29,846: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ')+on_magenta(bold(red('(')))+yellow('(')+yellow(')')+bold(yellow(')')) -2021-10-30 12:46:29,848: bpython.curtsiesfrontend.repl: DEBUG: Display line '(())' -> on_magenta(bold(red('(')))+yellow('(')+yellow(')')+bold(yellow(')')) -2021-10-30 12:46:29,849: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ')+on_magenta(bold(red('(')))+yellow('(')+yellow(')')+bold(yellow(')')) -2021-10-30 12:46:29,850: bpython.curtsiesfrontend.repl: DEBUG: Display line '(())' -> on_magenta(bold(red('(')))+yellow('(')+yellow(')')+bold(yellow(')')) -2021-10-30 12:46:29,850: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ')+on_magenta(bold(red('(')))+yellow('(')+yellow(')')+bold(yellow(')')) -2021-10-30 12:46:29,851: bpython.curtsiesfrontend.repl: DEBUG: Display line '(())' -> on_magenta(bold(red('(')))+yellow('(')+yellow(')')+bold(yellow(')')) -2021-10-30 12:46:29,852: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ')+on_magenta(bold(red('(')))+yellow('(')+yellow(')')+bold(yellow(')')) -2021-10-30 12:46:29,852: bpython.curtsiesfrontend.repl: DEBUG: about to exit: False -2021-10-30 12:46:29,853: curtsies.formatstringarray: DEBUG: slice: (1, slice(None, None, None)) -2021-10-30 12:46:29,853: curtsies.formatstringarray: DEBUG: num columns: 140 -2021-10-30 12:46:29,853: curtsies.formatstringarray: DEBUG: colslice: slice(None, None, None) -2021-10-30 12:46:29,854: bpython.curtsiesfrontend.repl: DEBUG: returning arr of size (2, 140) -2021-10-30 12:46:29,854: bpython.curtsiesfrontend.repl: DEBUG: cursor pos: (0, 7) -2021-10-30 12:46:29,855: curtsies.window: DEBUG: lines in last lines by row: dict_keys([70, 71]) -2021-10-30 12:46:29,855: curtsies.window: DEBUG: lines in current lines by row: dict_keys([70, 71]) -2021-10-30 12:46:30,159: curtsies.input: DEBUG: popping an event! (1635590790.1589813, ) [] -2021-10-30 12:46:30,160: bpython.curtsiesfrontend.repl: DEBUG: processing event -2021-10-30 12:46:30,162: bpython.curtsiesfrontend.repl: DEBUG: Display line '(())' -> on_magenta(bold(red('(')))+yellow('(')+yellow(')')+bold(yellow(')')) -2021-10-30 12:46:30,162: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ')+on_magenta(bold(red('(')))+yellow('(')+yellow(')')+bold(yellow(')')) -2021-10-30 12:46:30,163: bpython.curtsiesfrontend.repl: DEBUG: no history issues. start 0 -2021-10-30 12:46:30,164: curtsies.formatstringarray: DEBUG: slice: (slice(None, 0, None), slice(None, 140, None)) -2021-10-30 12:46:30,164: curtsies.formatstringarray: DEBUG: num columns: 140 -2021-10-30 12:46:30,164: curtsies.formatstringarray: DEBUG: colslice: slice(None, 140, None) -2021-10-30 12:46:30,164: bpython.curtsiesfrontend.repl: DEBUG: ---current line row slice 0, 1 -2021-10-30 12:46:30,165: bpython.curtsiesfrontend.repl: DEBUG: ---current line col slice 0, 140 -2021-10-30 12:46:30,165: curtsies.formatstringarray: DEBUG: slice: (slice(0, 1, None), slice(0, 140, None)) -2021-10-30 12:46:30,165: curtsies.formatstringarray: DEBUG: num columns: 140 -2021-10-30 12:46:30,165: curtsies.formatstringarray: DEBUG: colslice: slice(0, 140, None) -2021-10-30 12:46:30,167: bpython.curtsiesfrontend.repl: DEBUG: Display line '(())' -> on_magenta(bold(red('(')))+yellow('(')+yellow(')')+bold(yellow(')')) -2021-10-30 12:46:30,167: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ')+on_magenta(bold(red('(')))+yellow('(')+yellow(')')+bold(yellow(')')) -2021-10-30 12:46:30,169: bpython.curtsiesfrontend.repl: DEBUG: Display line '(())' -> on_magenta(bold(red('(')))+yellow('(')+yellow(')')+bold(yellow(')')) -2021-10-30 12:46:30,170: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ')+on_magenta(bold(red('(')))+yellow('(')+yellow(')')+bold(yellow(')')) -2021-10-30 12:46:30,171: bpython.curtsiesfrontend.repl: DEBUG: Display line '(())' -> on_magenta(bold(red('(')))+yellow('(')+yellow(')')+bold(yellow(')')) -2021-10-30 12:46:30,171: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ')+on_magenta(bold(red('(')))+yellow('(')+yellow(')')+bold(yellow(')')) -2021-10-30 12:46:30,172: bpython.curtsiesfrontend.repl: DEBUG: Display line '(())' -> on_magenta(bold(red('(')))+yellow('(')+yellow(')')+bold(yellow(')')) -2021-10-30 12:46:30,173: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ')+on_magenta(bold(red('(')))+yellow('(')+yellow(')')+bold(yellow(')')) -2021-10-30 12:46:30,173: bpython.curtsiesfrontend.repl: DEBUG: about to exit: False -2021-10-30 12:46:30,174: bpython.curtsiesfrontend.repl: DEBUG: returning arr of size (1, 140) -2021-10-30 12:46:30,174: bpython.curtsiesfrontend.repl: DEBUG: cursor pos: (0, 7) -2021-10-30 12:46:30,174: curtsies.window: DEBUG: lines in last lines by row: dict_keys([70, 71]) -2021-10-30 12:46:30,175: curtsies.window: DEBUG: lines in current lines by row: dict_keys([70, 71]) -2021-10-30 12:46:31,990: bpython.curtsiesfrontend.repl: DEBUG: processing event '' -2021-10-30 12:46:31,992: bpython.curtsiesfrontend.repl: DEBUG: Display line '(()' -> yellow('(')+on_magenta(bold(red('(')))+on_magenta(bold(red(')'))) -2021-10-30 12:46:31,993: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ')+yellow('(')+on_magenta(bold(red('(')))+on_magenta(bold(red(')'))) -2021-10-30 12:46:31,994: bpython.curtsiesfrontend.repl: DEBUG: no history issues. start 0 -2021-10-30 12:46:31,994: curtsies.formatstringarray: DEBUG: slice: (slice(None, 0, None), slice(None, 140, None)) -2021-10-30 12:46:31,994: curtsies.formatstringarray: DEBUG: num columns: 140 -2021-10-30 12:46:31,994: curtsies.formatstringarray: DEBUG: colslice: slice(None, 140, None) -2021-10-30 12:46:31,994: bpython.curtsiesfrontend.repl: DEBUG: ---current line row slice 0, 1 -2021-10-30 12:46:31,994: bpython.curtsiesfrontend.repl: DEBUG: ---current line col slice 0, 140 -2021-10-30 12:46:31,994: curtsies.formatstringarray: DEBUG: slice: (slice(0, 1, None), slice(0, 140, None)) -2021-10-30 12:46:31,994: curtsies.formatstringarray: DEBUG: num columns: 140 -2021-10-30 12:46:31,994: curtsies.formatstringarray: DEBUG: colslice: slice(0, 140, None) -2021-10-30 12:46:31,995: bpython.curtsiesfrontend.repl: DEBUG: Display line '(()' -> yellow('(')+on_magenta(bold(red('(')))+on_magenta(bold(red(')'))) -2021-10-30 12:46:31,995: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ')+yellow('(')+on_magenta(bold(red('(')))+on_magenta(bold(red(')'))) -2021-10-30 12:46:31,996: bpython.curtsiesfrontend.repl: DEBUG: Display line '(()' -> yellow('(')+on_magenta(bold(red('(')))+on_magenta(bold(red(')'))) -2021-10-30 12:46:31,996: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ')+yellow('(')+on_magenta(bold(red('(')))+on_magenta(bold(red(')'))) -2021-10-30 12:46:31,996: bpython.curtsiesfrontend.repl: DEBUG: Display line '(()' -> yellow('(')+on_magenta(bold(red('(')))+on_magenta(bold(red(')'))) -2021-10-30 12:46:31,996: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ')+yellow('(')+on_magenta(bold(red('(')))+on_magenta(bold(red(')'))) -2021-10-30 12:46:31,997: bpython.curtsiesfrontend.repl: DEBUG: Display line '(()' -> yellow('(')+on_magenta(bold(red('(')))+on_magenta(bold(red(')'))) -2021-10-30 12:46:31,997: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ')+yellow('(')+on_magenta(bold(red('(')))+on_magenta(bold(red(')'))) -2021-10-30 12:46:31,997: bpython.curtsiesfrontend.repl: DEBUG: about to exit: False -2021-10-30 12:46:31,997: bpython.curtsiesfrontend.repl: DEBUG: returning arr of size (1, 140) -2021-10-30 12:46:31,997: bpython.curtsiesfrontend.repl: DEBUG: cursor pos: (0, 7) -2021-10-30 12:46:32,613: curtsies.window: DEBUG: lines in last lines by row: dict_keys([70, 71]) -2021-10-30 12:46:32,613: curtsies.window: DEBUG: lines in current lines by row: dict_keys([70, 71]) -2021-10-30 12:46:32,614: bpython.curtsiesfrontend.repl: DEBUG: processing event -2021-10-30 12:46:32,614: bpython.curtsiesfrontend.repl: DEBUG: received sigint event -2021-10-30 12:46:32,615: bpython.curtsiesfrontend.repl: DEBUG: Display line '(()' -> yellow('(')+yellow('(')+yellow(')') -2021-10-30 12:46:32,616: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ')+yellow('(')+yellow('(')+yellow(')') -2021-10-30 12:46:32,618: bpython.curtsiesfrontend.repl: DEBUG: Display line '' -> -2021-10-30 12:46:32,618: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ') -2021-10-30 12:46:32,619: bpython.curtsiesfrontend.repl: DEBUG: no history issues. start 2 -2021-10-30 12:46:32,619: curtsies.formatstringarray: DEBUG: slice: (slice(None, 2, None), slice(None, 140, None)) -2021-10-30 12:46:32,620: curtsies.formatstringarray: DEBUG: num columns: 140 -2021-10-30 12:46:32,620: curtsies.formatstringarray: DEBUG: colslice: slice(None, 140, None) -2021-10-30 12:46:32,620: bpython.curtsiesfrontend.repl: DEBUG: ---current line row slice 2, 3 -2021-10-30 12:46:32,620: bpython.curtsiesfrontend.repl: DEBUG: ---current line col slice 0, 140 -2021-10-30 12:46:32,620: curtsies.formatstringarray: DEBUG: slice: (slice(2, 3, None), slice(0, 140, None)) -2021-10-30 12:46:32,621: curtsies.formatstringarray: DEBUG: num columns: 140 -2021-10-30 12:46:32,621: curtsies.formatstringarray: DEBUG: colslice: slice(0, 140, None) -2021-10-30 12:46:32,621: bpython.curtsiesfrontend.repl: DEBUG: Display line '' -> -2021-10-30 12:46:32,621: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ') -2021-10-30 12:46:32,621: bpython.curtsiesfrontend.repl: DEBUG: Display line '' -> -2021-10-30 12:46:32,621: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ') -2021-10-30 12:46:32,622: bpython.curtsiesfrontend.repl: DEBUG: Display line '' -> -2021-10-30 12:46:32,622: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ') -2021-10-30 12:46:32,622: bpython.curtsiesfrontend.repl: DEBUG: Display line '' -> -2021-10-30 12:46:32,622: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ') -2021-10-30 12:46:32,622: bpython.curtsiesfrontend.repl: DEBUG: about to exit: False -2021-10-30 12:46:32,622: bpython.curtsiesfrontend.repl: DEBUG: returning arr of size (3, 140) -2021-10-30 12:46:32,622: bpython.curtsiesfrontend.repl: DEBUG: cursor pos: (2, 4) -2021-10-30 12:46:32,622: curtsies.window: DEBUG: sending scroll down message w/ cursor on bottom line -2021-10-30 12:46:32,622: curtsies.window: DEBUG: new top_usable_row: 69 -2021-10-30 12:46:32,623: curtsies.window: DEBUG: lines in last lines by row: dict_keys([70, 71]) -2021-10-30 12:46:32,623: curtsies.window: DEBUG: lines in current lines by row: dict_keys([69, 70, 71]) -2021-10-30 12:46:33,256: bpython.curtsiesfrontend.repl: DEBUG: processing event -2021-10-30 12:46:33,256: bpython.curtsiesfrontend.repl: DEBUG: received sigint event -2021-10-30 12:46:33,256: bpython.curtsiesfrontend.repl: DEBUG: Display line '' -> -2021-10-30 12:46:33,256: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ') -2021-10-30 12:46:33,257: bpython.curtsiesfrontend.repl: DEBUG: Display line '' -> -2021-10-30 12:46:33,257: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ') -2021-10-30 12:46:33,257: bpython.curtsiesfrontend.repl: DEBUG: no history issues. start 4 -2021-10-30 12:46:33,257: curtsies.formatstringarray: DEBUG: slice: (slice(None, 4, None), slice(None, 140, None)) -2021-10-30 12:46:33,257: curtsies.formatstringarray: DEBUG: num columns: 140 -2021-10-30 12:46:33,258: curtsies.formatstringarray: DEBUG: colslice: slice(None, 140, None) -2021-10-30 12:46:33,258: bpython.curtsiesfrontend.repl: DEBUG: ---current line row slice 4, 5 -2021-10-30 12:46:33,258: bpython.curtsiesfrontend.repl: DEBUG: ---current line col slice 0, 140 -2021-10-30 12:46:33,258: curtsies.formatstringarray: DEBUG: slice: (slice(4, 5, None), slice(0, 140, None)) -2021-10-30 12:46:33,258: curtsies.formatstringarray: DEBUG: num columns: 140 -2021-10-30 12:46:33,258: curtsies.formatstringarray: DEBUG: colslice: slice(0, 140, None) -2021-10-30 12:46:33,258: bpython.curtsiesfrontend.repl: DEBUG: Display line '' -> -2021-10-30 12:46:33,258: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ') -2021-10-30 12:46:33,259: bpython.curtsiesfrontend.repl: DEBUG: Display line '' -> -2021-10-30 12:46:33,259: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ') -2021-10-30 12:46:33,259: bpython.curtsiesfrontend.repl: DEBUG: Display line '' -> -2021-10-30 12:46:33,259: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ') -2021-10-30 12:46:33,259: bpython.curtsiesfrontend.repl: DEBUG: Display line '' -> -2021-10-30 12:46:33,259: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ') -2021-10-30 12:46:33,259: bpython.curtsiesfrontend.repl: DEBUG: about to exit: False -2021-10-30 12:46:33,259: bpython.curtsiesfrontend.repl: DEBUG: returning arr of size (5, 140) -2021-10-30 12:46:33,259: bpython.curtsiesfrontend.repl: DEBUG: cursor pos: (4, 4) -2021-10-30 12:46:33,260: curtsies.window: DEBUG: sending scroll down message w/ cursor on bottom line -2021-10-30 12:46:33,260: curtsies.window: DEBUG: new top_usable_row: 68 -2021-10-30 12:46:33,260: curtsies.window: DEBUG: sending scroll down message w/ cursor on bottom line -2021-10-30 12:46:33,260: curtsies.window: DEBUG: new top_usable_row: 67 -2021-10-30 12:46:33,260: curtsies.window: DEBUG: lines in last lines by row: dict_keys([69, 70, 71]) -2021-10-30 12:46:33,260: curtsies.window: DEBUG: lines in current lines by row: dict_keys([67, 68, 69, 70, 71]) -2021-10-30 12:46:33,622: bpython.curtsiesfrontend.repl: DEBUG: processing event '' -2021-10-30 12:46:33,622: bpython.curtsiesfrontend.repl: DEBUG: unhighlighting paren for exit -2021-10-30 12:46:33,624: bpython.curtsiesfrontend.repl: DEBUG: Display line '' -> -2021-10-30 12:46:33,624: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ') -2021-10-30 12:46:33,625: bpython.curtsiesfrontend.repl: DEBUG: no history issues. start 4 -2021-10-30 12:46:33,626: curtsies.formatstringarray: DEBUG: slice: (slice(None, 4, None), slice(None, 140, None)) -2021-10-30 12:46:33,626: curtsies.formatstringarray: DEBUG: num columns: 140 -2021-10-30 12:46:33,627: curtsies.formatstringarray: DEBUG: colslice: slice(None, 140, None) -2021-10-30 12:46:33,627: bpython.curtsiesfrontend.repl: DEBUG: ---current line row slice 4, 5 -2021-10-30 12:46:33,627: bpython.curtsiesfrontend.repl: DEBUG: ---current line col slice 0, 140 -2021-10-30 12:46:33,627: curtsies.formatstringarray: DEBUG: slice: (slice(4, 5, None), slice(0, 140, None)) -2021-10-30 12:46:33,627: curtsies.formatstringarray: DEBUG: num columns: 140 -2021-10-30 12:46:33,627: curtsies.formatstringarray: DEBUG: colslice: slice(0, 140, None) -2021-10-30 12:46:33,627: bpython.curtsiesfrontend.repl: DEBUG: Display line '' -> -2021-10-30 12:46:33,628: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ') -2021-10-30 12:46:33,628: bpython.curtsiesfrontend.repl: DEBUG: Display line '' -> -2021-10-30 12:46:33,628: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ') -2021-10-30 12:46:33,628: bpython.curtsiesfrontend.repl: DEBUG: Display line '' -> -2021-10-30 12:46:33,628: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ') -2021-10-30 12:46:33,628: bpython.curtsiesfrontend.repl: DEBUG: Display line '' -> -2021-10-30 12:46:33,628: bpython.curtsiesfrontend.repl: DEBUG: current cursor line: ''+cyan('>>> ') -2021-10-30 12:46:33,629: bpython.curtsiesfrontend.repl: DEBUG: about to exit: True -2021-10-30 12:46:33,629: bpython.curtsiesfrontend.repl: DEBUG: returning arr of size (5, 140) -2021-10-30 12:46:33,629: bpython.curtsiesfrontend.repl: DEBUG: cursor pos: (4, 4) -2021-10-30 12:46:33,629: curtsies.window: DEBUG: lines in last lines by row: dict_keys([67, 68, 69, 70, 71]) -2021-10-30 12:46:33,629: curtsies.window: DEBUG: lines in current lines by row: dict_keys([67, 68, 69, 70, 71]) -2021-10-30 12:46:33,629: curtsies.window: DEBUG: running BaseWindow.__exit__ From aa321b1dcde313a48ba314c8fe0af7bf47e0cd4a Mon Sep 17 00:00:00 2001 From: samuelgregorovic Date: Sat, 30 Oct 2021 15:44:39 +0200 Subject: [PATCH 13/31] update and document on_tab method --- bpython/curtsiesfrontend/repl.py | 39 +++++++++++++++++++------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py index ae12991f..933e5d16 100644 --- a/bpython/curtsiesfrontend/repl.py +++ b/bpython/curtsiesfrontend/repl.py @@ -799,7 +799,7 @@ def process_key_event(self, e): self.add_normal_character(e) def insert_char_pair_start(self, e): - """Accepts character which is a part of CHARACTER_PAIRS + """Accepts character which is a part of PAIR_CHAR_MAP like brackets and quotes, and appends it to the line with an appropriate pair end @@ -813,7 +813,7 @@ def insert_char_pair_start(self, e): self.cursor_offset -= 1 def insert_char_pair_end(self, e): - """Accepts character which is a part of CHARACTER_PAIRS + """Accepts character which is a part of PAIR_CHAR_MAP like brackets and quotes, and checks whether it should be inserted to the line or overwritten @@ -943,10 +943,12 @@ def only_whitespace_left_of_cursor(): if self.matches_iter.is_cseq(): cursor_and_line = self.matches_iter.substitute_cseq() self._cursor_offset, self._current_line = cursor_and_line - if self.is_completion_callable(self._current_line): - self._current_line = self.append_closing_bracket( - self._current_line - ) + if self.config.brackets_completion: + # appends closing char pair if completion is a callable + if self.is_completion_callable(self._current_line): + self._current_line = self.append_closing_bracket( + self._current_line + ) # using _current_line so we don't trigger a completion reset if not self.matches_iter.matches: self.list_win_visible = self.complete() @@ -956,22 +958,27 @@ def only_whitespace_left_of_cursor(): ) cursor_and_line = self.matches_iter.cur_line() self._cursor_offset, self._current_line = cursor_and_line - if self.is_completion_callable(self._current_line): - self._current_line = self.append_closing_bracket( - self._current_line - ) + if self.config.brackets_completion: + # appends closing char pair if completion is a callable + if self.is_completion_callable(self._current_line): + self._current_line = self.append_closing_character( + self._current_line + ) # using _current_line so we don't trigger a completion reset self.list_win_visible = True def is_completion_callable(self, completion): - closing_char_map = {"(": ")", "{": "}", "[": "]", "'": "'", '"': '"'} + """Checks whether given completion is callable (e.x. function)""" completion_end = completion[-1] - return completion_end in closing_char_map + return completion_end in self.__class__.PAIR_CHAR_MAP - def append_closing_bracket(self, completion): - closing_char_map = {"(": ")", "{": "}", "[": "]", "'": "'", '"': '"'} - if completion[-1] in closing_char_map: - completion = f"{completion}{closing_char_map[completion[-1]]}" + def append_closing_character(self, completion): + """Appends closing character/bracket to the completion""" + completion_end = completion[-1] + if completion_end in self.__class__.PAIR_CHAR_MAP: + completion = ( + f"{completion}{self.__class__.PAIR_CHAR_MAP[completion_end]}" + ) return completion def on_control_d(self): From 05dc36d8b6182bde93ec38a83ad44b75d0490ba9 Mon Sep 17 00:00:00 2001 From: samuelgregorovic Date: Sat, 30 Oct 2021 15:53:13 +0200 Subject: [PATCH 14/31] added comment --- bpython/curtsiesfrontend/repl.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py index 933e5d16..01c6a1a0 100644 --- a/bpython/curtsiesfrontend/repl.py +++ b/bpython/curtsiesfrontend/repl.py @@ -930,11 +930,15 @@ def only_whitespace_left_of_cursor(): for unused in range(to_add): self.add_normal_character(" ") return - on_closing_char, _ = cursor_on_closing_char_pair( - self._cursor_offset, self._current_line - ) - if on_closing_char: - self._cursor_offset += 1 + # if cursor on closing character from pair, + # moves cursor behind it on tab + # ? should we leave it here as default? + if self.config.brackets_completion: + on_closing_char, _ = cursor_on_closing_char_pair( + self._cursor_offset, self._current_line + ) + if on_closing_char: + self._cursor_offset += 1 # run complete() if we don't already have matches if len(self.matches_iter.matches) == 0: self.list_win_visible = self.complete(tab=True) From dc9d1761b7ba95a007371888da51ca1ea55f709e Mon Sep 17 00:00:00 2001 From: samuelgregorovic Date: Sat, 30 Oct 2021 16:10:29 +0200 Subject: [PATCH 15/31] removed cmd argument --- bpython/args.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/bpython/args.py b/bpython/args.py index 0fd0e7dd..79ddcc67 100644 --- a/bpython/args.py +++ b/bpython/args.py @@ -144,11 +144,6 @@ def callback(group): "-L", help=_("Log output file"), ) - parser.add_argument( - "--brackets-completion", - "-B", - help=_("Enable brackets auto-completion"), - ) if extras is not None: extras_group = parser.add_argument_group(extras[0], extras[1]) From a34140aef2e7a9aa61a0b54921630f9f2df3f750 Mon Sep 17 00:00:00 2001 From: samuelgregorovic Date: Tue, 2 Nov 2021 12:39:51 +0100 Subject: [PATCH 16/31] removed unnecessary __class__ call + fix bad function call --- bpython/curtsiesfrontend/repl.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py index 01c6a1a0..e05c8875 100644 --- a/bpython/curtsiesfrontend/repl.py +++ b/bpython/curtsiesfrontend/repl.py @@ -791,9 +791,9 @@ def process_key_event(self, e): self.incr_search_mode = None elif e in ("",): self.add_normal_character(" ") - elif e in self.__class__.PAIR_CHAR_MAP.keys(): + elif e in self.PAIR_CHAR_MAP.keys(): self.insert_char_pair_start(e) - elif e in self.__class__.PAIR_CHAR_MAP.values(): + elif e in self.PAIR_CHAR_MAP.values(): self.insert_char_pair_end(e) else: self.add_normal_character(e) @@ -808,7 +808,7 @@ def insert_char_pair_start(self, e): """ self.add_normal_character(e) if self.config.brackets_completion: - closing_char = self.__class__.PAIR_CHAR_MAP[e] + closing_char = self.PAIR_CHAR_MAP[e] self.add_normal_character(closing_char) self.cursor_offset -= 1 @@ -950,7 +950,7 @@ def only_whitespace_left_of_cursor(): if self.config.brackets_completion: # appends closing char pair if completion is a callable if self.is_completion_callable(self._current_line): - self._current_line = self.append_closing_bracket( + self._current_line = self.append_closing_character( self._current_line ) # using _current_line so we don't trigger a completion reset @@ -974,15 +974,13 @@ def only_whitespace_left_of_cursor(): def is_completion_callable(self, completion): """Checks whether given completion is callable (e.x. function)""" completion_end = completion[-1] - return completion_end in self.__class__.PAIR_CHAR_MAP + return completion_end in self.PAIR_CHAR_MAP def append_closing_character(self, completion): """Appends closing character/bracket to the completion""" completion_end = completion[-1] - if completion_end in self.__class__.PAIR_CHAR_MAP: - completion = ( - f"{completion}{self.__class__.PAIR_CHAR_MAP[completion_end]}" - ) + if completion_end in self.PAIR_CHAR_MAP: + completion = f"{completion}{self.PAIR_CHAR_MAP[completion_end]}" return completion def on_control_d(self): From 5d302a5ac64ea7366b2a875d5e1349082ed3951a Mon Sep 17 00:00:00 2001 From: samuelgregorovic Date: Tue, 2 Nov 2021 12:40:51 +0100 Subject: [PATCH 17/31] removed unnecessary manpage entry --- doc/sphinx/source/man-bpython.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/sphinx/source/man-bpython.rst b/doc/sphinx/source/man-bpython.rst index 61ea00a4..fe37a25f 100644 --- a/doc/sphinx/source/man-bpython.rst +++ b/doc/sphinx/source/man-bpython.rst @@ -59,7 +59,6 @@ The following options are supported by all frontends: -V, --version Print :program:`bpython`'s version and exit. -l , --log-level= Set logging level -L , --log-output= Set log output file --B, --brackets-completion Enable brackets auto-completion In addition to the above options, :program:`bpython` also supports the following options: From 192663cd7fef193c5d5297a4ba73de2b15d16623 Mon Sep 17 00:00:00 2001 From: samuelgregorovic Date: Tue, 2 Nov 2021 12:56:55 +0100 Subject: [PATCH 18/31] moved CHARACTER_PAIR_MAP to __init__ + 0 index fix --- bpython/curtsiesfrontend/__init__.py | 1 + bpython/curtsiesfrontend/manual_readline.py | 17 ++++++++++------- bpython/curtsiesfrontend/repl.py | 19 +++++++++---------- 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/bpython/curtsiesfrontend/__init__.py b/bpython/curtsiesfrontend/__init__.py index e69de29b..612a8705 100644 --- a/bpython/curtsiesfrontend/__init__.py +++ b/bpython/curtsiesfrontend/__init__.py @@ -0,0 +1 @@ +CHARACTER_PAIR_MAP = {"(": ")", "{": "}", "[": "]", "'": "'", '"': '"'} diff --git a/bpython/curtsiesfrontend/manual_readline.py b/bpython/curtsiesfrontend/manual_readline.py index b028cca5..4c1fadb8 100644 --- a/bpython/curtsiesfrontend/manual_readline.py +++ b/bpython/curtsiesfrontend/manual_readline.py @@ -5,7 +5,7 @@ based on http://www.bigsmoke.us/readline/shortcuts""" from ..lazyre import LazyReCompile - +from . import CHARACTER_PAIR_MAP import inspect INDENT = 4 @@ -235,18 +235,21 @@ def cursor_on_closing_char_pair(cursor_offset, line): """Checks if cursor sits on closing character of a pair and whether its pair character is directly behind it """ - closing_char_map = {"(": ")", "{": "}", "[": "]", "'": "'", '"': '"'} on_closing_char, pair_close = False, False if line is None: return on_closing_char, pair_close if cursor_offset < len(line): cur_char = line[cursor_offset] - prev_char = line[cursor_offset - 1] - if cur_char in closing_char_map.values(): + if cur_char in CHARACTER_PAIR_MAP.values(): on_closing_char = True - if prev_char in closing_char_map: - if closing_char_map[prev_char] == cur_char: - pair_close = True + if cursor_offset > 0: + prev_char = line[cursor_offset - 1] + if ( + on_closing_char + and prev_char in CHARACTER_PAIR_MAP + and CHARACTER_PAIR_MAP[prev_char] == cur_char + ): + pair_close = True return on_closing_char, pair_close diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py index e05c8875..576a6c65 100644 --- a/bpython/curtsiesfrontend/repl.py +++ b/bpython/curtsiesfrontend/repl.py @@ -54,6 +54,7 @@ SourceNotFound, ) from ..translations import _ +from . import CHARACTER_PAIR_MAP logger = logging.getLogger(__name__) @@ -306,8 +307,6 @@ class BaseRepl(Repl): Subclasses are responsible for implementing several methods. """ - PAIR_CHAR_MAP = {"(": ")", "{": "}", "[": "]", "'": "'", '"': '"'} - def __init__( self, config, @@ -791,15 +790,15 @@ def process_key_event(self, e): self.incr_search_mode = None elif e in ("",): self.add_normal_character(" ") - elif e in self.PAIR_CHAR_MAP.keys(): + elif e in CHARACTER_PAIR_MAP.keys(): self.insert_char_pair_start(e) - elif e in self.PAIR_CHAR_MAP.values(): + elif e in CHARACTER_PAIR_MAP.values(): self.insert_char_pair_end(e) else: self.add_normal_character(e) def insert_char_pair_start(self, e): - """Accepts character which is a part of PAIR_CHAR_MAP + """Accepts character which is a part of CHARACTER_PAIR_MAP like brackets and quotes, and appends it to the line with an appropriate pair end @@ -808,12 +807,12 @@ def insert_char_pair_start(self, e): """ self.add_normal_character(e) if self.config.brackets_completion: - closing_char = self.PAIR_CHAR_MAP[e] + closing_char = CHARACTER_PAIR_MAP[e] self.add_normal_character(closing_char) self.cursor_offset -= 1 def insert_char_pair_end(self, e): - """Accepts character which is a part of PAIR_CHAR_MAP + """Accepts character which is a part of CHARACTER_PAIR_MAP like brackets and quotes, and checks whether it should be inserted to the line or overwritten @@ -974,13 +973,13 @@ def only_whitespace_left_of_cursor(): def is_completion_callable(self, completion): """Checks whether given completion is callable (e.x. function)""" completion_end = completion[-1] - return completion_end in self.PAIR_CHAR_MAP + return completion_end in CHARACTER_PAIR_MAP def append_closing_character(self, completion): """Appends closing character/bracket to the completion""" completion_end = completion[-1] - if completion_end in self.PAIR_CHAR_MAP: - completion = f"{completion}{self.PAIR_CHAR_MAP[completion_end]}" + if completion_end in CHARACTER_PAIR_MAP: + completion = f"{completion}{CHARACTER_PAIR_MAP[completion_end]}" return completion def on_control_d(self): From 66c317ba4999d51ab2bde027a295d0e9f5013879 Mon Sep 17 00:00:00 2001 From: samuelgregorovic Date: Tue, 2 Nov 2021 13:02:46 +0100 Subject: [PATCH 19/31] moved cursor_on_closing_char_pair to line.py --- bpython/curtsiesfrontend/manual_readline.py | 25 ++------------------- bpython/line.py | 24 ++++++++++++++++++++ 2 files changed, 26 insertions(+), 23 deletions(-) diff --git a/bpython/curtsiesfrontend/manual_readline.py b/bpython/curtsiesfrontend/manual_readline.py index 4c1fadb8..f95e66c5 100644 --- a/bpython/curtsiesfrontend/manual_readline.py +++ b/bpython/curtsiesfrontend/manual_readline.py @@ -5,9 +5,10 @@ based on http://www.bigsmoke.us/readline/shortcuts""" from ..lazyre import LazyReCompile -from . import CHARACTER_PAIR_MAP import inspect +from ..line import cursor_on_closing_char_pair + INDENT = 4 # TODO Allow user config of keybindings for these actions @@ -231,28 +232,6 @@ def delete(cursor_offset, line): return (cursor_offset, line[:cursor_offset] + line[cursor_offset + 1 :]) -def cursor_on_closing_char_pair(cursor_offset, line): - """Checks if cursor sits on closing character of a pair - and whether its pair character is directly behind it - """ - on_closing_char, pair_close = False, False - if line is None: - return on_closing_char, pair_close - if cursor_offset < len(line): - cur_char = line[cursor_offset] - if cur_char in CHARACTER_PAIR_MAP.values(): - on_closing_char = True - if cursor_offset > 0: - prev_char = line[cursor_offset - 1] - if ( - on_closing_char - and prev_char in CHARACTER_PAIR_MAP - and CHARACTER_PAIR_MAP[prev_char] == cur_char - ): - pair_close = True - return on_closing_char, pair_close - - @edit_keys.on("") @edit_keys.on(config="backspace_key") def backspace(cursor_offset, line): diff --git a/bpython/line.py b/bpython/line.py index b98302dd..e5921b94 100644 --- a/bpython/line.py +++ b/bpython/line.py @@ -11,6 +11,8 @@ from .lazyre import LazyReCompile +from bpython.curtsiesfrontend import CHARACTER_PAIR_MAP + class LinePart(NamedTuple): start: int @@ -287,3 +289,25 @@ def current_expression_attribute( if m.start(1) <= cursor_offset <= m.end(1): return LinePart(m.start(1), m.end(1), m.group(1)) return None + + +def cursor_on_closing_char_pair(cursor_offset, line): + """Checks if cursor sits on closing character of a pair + and whether its pair character is directly behind it + """ + on_closing_char, pair_close = False, False + if line is None: + return on_closing_char, pair_close + if cursor_offset < len(line): + cur_char = line[cursor_offset] + if cur_char in CHARACTER_PAIR_MAP.values(): + on_closing_char = True + if cursor_offset > 0: + prev_char = line[cursor_offset - 1] + if ( + on_closing_char + and prev_char in CHARACTER_PAIR_MAP + and CHARACTER_PAIR_MAP[prev_char] == cur_char + ): + pair_close = True + return on_closing_char, pair_close From a23843bb7257611b0f7d217ddcda7e8643df0863 Mon Sep 17 00:00:00 2001 From: samuelgregorovic Date: Tue, 2 Nov 2021 13:12:32 +0100 Subject: [PATCH 20/31] moved CHARACTER_PAIR_MAP to line.py --- bpython/curtsiesfrontend/__init__.py | 1 - bpython/curtsiesfrontend/repl.py | 2 +- bpython/line.py | 3 +-- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/bpython/curtsiesfrontend/__init__.py b/bpython/curtsiesfrontend/__init__.py index 612a8705..e69de29b 100644 --- a/bpython/curtsiesfrontend/__init__.py +++ b/bpython/curtsiesfrontend/__init__.py @@ -1 +0,0 @@ -CHARACTER_PAIR_MAP = {"(": ")", "{": "}", "[": "]", "'": "'", '"': '"'} diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py index 576a6c65..1db1668a 100644 --- a/bpython/curtsiesfrontend/repl.py +++ b/bpython/curtsiesfrontend/repl.py @@ -54,7 +54,7 @@ SourceNotFound, ) from ..translations import _ -from . import CHARACTER_PAIR_MAP +from ..line import CHARACTER_PAIR_MAP logger = logging.getLogger(__name__) diff --git a/bpython/line.py b/bpython/line.py index e5921b94..30124dc9 100644 --- a/bpython/line.py +++ b/bpython/line.py @@ -11,8 +11,6 @@ from .lazyre import LazyReCompile -from bpython.curtsiesfrontend import CHARACTER_PAIR_MAP - class LinePart(NamedTuple): start: int @@ -21,6 +19,7 @@ class LinePart(NamedTuple): _current_word_re = LazyReCompile(r"(? Optional[LinePart]: From 41750bf15fe5976b6bd060fcda27cea4912b85f9 Mon Sep 17 00:00:00 2001 From: samuelgregorovic Date: Tue, 2 Nov 2021 15:52:49 +0100 Subject: [PATCH 21/31] fix overwriting quotes --- bpython/curtsiesfrontend/repl.py | 17 ++++++++++++++++- bpython/line.py | 6 +++--- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py index 1db1668a..8d9d4d26 100644 --- a/bpython/curtsiesfrontend/repl.py +++ b/bpython/curtsiesfrontend/repl.py @@ -791,12 +791,27 @@ def process_key_event(self, e): elif e in ("",): self.add_normal_character(" ") elif e in CHARACTER_PAIR_MAP.keys(): - self.insert_char_pair_start(e) + if e in ["'", '"']: + if self.is_closing_quote(e): + self.insert_char_pair_end(e) + else: + self.insert_char_pair_start(e) elif e in CHARACTER_PAIR_MAP.values(): self.insert_char_pair_end(e) else: self.add_normal_character(e) + def is_closing_quote(self, e): + char_count = self._current_line.count(e) + if ( + char_count % 2 == 0 + and cursor_on_closing_char_pair( + self._cursor_offset, self._current_line, e + )[0] + ): + return True + return False + def insert_char_pair_start(self, e): """Accepts character which is a part of CHARACTER_PAIR_MAP like brackets and quotes, and appends it to the line with diff --git a/bpython/line.py b/bpython/line.py index 30124dc9..cbfa682d 100644 --- a/bpython/line.py +++ b/bpython/line.py @@ -290,7 +290,7 @@ def current_expression_attribute( return None -def cursor_on_closing_char_pair(cursor_offset, line): +def cursor_on_closing_char_pair(cursor_offset, line, ch=None): """Checks if cursor sits on closing character of a pair and whether its pair character is directly behind it """ @@ -300,7 +300,7 @@ def cursor_on_closing_char_pair(cursor_offset, line): if cursor_offset < len(line): cur_char = line[cursor_offset] if cur_char in CHARACTER_PAIR_MAP.values(): - on_closing_char = True + on_closing_char = True if not ch else cur_char == ch if cursor_offset > 0: prev_char = line[cursor_offset - 1] if ( @@ -308,5 +308,5 @@ def cursor_on_closing_char_pair(cursor_offset, line): and prev_char in CHARACTER_PAIR_MAP and CHARACTER_PAIR_MAP[prev_char] == cur_char ): - pair_close = True + pair_close = True if not ch else prev_char == ch return on_closing_char, pair_close From 6138b7a14d204c69bf9b006314e7491006b1d5b4 Mon Sep 17 00:00:00 2001 From: samuelgregorovic Date: Tue, 2 Nov 2021 16:41:29 +0100 Subject: [PATCH 22/31] fix autoclose quotes bug --- bpython/curtsiesfrontend/repl.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py index 8d9d4d26..6c536082 100644 --- a/bpython/curtsiesfrontend/repl.py +++ b/bpython/curtsiesfrontend/repl.py @@ -796,6 +796,8 @@ def process_key_event(self, e): self.insert_char_pair_end(e) else: self.insert_char_pair_start(e) + else: + self.insert_char_pair_start(e) elif e in CHARACTER_PAIR_MAP.values(): self.insert_char_pair_end(e) else: From 8be9bbbaddf92114f0c831bb17e65513f7888d7f Mon Sep 17 00:00:00 2001 From: samuelgregorovic Date: Tue, 2 Nov 2021 18:12:50 +0100 Subject: [PATCH 23/31] autocomplete enabled only before closing params or space --- bpython/curtsiesfrontend/repl.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py index 6c536082..bdfc215a 100644 --- a/bpython/curtsiesfrontend/repl.py +++ b/bpython/curtsiesfrontend/repl.py @@ -824,9 +824,20 @@ def insert_char_pair_start(self, e): """ self.add_normal_character(e) if self.config.brackets_completion: - closing_char = CHARACTER_PAIR_MAP[e] - self.add_normal_character(closing_char) - self.cursor_offset -= 1 + allowed_chars = ["}", ")", "]", " "] + start_of_line = len(self._current_line) == 1 + end_of_line = len(self._current_line) == self._cursor_offset + can_lookup_next = len(self._current_line) > self._cursor_offset + next_char = ( + None + if not can_lookup_next + else self._current_line[self._cursor_offset] + ) + next_char_allowed = next_char in allowed_chars + if start_of_line or end_of_line or next_char_allowed: + closing_char = CHARACTER_PAIR_MAP[e] + self.add_normal_character(closing_char) + self.cursor_offset -= 1 def insert_char_pair_end(self, e): """Accepts character which is a part of CHARACTER_PAIR_MAP From 73782decb1734814d6fe4ff1f69003655a084592 Mon Sep 17 00:00:00 2001 From: samuelgregorovic Date: Tue, 2 Nov 2021 19:22:44 +0100 Subject: [PATCH 24/31] fix matching history entries --- bpython/curtsiesfrontend/repl.py | 43 ++++++++++++++++---------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py index bdfc215a..7236d463 100644 --- a/bpython/curtsiesfrontend/repl.py +++ b/bpython/curtsiesfrontend/repl.py @@ -817,7 +817,8 @@ def is_closing_quote(self, e): def insert_char_pair_start(self, e): """Accepts character which is a part of CHARACTER_PAIR_MAP like brackets and quotes, and appends it to the line with - an appropriate pair end + an appropriate pair end. Closing param can only be inserted + when the next character is either a closing bracket or a space e.x. if you type "(" (lparen) , this will insert "()" into the line @@ -836,8 +837,8 @@ def insert_char_pair_start(self, e): next_char_allowed = next_char in allowed_chars if start_of_line or end_of_line or next_char_allowed: closing_char = CHARACTER_PAIR_MAP[e] - self.add_normal_character(closing_char) - self.cursor_offset -= 1 + self.add_normal_character(closing_char, add_to_search=False) + self._cursor_offset -= 1 def insert_char_pair_end(self, e): """Accepts character which is a part of CHARACTER_PAIR_MAP @@ -851,8 +852,8 @@ def insert_char_pair_end(self, e): character will be printed/appended to the line """ if self.config.brackets_completion: - if self.cursor_offset < len(self.current_line): - if self.current_line[self.cursor_offset] == e: + if self.cursor_offset < len(self._current_line): + if self._current_line[self.cursor_offset] == e: self.cursor_offset += 1 return self.add_normal_character(e) @@ -974,12 +975,6 @@ def only_whitespace_left_of_cursor(): if self.matches_iter.is_cseq(): cursor_and_line = self.matches_iter.substitute_cseq() self._cursor_offset, self._current_line = cursor_and_line - if self.config.brackets_completion: - # appends closing char pair if completion is a callable - if self.is_completion_callable(self._current_line): - self._current_line = self.append_closing_character( - self._current_line - ) # using _current_line so we don't trigger a completion reset if not self.matches_iter.matches: self.list_win_visible = self.complete() @@ -989,14 +984,14 @@ def only_whitespace_left_of_cursor(): ) cursor_and_line = self.matches_iter.cur_line() self._cursor_offset, self._current_line = cursor_and_line - if self.config.brackets_completion: - # appends closing char pair if completion is a callable - if self.is_completion_callable(self._current_line): - self._current_line = self.append_closing_character( - self._current_line - ) # using _current_line so we don't trigger a completion reset self.list_win_visible = True + if self.config.brackets_completion: + # appends closing char pair if completion is a callable + if self.is_completion_callable(self._current_line): + self._current_line = self.append_closing_character( + self._current_line + ) def is_completion_callable(self, completion): """Checks whether given completion is callable (e.x. function)""" @@ -1156,10 +1151,10 @@ def toggle_file_watch(self): ) # Handler Helpers - def add_normal_character(self, char): + def add_normal_character(self, char, add_to_search=True): if len(char) > 1 or is_nop(char): return - if self.incr_search_mode: + if self.incr_search_mode and add_to_search: self.add_to_incremental_search(char) else: self._set_current_line( @@ -1172,12 +1167,18 @@ def add_normal_character(self, char): reset_rl_history=False, clear_special_mode=False, ) - self.cursor_offset += 1 + if add_to_search: + self.cursor_offset += 1 + else: + self._cursor_offset += 1 if self.config.cli_trim_prompts and self.current_line.startswith( self.ps1 ): self.current_line = self.current_line[4:] - self.cursor_offset = max(0, self.cursor_offset - 4) + if add_to_search: + self.cursor_offset = max(0, self.cursor_offset - 4) + else: + self._cursor_offset += max(0, self.cursor_offset - 4) def add_to_incremental_search(self, char=None, backspace=False): """Modify the current search term while in incremental search. From f3f03e2023b1a2e8f7347324dba55daa99f7cc1e Mon Sep 17 00:00:00 2001 From: samuelgregorovic Date: Wed, 3 Nov 2021 08:42:36 +0100 Subject: [PATCH 25/31] basic tests without history --- bpython/test/test_brackets_completion.py | 151 +++++++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 bpython/test/test_brackets_completion.py diff --git a/bpython/test/test_brackets_completion.py b/bpython/test/test_brackets_completion.py new file mode 100644 index 00000000..009c84b9 --- /dev/null +++ b/bpython/test/test_brackets_completion.py @@ -0,0 +1,151 @@ +import os + +from bpython.test import FixLanguageTestCase as TestCase, TEST_CONFIG +from bpython.curtsiesfrontend import repl as curtsiesrepl +from bpython import config + + +def setup_config(conf): + config_struct = config.Config(TEST_CONFIG) + for key, value in conf.items(): + if not hasattr(config_struct, key): + raise ValueError(f"{key!r} is not a valid config attribute") + setattr(config_struct, key, value) + return config_struct + + +def create_repl(brackets_enabled=False, **kwargs): + config = setup_config( + {"editor": "true", "brackets_completion": brackets_enabled} + ) + repl = curtsiesrepl.BaseRepl(config, **kwargs) + os.environ["PAGER"] = "true" + os.environ.pop("PYTHONSTARTUP", None) + repl.width = 50 + repl.height = 20 + return repl + + +class TestBracketCompletionEnabled(TestCase): + def setUp(self): + self.repl = create_repl(brackets_enabled=True) + + def test_start_line(self): + self.repl.process_event("(") + self.assertEqual(self.repl._current_line, "()") + self.assertEqual(self.repl._cursor_offset, 1) + + def test_nested_brackets(self): + self.repl.process_event("(") + self.repl.process_event("[") + self.repl.process_event("{") + self.assertEqual(self.repl._current_line, """([{}])""") + self.assertEqual(self.repl._cursor_offset, 3) + + def test_bracket_overwrite_closing_char(self): + self.repl.process_event("(") + self.repl.process_event("[") + self.repl.process_event("{") + self.assertEqual(self.repl._current_line, """([{}])""") + self.assertEqual(self.repl._cursor_offset, 3) + self.repl.process_event("}") + self.repl.process_event("]") + self.repl.process_event(")") + self.assertEqual(self.repl._current_line, """([{}])""") + self.assertEqual(self.repl._cursor_offset, 6) + + def test_brackets_move_cursor_on_tab(self): + self.repl.process_event("(") + self.repl.process_event("[") + self.repl.process_event("{") + self.assertEqual(self.repl._current_line, """([{}])""") + self.assertEqual(self.repl._cursor_offset, 3) + self.repl.process_event("") + self.assertEqual(self.repl._current_line, """([{}])""") + self.assertEqual(self.repl._cursor_offset, 4) + self.repl.process_event("") + self.assertEqual(self.repl._current_line, """([{}])""") + self.assertEqual(self.repl._cursor_offset, 5) + self.repl.process_event("") + self.assertEqual(self.repl._current_line, """([{}])""") + self.assertEqual(self.repl._cursor_offset, 6) + + def test_brackets_non_whitespace_following_char(self): + self.repl.current_line = "s = s.connect('localhost', 8080)" + self.repl.cursor_offset = 14 + self.repl.process_event("(") + self.assertEqual( + self.repl._current_line, "s = s.connect(('localhost', 8080)" + ) + self.assertEqual(self.repl._cursor_offset, 15) + + def test_brackets_deletion_on_backspace(self): + self.repl.current_line = "def foo()" + self.repl.cursor_offset = 8 + self.repl.process_event("") + self.assertEqual(self.repl._current_line, "def foo") + self.assertEqual(self.repl.cursor_offset, 7) + + def test_brackets_deletion_on_backspace_nested(self): + self.repl.current_line = '([{""}])' + self.repl.cursor_offset = 4 + self.repl.process_event("") + self.repl.process_event("") + self.repl.process_event("") + self.assertEqual(self.repl._current_line, "()") + self.assertEqual(self.repl.cursor_offset, 1) + + +class TestBracketCompletionDisabled(TestCase): + def setUp(self): + self.repl = create_repl(brackets_enabled=False) + + def test_start_line(self): + self.repl.process_event("(") + self.assertEqual(self.repl._current_line, "(") + self.assertEqual(self.repl._cursor_offset, 1) + + def test_nested_brackets(self): + self.repl.process_event("(") + self.repl.process_event("[") + self.repl.process_event("{") + self.assertEqual(self.repl._current_line, "([{") + self.assertEqual(self.repl._cursor_offset, 3) + + def test_bracket_overwrite_closing_char(self): + self.repl.process_event("(") + self.repl.process_event("[") + self.repl.process_event("{") + self.assertEqual(self.repl._current_line, """([{""") + self.assertEqual(self.repl._cursor_offset, 3) + self.repl.process_event("}") + self.repl.process_event("]") + self.repl.process_event(")") + self.assertEqual(self.repl._current_line, """([{}])""") + self.assertEqual(self.repl._cursor_offset, 6) + + def test_brackets_move_cursor_on_tab(self): + self.repl.process_event("(") + self.repl.process_event("[") + self.repl.process_event("{") + self.assertEqual(self.repl._current_line, """([{""") + self.assertEqual(self.repl._cursor_offset, 3) + self.repl.process_event("") + self.assertEqual(self.repl._current_line, """([{""") + self.assertEqual(self.repl._cursor_offset, 3) + + def test_brackets_deletion_on_backspace(self): + self.repl.current_line = "def foo()" + self.repl.cursor_offset = 8 + self.repl.process_event("") + self.assertEqual(self.repl._current_line, "def foo") + self.assertEqual(self.repl.cursor_offset, 7) + + def test_brackets_deletion_on_backspace_nested(self): + self.repl.current_line = '([{""}])' + self.repl.cursor_offset = 4 + self.repl.process_event("") + self.repl.process_event("") + self.repl.process_event("") + self.assertEqual(self.repl._current_line, "()") + self.assertEqual(self.repl.cursor_offset, 1) From 81bc62293fb1131b82a1c04b4fc22f8f9297c60a Mon Sep 17 00:00:00 2001 From: samuelgregorovic Date: Wed, 3 Nov 2021 09:26:05 +0100 Subject: [PATCH 26/31] added quote test --- bpython/test/test_brackets_completion.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/bpython/test/test_brackets_completion.py b/bpython/test/test_brackets_completion.py index 009c84b9..7a22fcba 100644 --- a/bpython/test/test_brackets_completion.py +++ b/bpython/test/test_brackets_completion.py @@ -42,6 +42,21 @@ def test_nested_brackets(self): self.assertEqual(self.repl._current_line, """([{}])""") self.assertEqual(self.repl._cursor_offset, 3) + def test_quotes(self): + self.repl.process_event("(") + self.repl.process_event("'") + self.repl.process_event("x") + self.repl.process_event("") + self.repl.process_event(",") + self.repl.process_event("[") + self.repl.process_event('"') + self.repl.process_event("y") + self.repl.process_event("") + self.repl.process_event("") + self.repl.process_event("") + self.assertEqual(self.repl._current_line, """('x',["y"])""") + self.assertEqual(self.repl._cursor_offset, 11) + def test_bracket_overwrite_closing_char(self): self.repl.process_event("(") self.repl.process_event("[") From f33cf55450694be5f6a7ec57dfd93bab56d48b1d Mon Sep 17 00:00:00 2001 From: samuelgregorovic Date: Wed, 3 Nov 2021 17:32:01 +0100 Subject: [PATCH 27/31] renamed add_to_search to narrow_search --- bpython/curtsiesfrontend/repl.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py index 7236d463..eb1a7fe4 100644 --- a/bpython/curtsiesfrontend/repl.py +++ b/bpython/curtsiesfrontend/repl.py @@ -837,7 +837,7 @@ def insert_char_pair_start(self, e): next_char_allowed = next_char in allowed_chars if start_of_line or end_of_line or next_char_allowed: closing_char = CHARACTER_PAIR_MAP[e] - self.add_normal_character(closing_char, add_to_search=False) + self.add_normal_character(closing_char, narrow_search=False) self._cursor_offset -= 1 def insert_char_pair_end(self, e): @@ -1151,10 +1151,10 @@ def toggle_file_watch(self): ) # Handler Helpers - def add_normal_character(self, char, add_to_search=True): + def add_normal_character(self, char, narrow_search=True): if len(char) > 1 or is_nop(char): return - if self.incr_search_mode and add_to_search: + if self.incr_search_mode and narrow_search: self.add_to_incremental_search(char) else: self._set_current_line( From 66d34cfc9bf9d73c3d66baeee6859d34bbc4edb2 Mon Sep 17 00:00:00 2001 From: samuelgregorovic Date: Wed, 3 Nov 2021 17:33:06 +0100 Subject: [PATCH 28/31] changed default config value to False --- bpython/sample-config | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bpython/sample-config b/bpython/sample-config index c07a7e11..03127f1b 100644 --- a/bpython/sample-config +++ b/bpython/sample-config @@ -61,7 +61,8 @@ # Enable autoreload feature by default (default: False). # default_autoreload = False -# brackets_completion = True +# Enable autocompletion of brackets and quotes (default: False) +# brackets_completion = False [keyboard] From d14207d449e6d455c6d8ff21a072040942834b66 Mon Sep 17 00:00:00 2001 From: samuelgregorovic Date: Wed, 3 Nov 2021 17:41:15 +0100 Subject: [PATCH 29/31] fixed test DRY problem with helper method --- bpython/curtsiesfrontend/repl.py | 4 +- bpython/test/test_brackets_completion.py | 65 +++++++++--------------- 2 files changed, 26 insertions(+), 43 deletions(-) diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py index eb1a7fe4..744d0aaa 100644 --- a/bpython/curtsiesfrontend/repl.py +++ b/bpython/curtsiesfrontend/repl.py @@ -1167,7 +1167,7 @@ def add_normal_character(self, char, narrow_search=True): reset_rl_history=False, clear_special_mode=False, ) - if add_to_search: + if narrow_search: self.cursor_offset += 1 else: self._cursor_offset += 1 @@ -1175,7 +1175,7 @@ def add_normal_character(self, char, narrow_search=True): self.ps1 ): self.current_line = self.current_line[4:] - if add_to_search: + if narrow_search: self.cursor_offset = max(0, self.cursor_offset - 4) else: self._cursor_offset += max(0, self.cursor_offset - 4) diff --git a/bpython/test/test_brackets_completion.py b/bpython/test/test_brackets_completion.py index 7a22fcba..fd983665 100644 --- a/bpython/test/test_brackets_completion.py +++ b/bpython/test/test_brackets_completion.py @@ -30,49 +30,36 @@ class TestBracketCompletionEnabled(TestCase): def setUp(self): self.repl = create_repl(brackets_enabled=True) + def process_multiple_events(self, event_list): + for event in event_list: + self.repl.process_event(event) + def test_start_line(self): self.repl.process_event("(") self.assertEqual(self.repl._current_line, "()") self.assertEqual(self.repl._cursor_offset, 1) def test_nested_brackets(self): - self.repl.process_event("(") - self.repl.process_event("[") - self.repl.process_event("{") + self.process_multiple_events(["(", "[", "{"]) self.assertEqual(self.repl._current_line, """([{}])""") self.assertEqual(self.repl._cursor_offset, 3) def test_quotes(self): - self.repl.process_event("(") - self.repl.process_event("'") - self.repl.process_event("x") - self.repl.process_event("") - self.repl.process_event(",") - self.repl.process_event("[") - self.repl.process_event('"') - self.repl.process_event("y") - self.repl.process_event("") - self.repl.process_event("") - self.repl.process_event("") + self.process_multiple_events(["(", "'", "x", "", ","]) + self.process_multiple_events(["[", '"', "y", "", "", ""]) self.assertEqual(self.repl._current_line, """('x',["y"])""") self.assertEqual(self.repl._cursor_offset, 11) def test_bracket_overwrite_closing_char(self): - self.repl.process_event("(") - self.repl.process_event("[") - self.repl.process_event("{") + self.process_multiple_events(["(", "[", "{"]) self.assertEqual(self.repl._current_line, """([{}])""") self.assertEqual(self.repl._cursor_offset, 3) - self.repl.process_event("}") - self.repl.process_event("]") - self.repl.process_event(")") + self.process_multiple_events(["}", "]", ")"]) self.assertEqual(self.repl._current_line, """([{}])""") self.assertEqual(self.repl._cursor_offset, 6) def test_brackets_move_cursor_on_tab(self): - self.repl.process_event("(") - self.repl.process_event("[") - self.repl.process_event("{") + self.process_multiple_events(["(", "[", "{"]) self.assertEqual(self.repl._current_line, """([{}])""") self.assertEqual(self.repl._cursor_offset, 3) self.repl.process_event("") @@ -104,9 +91,9 @@ def test_brackets_deletion_on_backspace(self): def test_brackets_deletion_on_backspace_nested(self): self.repl.current_line = '([{""}])' self.repl.cursor_offset = 4 - self.repl.process_event("") - self.repl.process_event("") - self.repl.process_event("") + self.process_multiple_events( + ["", "", ""] + ) self.assertEqual(self.repl._current_line, "()") self.assertEqual(self.repl.cursor_offset, 1) @@ -115,34 +102,30 @@ class TestBracketCompletionDisabled(TestCase): def setUp(self): self.repl = create_repl(brackets_enabled=False) + def process_multiple_events(self, event_list): + for event in event_list: + self.repl.process_event(event) + def test_start_line(self): self.repl.process_event("(") self.assertEqual(self.repl._current_line, "(") self.assertEqual(self.repl._cursor_offset, 1) def test_nested_brackets(self): - self.repl.process_event("(") - self.repl.process_event("[") - self.repl.process_event("{") + self.process_multiple_events(["(", "[", "{"]) self.assertEqual(self.repl._current_line, "([{") self.assertEqual(self.repl._cursor_offset, 3) def test_bracket_overwrite_closing_char(self): - self.repl.process_event("(") - self.repl.process_event("[") - self.repl.process_event("{") + self.process_multiple_events(["(", "[", "{"]) self.assertEqual(self.repl._current_line, """([{""") self.assertEqual(self.repl._cursor_offset, 3) - self.repl.process_event("}") - self.repl.process_event("]") - self.repl.process_event(")") + self.process_multiple_events(["}", "]", ")"]) self.assertEqual(self.repl._current_line, """([{}])""") self.assertEqual(self.repl._cursor_offset, 6) def test_brackets_move_cursor_on_tab(self): - self.repl.process_event("(") - self.repl.process_event("[") - self.repl.process_event("{") + self.process_multiple_events(["(", "[", "{"]) self.assertEqual(self.repl._current_line, """([{""") self.assertEqual(self.repl._cursor_offset, 3) self.repl.process_event("") @@ -159,8 +142,8 @@ def test_brackets_deletion_on_backspace(self): def test_brackets_deletion_on_backspace_nested(self): self.repl.current_line = '([{""}])' self.repl.cursor_offset = 4 - self.repl.process_event("") - self.repl.process_event("") - self.repl.process_event("") + self.process_multiple_events( + ["", "", ""] + ) self.assertEqual(self.repl._current_line, "()") self.assertEqual(self.repl.cursor_offset, 1) From 100735d8b92975b77e13c39e42654261382a0f1f Mon Sep 17 00:00:00 2001 From: samuelgregorovic Date: Wed, 3 Nov 2021 17:43:41 +0100 Subject: [PATCH 30/31] fixed insert_char_pair_start docstring --- bpython/curtsiesfrontend/repl.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py index 744d0aaa..4a9f1eb5 100644 --- a/bpython/curtsiesfrontend/repl.py +++ b/bpython/curtsiesfrontend/repl.py @@ -817,8 +817,8 @@ def is_closing_quote(self, e): def insert_char_pair_start(self, e): """Accepts character which is a part of CHARACTER_PAIR_MAP like brackets and quotes, and appends it to the line with - an appropriate pair end. Closing param can only be inserted - when the next character is either a closing bracket or a space + an appropriate character pair ending. Closing character can only be inserted + when the next character is either a closing character or a space e.x. if you type "(" (lparen) , this will insert "()" into the line From 2c683fc53e60af7913fd7753814f68a374cdec4b Mon Sep 17 00:00:00 2001 From: samuelgregorovic Date: Wed, 3 Nov 2021 19:08:46 +0100 Subject: [PATCH 31/31] fix bad behavior of reverse-incremental search --- bpython/curtsiesfrontend/repl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bpython/curtsiesfrontend/repl.py b/bpython/curtsiesfrontend/repl.py index 4a9f1eb5..657a0188 100644 --- a/bpython/curtsiesfrontend/repl.py +++ b/bpython/curtsiesfrontend/repl.py @@ -1154,7 +1154,7 @@ def toggle_file_watch(self): def add_normal_character(self, char, narrow_search=True): if len(char) > 1 or is_nop(char): return - if self.incr_search_mode and narrow_search: + if self.incr_search_mode: self.add_to_incremental_search(char) else: self._set_current_line(