##// END OF EJS Templates
Fix greedy completion for qtconsole
Martin Bergtholdt -
Show More
@@ -1,74 +1,79 b''
1 # System library imports
1 # System library imports
2 from pygments.token import Token, is_token_subtype
2 from pygments.token import Token, is_token_subtype
3
3
4
4
5 class CompletionLexer(object):
5 class CompletionLexer(object):
6 """ Uses Pygments and some auxillary information to lex code snippets for
6 """ Uses Pygments and some auxillary information to lex code snippets for
7 symbol contexts.
7 symbol contexts.
8 """
8 """
9
9
10 # Maps Lexer names to a list of possible name separators
10 # Maps Lexer names to a list of possible name separators
11 separator_map = { 'C' : [ '.', '->' ],
11 separator_map = { 'C' : [ '.', '->' ],
12 'C++' : [ '.', '->', '::' ],
12 'C++' : [ '.', '->', '::' ],
13 'Python' : [ '.' ] }
13 'Python' : [ '.' ] }
14
14
15 def __init__(self, lexer):
15 def __init__(self, lexer):
16 """ Create a CompletionLexer using the specified Pygments lexer.
16 """ Create a CompletionLexer using the specified Pygments lexer.
17 """
17 """
18 self.lexer = lexer
18 self.lexer = lexer
19
19
20 def get_context(self, string):
20 def get_context(self, string):
21 """ Assuming the cursor is at the end of the specified string, get the
21 """ Assuming the cursor is at the end of the specified string, get the
22 context (a list of names) for the symbol at cursor position.
22 context (a list of names) for the symbol at cursor position.
23 """
23 """
24 context = []
24 context = []
25 reversed_tokens = list(self._lexer.get_tokens(string))
25 reversed_tokens = list(self._lexer.get_tokens(string))
26 reversed_tokens.reverse()
26 reversed_tokens.reverse()
27
27
28 # Pygments often tacks on a newline when none is specified in the input.
28 # Pygments often tacks on a newline when none is specified in the input.
29 # Remove this newline.
29 # Remove this newline.
30 if reversed_tokens and reversed_tokens[0][1].endswith('\n') and \
30 if reversed_tokens and reversed_tokens[0][1].endswith('\n') and \
31 not string.endswith('\n'):
31 not string.endswith('\n'):
32 reversed_tokens.pop(0)
32 reversed_tokens.pop(0)
33
33
34 current_op = ''
34 current_op = ''
35 for token, text in reversed_tokens:
35 for token, text in reversed_tokens:
36
36
37 if is_token_subtype(token, Token.Name):
37 if is_token_subtype(token, Token.Name):
38
38
39 # Handle a trailing separator, e.g 'foo.bar.'
39 # Handle a trailing separator, e.g 'foo.bar.'
40 if current_op in self._name_separators:
40 if current_op in self._name_separators:
41 if not context:
41 if not context:
42 context.insert(0, '')
42 context.insert(0, '')
43
43
44 # Handle non-separator operators and punction.
44 # Handle non-separator operators and punction.
45 elif current_op:
45 elif current_op:
46 break
46 break
47
47
48 context.insert(0, text)
48 context.insert(0, text)
49 current_op = ''
49 current_op = ''
50
50
51 # Pygments doesn't understand that, e.g., '->' is a single operator
51 # Pygments doesn't understand that, e.g., '->' is a single operator
52 # in C++. This is why we have to build up an operator from
52 # in C++. This is why we have to build up an operator from
53 # potentially several tokens.
53 # potentially several tokens.
54 elif token is Token.Operator or token is Token.Punctuation:
54 elif token is Token.Operator or token is Token.Punctuation:
55 current_op = text + current_op
55 # Handle a trailing separator, e.g 'foo.bar.'
56 if current_op in self._name_separators:
57 if not context:
58 context.insert(0, '')
59 else:
60 current_op = text + current_op
56
61
57 # Break on anything that is not a Operator, Punctuation, or Name.
62 # Break on anything that is not a Operator, Punctuation, or Name.
58 else:
63 else:
59 break
64 break
60
65
61 return context
66 return context
62
67
63 def get_lexer(self, lexer):
68 def get_lexer(self, lexer):
64 return self._lexer
69 return self._lexer
65
70
66 def set_lexer(self, lexer, name_separators=None):
71 def set_lexer(self, lexer, name_separators=None):
67 self._lexer = lexer
72 self._lexer = lexer
68 if name_separators is None:
73 if name_separators is None:
69 self._name_separators = self.separator_map.get(lexer.name, ['.'])
74 self._name_separators = self.separator_map.get(lexer.name, ['.'])
70 else:
75 else:
71 self._name_separators = list(name_separators)
76 self._name_separators = list(name_separators)
72
77
73 lexer = property(get_lexer, set_lexer)
78 lexer = property(get_lexer, set_lexer)
74
79
General Comments 0
You need to be logged in to leave comments. Login now