##// END OF EJS Templates
Add line splitting for text completion (like readline does internally)....
Fernando Perez -
Show More
@@ -1,722 +1,774 b''
1 """Word completion for IPython.
1 """Word completion for IPython.
2
2
3 This module is a fork of the rlcompleter module in the Python standard
3 This module is a fork of the rlcompleter module in the Python standard
4 library. The original enhancements made to rlcompleter have been sent
4 library. The original enhancements made to rlcompleter have been sent
5 upstream and were accepted as of Python 2.3, but we need a lot more
5 upstream and were accepted as of Python 2.3, but we need a lot more
6 functionality specific to IPython, so this module will continue to live as an
6 functionality specific to IPython, so this module will continue to live as an
7 IPython-specific utility.
7 IPython-specific utility.
8
8
9 Original rlcompleter documentation:
9 Original rlcompleter documentation:
10
10
11 This requires the latest extension to the readline module (the
11 This requires the latest extension to the readline module (the
12 completes keywords, built-ins and globals in __main__; when completing
12 completes keywords, built-ins and globals in __main__; when completing
13 NAME.NAME..., it evaluates (!) the expression up to the last dot and
13 NAME.NAME..., it evaluates (!) the expression up to the last dot and
14 completes its attributes.
14 completes its attributes.
15
15
16 It's very cool to do "import string" type "string.", hit the
16 It's very cool to do "import string" type "string.", hit the
17 completion key (twice), and see the list of names defined by the
17 completion key (twice), and see the list of names defined by the
18 string module!
18 string module!
19
19
20 Tip: to use the tab key as the completion key, call
20 Tip: to use the tab key as the completion key, call
21
21
22 readline.parse_and_bind("tab: complete")
22 readline.parse_and_bind("tab: complete")
23
23
24 Notes:
24 Notes:
25
25
26 - Exceptions raised by the completer function are *ignored* (and
26 - Exceptions raised by the completer function are *ignored* (and
27 generally cause the completion to fail). This is a feature -- since
27 generally cause the completion to fail). This is a feature -- since
28 readline sets the tty device in raw (or cbreak) mode, printing a
28 readline sets the tty device in raw (or cbreak) mode, printing a
29 traceback wouldn't work well without some complicated hoopla to save,
29 traceback wouldn't work well without some complicated hoopla to save,
30 reset and restore the tty state.
30 reset and restore the tty state.
31
31
32 - The evaluation of the NAME.NAME... form may cause arbitrary
32 - The evaluation of the NAME.NAME... form may cause arbitrary
33 application defined code to be executed if an object with a
33 application defined code to be executed if an object with a
34 __getattr__ hook is found. Since it is the responsibility of the
34 __getattr__ hook is found. Since it is the responsibility of the
35 application (or the user) to enable this feature, I consider this an
35 application (or the user) to enable this feature, I consider this an
36 acceptable risk. More complicated expressions (e.g. function calls or
36 acceptable risk. More complicated expressions (e.g. function calls or
37 indexing operations) are *not* evaluated.
37 indexing operations) are *not* evaluated.
38
38
39 - GNU readline is also used by the built-in functions input() and
39 - GNU readline is also used by the built-in functions input() and
40 raw_input(), and thus these also benefit/suffer from the completer
40 raw_input(), and thus these also benefit/suffer from the completer
41 features. Clearly an interactive application can benefit by
41 features. Clearly an interactive application can benefit by
42 specifying its own completer function and using raw_input() for all
42 specifying its own completer function and using raw_input() for all
43 its input.
43 its input.
44
44
45 - When the original stdin is not a tty device, GNU readline is never
45 - When the original stdin is not a tty device, GNU readline is never
46 used, and this module (and the readline module) are silently inactive.
46 used, and this module (and the readline module) are silently inactive.
47 """
47 """
48
48
49 #*****************************************************************************
49 #*****************************************************************************
50 #
50 #
51 # Since this file is essentially a minimally modified copy of the rlcompleter
51 # Since this file is essentially a minimally modified copy of the rlcompleter
52 # module which is part of the standard Python distribution, I assume that the
52 # module which is part of the standard Python distribution, I assume that the
53 # proper procedure is to maintain its copyright as belonging to the Python
53 # proper procedure is to maintain its copyright as belonging to the Python
54 # Software Foundation (in addition to my own, for all new code).
54 # Software Foundation (in addition to my own, for all new code).
55 #
55 #
56 # Copyright (C) 2008-2010 IPython Development Team
56 # Copyright (C) 2008-2010 IPython Development Team
57 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
57 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
58 # Copyright (C) 2001 Python Software Foundation, www.python.org
58 # Copyright (C) 2001 Python Software Foundation, www.python.org
59 #
59 #
60 # Distributed under the terms of the BSD License. The full license is in
60 # Distributed under the terms of the BSD License. The full license is in
61 # the file COPYING, distributed as part of this software.
61 # the file COPYING, distributed as part of this software.
62 #
62 #
63 #*****************************************************************************
63 #*****************************************************************************
64 from __future__ import print_function
64
65
65 #-----------------------------------------------------------------------------
66 #-----------------------------------------------------------------------------
66 # Imports
67 # Imports
67 #-----------------------------------------------------------------------------
68 #-----------------------------------------------------------------------------
68
69
69 import __builtin__
70 import __builtin__
70 import __main__
71 import __main__
71 import glob
72 import glob
72 import inspect
73 import inspect
73 import itertools
74 import itertools
74 import keyword
75 import keyword
75 import os
76 import os
76 import re
77 import re
77 import shlex
78 import shlex
78 import sys
79 import sys
79
80
80 from IPython.core.error import TryNext
81 from IPython.core.error import TryNext
81 from IPython.core.prefilter import ESC_MAGIC
82 from IPython.core.prefilter import ESC_MAGIC
82 from IPython.utils import generics
83 from IPython.utils import generics, io
83 from IPython.utils.frame import debugx
84 from IPython.utils.frame import debugx
84 from IPython.utils.dir2 import dir2
85 from IPython.utils.dir2 import dir2
85
86
86 #-----------------------------------------------------------------------------
87 #-----------------------------------------------------------------------------
87 # Globals
88 # Globals
88 #-----------------------------------------------------------------------------
89 #-----------------------------------------------------------------------------
89
90
90 # Public API
91 # Public API
91 __all__ = ['Completer','IPCompleter']
92 __all__ = ['Completer','IPCompleter']
92
93
93 if sys.platform == 'win32':
94 if sys.platform == 'win32':
94 PROTECTABLES = ' '
95 PROTECTABLES = ' '
95 else:
96 else:
96 PROTECTABLES = ' ()'
97 PROTECTABLES = ' ()'
97
98
98 #-----------------------------------------------------------------------------
99 #-----------------------------------------------------------------------------
99 # Main functions and classes
100 # Main functions and classes
100 #-----------------------------------------------------------------------------
101 #-----------------------------------------------------------------------------
101
102
102 def protect_filename(s):
103 def protect_filename(s):
103 """Escape a string to protect certain characters."""
104 """Escape a string to protect certain characters."""
104
105
105 return "".join([(ch in PROTECTABLES and '\\' + ch or ch)
106 return "".join([(ch in PROTECTABLES and '\\' + ch or ch)
106 for ch in s])
107 for ch in s])
107
108
108
109
109 def mark_dirs(matches):
110 def mark_dirs(matches):
110 """Mark directories in input list by appending '/' to their names."""
111 """Mark directories in input list by appending '/' to their names."""
111 out = []
112 out = []
112 isdir = os.path.isdir
113 isdir = os.path.isdir
113 for x in matches:
114 for x in matches:
114 if isdir(x):
115 if isdir(x):
115 out.append(x+'/')
116 out.append(x+'/')
116 else:
117 else:
117 out.append(x)
118 out.append(x)
118 return out
119 return out
119
120
120
121
121 def single_dir_expand(matches):
122 def single_dir_expand(matches):
122 "Recursively expand match lists containing a single dir."
123 "Recursively expand match lists containing a single dir."
123
124
124 if len(matches) == 1 and os.path.isdir(matches[0]):
125 if len(matches) == 1 and os.path.isdir(matches[0]):
125 # Takes care of links to directories also. Use '/'
126 # Takes care of links to directories also. Use '/'
126 # explicitly, even under Windows, so that name completions
127 # explicitly, even under Windows, so that name completions
127 # don't end up escaped.
128 # don't end up escaped.
128 d = matches[0]
129 d = matches[0]
129 if d[-1] in ['/','\\']:
130 if d[-1] in ['/','\\']:
130 d = d[:-1]
131 d = d[:-1]
131
132
132 subdirs = os.listdir(d)
133 subdirs = os.listdir(d)
133 if subdirs:
134 if subdirs:
134 matches = [ (d + '/' + p) for p in subdirs]
135 matches = [ (d + '/' + p) for p in subdirs]
135 return single_dir_expand(matches)
136 return single_dir_expand(matches)
136 else:
137 else:
137 return matches
138 return matches
138 else:
139 else:
139 return matches
140 return matches
140
141
141 class Bunch: pass
142
142
143 class Completer:
143 class Bunch(object): pass
144
145
146 class CompletionSplitter(object):
147 """An object to split an input line in a manner similar to readline.
148
149 By having our own implementation, we can expose readline-like completion in
150 a uniform manner to all frontends. This object only needs to be given the
151 line of text to be split and the cursor position on said line, and it
152 returns the 'word' to be completed on at the cursor after splitting the
153 entire line.
154
155 What characters are used as splitting delimiters can be controlled by
156 setting the `delims` attribute (this is a property that internally
157 automatically builds the necessary """
158
159 # Private interface
160
161 # A string of delimiter characters. The default value makes sense for
162 # IPython's most typical usage patterns.
163 _delims = ' \t\n`!@#$^&*()=+[{]}\\|;:\'",<>?'
164
165 # The expression (a normal string) to be compiled into a regular expression
166 # for actual splitting. We store it as an attribute mostly for ease of
167 # debugging, since this type of code can be so tricky to debug.
168 _delim_expr = None
169
170 # The regular expression that does the actual splitting
171 _delim_re = None
172
173 def __init__(self, delims=None):
174 delims = CompletionSplitter._delims if delims is None else delims
175 self.set_delims(delims)
176
177 def set_delims(self, delims):
178 """Set the delimiters for line splitting."""
179 expr = '[' + ''.join('\\'+ c for c in delims) + ']'
180 self._delim_re = re.compile(expr)
181 self._delims = delims
182 self._delim_expr = expr
183
184 def get_delims(self):
185 """Return the string of delimiter characters."""
186 return self._delims
187
188 def split_line(self, line, cursor_pos=None):
189 """Split a line of text with a cursor at the given position.
190 """
191 l = line if cursor_pos is None else line[:cursor_pos]
192 return self._delim_re.split(l)[-1]
193
194
195 class Completer(object):
144 def __init__(self,namespace=None,global_namespace=None):
196 def __init__(self,namespace=None,global_namespace=None):
145 """Create a new completer for the command line.
197 """Create a new completer for the command line.
146
198
147 Completer([namespace,global_namespace]) -> completer instance.
199 Completer([namespace,global_namespace]) -> completer instance.
148
200
149 If unspecified, the default namespace where completions are performed
201 If unspecified, the default namespace where completions are performed
150 is __main__ (technically, __main__.__dict__). Namespaces should be
202 is __main__ (technically, __main__.__dict__). Namespaces should be
151 given as dictionaries.
203 given as dictionaries.
152
204
153 An optional second namespace can be given. This allows the completer
205 An optional second namespace can be given. This allows the completer
154 to handle cases where both the local and global scopes need to be
206 to handle cases where both the local and global scopes need to be
155 distinguished.
207 distinguished.
156
208
157 Completer instances should be used as the completion mechanism of
209 Completer instances should be used as the completion mechanism of
158 readline via the set_completer() call:
210 readline via the set_completer() call:
159
211
160 readline.set_completer(Completer(my_namespace).complete)
212 readline.set_completer(Completer(my_namespace).complete)
161 """
213 """
162
214
163 # Don't bind to namespace quite yet, but flag whether the user wants a
215 # Don't bind to namespace quite yet, but flag whether the user wants a
164 # specific namespace or to use __main__.__dict__. This will allow us
216 # specific namespace or to use __main__.__dict__. This will allow us
165 # to bind to __main__.__dict__ at completion time, not now.
217 # to bind to __main__.__dict__ at completion time, not now.
166 if namespace is None:
218 if namespace is None:
167 self.use_main_ns = 1
219 self.use_main_ns = 1
168 else:
220 else:
169 self.use_main_ns = 0
221 self.use_main_ns = 0
170 self.namespace = namespace
222 self.namespace = namespace
171
223
172 # The global namespace, if given, can be bound directly
224 # The global namespace, if given, can be bound directly
173 if global_namespace is None:
225 if global_namespace is None:
174 self.global_namespace = {}
226 self.global_namespace = {}
175 else:
227 else:
176 self.global_namespace = global_namespace
228 self.global_namespace = global_namespace
177
229
178 def complete(self, text, state):
230 def complete(self, text, state):
179 """Return the next possible completion for 'text'.
231 """Return the next possible completion for 'text'.
180
232
181 This is called successively with state == 0, 1, 2, ... until it
233 This is called successively with state == 0, 1, 2, ... until it
182 returns None. The completion should begin with 'text'.
234 returns None. The completion should begin with 'text'.
183
235
184 """
236 """
185 if self.use_main_ns:
237 if self.use_main_ns:
186 self.namespace = __main__.__dict__
238 self.namespace = __main__.__dict__
187
239
188 if state == 0:
240 if state == 0:
189 if "." in text:
241 if "." in text:
190 self.matches = self.attr_matches(text)
242 self.matches = self.attr_matches(text)
191 else:
243 else:
192 self.matches = self.global_matches(text)
244 self.matches = self.global_matches(text)
193 try:
245 try:
194 return self.matches[state]
246 return self.matches[state]
195 except IndexError:
247 except IndexError:
196 return None
248 return None
197
249
198 def global_matches(self, text):
250 def global_matches(self, text):
199 """Compute matches when text is a simple name.
251 """Compute matches when text is a simple name.
200
252
201 Return a list of all keywords, built-in functions and names currently
253 Return a list of all keywords, built-in functions and names currently
202 defined in self.namespace or self.global_namespace that match.
254 defined in self.namespace or self.global_namespace that match.
203
255
204 """
256 """
205 #print 'Completer->global_matches, txt=%r' % text # dbg
257 #print 'Completer->global_matches, txt=%r' % text # dbg
206 matches = []
258 matches = []
207 match_append = matches.append
259 match_append = matches.append
208 n = len(text)
260 n = len(text)
209 for lst in [keyword.kwlist,
261 for lst in [keyword.kwlist,
210 __builtin__.__dict__.keys(),
262 __builtin__.__dict__.keys(),
211 self.namespace.keys(),
263 self.namespace.keys(),
212 self.global_namespace.keys()]:
264 self.global_namespace.keys()]:
213 for word in lst:
265 for word in lst:
214 if word[:n] == text and word != "__builtins__":
266 if word[:n] == text and word != "__builtins__":
215 match_append(word)
267 match_append(word)
216 return matches
268 return matches
217
269
218 def attr_matches(self, text):
270 def attr_matches(self, text):
219 """Compute matches when text contains a dot.
271 """Compute matches when text contains a dot.
220
272
221 Assuming the text is of the form NAME.NAME....[NAME], and is
273 Assuming the text is of the form NAME.NAME....[NAME], and is
222 evaluatable in self.namespace or self.global_namespace, it will be
274 evaluatable in self.namespace or self.global_namespace, it will be
223 evaluated and its attributes (as revealed by dir()) are used as
275 evaluated and its attributes (as revealed by dir()) are used as
224 possible completions. (For class instances, class members are are
276 possible completions. (For class instances, class members are are
225 also considered.)
277 also considered.)
226
278
227 WARNING: this can still invoke arbitrary C code, if an object
279 WARNING: this can still invoke arbitrary C code, if an object
228 with a __getattr__ hook is evaluated.
280 with a __getattr__ hook is evaluated.
229
281
230 """
282 """
231
283
232 #print 'Completer->attr_matches, txt=%r' % text # dbg
284 #print 'Completer->attr_matches, txt=%r' % text # dbg
233 # Another option, seems to work great. Catches things like ''.<tab>
285 # Another option, seems to work great. Catches things like ''.<tab>
234 m = re.match(r"(\S+(\.\w+)*)\.(\w*)$", text)
286 m = re.match(r"(\S+(\.\w+)*)\.(\w*)$", text)
235
287
236 if not m:
288 if not m:
237 return []
289 return []
238
290
239 expr, attr = m.group(1, 3)
291 expr, attr = m.group(1, 3)
240 try:
292 try:
241 obj = eval(expr, self.namespace)
293 obj = eval(expr, self.namespace)
242 except:
294 except:
243 try:
295 try:
244 obj = eval(expr, self.global_namespace)
296 obj = eval(expr, self.global_namespace)
245 except:
297 except:
246 return []
298 return []
247
299
248 words = dir2(obj)
300 words = dir2(obj)
249
301
250 try:
302 try:
251 words = generics.complete_object(obj, words)
303 words = generics.complete_object(obj, words)
252 except TryNext:
304 except TryNext:
253 pass
305 pass
254 # Build match list to return
306 # Build match list to return
255 n = len(attr)
307 n = len(attr)
256 res = ["%s.%s" % (expr, w) for w in words if w[:n] == attr ]
308 res = ["%s.%s" % (expr, w) for w in words if w[:n] == attr ]
257 return res
309 return res
258
310
259
311
260 class IPCompleter(Completer):
312 class IPCompleter(Completer):
261 """Extension of the completer class with IPython-specific features"""
313 """Extension of the completer class with IPython-specific features"""
262
314
263 def __init__(self, shell, namespace=None, global_namespace=None,
315 def __init__(self, shell, namespace=None, global_namespace=None,
264 omit__names=0, alias_table=None, use_readline=True):
316 omit__names=0, alias_table=None, use_readline=True):
265 """IPCompleter() -> completer
317 """IPCompleter() -> completer
266
318
267 Return a completer object suitable for use by the readline library
319 Return a completer object suitable for use by the readline library
268 via readline.set_completer().
320 via readline.set_completer().
269
321
270 Inputs:
322 Inputs:
271
323
272 - shell: a pointer to the ipython shell itself. This is needed
324 - shell: a pointer to the ipython shell itself. This is needed
273 because this completer knows about magic functions, and those can
325 because this completer knows about magic functions, and those can
274 only be accessed via the ipython instance.
326 only be accessed via the ipython instance.
275
327
276 - namespace: an optional dict where completions are performed.
328 - namespace: an optional dict where completions are performed.
277
329
278 - global_namespace: secondary optional dict for completions, to
330 - global_namespace: secondary optional dict for completions, to
279 handle cases (such as IPython embedded inside functions) where
331 handle cases (such as IPython embedded inside functions) where
280 both Python scopes are visible.
332 both Python scopes are visible.
281
333
282 - The optional omit__names parameter sets the completer to omit the
334 - The optional omit__names parameter sets the completer to omit the
283 'magic' names (__magicname__) for python objects unless the text
335 'magic' names (__magicname__) for python objects unless the text
284 to be completed explicitly starts with one or more underscores.
336 to be completed explicitly starts with one or more underscores.
285
337
286 - If alias_table is supplied, it should be a dictionary of aliases
338 - If alias_table is supplied, it should be a dictionary of aliases
287 to complete.
339 to complete.
288
340
289 use_readline : bool, optional
341 use_readline : bool, optional
290 If true, use the readline library. This completer can still function
342 If true, use the readline library. This completer can still function
291 without readline, though in that case callers must provide some extra
343 without readline, though in that case callers must provide some extra
292 information on each call about the current line."""
344 information on each call about the current line."""
293
345
294 Completer.__init__(self,namespace,global_namespace)
346 Completer.__init__(self,namespace,global_namespace)
295
347
296 self.magic_escape = ESC_MAGIC
348 self.magic_escape = ESC_MAGIC
297
349
298 # Readline-dependent code
350 # Readline-dependent code
299 self.use_readline = use_readline
351 self.use_readline = use_readline
300 if use_readline:
352 if use_readline:
301 import IPython.utils.rlineimpl as readline
353 import IPython.utils.rlineimpl as readline
302 self.readline = readline
354 self.readline = readline
303 delims = self.readline.get_completer_delims()
355 delims = self.readline.get_completer_delims()
304 delims = delims.replace(self.magic_escape,'')
356 delims = delims.replace(self.magic_escape,'')
305 self.readline.set_completer_delims(delims)
357 self.readline.set_completer_delims(delims)
306 self.get_line_buffer = self.readline.get_line_buffer
358 self.get_line_buffer = self.readline.get_line_buffer
307 self.get_endidx = self.readline.get_endidx
359 self.get_endidx = self.readline.get_endidx
308 # /end readline-dependent code
360 # /end readline-dependent code
309
361
310 # List where completion matches will be stored
362 # List where completion matches will be stored
311 self.matches = []
363 self.matches = []
312 self.omit__names = omit__names
364 self.omit__names = omit__names
313 self.merge_completions = shell.readline_merge_completions
365 self.merge_completions = shell.readline_merge_completions
314 self.shell = shell.shell
366 self.shell = shell.shell
315 if alias_table is None:
367 if alias_table is None:
316 alias_table = {}
368 alias_table = {}
317 self.alias_table = alias_table
369 self.alias_table = alias_table
318 # Regexp to split filenames with spaces in them
370 # Regexp to split filenames with spaces in them
319 self.space_name_re = re.compile(r'([^\\] )')
371 self.space_name_re = re.compile(r'([^\\] )')
320 # Hold a local ref. to glob.glob for speed
372 # Hold a local ref. to glob.glob for speed
321 self.glob = glob.glob
373 self.glob = glob.glob
322
374
323 # Determine if we are running on 'dumb' terminals, like (X)Emacs
375 # Determine if we are running on 'dumb' terminals, like (X)Emacs
324 # buffers, to avoid completion problems.
376 # buffers, to avoid completion problems.
325 term = os.environ.get('TERM','xterm')
377 term = os.environ.get('TERM','xterm')
326 self.dumb_terminal = term in ['dumb','emacs']
378 self.dumb_terminal = term in ['dumb','emacs']
327
379
328 # Special handling of backslashes needed in win32 platforms
380 # Special handling of backslashes needed in win32 platforms
329 if sys.platform == "win32":
381 if sys.platform == "win32":
330 self.clean_glob = self._clean_glob_win32
382 self.clean_glob = self._clean_glob_win32
331 else:
383 else:
332 self.clean_glob = self._clean_glob
384 self.clean_glob = self._clean_glob
333
385
334 # All active matcher routines for completion
386 # All active matcher routines for completion
335 self.matchers = [self.python_matches,
387 self.matchers = [self.python_matches,
336 self.file_matches,
388 self.file_matches,
337 self.magic_matches,
389 self.magic_matches,
338 self.alias_matches,
390 self.alias_matches,
339 self.python_func_kw_matches,
391 self.python_func_kw_matches,
340 ]
392 ]
341
393
342 # Code contributed by Alex Schmolck, for ipython/emacs integration
394 # Code contributed by Alex Schmolck, for ipython/emacs integration
343 def all_completions(self, text):
395 def all_completions(self, text):
344 """Return all possible completions for the benefit of emacs."""
396 """Return all possible completions for the benefit of emacs."""
345
397
346 completions = []
398 completions = []
347 comp_append = completions.append
399 comp_append = completions.append
348 try:
400 try:
349 for i in xrange(sys.maxint):
401 for i in xrange(sys.maxint):
350 res = self.complete(text, i, text)
402 res = self.complete(text, i, text)
351 if not res:
403 if not res:
352 break
404 break
353 comp_append(res)
405 comp_append(res)
354 #XXX workaround for ``notDefined.<tab>``
406 #XXX workaround for ``notDefined.<tab>``
355 except NameError:
407 except NameError:
356 pass
408 pass
357 return completions
409 return completions
358 # /end Alex Schmolck code.
410 # /end Alex Schmolck code.
359
411
360 def _clean_glob(self,text):
412 def _clean_glob(self,text):
361 return self.glob("%s*" % text)
413 return self.glob("%s*" % text)
362
414
363 def _clean_glob_win32(self,text):
415 def _clean_glob_win32(self,text):
364 return [f.replace("\\","/")
416 return [f.replace("\\","/")
365 for f in self.glob("%s*" % text)]
417 for f in self.glob("%s*" % text)]
366
418
367 def file_matches(self, text):
419 def file_matches(self, text):
368 """Match filenames, expanding ~USER type strings.
420 """Match filenames, expanding ~USER type strings.
369
421
370 Most of the seemingly convoluted logic in this completer is an
422 Most of the seemingly convoluted logic in this completer is an
371 attempt to handle filenames with spaces in them. And yet it's not
423 attempt to handle filenames with spaces in them. And yet it's not
372 quite perfect, because Python's readline doesn't expose all of the
424 quite perfect, because Python's readline doesn't expose all of the
373 GNU readline details needed for this to be done correctly.
425 GNU readline details needed for this to be done correctly.
374
426
375 For a filename with a space in it, the printed completions will be
427 For a filename with a space in it, the printed completions will be
376 only the parts after what's already been typed (instead of the
428 only the parts after what's already been typed (instead of the
377 full completions, as is normally done). I don't think with the
429 full completions, as is normally done). I don't think with the
378 current (as of Python 2.3) Python readline it's possible to do
430 current (as of Python 2.3) Python readline it's possible to do
379 better."""
431 better."""
380
432
381 #print 'Completer->file_matches: <%s>' % text # dbg
433 #print 'Completer->file_matches: <%s>' % text # dbg
382
434
383 # chars that require escaping with backslash - i.e. chars
435 # chars that require escaping with backslash - i.e. chars
384 # that readline treats incorrectly as delimiters, but we
436 # that readline treats incorrectly as delimiters, but we
385 # don't want to treat as delimiters in filename matching
437 # don't want to treat as delimiters in filename matching
386 # when escaped with backslash
438 # when escaped with backslash
387
439
388 if text.startswith('!'):
440 if text.startswith('!'):
389 text = text[1:]
441 text = text[1:]
390 text_prefix = '!'
442 text_prefix = '!'
391 else:
443 else:
392 text_prefix = ''
444 text_prefix = ''
393
445
394 lbuf = self.lbuf
446 lbuf = self.lbuf
395 open_quotes = 0 # track strings with open quotes
447 open_quotes = 0 # track strings with open quotes
396 try:
448 try:
397 lsplit = shlex.split(lbuf)[-1]
449 lsplit = shlex.split(lbuf)[-1]
398 except ValueError:
450 except ValueError:
399 # typically an unmatched ", or backslash without escaped char.
451 # typically an unmatched ", or backslash without escaped char.
400 if lbuf.count('"')==1:
452 if lbuf.count('"')==1:
401 open_quotes = 1
453 open_quotes = 1
402 lsplit = lbuf.split('"')[-1]
454 lsplit = lbuf.split('"')[-1]
403 elif lbuf.count("'")==1:
455 elif lbuf.count("'")==1:
404 open_quotes = 1
456 open_quotes = 1
405 lsplit = lbuf.split("'")[-1]
457 lsplit = lbuf.split("'")[-1]
406 else:
458 else:
407 return []
459 return []
408 except IndexError:
460 except IndexError:
409 # tab pressed on empty line
461 # tab pressed on empty line
410 lsplit = ""
462 lsplit = ""
411
463
412 if lsplit != protect_filename(lsplit):
464 if lsplit != protect_filename(lsplit):
413 # if protectables are found, do matching on the whole escaped
465 # if protectables are found, do matching on the whole escaped
414 # name
466 # name
415 has_protectables = 1
467 has_protectables = 1
416 text0,text = text,lsplit
468 text0,text = text,lsplit
417 else:
469 else:
418 has_protectables = 0
470 has_protectables = 0
419 text = os.path.expanduser(text)
471 text = os.path.expanduser(text)
420
472
421 if text == "":
473 if text == "":
422 return [text_prefix + protect_filename(f) for f in self.glob("*")]
474 return [text_prefix + protect_filename(f) for f in self.glob("*")]
423
475
424 m0 = self.clean_glob(text.replace('\\',''))
476 m0 = self.clean_glob(text.replace('\\',''))
425 if has_protectables:
477 if has_protectables:
426 # If we had protectables, we need to revert our changes to the
478 # If we had protectables, we need to revert our changes to the
427 # beginning of filename so that we don't double-write the part
479 # beginning of filename so that we don't double-write the part
428 # of the filename we have so far
480 # of the filename we have so far
429 len_lsplit = len(lsplit)
481 len_lsplit = len(lsplit)
430 matches = [text_prefix + text0 +
482 matches = [text_prefix + text0 +
431 protect_filename(f[len_lsplit:]) for f in m0]
483 protect_filename(f[len_lsplit:]) for f in m0]
432 else:
484 else:
433 if open_quotes:
485 if open_quotes:
434 # if we have a string with an open quote, we don't need to
486 # if we have a string with an open quote, we don't need to
435 # protect the names at all (and we _shouldn't_, as it
487 # protect the names at all (and we _shouldn't_, as it
436 # would cause bugs when the filesystem call is made).
488 # would cause bugs when the filesystem call is made).
437 matches = m0
489 matches = m0
438 else:
490 else:
439 matches = [text_prefix +
491 matches = [text_prefix +
440 protect_filename(f) for f in m0]
492 protect_filename(f) for f in m0]
441
493
442 #print 'mm',matches # dbg
494 #print 'mm',matches # dbg
443 #return single_dir_expand(matches)
495 #return single_dir_expand(matches)
444 return mark_dirs(matches)
496 return mark_dirs(matches)
445
497
446 def magic_matches(self, text):
498 def magic_matches(self, text):
447 """Match magics"""
499 """Match magics"""
448 #print 'Completer->magic_matches:',text,'lb',self.lbuf # dbg
500 #print 'Completer->magic_matches:',text,'lb',self.lbuf # dbg
449 # Get all shell magics now rather than statically, so magics loaded at
501 # Get all shell magics now rather than statically, so magics loaded at
450 # runtime show up too
502 # runtime show up too
451 magics = self.shell.lsmagic()
503 magics = self.shell.lsmagic()
452 pre = self.magic_escape
504 pre = self.magic_escape
453 baretext = text.lstrip(pre)
505 baretext = text.lstrip(pre)
454 return [ pre+m for m in magics if m.startswith(baretext)]
506 return [ pre+m for m in magics if m.startswith(baretext)]
455
507
456 def alias_matches(self, text):
508 def alias_matches(self, text):
457 """Match internal system aliases"""
509 """Match internal system aliases"""
458 #print 'Completer->alias_matches:',text,'lb',self.lbuf # dbg
510 #print 'Completer->alias_matches:',text,'lb',self.lbuf # dbg
459
511
460 # if we are not in the first 'item', alias matching
512 # if we are not in the first 'item', alias matching
461 # doesn't make sense - unless we are starting with 'sudo' command.
513 # doesn't make sense - unless we are starting with 'sudo' command.
462 if ' ' in self.lbuf.lstrip() and \
514 if ' ' in self.lbuf.lstrip() and \
463 not self.lbuf.lstrip().startswith('sudo'):
515 not self.lbuf.lstrip().startswith('sudo'):
464 return []
516 return []
465 text = os.path.expanduser(text)
517 text = os.path.expanduser(text)
466 aliases = self.alias_table.keys()
518 aliases = self.alias_table.keys()
467 if text == "":
519 if text == "":
468 return aliases
520 return aliases
469 else:
521 else:
470 return [alias for alias in aliases if alias.startswith(text)]
522 return [alias for alias in aliases if alias.startswith(text)]
471
523
472 def python_matches(self,text):
524 def python_matches(self,text):
473 """Match attributes or global python names"""
525 """Match attributes or global python names"""
474
526
475 #print 'Completer->python_matches, txt=%r' % text # dbg
527 #print 'Completer->python_matches, txt=%r' % text # dbg
476 if "." in text:
528 if "." in text:
477 try:
529 try:
478 matches = self.attr_matches(text)
530 matches = self.attr_matches(text)
479 if text.endswith('.') and self.omit__names:
531 if text.endswith('.') and self.omit__names:
480 if self.omit__names == 1:
532 if self.omit__names == 1:
481 # true if txt is _not_ a __ name, false otherwise:
533 # true if txt is _not_ a __ name, false otherwise:
482 no__name = (lambda txt:
534 no__name = (lambda txt:
483 re.match(r'.*\.__.*?__',txt) is None)
535 re.match(r'.*\.__.*?__',txt) is None)
484 else:
536 else:
485 # true if txt is _not_ a _ name, false otherwise:
537 # true if txt is _not_ a _ name, false otherwise:
486 no__name = (lambda txt:
538 no__name = (lambda txt:
487 re.match(r'.*\._.*?',txt) is None)
539 re.match(r'.*\._.*?',txt) is None)
488 matches = filter(no__name, matches)
540 matches = filter(no__name, matches)
489 except NameError:
541 except NameError:
490 # catches <undefined attributes>.<tab>
542 # catches <undefined attributes>.<tab>
491 matches = []
543 matches = []
492 else:
544 else:
493 matches = self.global_matches(text)
545 matches = self.global_matches(text)
494
546
495 return matches
547 return matches
496
548
497 def _default_arguments(self, obj):
549 def _default_arguments(self, obj):
498 """Return the list of default arguments of obj if it is callable,
550 """Return the list of default arguments of obj if it is callable,
499 or empty list otherwise."""
551 or empty list otherwise."""
500
552
501 if not (inspect.isfunction(obj) or inspect.ismethod(obj)):
553 if not (inspect.isfunction(obj) or inspect.ismethod(obj)):
502 # for classes, check for __init__,__new__
554 # for classes, check for __init__,__new__
503 if inspect.isclass(obj):
555 if inspect.isclass(obj):
504 obj = (getattr(obj,'__init__',None) or
556 obj = (getattr(obj,'__init__',None) or
505 getattr(obj,'__new__',None))
557 getattr(obj,'__new__',None))
506 # for all others, check if they are __call__able
558 # for all others, check if they are __call__able
507 elif hasattr(obj, '__call__'):
559 elif hasattr(obj, '__call__'):
508 obj = obj.__call__
560 obj = obj.__call__
509 # XXX: is there a way to handle the builtins ?
561 # XXX: is there a way to handle the builtins ?
510 try:
562 try:
511 args,_,_1,defaults = inspect.getargspec(obj)
563 args,_,_1,defaults = inspect.getargspec(obj)
512 if defaults:
564 if defaults:
513 return args[-len(defaults):]
565 return args[-len(defaults):]
514 except TypeError: pass
566 except TypeError: pass
515 return []
567 return []
516
568
517 def python_func_kw_matches(self,text):
569 def python_func_kw_matches(self,text):
518 """Match named parameters (kwargs) of the last open function"""
570 """Match named parameters (kwargs) of the last open function"""
519
571
520 if "." in text: # a parameter cannot be dotted
572 if "." in text: # a parameter cannot be dotted
521 return []
573 return []
522 try: regexp = self.__funcParamsRegex
574 try: regexp = self.__funcParamsRegex
523 except AttributeError:
575 except AttributeError:
524 regexp = self.__funcParamsRegex = re.compile(r'''
576 regexp = self.__funcParamsRegex = re.compile(r'''
525 '.*?' | # single quoted strings or
577 '.*?' | # single quoted strings or
526 ".*?" | # double quoted strings or
578 ".*?" | # double quoted strings or
527 \w+ | # identifier
579 \w+ | # identifier
528 \S # other characters
580 \S # other characters
529 ''', re.VERBOSE | re.DOTALL)
581 ''', re.VERBOSE | re.DOTALL)
530 # 1. find the nearest identifier that comes before an unclosed
582 # 1. find the nearest identifier that comes before an unclosed
531 # parenthesis e.g. for "foo (1+bar(x), pa", the candidate is "foo"
583 # parenthesis e.g. for "foo (1+bar(x), pa", the candidate is "foo"
532 tokens = regexp.findall(self.get_line_buffer())
584 tokens = regexp.findall(self.get_line_buffer())
533 tokens.reverse()
585 tokens.reverse()
534 iterTokens = iter(tokens); openPar = 0
586 iterTokens = iter(tokens); openPar = 0
535 for token in iterTokens:
587 for token in iterTokens:
536 if token == ')':
588 if token == ')':
537 openPar -= 1
589 openPar -= 1
538 elif token == '(':
590 elif token == '(':
539 openPar += 1
591 openPar += 1
540 if openPar > 0:
592 if openPar > 0:
541 # found the last unclosed parenthesis
593 # found the last unclosed parenthesis
542 break
594 break
543 else:
595 else:
544 return []
596 return []
545 # 2. Concatenate dotted names ("foo.bar" for "foo.bar(x, pa" )
597 # 2. Concatenate dotted names ("foo.bar" for "foo.bar(x, pa" )
546 ids = []
598 ids = []
547 isId = re.compile(r'\w+$').match
599 isId = re.compile(r'\w+$').match
548 while True:
600 while True:
549 try:
601 try:
550 ids.append(iterTokens.next())
602 ids.append(iterTokens.next())
551 if not isId(ids[-1]):
603 if not isId(ids[-1]):
552 ids.pop(); break
604 ids.pop(); break
553 if not iterTokens.next() == '.':
605 if not iterTokens.next() == '.':
554 break
606 break
555 except StopIteration:
607 except StopIteration:
556 break
608 break
557 # lookup the candidate callable matches either using global_matches
609 # lookup the candidate callable matches either using global_matches
558 # or attr_matches for dotted names
610 # or attr_matches for dotted names
559 if len(ids) == 1:
611 if len(ids) == 1:
560 callableMatches = self.global_matches(ids[0])
612 callableMatches = self.global_matches(ids[0])
561 else:
613 else:
562 callableMatches = self.attr_matches('.'.join(ids[::-1]))
614 callableMatches = self.attr_matches('.'.join(ids[::-1]))
563 argMatches = []
615 argMatches = []
564 for callableMatch in callableMatches:
616 for callableMatch in callableMatches:
565 try:
617 try:
566 namedArgs = self._default_arguments(eval(callableMatch,
618 namedArgs = self._default_arguments(eval(callableMatch,
567 self.namespace))
619 self.namespace))
568 except:
620 except:
569 continue
621 continue
570 for namedArg in namedArgs:
622 for namedArg in namedArgs:
571 if namedArg.startswith(text):
623 if namedArg.startswith(text):
572 argMatches.append("%s=" %namedArg)
624 argMatches.append("%s=" %namedArg)
573 return argMatches
625 return argMatches
574
626
575 def dispatch_custom_completer(self,text):
627 def dispatch_custom_completer(self,text):
576 #print "Custom! '%s' %s" % (text, self.custom_completers) # dbg
628 #print "Custom! '%s' %s" % (text, self.custom_completers) # dbg
577 line = self.full_lbuf
629 line = self.full_lbuf
578 if not line.strip():
630 if not line.strip():
579 return None
631 return None
580
632
581 event = Bunch()
633 event = Bunch()
582 event.line = line
634 event.line = line
583 event.symbol = text
635 event.symbol = text
584 cmd = line.split(None,1)[0]
636 cmd = line.split(None,1)[0]
585 event.command = cmd
637 event.command = cmd
586 #print "\ncustom:{%s]\n" % event # dbg
638 #print "\ncustom:{%s]\n" % event # dbg
587
639
588 # for foo etc, try also to find completer for %foo
640 # for foo etc, try also to find completer for %foo
589 if not cmd.startswith(self.magic_escape):
641 if not cmd.startswith(self.magic_escape):
590 try_magic = self.custom_completers.s_matches(
642 try_magic = self.custom_completers.s_matches(
591 self.magic_escape + cmd)
643 self.magic_escape + cmd)
592 else:
644 else:
593 try_magic = []
645 try_magic = []
594
646
595 for c in itertools.chain(self.custom_completers.s_matches(cmd),
647 for c in itertools.chain(self.custom_completers.s_matches(cmd),
596 try_magic,
648 try_magic,
597 self.custom_completers.flat_matches(self.lbuf)):
649 self.custom_completers.flat_matches(self.lbuf)):
598 #print "try",c # dbg
650 #print "try",c # dbg
599 try:
651 try:
600 res = c(event)
652 res = c(event)
601 # first, try case sensitive match
653 # first, try case sensitive match
602 withcase = [r for r in res if r.startswith(text)]
654 withcase = [r for r in res if r.startswith(text)]
603 if withcase:
655 if withcase:
604 return withcase
656 return withcase
605 # if none, then case insensitive ones are ok too
657 # if none, then case insensitive ones are ok too
606 text_low = text.lower()
658 text_low = text.lower()
607 return [r for r in res if r.lower().startswith(text_low)]
659 return [r for r in res if r.lower().startswith(text_low)]
608 except TryNext:
660 except TryNext:
609 pass
661 pass
610
662
611 return None
663 return None
612
664
613 def complete(self, text, line_buffer, cursor_pos=None):
665 def complete(self, text, line_buffer, cursor_pos=None):
614 """Return the state-th possible completion for 'text'.
666 """Return the state-th possible completion for 'text'.
615
667
616 This is called successively with state == 0, 1, 2, ... until it
668 This is called successively with state == 0, 1, 2, ... until it
617 returns None. The completion should begin with 'text'.
669 returns None. The completion should begin with 'text'.
618
670
619 Parameters
671 Parameters
620 ----------
672 ----------
621 text : string
673 text : string
622 Text to perform the completion on.
674 Text to perform the completion on.
623
675
624 line_buffer : string, optional
676 line_buffer : string, optional
625 If not given, the completer attempts to obtain the current line
677 If not given, the completer attempts to obtain the current line
626 buffer via readline. This keyword allows clients which are
678 buffer via readline. This keyword allows clients which are
627 requesting for text completions in non-readline contexts to inform
679 requesting for text completions in non-readline contexts to inform
628 the completer of the entire text.
680 the completer of the entire text.
629
681
630 cursor_pos : int, optional
682 cursor_pos : int, optional
631 Index of the cursor in the full line buffer. Should be provided by
683 Index of the cursor in the full line buffer. Should be provided by
632 remote frontends where kernel has no access to frontend state.
684 remote frontends where kernel has no access to frontend state.
633 """
685 """
634
686 #io.rprint('COMP', text, line_buffer, cursor_pos) # dbg
687
635 magic_escape = self.magic_escape
688 magic_escape = self.magic_escape
636 self.full_lbuf = line_buffer
689 self.full_lbuf = line_buffer
637 self.lbuf = self.full_lbuf[:cursor_pos]
690 self.lbuf = self.full_lbuf[:cursor_pos]
638
691
639 if text.startswith('~'):
692 if text.startswith('~'):
640 text = os.path.expanduser(text)
693 text = os.path.expanduser(text)
641
694
642 # Start with a clean slate of completions
695 # Start with a clean slate of completions
643 self.matches[:] = []
696 self.matches[:] = []
644 custom_res = self.dispatch_custom_completer(text)
697 custom_res = self.dispatch_custom_completer(text)
645 if custom_res is not None:
698 if custom_res is not None:
646 # did custom completers produce something?
699 # did custom completers produce something?
647 self.matches = custom_res
700 self.matches = custom_res
648 else:
701 else:
649 # Extend the list of completions with the results of each
702 # Extend the list of completions with the results of each
650 # matcher, so we return results to the user from all
703 # matcher, so we return results to the user from all
651 # namespaces.
704 # namespaces.
652 if self.merge_completions:
705 if self.merge_completions:
653 self.matches = []
706 self.matches = []
654 for matcher in self.matchers:
707 for matcher in self.matchers:
655 self.matches.extend(matcher(text))
708 self.matches.extend(matcher(text))
656 else:
709 else:
657 for matcher in self.matchers:
710 for matcher in self.matchers:
658 self.matches = matcher(text)
711 self.matches = matcher(text)
659 if self.matches:
712 if self.matches:
660 break
713 break
661 # FIXME: we should extend our api to return a dict with completions for
714 # FIXME: we should extend our api to return a dict with completions for
662 # different types of objects. The rlcomplete() method could then
715 # different types of objects. The rlcomplete() method could then
663 # simply collapse the dict into a list for readline, but we'd have
716 # simply collapse the dict into a list for readline, but we'd have
664 # richer completion semantics in other evironments.
717 # richer completion semantics in other evironments.
665 self.matches = sorted(set(self.matches))
718 self.matches = sorted(set(self.matches))
666 #from IPython.utils.io import rprint; rprint(self.matches) # dbg
719 #io.rprint('MATCHES', self.matches) # dbg
667 return self.matches
720 return self.matches
668
721
669 def rlcomplete(self, text, state):
722 def rlcomplete(self, text, state):
670 """Return the state-th possible completion for 'text'.
723 """Return the state-th possible completion for 'text'.
671
724
672 This is called successively with state == 0, 1, 2, ... until it
725 This is called successively with state == 0, 1, 2, ... until it
673 returns None. The completion should begin with 'text'.
726 returns None. The completion should begin with 'text'.
674
727
675 Parameters
728 Parameters
676 ----------
729 ----------
677 text : string
730 text : string
678 Text to perform the completion on.
731 Text to perform the completion on.
679
732
680 state : int
733 state : int
681 Counter used by readline.
734 Counter used by readline.
682
683 """
735 """
684
685 #print "rlcomplete! '%s' %s" % (text, state) # dbg
686
687 if state==0:
736 if state==0:
737
688 self.full_lbuf = line_buffer = self.get_line_buffer()
738 self.full_lbuf = line_buffer = self.get_line_buffer()
689 cursor_pos = self.get_endidx()
739 cursor_pos = self.get_endidx()
690
740
741 #io.rprint("\nRLCOMPLETE: %r %r %r" %
742 # (text, line_buffer, cursor_pos) ) # dbg
743
691 # if there is only a tab on a line with only whitespace, instead of
744 # if there is only a tab on a line with only whitespace, instead of
692 # the mostly useless 'do you want to see all million completions'
745 # the mostly useless 'do you want to see all million completions'
693 # message, just do the right thing and give the user his tab!
746 # message, just do the right thing and give the user his tab!
694 # Incidentally, this enables pasting of tabbed text from an editor
747 # Incidentally, this enables pasting of tabbed text from an editor
695 # (as long as autoindent is off).
748 # (as long as autoindent is off).
696
749
697 # It should be noted that at least pyreadline still shows file
750 # It should be noted that at least pyreadline still shows file
698 # completions - is there a way around it?
751 # completions - is there a way around it?
699
752
700 # don't apply this on 'dumb' terminals, such as emacs buffers, so
753 # don't apply this on 'dumb' terminals, such as emacs buffers, so
701 # we don't interfere with their own tab-completion mechanism.
754 # we don't interfere with their own tab-completion mechanism.
702 if not (self.dumb_terminal or self.full_lbuf.strip()):
755 if not (self.dumb_terminal or line_buffer.strip()):
703 self.readline.insert_text('\t')
756 self.readline.insert_text('\t')
704 sys.stdout.flush()
757 sys.stdout.flush()
705 return None
758 return None
706
759
707 # This method computes the self.matches array
760 # This method computes the self.matches array
708 self.complete(text, line_buffer, cursor_pos)
761 self.complete(text, line_buffer, cursor_pos)
709
762
710 # Debug version, since readline silences all exceptions making it
763 # Debug version, since readline silences all exceptions making it
711 # impossible to debug any problem in the above code
764 # impossible to debug any problem in the above code
712
765
713 ## try:
766 ## try:
714 ## self.complete(text, line_buffer, cursor_pos)
767 ## self.complete(text, line_buffer, cursor_pos)
715 ## except:
768 ## except:
716 ## import traceback; traceback.print_exc()
769 ## import traceback; traceback.print_exc()
717
770
718 try:
771 try:
719 return self.matches[state]
772 return self.matches[state]
720 except IndexError:
773 except IndexError:
721 return None
774 return None
722
@@ -1,35 +1,84 b''
1 """Tests for the IPython tab-completion machinery.
1 """Tests for the IPython tab-completion machinery.
2 """
2 """
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Module imports
4 # Module imports
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6
6
7 # stdlib
7 # stdlib
8 import sys
8 import sys
9 import unittest
9
10
10 # third party
11 # third party
11 import nose.tools as nt
12 import nose.tools as nt
12
13
13 # our own packages
14 # our own packages
14 from IPython.core import completer
15 from IPython.core import completer
15
16
16 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
17 # Test functions
18 # Test functions
18 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
19 def test_protect_filename():
20 def test_protect_filename():
20 pairs = [ ('abc','abc'),
21 pairs = [ ('abc','abc'),
21 (' abc',r'\ abc'),
22 (' abc',r'\ abc'),
22 ('a bc',r'a\ bc'),
23 ('a bc',r'a\ bc'),
23 ('a bc',r'a\ \ bc'),
24 ('a bc',r'a\ \ bc'),
24 (' bc',r'\ \ bc'),
25 (' bc',r'\ \ bc'),
25 ]
26 ]
26 # On posix, we also protect parens
27 # On posix, we also protect parens
27 if sys.platform != 'win32':
28 if sys.platform != 'win32':
28 pairs.extend( [('a(bc',r'a\(bc'),
29 pairs.extend( [('a(bc',r'a\(bc'),
29 ('a)bc',r'a\)bc'),
30 ('a)bc',r'a\)bc'),
30 ('a( )bc',r'a\(\ \)bc'),
31 ('a( )bc',r'a\(\ \)bc'),
31 ] )
32 ] )
32 # run the actual tests
33 # run the actual tests
33 for s1, s2 in pairs:
34 for s1, s2 in pairs:
34 s1p = completer.protect_filename(s1)
35 s1p = completer.protect_filename(s1)
35 nt.assert_equals(s1p, s2)
36 nt.assert_equals(s1p, s2)
37
38
39 def check_line_split(splitter, test_specs):
40 for part1, part2, split in test_specs:
41 cursor_pos = len(part1)
42 line = part1+part2
43 out = splitter.split_line(line, cursor_pos)
44 nt.assert_equal(out, split)
45
46
47 def test_line_split():
48 """Basice line splitter test with default specs."""
49 sp = completer.CompletionSplitter()
50 # The format of the test specs is: part1, part2, expected answer. Parts 1
51 # and 2 are joined into the 'line' sent to the splitter, as if the cursor
52 # was at the end of part1. So an empty part2 represents someone hitting
53 # tab at the end of the line, the most common case.
54 t = [('run some/scrip', '', 'some/scrip'),
55 ('run scripts/er', 'ror.py foo', 'scripts/er'),
56 ('echo $HOM', '', 'HOM'),
57 ('print sys.pa', '', 'sys.pa'),
58 ('print(sys.pa', '', 'sys.pa'),
59 ("execfile('scripts/er", '', 'scripts/er'),
60 ('a[x.', '', 'x.'),
61 ('a[x.', 'y', 'x.'),
62 ('cd "some_file/', '', 'some_file/'),
63 ]
64 check_line_split(sp, t)
65
66
67 class CompletionSplitterTestCase(unittest.TestCase):
68 def setUp(self):
69 self.sp = completer.CompletionSplitter()
70
71 def test_delim_setting(self):
72 self.sp.delims = ' '
73 # Validate that property handling works ok
74 nt.assert_equal(self.sp.delims, ' ')
75 nt.assert_equal(self.sp.delim_expr, '[\ ]')
76
77 def test_spaces(self):
78 """Test with only spaces as split chars."""
79 self.sp.delims = ' '
80 t = [('foo', '', 'foo'),
81 ('run foo', '', 'foo'),
82 ('run foo', 'bar', 'foo'),
83 ]
84 check_line_split(self.sp, t)
General Comments 0
You need to be logged in to leave comments. Login now