Show More
@@ -1,16 +1,8 b'' | |||||
1 | # coding: utf-8 |
|
1 | # coding: utf-8 | |
2 | """test the IPython Kernel""" |
|
2 | """test the IPython Kernel""" | |
3 |
|
3 | |||
4 | #------------------------------------------------------------------------------- |
|
4 | # Copyright (c) IPython Development Team. | |
5 | # Copyright (C) 2013 The IPython Development Team |
|
5 | # Distributed under the terms of the Modified BSD License. | |
6 | # |
|
|||
7 | # Distributed under the terms of the BSD License. The full license is in |
|
|||
8 | # the file COPYING, distributed as part of this software. |
|
|||
9 | #------------------------------------------------------------------------------- |
|
|||
10 |
|
||||
11 | #------------------------------------------------------------------------------- |
|
|||
12 | # Imports |
|
|||
13 | #------------------------------------------------------------------------------- |
|
|||
14 |
|
6 | |||
15 | import io |
|
7 | import io | |
16 | import os.path |
|
8 | import os.path | |
@@ -26,10 +18,6 b' from IPython.utils.tempdir import TemporaryDirectory' | |||||
26 | from .utils import (new_kernel, kernel, TIMEOUT, assemble_output, execute, |
|
18 | from .utils import (new_kernel, kernel, TIMEOUT, assemble_output, execute, | |
27 | flush_channels, wait_for_idle) |
|
19 | flush_channels, wait_for_idle) | |
28 |
|
20 | |||
29 | #------------------------------------------------------------------------------- |
|
|||
30 | # Tests |
|
|||
31 | #------------------------------------------------------------------------------- |
|
|||
32 |
|
||||
33 |
|
21 | |||
34 | def _check_mp_mode(kc, expected=False, stream="stdout"): |
|
22 | def _check_mp_mode(kc, expected=False, stream="stdout"): | |
35 | execute(kc=kc, code="import sys") |
|
23 | execute(kc=kc, code="import sys") | |
@@ -213,7 +201,7 b' def test_is_complete():' | |||||
213 | reply = kc.get_shell_msg(block=True, timeout=TIMEOUT) |
|
201 | reply = kc.get_shell_msg(block=True, timeout=TIMEOUT) | |
214 | assert reply['content']['status'] == 'complete' |
|
202 | assert reply['content']['status'] == 'complete' | |
215 |
|
203 | |||
216 |
# SyntaxError should mean it's complete |
|
204 | # SyntaxError should mean it's complete | |
217 | kc.is_complete('raise = 2') |
|
205 | kc.is_complete('raise = 2') | |
218 | reply = kc.get_shell_msg(block=True, timeout=TIMEOUT) |
|
206 | reply = kc.get_shell_msg(block=True, timeout=TIMEOUT) | |
219 | assert reply['content']['status'] == 'invalid' |
|
207 | assert reply['content']['status'] == 'invalid' | |
@@ -221,4 +209,20 b' def test_is_complete():' | |||||
221 | kc.is_complete('a = [1,\n2,') |
|
209 | kc.is_complete('a = [1,\n2,') | |
222 | reply = kc.get_shell_msg(block=True, timeout=TIMEOUT) |
|
210 | reply = kc.get_shell_msg(block=True, timeout=TIMEOUT) | |
223 | assert reply['content']['status'] == 'incomplete' |
|
211 | assert reply['content']['status'] == 'incomplete' | |
224 | assert reply['content']['indent'] == '' No newline at end of file |
|
212 | assert reply['content']['indent'] == '' | |
|
213 | ||||
|
214 | def test_complete(): | |||
|
215 | with kernel() as kc: | |||
|
216 | execute(u'a = 1', kc=kc) | |||
|
217 | wait_for_idle(kc) | |||
|
218 | cell = 'import IPython\nb = a.' | |||
|
219 | kc.complete(cell) | |||
|
220 | reply = kc.get_shell_msg(block=True, timeout=TIMEOUT) | |||
|
221 | c = reply['content'] | |||
|
222 | nt.assert_equal(c['status'], 'ok') | |||
|
223 | nt.assert_equal(c['cursor_start'], cell.find('a.')) | |||
|
224 | nt.assert_equal(c['cursor_end'], cell.find('a.') + 2) | |||
|
225 | matches = c['matches'] | |||
|
226 | nt.assert_greater(len(matches), 0) | |||
|
227 | for match in matches: | |||
|
228 | nt.assert_equal(match[:2], 'a.') |
@@ -79,6 +79,8 b' def start_global_kernel():' | |||||
79 | if KM is None: |
|
79 | if KM is None: | |
80 | KM, KC = start_new_kernel() |
|
80 | KM, KC = start_new_kernel() | |
81 | atexit.register(stop_global_kernel) |
|
81 | atexit.register(stop_global_kernel) | |
|
82 | else: | |||
|
83 | flush_channels(KC) | |||
82 | return KC |
|
84 | return KC | |
83 |
|
85 | |||
84 | @contextmanager |
|
86 | @contextmanager |
@@ -6,7 +6,7 b' import traceback' | |||||
6 |
|
6 | |||
7 | from IPython.core import release |
|
7 | from IPython.core import release | |
8 | from IPython.utils.py3compat import builtin_mod, PY3 |
|
8 | from IPython.utils.py3compat import builtin_mod, PY3 | |
9 | from IPython.utils.tokenutil import token_at_cursor |
|
9 | from IPython.utils.tokenutil import token_at_cursor, line_at_cursor | |
10 | from IPython.utils.traitlets import Instance, Type, Any |
|
10 | from IPython.utils.traitlets import Instance, Type, Any | |
11 | from IPython.utils.decorators import undoc |
|
11 | from IPython.utils.decorators import undoc | |
12 |
|
12 | |||
@@ -186,7 +186,15 b' class IPythonKernel(KernelBase):' | |||||
186 | return reply_content |
|
186 | return reply_content | |
187 |
|
187 | |||
188 | def do_complete(self, code, cursor_pos): |
|
188 | def do_complete(self, code, cursor_pos): | |
189 | txt, matches = self.shell.complete('', code, cursor_pos) |
|
189 | # FIXME: IPython completers currently assume single line, | |
|
190 | # but completion messages give multi-line context | |||
|
191 | # For now, extract line from cell, based on cursor_pos: | |||
|
192 | if cursor_pos is None: | |||
|
193 | cursor_pos = len(code) | |||
|
194 | line, offset = line_at_cursor(code, cursor_pos) | |||
|
195 | line_cursor = cursor_pos - offset | |||
|
196 | ||||
|
197 | txt, matches = self.shell.complete('', line, line_cursor) | |||
190 | return {'matches' : matches, |
|
198 | return {'matches' : matches, | |
191 | 'cursor_end' : cursor_pos, |
|
199 | 'cursor_end' : cursor_pos, | |
192 | 'cursor_start' : cursor_pos - len(txt), |
|
200 | 'cursor_start' : cursor_pos - len(txt), |
@@ -23,6 +23,34 b' def generate_tokens(readline):' | |||||
23 | # catch EOF error |
|
23 | # catch EOF error | |
24 | return |
|
24 | return | |
25 |
|
25 | |||
|
26 | def line_at_cursor(cell, cursor_pos=0): | |||
|
27 | """Return the line in a cell at a given cursor position | |||
|
28 | ||||
|
29 | Used for calling line-based APIs that don't support multi-line input, yet. | |||
|
30 | ||||
|
31 | Parameters | |||
|
32 | ---------- | |||
|
33 | ||||
|
34 | cell: text | |||
|
35 | multiline block of text | |||
|
36 | cursor_pos: integer | |||
|
37 | the cursor position | |||
|
38 | ||||
|
39 | Returns | |||
|
40 | ------- | |||
|
41 | ||||
|
42 | (line, offset): (text, integer) | |||
|
43 | The line with the current cursor, and the character offset of the start of the line. | |||
|
44 | """ | |||
|
45 | offset = 0 | |||
|
46 | lines = cell.splitlines(True) | |||
|
47 | for line in lines: | |||
|
48 | next_offset = offset + len(line) | |||
|
49 | if next_offset >= cursor_pos: | |||
|
50 | break | |||
|
51 | offset = next_offset | |||
|
52 | return (line, offset) | |||
|
53 | ||||
26 | def token_at_cursor(cell, cursor_pos=0): |
|
54 | def token_at_cursor(cell, cursor_pos=0): | |
27 | """Get the token at a given cursor |
|
55 | """Get the token at a given cursor | |
28 |
|
56 |
General Comments 0
You need to be logged in to leave comments.
Login now