##// 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 - pip install setuptools --upgrade
38 - pip install setuptools --upgrade
39 - pip install -e file://$PWD#egg=ipython[test] --upgrade
39 - pip install -e file://$PWD#egg=ipython[test] --upgrade
40 - pip install trio curio --upgrade --upgrade-strategy eager
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 - pip install codecov check-manifest --upgrade
42 - pip install codecov check-manifest --upgrade
43
43
44 script:
44 script:
@@ -50,6 +50,7 b' script:'
50 fi
50 fi
51 - cd /tmp && iptest --coverage xml && cd -
51 - cd /tmp && iptest --coverage xml && cd -
52 - pytest IPython
52 - pytest IPython
53 - mypy --ignore-missing-imports -m IPython.terminal.ptutils
53 # On the latest Python (on Linux) only, make sure that the docs build.
54 # On the latest Python (on Linux) only, make sure that the docs build.
54 - |
55 - |
55 if [[ "$TRAVIS_PYTHON_VERSION" == "3.7" ]] && [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
56 if [[ "$TRAVIS_PYTHON_VERSION" == "3.7" ]] && [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
@@ -2217,7 +2217,7 b' class InteractiveShell(SingletonConfigurable):'
2217 The position argument (defaults to 0) is the index in the completers
2217 The position argument (defaults to 0) is the index in the completers
2218 list where you want the completer to be inserted."""
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 self.Completer.custom_matchers.insert(pos,newcomp)
2221 self.Completer.custom_matchers.insert(pos,newcomp)
2222
2222
2223 def set_completer_frame(self, frame=None):
2223 def set_completer_frame(self, frame=None):
@@ -23,7 +23,7 b' import os'
23
23
24 _completion_sentinel = object()
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 If a string is long enough, and has at least 3 dots,
28 If a string is long enough, and has at least 3 dots,
29 replace the middle part with ellipses.
29 replace the middle part with ellipses.
@@ -53,6 +53,26 b' def _elide(string, *, min_elide=30):'
53
53
54 return string
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 def _adjust_completion_text_based_on_context(text, body, offset):
77 def _adjust_completion_text_based_on_context(text, body, offset):
58 if text.endswith('=') and len(body) > offset and body[offset] == '=':
78 if text.endswith('=') and len(body) > offset and body[offset] == '=':
@@ -89,7 +109,11 b' class IPythonPTCompleter(Completer):'
89 cursor_col = document.cursor_position_col
109 cursor_col = document.cursor_position_col
90 cursor_position = document.cursor_position
110 cursor_position = document.cursor_position
91 offset = cursor_to_position(body, cursor_row, cursor_col)
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 @staticmethod
118 @staticmethod
95 def _get_completions(body, offset, cursor_position, ipyc):
119 def _get_completions(body, offset, cursor_position, ipyc):
@@ -128,9 +152,9 b' class IPythonPTCompleter(Completer):'
128
152
129 adjusted_text = _adjust_completion_text_based_on_context(c.text, body, offset)
153 adjusted_text = _adjust_completion_text_based_on_context(c.text, body, offset)
130 if c.type == 'function':
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 else:
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 class IPythonPTLexer(Lexer):
159 class IPythonPTLexer(Lexer):
136 """
160 """
@@ -17,14 +17,32 b' import nose.tools as nt'
17 class TestElide(unittest.TestCase):
17 class TestElide(unittest.TestCase):
18
18
19 def test_elide(self):
19 def test_elide(self):
20 _elide('concatenate((a1, a2, ...), axis') # do not raise
20 _elide('concatenate((a1, a2, ...), axis', '') # do not raise
21 _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')
22 nt.assert_equal(_elide('aaaa.bbbb.ccccc.dddddd.eeeee.fffff.gggggg.hhhhhh',''), 'aaaa.b…g.hhhhhh')
23
23
24 test_string = os.sep.join(['', 10*'a', 10*'b', 10*'c', ''])
24 test_string = os.sep.join(['', 10*'a', 10*'b', 10*'c', ''])
25 expect_stirng = os.sep + 'a' + '\N{HORIZONTAL ELLIPSIS}' + 'b' + os.sep + 10*'c'
25 expect_stirng = os.sep + 'a' + '\N{HORIZONTAL ELLIPSIS}' + 'b' + os.sep + 10*'c'
26 nt.assert_equal(_elide(test_string), expect_stirng)
26 nt.assert_equal(_elide(test_string, ''), expect_stirng)
27
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 class TestContextAwareCompletion(unittest.TestCase):
47 class TestContextAwareCompletion(unittest.TestCase):
30
48
General Comments 0
You need to be logged in to leave comments. Login now