From d5704fdc29c695d0349b411192b7acdd251dacc8 2020-05-04 23:29:07 From: Matthias Bussonnier Date: 2020-05-04 23:29:07 Subject: [PATCH] Try to elide long completion based on user input. If what the user has typed is already in the completion and the completion is really long, try to elide what the user has already typed from the displayed text of the completion. Keep the first 3 and last 3 of what is already present. This will behave weirdly if all the completion have a common prefix as I believe prompt toolkit will insert the common prefix (or do we?). I'll have to check how to consider the common prefix as being typed. --- diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index 848a14a..f5fdba6 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -2217,7 +2217,7 @@ class InteractiveShell(SingletonConfigurable): The position argument (defaults to 0) is the index in the completers list where you want the completer to be inserted.""" - newcomp = types.MethodType(completer,self.Completer) + newcomp = types.MethodType(completer, self.Completer) self.Completer.custom_matchers.insert(pos,newcomp) def set_completer_frame(self, frame=None): diff --git a/IPython/terminal/ptutils.py b/IPython/terminal/ptutils.py index 47fd6f4..7c19e95 100644 --- a/IPython/terminal/ptutils.py +++ b/IPython/terminal/ptutils.py @@ -23,7 +23,7 @@ import os _completion_sentinel = object() -def _elide(string, *, min_elide=30): +def _elide_point(string, *, min_elide=30): """ If a string is long enough, and has at least 3 dots, replace the middle part with ellipses. @@ -53,6 +53,24 @@ def _elide(string, *, min_elide=30): return string +def _elide_typed(string, typed, *, min_elide=30): + """ + Elide the middle of a long string if the beginning has already been typed. + """ + + if len(string) < min_elide: + return string + cut_how_much = len(typed)-3 + if string.startswith(typed) and len(string)> len(typed): + return f"{string[:3]}\N{HORIZONTAL ELLIPSIS}{string[cut_how_much:]}" + return string + +def _elide(string, typed, min_elide=30): + return _elide_typed( + _elide_point(string, min_elide=min_elide), + typed, min_elide=min_elide) + + def _adjust_completion_text_based_on_context(text, body, offset): if text.endswith('=') and len(body) > offset and body[offset] == '=': @@ -89,7 +107,11 @@ class IPythonPTCompleter(Completer): cursor_col = document.cursor_position_col cursor_position = document.cursor_position offset = cursor_to_position(body, cursor_row, cursor_col) - yield from self._get_completions(body, offset, cursor_position, self.ipy_completer) + try: + yield from self._get_completions(body, offset, cursor_position, self.ipy_completer) + except Exception as e: + from traceback import print_tb + print_tb(e) @staticmethod def _get_completions(body, offset, cursor_position, ipyc): @@ -128,9 +150,9 @@ class IPythonPTCompleter(Completer): adjusted_text = _adjust_completion_text_based_on_context(c.text, body, offset) if c.type == 'function': - yield Completion(adjusted_text, start_position=c.start - offset, display=_elide(display_text+'()'), display_meta=c.type+c.signature) + yield Completion(adjusted_text, start_position=c.start - offset, display=_elide(display_text+'()', body[c.start:c.end]), display_meta=c.type+c.signature) else: - yield Completion(adjusted_text, start_position=c.start - offset, display=_elide(display_text), display_meta=c.type) + yield Completion(adjusted_text, start_position=c.start - offset, display=_elide(display_text, body[c.start:c.end]), display_meta=c.type) class IPythonPTLexer(Lexer): """