##// END OF EJS Templates
Backport PR #12284: Try to elide long completion based on user input.
Matthias Bussonnier -
Show More
@@ -38,7 +38,7 b' install:'
38 38 - pip install setuptools --upgrade
39 39 - pip install -e file://$PWD#egg=ipython[test] --upgrade
40 40 - pip install trio curio --upgrade --upgrade-strategy eager
41 - pip install pytest 'matplotlib !=3.2.0'
41 - pip install pytest 'matplotlib !=3.2.0' mypy
42 42 - pip install codecov check-manifest --upgrade
43 43
44 44 script:
@@ -50,6 +50,7 b' script:'
50 50 fi
51 51 - cd /tmp && iptest --coverage xml && cd -
52 52 - pytest IPython
53 - mypy --ignore-missing-imports -m IPython.terminal.ptutils
53 54 # On the latest Python (on Linux) only, make sure that the docs build.
54 55 - |
55 56 if [[ "$TRAVIS_PYTHON_VERSION" == "3.7" ]] && [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
@@ -2217,7 +2217,7 b' class InteractiveShell(SingletonConfigurable):'
2217 2217 The position argument (defaults to 0) is the index in the completers
2218 2218 list where you want the completer to be inserted."""
2219 2219
2220 newcomp = types.MethodType(completer,self.Completer)
2220 newcomp = types.MethodType(completer, self.Completer)
2221 2221 self.Completer.custom_matchers.insert(pos,newcomp)
2222 2222
2223 2223 def set_completer_frame(self, frame=None):
@@ -23,7 +23,7 b' import os'
23 23
24 24 _completion_sentinel = object()
25 25
26 def _elide(string, *, min_elide=30):
26 def _elide_point(string:str, *, min_elide=30)->str:
27 27 """
28 28 If a string is long enough, and has at least 3 dots,
29 29 replace the middle part with ellipses.
@@ -53,6 +53,26 b' def _elide(string, *, min_elide=30):'
53 53
54 54 return string
55 55
56 def _elide_typed(string:str, typed:str, *, min_elide:int=30)->str:
57 """
58 Elide the middle of a long string if the beginning has already been typed.
59 """
60
61 if len(string) < min_elide:
62 return string
63 cut_how_much = len(typed)-3
64 if cut_how_much < 7:
65 return string
66 if string.startswith(typed) and len(string)> len(typed):
67 return f"{string[:3]}\N{HORIZONTAL ELLIPSIS}{string[cut_how_much:]}"
68 return string
69
70 def _elide(string:str, typed:str, min_elide=30)->str:
71 return _elide_typed(
72 _elide_point(string, min_elide=min_elide),
73 typed, min_elide=min_elide)
74
75
56 76
57 77 def _adjust_completion_text_based_on_context(text, body, offset):
58 78 if text.endswith('=') and len(body) > offset and body[offset] == '=':
@@ -89,7 +109,11 b' class IPythonPTCompleter(Completer):'
89 109 cursor_col = document.cursor_position_col
90 110 cursor_position = document.cursor_position
91 111 offset = cursor_to_position(body, cursor_row, cursor_col)
92 yield from self._get_completions(body, offset, cursor_position, self.ipy_completer)
112 try:
113 yield from self._get_completions(body, offset, cursor_position, self.ipy_completer)
114 except Exception as e:
115 from traceback import print_tb
116 print_tb(e)
93 117
94 118 @staticmethod
95 119 def _get_completions(body, offset, cursor_position, ipyc):
@@ -128,9 +152,9 b' class IPythonPTCompleter(Completer):'
128 152
129 153 adjusted_text = _adjust_completion_text_based_on_context(c.text, body, offset)
130 154 if c.type == 'function':
131 yield Completion(adjusted_text, start_position=c.start - offset, display=_elide(display_text+'()'), display_meta=c.type+c.signature)
155 yield Completion(adjusted_text, start_position=c.start - offset, display=_elide(display_text+'()', body[c.start:c.end]), display_meta=c.type+c.signature)
132 156 else:
133 yield Completion(adjusted_text, start_position=c.start - offset, display=_elide(display_text), display_meta=c.type)
157 yield Completion(adjusted_text, start_position=c.start - offset, display=_elide(display_text, body[c.start:c.end]), display_meta=c.type)
134 158
135 159 class IPythonPTLexer(Lexer):
136 160 """
@@ -17,14 +17,32 b' import nose.tools as nt'
17 17 class TestElide(unittest.TestCase):
18 18
19 19 def test_elide(self):
20 _elide('concatenate((a1, a2, ...), axis') # do not raise
21 _elide('concatenate((a1, a2, ..), . axis') # do not raise
22 nt.assert_equal(_elide('aaaa.bbbb.ccccc.dddddd.eeeee.fffff.gggggg.hhhhhh'), 'aaaa.b…g.hhhhhh')
23
20 _elide('concatenate((a1, a2, ...), axis', '') # do not raise
21 _elide('concatenate((a1, a2, ..), . axis', '') # do not raise
22 nt.assert_equal(_elide('aaaa.bbbb.ccccc.dddddd.eeeee.fffff.gggggg.hhhhhh',''), 'aaaa.b…g.hhhhhh')
23
24 24 test_string = os.sep.join(['', 10*'a', 10*'b', 10*'c', ''])
25 25 expect_stirng = os.sep + 'a' + '\N{HORIZONTAL ELLIPSIS}' + 'b' + os.sep + 10*'c'
26 nt.assert_equal(_elide(test_string), expect_stirng)
27
26 nt.assert_equal(_elide(test_string, ''), expect_stirng)
27
28 def test_elide_typed_normal(self):
29 nt.assert_equal(_elide('the quick brown fox jumped over the lazy dog', 'the quick brown fox', min_elide=10), 'the…fox jumped over the lazy dog')
30
31
32 def test_elide_typed_short_match(self):
33 """
34 if the match is too short we don't elide.
35 avoid the "the...the"
36 """
37 nt.assert_equal(_elide('the quick brown fox jumped over the lazy dog', 'the', min_elide=10), 'the quick brown fox jumped over the lazy dog')
38
39 def test_elide_typed_no_match(self):
40 """
41 if the match is too short we don't elide.
42 avoid the "the...the"
43 """
44 # here we typed red instead of brown
45 nt.assert_equal(_elide('the quick brown fox jumped over the lazy dog', 'the quick red fox', min_elide=10), 'the quick brown fox jumped over the lazy dog')
28 46
29 47 class TestContextAwareCompletion(unittest.TestCase):
30 48
General Comments 0
You need to be logged in to leave comments. Login now