##// END OF EJS Templates
add utils.tokenutil for getting the token at a cursor offset
MinRK -
Show More
@@ -0,0 +1,56 b''
1 """Tests for tokenutil"""
2 # Copyright (c) IPython Development Team.
3 # Distributed under the terms of the Modified BSD License.
4
5 import nose.tools as nt
6
7 from IPython.utils.tokenutil import token_at_cursor
8
9 def expect_token(expected, cell, column, line=0):
10 token = token_at_cursor(cell, column, line)
11
12 lines = cell.splitlines()
13 line_with_cursor = '%s|%s' % (lines[line][:column], lines[line][column:])
14 line
15 nt.assert_equal(token, expected,
16 "Excpected %r, got %r in: %s" % (
17 expected, token, line_with_cursor)
18 )
19
20 def test_simple():
21 cell = "foo"
22 for i in range(len(cell)):
23 expect_token("foo", cell, i)
24
25 def test_function():
26 cell = "foo(a=5, b='10')"
27 expected = 'foo'
28 for i in (6,7,8,10,11,12):
29 expect_token("foo", cell, i)
30
31 def test_multiline():
32 cell = '\n'.join([
33 'a = 5',
34 'b = hello("string", there)'
35 ])
36 expected = 'hello'
37 for i in range(4,9):
38 expect_token(expected, cell, i, 1)
39 expected = 'there'
40 for i in range(21,27):
41 expect_token(expected, cell, i, 1)
42
43 def test_attrs():
44 cell = "foo(a=obj.attr.subattr)"
45 expected = 'obj'
46 idx = cell.find('obj')
47 for i in range(idx, idx + 3):
48 expect_token(expected, cell, i)
49 idx = idx + 4
50 expected = 'obj.attr'
51 for i in range(idx, idx + 4):
52 expect_token(expected, cell, i)
53 idx = idx + 5
54 expected = 'obj.attr.subattr'
55 for i in range(idx, len(cell)):
56 expect_token(expected, cell, i)
@@ -0,0 +1,80 b''
1 """Token-related utilities"""
2
3 # Copyright (c) IPython Development Team.
4 # Distributed under the terms of the Modified BSD License.
5
6 from __future__ import absolute_import, print_function
7
8 from collections import namedtuple
9 from io import StringIO
10 from keyword import iskeyword
11
12 from . import tokenize2
13 from .py3compat import cast_unicode_py2
14
15 Token = namedtuple('Token', ['token', 'text', 'start', 'end', 'line'])
16
17 def generate_tokens(readline):
18 """wrap generate_tokens to catch EOF errors"""
19 try:
20 for token in tokenize2.generate_tokens(readline):
21 yield token
22 except tokenize2.TokenError:
23 # catch EOF error
24 return
25
26 def token_at_cursor(cell, column, line=0):
27 """Get the token at a given cursor
28
29 Used for introspection.
30
31 Parameters
32 ----------
33
34 cell : unicode
35 A block of Python code
36 column : int
37 The column of the cursor offset, where the token should be found
38 line : int, optional
39 The line where the token should be found (optional if cell is a single line)
40 """
41 cell = cast_unicode_py2(cell)
42 names = []
43 tokens = []
44 current_line = 0
45 for tup in generate_tokens(StringIO(cell).readline):
46
47 tok = Token(*tup)
48
49 # token, text, start, end, line = tup
50 start_col = tok.start[1]
51 end_col = tok.end[1]
52 if line == current_line and start_col > column:
53 # current token starts after the cursor,
54 # don't consume it
55 break
56
57 if tok.token == tokenize2.NAME and not iskeyword(tok.text):
58 if names and tokens and tokens[-1].token == tokenize2.OP and tokens[-1].text == '.':
59 names[-1] = "%s.%s" % (names[-1], tok.text)
60 else:
61 names.append(tok.text)
62 elif tok.token == tokenize2.OP:
63 if tok.text == '=' and names:
64 # don't inspect the lhs of an assignment
65 names.pop(-1)
66
67 if line == current_line and end_col > column:
68 # we found the cursor, stop reading
69 break
70
71 tokens.append(tok)
72 if tok.token == tokenize2.NEWLINE:
73 current_line += 1
74
75 if names:
76 return names[-1]
77 else:
78 return ''
79
80
General Comments 0
You need to be logged in to leave comments. Login now