##// END OF EJS Templates
Minor bug fixes and comments to address review....
Brian Granger -
Show More
@@ -1,642 +1,642 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 #
51 #
52 # Since this file is essentially a minimally modified copy of the rlcompleter
52 # Since this file is essentially a minimally modified copy of the rlcompleter
53 # module which is part of the standard Python distribution, I assume that the
53 # module which is part of the standard Python distribution, I assume that the
54 # proper procedure is to maintain its copyright as belonging to the Python
54 # proper procedure is to maintain its copyright as belonging to the Python
55 # Software Foundation (in addition to my own, for all new code).
55 # Software Foundation (in addition to my own, for all new code).
56 #
56 #
57 # Copyright (C) 2001 Python Software Foundation, www.python.org
57 # Copyright (C) 2001 Python Software Foundation, www.python.org
58 # Copyright (C) 2001-2006 Fernando Perez. <fperez@colorado.edu>
58 # Copyright (C) 2001-2006 Fernando Perez. <fperez@colorado.edu>
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
64
65 import __builtin__
65 import __builtin__
66 import __main__
66 import __main__
67 import glob
67 import glob
68 import itertools
68 import keyword
69 import keyword
69 import os
70 import os
70 import re
71 import re
71 import shlex
72 import shlex
72 import sys
73 import sys
73 import itertools
74 import types
74 import types
75
75
76 from IPython.core.error import TryNext
76 from IPython.core.error import TryNext
77 from IPython.core.prefilter import ESC_MAGIC
77 from IPython.core.prefilter import ESC_MAGIC
78
78
79 import IPython.utils.rlineimpl as readline
79 import IPython.utils.rlineimpl as readline
80 from IPython.utils.ipstruct import Struct
80 from IPython.utils.ipstruct import Struct
81 from IPython.utils import generics
81 from IPython.utils import generics
82
82
83 # Python 2.4 offers sets as a builtin
83 # Python 2.4 offers sets as a builtin
84 try:
84 try:
85 set()
85 set()
86 except NameError:
86 except NameError:
87 from sets import Set as set
87 from sets import Set as set
88
88
89 from IPython.utils.genutils import debugx, dir2
89 from IPython.utils.genutils import debugx, dir2
90
90
91 __all__ = ['Completer','IPCompleter']
91 __all__ = ['Completer','IPCompleter']
92
92
93 class Completer:
93 class Completer:
94 def __init__(self,namespace=None,global_namespace=None):
94 def __init__(self,namespace=None,global_namespace=None):
95 """Create a new completer for the command line.
95 """Create a new completer for the command line.
96
96
97 Completer([namespace,global_namespace]) -> completer instance.
97 Completer([namespace,global_namespace]) -> completer instance.
98
98
99 If unspecified, the default namespace where completions are performed
99 If unspecified, the default namespace where completions are performed
100 is __main__ (technically, __main__.__dict__). Namespaces should be
100 is __main__ (technically, __main__.__dict__). Namespaces should be
101 given as dictionaries.
101 given as dictionaries.
102
102
103 An optional second namespace can be given. This allows the completer
103 An optional second namespace can be given. This allows the completer
104 to handle cases where both the local and global scopes need to be
104 to handle cases where both the local and global scopes need to be
105 distinguished.
105 distinguished.
106
106
107 Completer instances should be used as the completion mechanism of
107 Completer instances should be used as the completion mechanism of
108 readline via the set_completer() call:
108 readline via the set_completer() call:
109
109
110 readline.set_completer(Completer(my_namespace).complete)
110 readline.set_completer(Completer(my_namespace).complete)
111 """
111 """
112
112
113 # Don't bind to namespace quite yet, but flag whether the user wants a
113 # Don't bind to namespace quite yet, but flag whether the user wants a
114 # specific namespace or to use __main__.__dict__. This will allow us
114 # specific namespace or to use __main__.__dict__. This will allow us
115 # to bind to __main__.__dict__ at completion time, not now.
115 # to bind to __main__.__dict__ at completion time, not now.
116 if namespace is None:
116 if namespace is None:
117 self.use_main_ns = 1
117 self.use_main_ns = 1
118 else:
118 else:
119 self.use_main_ns = 0
119 self.use_main_ns = 0
120 self.namespace = namespace
120 self.namespace = namespace
121
121
122 # The global namespace, if given, can be bound directly
122 # The global namespace, if given, can be bound directly
123 if global_namespace is None:
123 if global_namespace is None:
124 self.global_namespace = {}
124 self.global_namespace = {}
125 else:
125 else:
126 self.global_namespace = global_namespace
126 self.global_namespace = global_namespace
127
127
128 def complete(self, text, state):
128 def complete(self, text, state):
129 """Return the next possible completion for 'text'.
129 """Return the next possible completion for 'text'.
130
130
131 This is called successively with state == 0, 1, 2, ... until it
131 This is called successively with state == 0, 1, 2, ... until it
132 returns None. The completion should begin with 'text'.
132 returns None. The completion should begin with 'text'.
133
133
134 """
134 """
135 if self.use_main_ns:
135 if self.use_main_ns:
136 self.namespace = __main__.__dict__
136 self.namespace = __main__.__dict__
137
137
138 if state == 0:
138 if state == 0:
139 if "." in text:
139 if "." in text:
140 self.matches = self.attr_matches(text)
140 self.matches = self.attr_matches(text)
141 else:
141 else:
142 self.matches = self.global_matches(text)
142 self.matches = self.global_matches(text)
143 try:
143 try:
144 return self.matches[state]
144 return self.matches[state]
145 except IndexError:
145 except IndexError:
146 return None
146 return None
147
147
148 def global_matches(self, text):
148 def global_matches(self, text):
149 """Compute matches when text is a simple name.
149 """Compute matches when text is a simple name.
150
150
151 Return a list of all keywords, built-in functions and names currently
151 Return a list of all keywords, built-in functions and names currently
152 defined in self.namespace or self.global_namespace that match.
152 defined in self.namespace or self.global_namespace that match.
153
153
154 """
154 """
155 matches = []
155 matches = []
156 match_append = matches.append
156 match_append = matches.append
157 n = len(text)
157 n = len(text)
158 for lst in [keyword.kwlist,
158 for lst in [keyword.kwlist,
159 __builtin__.__dict__.keys(),
159 __builtin__.__dict__.keys(),
160 self.namespace.keys(),
160 self.namespace.keys(),
161 self.global_namespace.keys()]:
161 self.global_namespace.keys()]:
162 for word in lst:
162 for word in lst:
163 if word[:n] == text and word != "__builtins__":
163 if word[:n] == text and word != "__builtins__":
164 match_append(word)
164 match_append(word)
165 return matches
165 return matches
166
166
167 def attr_matches(self, text):
167 def attr_matches(self, text):
168 """Compute matches when text contains a dot.
168 """Compute matches when text contains a dot.
169
169
170 Assuming the text is of the form NAME.NAME....[NAME], and is
170 Assuming the text is of the form NAME.NAME....[NAME], and is
171 evaluatable in self.namespace or self.global_namespace, it will be
171 evaluatable in self.namespace or self.global_namespace, it will be
172 evaluated and its attributes (as revealed by dir()) are used as
172 evaluated and its attributes (as revealed by dir()) are used as
173 possible completions. (For class instances, class members are are
173 possible completions. (For class instances, class members are are
174 also considered.)
174 also considered.)
175
175
176 WARNING: this can still invoke arbitrary C code, if an object
176 WARNING: this can still invoke arbitrary C code, if an object
177 with a __getattr__ hook is evaluated.
177 with a __getattr__ hook is evaluated.
178
178
179 """
179 """
180 import re
180 import re
181
181
182 # Another option, seems to work great. Catches things like ''.<tab>
182 # Another option, seems to work great. Catches things like ''.<tab>
183 m = re.match(r"(\S+(\.\w+)*)\.(\w*)$", text)
183 m = re.match(r"(\S+(\.\w+)*)\.(\w*)$", text)
184
184
185 if not m:
185 if not m:
186 return []
186 return []
187
187
188 expr, attr = m.group(1, 3)
188 expr, attr = m.group(1, 3)
189 try:
189 try:
190 obj = eval(expr, self.namespace)
190 obj = eval(expr, self.namespace)
191 except:
191 except:
192 try:
192 try:
193 obj = eval(expr, self.global_namespace)
193 obj = eval(expr, self.global_namespace)
194 except:
194 except:
195 return []
195 return []
196
196
197 words = dir2(obj)
197 words = dir2(obj)
198
198
199 try:
199 try:
200 words = generics.complete_object(obj, words)
200 words = generics.complete_object(obj, words)
201 except TryNext:
201 except TryNext:
202 pass
202 pass
203 # Build match list to return
203 # Build match list to return
204 n = len(attr)
204 n = len(attr)
205 res = ["%s.%s" % (expr, w) for w in words if w[:n] == attr ]
205 res = ["%s.%s" % (expr, w) for w in words if w[:n] == attr ]
206 return res
206 return res
207
207
208 class IPCompleter(Completer):
208 class IPCompleter(Completer):
209 """Extension of the completer class with IPython-specific features"""
209 """Extension of the completer class with IPython-specific features"""
210
210
211 def __init__(self,shell,namespace=None,global_namespace=None,
211 def __init__(self,shell,namespace=None,global_namespace=None,
212 omit__names=0,alias_table=None):
212 omit__names=0,alias_table=None):
213 """IPCompleter() -> completer
213 """IPCompleter() -> completer
214
214
215 Return a completer object suitable for use by the readline library
215 Return a completer object suitable for use by the readline library
216 via readline.set_completer().
216 via readline.set_completer().
217
217
218 Inputs:
218 Inputs:
219
219
220 - shell: a pointer to the ipython shell itself. This is needed
220 - shell: a pointer to the ipython shell itself. This is needed
221 because this completer knows about magic functions, and those can
221 because this completer knows about magic functions, and those can
222 only be accessed via the ipython instance.
222 only be accessed via the ipython instance.
223
223
224 - namespace: an optional dict where completions are performed.
224 - namespace: an optional dict where completions are performed.
225
225
226 - global_namespace: secondary optional dict for completions, to
226 - global_namespace: secondary optional dict for completions, to
227 handle cases (such as IPython embedded inside functions) where
227 handle cases (such as IPython embedded inside functions) where
228 both Python scopes are visible.
228 both Python scopes are visible.
229
229
230 - The optional omit__names parameter sets the completer to omit the
230 - The optional omit__names parameter sets the completer to omit the
231 'magic' names (__magicname__) for python objects unless the text
231 'magic' names (__magicname__) for python objects unless the text
232 to be completed explicitly starts with one or more underscores.
232 to be completed explicitly starts with one or more underscores.
233
233
234 - If alias_table is supplied, it should be a dictionary of aliases
234 - If alias_table is supplied, it should be a dictionary of aliases
235 to complete. """
235 to complete. """
236
236
237 Completer.__init__(self,namespace,global_namespace)
237 Completer.__init__(self,namespace,global_namespace)
238 self.magic_prefix = shell.name+'.magic_'
238 self.magic_prefix = shell.name+'.magic_'
239 self.magic_escape = ESC_MAGIC
239 self.magic_escape = ESC_MAGIC
240 self.readline = readline
240 self.readline = readline
241 delims = self.readline.get_completer_delims()
241 delims = self.readline.get_completer_delims()
242 delims = delims.replace(self.magic_escape,'')
242 delims = delims.replace(self.magic_escape,'')
243 self.readline.set_completer_delims(delims)
243 self.readline.set_completer_delims(delims)
244 self.get_line_buffer = self.readline.get_line_buffer
244 self.get_line_buffer = self.readline.get_line_buffer
245 self.get_endidx = self.readline.get_endidx
245 self.get_endidx = self.readline.get_endidx
246 self.omit__names = omit__names
246 self.omit__names = omit__names
247 self.merge_completions = shell.readline_merge_completions
247 self.merge_completions = shell.readline_merge_completions
248 if alias_table is None:
248 if alias_table is None:
249 alias_table = {}
249 alias_table = {}
250 self.alias_table = alias_table
250 self.alias_table = alias_table
251 # Regexp to split filenames with spaces in them
251 # Regexp to split filenames with spaces in them
252 self.space_name_re = re.compile(r'([^\\] )')
252 self.space_name_re = re.compile(r'([^\\] )')
253 # Hold a local ref. to glob.glob for speed
253 # Hold a local ref. to glob.glob for speed
254 self.glob = glob.glob
254 self.glob = glob.glob
255
255
256 # Determine if we are running on 'dumb' terminals, like (X)Emacs
256 # Determine if we are running on 'dumb' terminals, like (X)Emacs
257 # buffers, to avoid completion problems.
257 # buffers, to avoid completion problems.
258 term = os.environ.get('TERM','xterm')
258 term = os.environ.get('TERM','xterm')
259 self.dumb_terminal = term in ['dumb','emacs']
259 self.dumb_terminal = term in ['dumb','emacs']
260
260
261 # Special handling of backslashes needed in win32 platforms
261 # Special handling of backslashes needed in win32 platforms
262 if sys.platform == "win32":
262 if sys.platform == "win32":
263 self.clean_glob = self._clean_glob_win32
263 self.clean_glob = self._clean_glob_win32
264 else:
264 else:
265 self.clean_glob = self._clean_glob
265 self.clean_glob = self._clean_glob
266 self.matchers = [self.python_matches,
266 self.matchers = [self.python_matches,
267 self.file_matches,
267 self.file_matches,
268 self.alias_matches,
268 self.alias_matches,
269 self.python_func_kw_matches]
269 self.python_func_kw_matches]
270
270
271
271
272 # Code contributed by Alex Schmolck, for ipython/emacs integration
272 # Code contributed by Alex Schmolck, for ipython/emacs integration
273 def all_completions(self, text):
273 def all_completions(self, text):
274 """Return all possible completions for the benefit of emacs."""
274 """Return all possible completions for the benefit of emacs."""
275
275
276 completions = []
276 completions = []
277 comp_append = completions.append
277 comp_append = completions.append
278 try:
278 try:
279 for i in xrange(sys.maxint):
279 for i in xrange(sys.maxint):
280 res = self.complete(text, i)
280 res = self.complete(text, i)
281
281
282 if not res: break
282 if not res: break
283
283
284 comp_append(res)
284 comp_append(res)
285 #XXX workaround for ``notDefined.<tab>``
285 #XXX workaround for ``notDefined.<tab>``
286 except NameError:
286 except NameError:
287 pass
287 pass
288 return completions
288 return completions
289 # /end Alex Schmolck code.
289 # /end Alex Schmolck code.
290
290
291 def _clean_glob(self,text):
291 def _clean_glob(self,text):
292 return self.glob("%s*" % text)
292 return self.glob("%s*" % text)
293
293
294 def _clean_glob_win32(self,text):
294 def _clean_glob_win32(self,text):
295 return [f.replace("\\","/")
295 return [f.replace("\\","/")
296 for f in self.glob("%s*" % text)]
296 for f in self.glob("%s*" % text)]
297
297
298 def file_matches(self, text):
298 def file_matches(self, text):
299 """Match filenames, expanding ~USER type strings.
299 """Match filenames, expanding ~USER type strings.
300
300
301 Most of the seemingly convoluted logic in this completer is an
301 Most of the seemingly convoluted logic in this completer is an
302 attempt to handle filenames with spaces in them. And yet it's not
302 attempt to handle filenames with spaces in them. And yet it's not
303 quite perfect, because Python's readline doesn't expose all of the
303 quite perfect, because Python's readline doesn't expose all of the
304 GNU readline details needed for this to be done correctly.
304 GNU readline details needed for this to be done correctly.
305
305
306 For a filename with a space in it, the printed completions will be
306 For a filename with a space in it, the printed completions will be
307 only the parts after what's already been typed (instead of the
307 only the parts after what's already been typed (instead of the
308 full completions, as is normally done). I don't think with the
308 full completions, as is normally done). I don't think with the
309 current (as of Python 2.3) Python readline it's possible to do
309 current (as of Python 2.3) Python readline it's possible to do
310 better."""
310 better."""
311
311
312 #print 'Completer->file_matches: <%s>' % text # dbg
312 #print 'Completer->file_matches: <%s>' % text # dbg
313
313
314 # chars that require escaping with backslash - i.e. chars
314 # chars that require escaping with backslash - i.e. chars
315 # that readline treats incorrectly as delimiters, but we
315 # that readline treats incorrectly as delimiters, but we
316 # don't want to treat as delimiters in filename matching
316 # don't want to treat as delimiters in filename matching
317 # when escaped with backslash
317 # when escaped with backslash
318
318
319 if sys.platform == 'win32':
319 if sys.platform == 'win32':
320 protectables = ' '
320 protectables = ' '
321 else:
321 else:
322 protectables = ' ()'
322 protectables = ' ()'
323
323
324 if text.startswith('!'):
324 if text.startswith('!'):
325 text = text[1:]
325 text = text[1:]
326 text_prefix = '!'
326 text_prefix = '!'
327 else:
327 else:
328 text_prefix = ''
328 text_prefix = ''
329
329
330 def protect_filename(s):
330 def protect_filename(s):
331 return "".join([(ch in protectables and '\\' + ch or ch)
331 return "".join([(ch in protectables and '\\' + ch or ch)
332 for ch in s])
332 for ch in s])
333
333
334 def single_dir_expand(matches):
334 def single_dir_expand(matches):
335 "Recursively expand match lists containing a single dir."
335 "Recursively expand match lists containing a single dir."
336
336
337 if len(matches) == 1 and os.path.isdir(matches[0]):
337 if len(matches) == 1 and os.path.isdir(matches[0]):
338 # Takes care of links to directories also. Use '/'
338 # Takes care of links to directories also. Use '/'
339 # explicitly, even under Windows, so that name completions
339 # explicitly, even under Windows, so that name completions
340 # don't end up escaped.
340 # don't end up escaped.
341 d = matches[0]
341 d = matches[0]
342 if d[-1] in ['/','\\']:
342 if d[-1] in ['/','\\']:
343 d = d[:-1]
343 d = d[:-1]
344
344
345 subdirs = os.listdir(d)
345 subdirs = os.listdir(d)
346 if subdirs:
346 if subdirs:
347 matches = [ (d + '/' + p) for p in subdirs]
347 matches = [ (d + '/' + p) for p in subdirs]
348 return single_dir_expand(matches)
348 return single_dir_expand(matches)
349 else:
349 else:
350 return matches
350 return matches
351 else:
351 else:
352 return matches
352 return matches
353
353
354 lbuf = self.lbuf
354 lbuf = self.lbuf
355 open_quotes = 0 # track strings with open quotes
355 open_quotes = 0 # track strings with open quotes
356 try:
356 try:
357 lsplit = shlex.split(lbuf)[-1]
357 lsplit = shlex.split(lbuf)[-1]
358 except ValueError:
358 except ValueError:
359 # typically an unmatched ", or backslash without escaped char.
359 # typically an unmatched ", or backslash without escaped char.
360 if lbuf.count('"')==1:
360 if lbuf.count('"')==1:
361 open_quotes = 1
361 open_quotes = 1
362 lsplit = lbuf.split('"')[-1]
362 lsplit = lbuf.split('"')[-1]
363 elif lbuf.count("'")==1:
363 elif lbuf.count("'")==1:
364 open_quotes = 1
364 open_quotes = 1
365 lsplit = lbuf.split("'")[-1]
365 lsplit = lbuf.split("'")[-1]
366 else:
366 else:
367 return []
367 return []
368 except IndexError:
368 except IndexError:
369 # tab pressed on empty line
369 # tab pressed on empty line
370 lsplit = ""
370 lsplit = ""
371
371
372 if lsplit != protect_filename(lsplit):
372 if lsplit != protect_filename(lsplit):
373 # if protectables are found, do matching on the whole escaped
373 # if protectables are found, do matching on the whole escaped
374 # name
374 # name
375 has_protectables = 1
375 has_protectables = 1
376 text0,text = text,lsplit
376 text0,text = text,lsplit
377 else:
377 else:
378 has_protectables = 0
378 has_protectables = 0
379 text = os.path.expanduser(text)
379 text = os.path.expanduser(text)
380
380
381 if text == "":
381 if text == "":
382 return [text_prefix + protect_filename(f) for f in self.glob("*")]
382 return [text_prefix + protect_filename(f) for f in self.glob("*")]
383
383
384 m0 = self.clean_glob(text.replace('\\',''))
384 m0 = self.clean_glob(text.replace('\\',''))
385 if has_protectables:
385 if has_protectables:
386 # If we had protectables, we need to revert our changes to the
386 # If we had protectables, we need to revert our changes to the
387 # beginning of filename so that we don't double-write the part
387 # beginning of filename so that we don't double-write the part
388 # of the filename we have so far
388 # of the filename we have so far
389 len_lsplit = len(lsplit)
389 len_lsplit = len(lsplit)
390 matches = [text_prefix + text0 +
390 matches = [text_prefix + text0 +
391 protect_filename(f[len_lsplit:]) for f in m0]
391 protect_filename(f[len_lsplit:]) for f in m0]
392 else:
392 else:
393 if open_quotes:
393 if open_quotes:
394 # if we have a string with an open quote, we don't need to
394 # if we have a string with an open quote, we don't need to
395 # protect the names at all (and we _shouldn't_, as it
395 # protect the names at all (and we _shouldn't_, as it
396 # would cause bugs when the filesystem call is made).
396 # would cause bugs when the filesystem call is made).
397 matches = m0
397 matches = m0
398 else:
398 else:
399 matches = [text_prefix +
399 matches = [text_prefix +
400 protect_filename(f) for f in m0]
400 protect_filename(f) for f in m0]
401
401
402 #print 'mm',matches # dbg
402 #print 'mm',matches # dbg
403 return single_dir_expand(matches)
403 return single_dir_expand(matches)
404
404
405 def alias_matches(self, text):
405 def alias_matches(self, text):
406 """Match internal system aliases"""
406 """Match internal system aliases"""
407 #print 'Completer->alias_matches:',text,'lb',self.lbuf # dbg
407 #print 'Completer->alias_matches:',text,'lb',self.lbuf # dbg
408
408
409 # if we are not in the first 'item', alias matching
409 # if we are not in the first 'item', alias matching
410 # doesn't make sense - unless we are starting with 'sudo' command.
410 # doesn't make sense - unless we are starting with 'sudo' command.
411 if ' ' in self.lbuf.lstrip() and not self.lbuf.lstrip().startswith('sudo'):
411 if ' ' in self.lbuf.lstrip() and not self.lbuf.lstrip().startswith('sudo'):
412 return []
412 return []
413 text = os.path.expanduser(text)
413 text = os.path.expanduser(text)
414 aliases = self.alias_table.keys()
414 aliases = self.alias_table.keys()
415 if text == "":
415 if text == "":
416 return aliases
416 return aliases
417 else:
417 else:
418 return [alias for alias in aliases if alias.startswith(text)]
418 return [alias for alias in aliases if alias.startswith(text)]
419
419
420 def python_matches(self,text):
420 def python_matches(self,text):
421 """Match attributes or global python names"""
421 """Match attributes or global python names"""
422
422
423 #print 'Completer->python_matches, txt=<%s>' % text # dbg
423 #print 'Completer->python_matches, txt=<%s>' % text # dbg
424 if "." in text:
424 if "." in text:
425 try:
425 try:
426 matches = self.attr_matches(text)
426 matches = self.attr_matches(text)
427 if text.endswith('.') and self.omit__names:
427 if text.endswith('.') and self.omit__names:
428 if self.omit__names == 1:
428 if self.omit__names == 1:
429 # true if txt is _not_ a __ name, false otherwise:
429 # true if txt is _not_ a __ name, false otherwise:
430 no__name = (lambda txt:
430 no__name = (lambda txt:
431 re.match(r'.*\.__.*?__',txt) is None)
431 re.match(r'.*\.__.*?__',txt) is None)
432 else:
432 else:
433 # true if txt is _not_ a _ name, false otherwise:
433 # true if txt is _not_ a _ name, false otherwise:
434 no__name = (lambda txt:
434 no__name = (lambda txt:
435 re.match(r'.*\._.*?',txt) is None)
435 re.match(r'.*\._.*?',txt) is None)
436 matches = filter(no__name, matches)
436 matches = filter(no__name, matches)
437 except NameError:
437 except NameError:
438 # catches <undefined attributes>.<tab>
438 # catches <undefined attributes>.<tab>
439 matches = []
439 matches = []
440 else:
440 else:
441 matches = self.global_matches(text)
441 matches = self.global_matches(text)
442 # this is so completion finds magics when automagic is on:
442 # this is so completion finds magics when automagic is on:
443 if (matches == [] and
443 if (matches == [] and
444 not text.startswith(os.sep) and
444 not text.startswith(os.sep) and
445 not ' ' in self.lbuf):
445 not ' ' in self.lbuf):
446 matches = self.attr_matches(self.magic_prefix+text)
446 matches = self.attr_matches(self.magic_prefix+text)
447 return matches
447 return matches
448
448
449 def _default_arguments(self, obj):
449 def _default_arguments(self, obj):
450 """Return the list of default arguments of obj if it is callable,
450 """Return the list of default arguments of obj if it is callable,
451 or empty list otherwise."""
451 or empty list otherwise."""
452
452
453 if not (inspect.isfunction(obj) or inspect.ismethod(obj)):
453 if not (inspect.isfunction(obj) or inspect.ismethod(obj)):
454 # for classes, check for __init__,__new__
454 # for classes, check for __init__,__new__
455 if inspect.isclass(obj):
455 if inspect.isclass(obj):
456 obj = (getattr(obj,'__init__',None) or
456 obj = (getattr(obj,'__init__',None) or
457 getattr(obj,'__new__',None))
457 getattr(obj,'__new__',None))
458 # for all others, check if they are __call__able
458 # for all others, check if they are __call__able
459 elif hasattr(obj, '__call__'):
459 elif hasattr(obj, '__call__'):
460 obj = obj.__call__
460 obj = obj.__call__
461 # XXX: is there a way to handle the builtins ?
461 # XXX: is there a way to handle the builtins ?
462 try:
462 try:
463 args,_,_1,defaults = inspect.getargspec(obj)
463 args,_,_1,defaults = inspect.getargspec(obj)
464 if defaults:
464 if defaults:
465 return args[-len(defaults):]
465 return args[-len(defaults):]
466 except TypeError: pass
466 except TypeError: pass
467 return []
467 return []
468
468
469 def python_func_kw_matches(self,text):
469 def python_func_kw_matches(self,text):
470 """Match named parameters (kwargs) of the last open function"""
470 """Match named parameters (kwargs) of the last open function"""
471
471
472 if "." in text: # a parameter cannot be dotted
472 if "." in text: # a parameter cannot be dotted
473 return []
473 return []
474 try: regexp = self.__funcParamsRegex
474 try: regexp = self.__funcParamsRegex
475 except AttributeError:
475 except AttributeError:
476 regexp = self.__funcParamsRegex = re.compile(r'''
476 regexp = self.__funcParamsRegex = re.compile(r'''
477 '.*?' | # single quoted strings or
477 '.*?' | # single quoted strings or
478 ".*?" | # double quoted strings or
478 ".*?" | # double quoted strings or
479 \w+ | # identifier
479 \w+ | # identifier
480 \S # other characters
480 \S # other characters
481 ''', re.VERBOSE | re.DOTALL)
481 ''', re.VERBOSE | re.DOTALL)
482 # 1. find the nearest identifier that comes before an unclosed
482 # 1. find the nearest identifier that comes before an unclosed
483 # parenthesis e.g. for "foo (1+bar(x), pa", the candidate is "foo"
483 # parenthesis e.g. for "foo (1+bar(x), pa", the candidate is "foo"
484 tokens = regexp.findall(self.get_line_buffer())
484 tokens = regexp.findall(self.get_line_buffer())
485 tokens.reverse()
485 tokens.reverse()
486 iterTokens = iter(tokens); openPar = 0
486 iterTokens = iter(tokens); openPar = 0
487 for token in iterTokens:
487 for token in iterTokens:
488 if token == ')':
488 if token == ')':
489 openPar -= 1
489 openPar -= 1
490 elif token == '(':
490 elif token == '(':
491 openPar += 1
491 openPar += 1
492 if openPar > 0:
492 if openPar > 0:
493 # found the last unclosed parenthesis
493 # found the last unclosed parenthesis
494 break
494 break
495 else:
495 else:
496 return []
496 return []
497 # 2. Concatenate dotted names ("foo.bar" for "foo.bar(x, pa" )
497 # 2. Concatenate dotted names ("foo.bar" for "foo.bar(x, pa" )
498 ids = []
498 ids = []
499 isId = re.compile(r'\w+$').match
499 isId = re.compile(r'\w+$').match
500 while True:
500 while True:
501 try:
501 try:
502 ids.append(iterTokens.next())
502 ids.append(iterTokens.next())
503 if not isId(ids[-1]):
503 if not isId(ids[-1]):
504 ids.pop(); break
504 ids.pop(); break
505 if not iterTokens.next() == '.':
505 if not iterTokens.next() == '.':
506 break
506 break
507 except StopIteration:
507 except StopIteration:
508 break
508 break
509 # lookup the candidate callable matches either using global_matches
509 # lookup the candidate callable matches either using global_matches
510 # or attr_matches for dotted names
510 # or attr_matches for dotted names
511 if len(ids) == 1:
511 if len(ids) == 1:
512 callableMatches = self.global_matches(ids[0])
512 callableMatches = self.global_matches(ids[0])
513 else:
513 else:
514 callableMatches = self.attr_matches('.'.join(ids[::-1]))
514 callableMatches = self.attr_matches('.'.join(ids[::-1]))
515 argMatches = []
515 argMatches = []
516 for callableMatch in callableMatches:
516 for callableMatch in callableMatches:
517 try: namedArgs = self._default_arguments(eval(callableMatch,
517 try: namedArgs = self._default_arguments(eval(callableMatch,
518 self.namespace))
518 self.namespace))
519 except: continue
519 except: continue
520 for namedArg in namedArgs:
520 for namedArg in namedArgs:
521 if namedArg.startswith(text):
521 if namedArg.startswith(text):
522 argMatches.append("%s=" %namedArg)
522 argMatches.append("%s=" %namedArg)
523 return argMatches
523 return argMatches
524
524
525 def dispatch_custom_completer(self,text):
525 def dispatch_custom_completer(self,text):
526 #print "Custom! '%s' %s" % (text, self.custom_completers) # dbg
526 #print "Custom! '%s' %s" % (text, self.custom_completers) # dbg
527 line = self.full_lbuf
527 line = self.full_lbuf
528 if not line.strip():
528 if not line.strip():
529 return None
529 return None
530
530
531 event = Struct()
531 event = Struct()
532 event.line = line
532 event.line = line
533 event.symbol = text
533 event.symbol = text
534 cmd = line.split(None,1)[0]
534 cmd = line.split(None,1)[0]
535 event.command = cmd
535 event.command = cmd
536 #print "\ncustom:{%s]\n" % event # dbg
536 #print "\ncustom:{%s]\n" % event # dbg
537
537
538 # for foo etc, try also to find completer for %foo
538 # for foo etc, try also to find completer for %foo
539 if not cmd.startswith(self.magic_escape):
539 if not cmd.startswith(self.magic_escape):
540 try_magic = self.custom_completers.s_matches(
540 try_magic = self.custom_completers.s_matches(
541 self.magic_escape + cmd)
541 self.magic_escape + cmd)
542 else:
542 else:
543 try_magic = []
543 try_magic = []
544
544
545
545
546 for c in itertools.chain(
546 for c in itertools.chain(
547 self.custom_completers.s_matches(cmd),
547 self.custom_completers.s_matches(cmd),
548 try_magic,
548 try_magic,
549 self.custom_completers.flat_matches(self.lbuf)):
549 self.custom_completers.flat_matches(self.lbuf)):
550 #print "try",c # dbg
550 #print "try",c # dbg
551 try:
551 try:
552 res = c(event)
552 res = c(event)
553 # first, try case sensitive match
553 # first, try case sensitive match
554 withcase = [r for r in res if r.startswith(text)]
554 withcase = [r for r in res if r.startswith(text)]
555 if withcase:
555 if withcase:
556 return withcase
556 return withcase
557 # if none, then case insensitive ones are ok too
557 # if none, then case insensitive ones are ok too
558 return [r for r in res if r.lower().startswith(text.lower())]
558 return [r for r in res if r.lower().startswith(text.lower())]
559 except TryNext:
559 except TryNext:
560 pass
560 pass
561
561
562 return None
562 return None
563
563
564 def complete(self, text, state,line_buffer=None):
564 def complete(self, text, state,line_buffer=None):
565 """Return the next possible completion for 'text'.
565 """Return the next possible completion for 'text'.
566
566
567 This is called successively with state == 0, 1, 2, ... until it
567 This is called successively with state == 0, 1, 2, ... until it
568 returns None. The completion should begin with 'text'.
568 returns None. The completion should begin with 'text'.
569
569
570 :Keywords:
570 :Keywords:
571 - line_buffer: string
571 - line_buffer: string
572 If not given, the completer attempts to obtain the current line buffer
572 If not given, the completer attempts to obtain the current line buffer
573 via readline. This keyword allows clients which are requesting for
573 via readline. This keyword allows clients which are requesting for
574 text completions in non-readline contexts to inform the completer of
574 text completions in non-readline contexts to inform the completer of
575 the entire text.
575 the entire text.
576 """
576 """
577
577
578 #print '\n*** COMPLETE: <%s> (%s)' % (text,state) # dbg
578 #print '\n*** COMPLETE: <%s> (%s)' % (text,state) # dbg
579
579
580 # if there is only a tab on a line with only whitespace, instead
580 # if there is only a tab on a line with only whitespace, instead
581 # of the mostly useless 'do you want to see all million
581 # of the mostly useless 'do you want to see all million
582 # completions' message, just do the right thing and give the user
582 # completions' message, just do the right thing and give the user
583 # his tab! Incidentally, this enables pasting of tabbed text from
583 # his tab! Incidentally, this enables pasting of tabbed text from
584 # an editor (as long as autoindent is off).
584 # an editor (as long as autoindent is off).
585
585
586 # It should be noted that at least pyreadline still shows
586 # It should be noted that at least pyreadline still shows
587 # file completions - is there a way around it?
587 # file completions - is there a way around it?
588
588
589 # don't apply this on 'dumb' terminals, such as emacs buffers, so we
589 # don't apply this on 'dumb' terminals, such as emacs buffers, so we
590 # don't interfere with their own tab-completion mechanism.
590 # don't interfere with their own tab-completion mechanism.
591 if line_buffer is None:
591 if line_buffer is None:
592 self.full_lbuf = self.get_line_buffer()
592 self.full_lbuf = self.get_line_buffer()
593 else:
593 else:
594 self.full_lbuf = line_buffer
594 self.full_lbuf = line_buffer
595
595
596 if not (self.dumb_terminal or self.full_lbuf.strip()):
596 if not (self.dumb_terminal or self.full_lbuf.strip()):
597 self.readline.insert_text('\t')
597 self.readline.insert_text('\t')
598 return None
598 return None
599
599
600 magic_escape = self.magic_escape
600 magic_escape = self.magic_escape
601 magic_prefix = self.magic_prefix
601 magic_prefix = self.magic_prefix
602
602
603 self.lbuf = self.full_lbuf[:self.get_endidx()]
603 self.lbuf = self.full_lbuf[:self.get_endidx()]
604
604
605 try:
605 try:
606 if text.startswith(magic_escape):
606 if text.startswith(magic_escape):
607 text = text.replace(magic_escape,magic_prefix)
607 text = text.replace(magic_escape,magic_prefix)
608 elif text.startswith('~'):
608 elif text.startswith('~'):
609 text = os.path.expanduser(text)
609 text = os.path.expanduser(text)
610 if state == 0:
610 if state == 0:
611 custom_res = self.dispatch_custom_completer(text)
611 custom_res = self.dispatch_custom_completer(text)
612 if custom_res is not None:
612 if custom_res is not None:
613 # did custom completers produce something?
613 # did custom completers produce something?
614 self.matches = custom_res
614 self.matches = custom_res
615 else:
615 else:
616 # Extend the list of completions with the results of each
616 # Extend the list of completions with the results of each
617 # matcher, so we return results to the user from all
617 # matcher, so we return results to the user from all
618 # namespaces.
618 # namespaces.
619 if self.merge_completions:
619 if self.merge_completions:
620 self.matches = []
620 self.matches = []
621 for matcher in self.matchers:
621 for matcher in self.matchers:
622 self.matches.extend(matcher(text))
622 self.matches.extend(matcher(text))
623 else:
623 else:
624 for matcher in self.matchers:
624 for matcher in self.matchers:
625 self.matches = matcher(text)
625 self.matches = matcher(text)
626 if self.matches:
626 if self.matches:
627 break
627 break
628 def uniq(alist):
628 def uniq(alist):
629 set = {}
629 set = {}
630 return [set.setdefault(e,e) for e in alist if e not in set]
630 return [set.setdefault(e,e) for e in alist if e not in set]
631 self.matches = uniq(self.matches)
631 self.matches = uniq(self.matches)
632 try:
632 try:
633 ret = self.matches[state].replace(magic_prefix,magic_escape)
633 ret = self.matches[state].replace(magic_prefix,magic_escape)
634 return ret
634 return ret
635 except IndexError:
635 except IndexError:
636 return None
636 return None
637 except:
637 except:
638 #from IPython.core.ultratb import AutoFormattedTB; # dbg
638 #from IPython.core.ultratb import AutoFormattedTB; # dbg
639 #tb=AutoFormattedTB('Verbose');tb() #dbg
639 #tb=AutoFormattedTB('Verbose');tb() #dbg
640
640
641 # If completion fails, don't annoy the user.
641 # If completion fails, don't annoy the user.
642 return None
642 return None
@@ -1,306 +1,306 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 Paging capabilities for IPython.core
4 Paging capabilities for IPython.core
5
5
6 Authors:
6 Authors:
7
7
8 * Brian Granger
8 * Brian Granger
9 * Fernando Perez
9 * Fernando Perez
10
10
11 Notes
11 Notes
12 -----
12 -----
13
13
14 For now this uses ipapi, so it can't be in IPython.utils. If we can get
14 For now this uses ipapi, so it can't be in IPython.utils. If we can get
15 rid of that dependency, we could move it there.
15 rid of that dependency, we could move it there.
16 -----
16 -----
17 """
17 """
18
18
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20 # Copyright (C) 2008-2009 The IPython Development Team
20 # Copyright (C) 2008-2009 The IPython Development Team
21 #
21 #
22 # Distributed under the terms of the BSD License. The full license is in
22 # Distributed under the terms of the BSD License. The full license is in
23 # the file COPYING, distributed as part of this software.
23 # the file COPYING, distributed as part of this software.
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25
25
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27 # Imports
27 # Imports
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29
29
30 import os
30 import os
31 import re
31 import re
32 import sys
32 import sys
33
33
34 from IPython.core import ipapi
34 from IPython.core import ipapi
35 from IPython.core.error import TryNext
35 from IPython.core.error import TryNext
36 from IPython.utils.genutils import (
36 from IPython.utils.genutils import (
37 chop, Term
37 chop, Term, USE_CURSES
38 )
38 )
39
39
40 if os.name == "nt":
40 if os.name == "nt":
41 from IPython.utils.winconsole import get_console_size
41 from IPython.utils.winconsole import get_console_size
42
42
43
43
44 #-----------------------------------------------------------------------------
44 #-----------------------------------------------------------------------------
45 # Classes and functions
45 # Classes and functions
46 #-----------------------------------------------------------------------------
46 #-----------------------------------------------------------------------------
47
47
48 esc_re = re.compile(r"(\x1b[^m]+m)")
48 esc_re = re.compile(r"(\x1b[^m]+m)")
49
49
50 def page_dumb(strng,start=0,screen_lines=25):
50 def page_dumb(strng,start=0,screen_lines=25):
51 """Very dumb 'pager' in Python, for when nothing else works.
51 """Very dumb 'pager' in Python, for when nothing else works.
52
52
53 Only moves forward, same interface as page(), except for pager_cmd and
53 Only moves forward, same interface as page(), except for pager_cmd and
54 mode."""
54 mode."""
55
55
56 out_ln = strng.splitlines()[start:]
56 out_ln = strng.splitlines()[start:]
57 screens = chop(out_ln,screen_lines-1)
57 screens = chop(out_ln,screen_lines-1)
58 if len(screens) == 1:
58 if len(screens) == 1:
59 print >>Term.cout, os.linesep.join(screens[0])
59 print >>Term.cout, os.linesep.join(screens[0])
60 else:
60 else:
61 last_escape = ""
61 last_escape = ""
62 for scr in screens[0:-1]:
62 for scr in screens[0:-1]:
63 hunk = os.linesep.join(scr)
63 hunk = os.linesep.join(scr)
64 print >>Term.cout, last_escape + hunk
64 print >>Term.cout, last_escape + hunk
65 if not page_more():
65 if not page_more():
66 return
66 return
67 esc_list = esc_re.findall(hunk)
67 esc_list = esc_re.findall(hunk)
68 if len(esc_list) > 0:
68 if len(esc_list) > 0:
69 last_escape = esc_list[-1]
69 last_escape = esc_list[-1]
70 print >>Term.cout, last_escape + os.linesep.join(screens[-1])
70 print >>Term.cout, last_escape + os.linesep.join(screens[-1])
71
71
72 #----------------------------------------------------------------------------
72 #----------------------------------------------------------------------------
73 def page(strng,start=0,screen_lines=0,pager_cmd = None):
73 def page(strng,start=0,screen_lines=0,pager_cmd = None):
74 """Print a string, piping through a pager after a certain length.
74 """Print a string, piping through a pager after a certain length.
75
75
76 The screen_lines parameter specifies the number of *usable* lines of your
76 The screen_lines parameter specifies the number of *usable* lines of your
77 terminal screen (total lines minus lines you need to reserve to show other
77 terminal screen (total lines minus lines you need to reserve to show other
78 information).
78 information).
79
79
80 If you set screen_lines to a number <=0, page() will try to auto-determine
80 If you set screen_lines to a number <=0, page() will try to auto-determine
81 your screen size and will only use up to (screen_size+screen_lines) for
81 your screen size and will only use up to (screen_size+screen_lines) for
82 printing, paging after that. That is, if you want auto-detection but need
82 printing, paging after that. That is, if you want auto-detection but need
83 to reserve the bottom 3 lines of the screen, use screen_lines = -3, and for
83 to reserve the bottom 3 lines of the screen, use screen_lines = -3, and for
84 auto-detection without any lines reserved simply use screen_lines = 0.
84 auto-detection without any lines reserved simply use screen_lines = 0.
85
85
86 If a string won't fit in the allowed lines, it is sent through the
86 If a string won't fit in the allowed lines, it is sent through the
87 specified pager command. If none given, look for PAGER in the environment,
87 specified pager command. If none given, look for PAGER in the environment,
88 and ultimately default to less.
88 and ultimately default to less.
89
89
90 If no system pager works, the string is sent through a 'dumb pager'
90 If no system pager works, the string is sent through a 'dumb pager'
91 written in python, very simplistic.
91 written in python, very simplistic.
92 """
92 """
93
93
94 # Some routines may auto-compute start offsets incorrectly and pass a
94 # Some routines may auto-compute start offsets incorrectly and pass a
95 # negative value. Offset to 0 for robustness.
95 # negative value. Offset to 0 for robustness.
96 start = max(0,start)
96 start = max(0,start)
97
97
98 # first, try the hook
98 # first, try the hook
99 ip = ipapi.get()
99 ip = ipapi.get()
100 if ip:
100 if ip:
101 try:
101 try:
102 ip.hooks.show_in_pager(strng)
102 ip.hooks.show_in_pager(strng)
103 return
103 return
104 except TryNext:
104 except TryNext:
105 pass
105 pass
106
106
107 # Ugly kludge, but calling curses.initscr() flat out crashes in emacs
107 # Ugly kludge, but calling curses.initscr() flat out crashes in emacs
108 TERM = os.environ.get('TERM','dumb')
108 TERM = os.environ.get('TERM','dumb')
109 if TERM in ['dumb','emacs'] and os.name != 'nt':
109 if TERM in ['dumb','emacs'] and os.name != 'nt':
110 print strng
110 print strng
111 return
111 return
112 # chop off the topmost part of the string we don't want to see
112 # chop off the topmost part of the string we don't want to see
113 str_lines = strng.split(os.linesep)[start:]
113 str_lines = strng.split(os.linesep)[start:]
114 str_toprint = os.linesep.join(str_lines)
114 str_toprint = os.linesep.join(str_lines)
115 num_newlines = len(str_lines)
115 num_newlines = len(str_lines)
116 len_str = len(str_toprint)
116 len_str = len(str_toprint)
117
117
118 # Dumb heuristics to guesstimate number of on-screen lines the string
118 # Dumb heuristics to guesstimate number of on-screen lines the string
119 # takes. Very basic, but good enough for docstrings in reasonable
119 # takes. Very basic, but good enough for docstrings in reasonable
120 # terminals. If someone later feels like refining it, it's not hard.
120 # terminals. If someone later feels like refining it, it's not hard.
121 numlines = max(num_newlines,int(len_str/80)+1)
121 numlines = max(num_newlines,int(len_str/80)+1)
122
122
123 if os.name == "nt":
123 if os.name == "nt":
124 screen_lines_def = get_console_size(defaulty=25)[1]
124 screen_lines_def = get_console_size(defaulty=25)[1]
125 else:
125 else:
126 screen_lines_def = 25 # default value if we can't auto-determine
126 screen_lines_def = 25 # default value if we can't auto-determine
127
127
128 # auto-determine screen size
128 # auto-determine screen size
129 if screen_lines <= 0:
129 if screen_lines <= 0:
130 if TERM=='xterm':
130 if TERM=='xterm':
131 use_curses = USE_CURSES
131 use_curses = USE_CURSES
132 else:
132 else:
133 # curses causes problems on many terminals other than xterm.
133 # curses causes problems on many terminals other than xterm.
134 use_curses = False
134 use_curses = False
135 if use_curses:
135 if use_curses:
136 # There is a bug in curses, where *sometimes* it fails to properly
136 # There is a bug in curses, where *sometimes* it fails to properly
137 # initialize, and then after the endwin() call is made, the
137 # initialize, and then after the endwin() call is made, the
138 # terminal is left in an unusable state. Rather than trying to
138 # terminal is left in an unusable state. Rather than trying to
139 # check everytime for this (by requesting and comparing termios
139 # check everytime for this (by requesting and comparing termios
140 # flags each time), we just save the initial terminal state and
140 # flags each time), we just save the initial terminal state and
141 # unconditionally reset it every time. It's cheaper than making
141 # unconditionally reset it every time. It's cheaper than making
142 # the checks.
142 # the checks.
143 term_flags = termios.tcgetattr(sys.stdout)
143 term_flags = termios.tcgetattr(sys.stdout)
144 scr = curses.initscr()
144 scr = curses.initscr()
145 screen_lines_real,screen_cols = scr.getmaxyx()
145 screen_lines_real,screen_cols = scr.getmaxyx()
146 curses.endwin()
146 curses.endwin()
147 # Restore terminal state in case endwin() didn't.
147 # Restore terminal state in case endwin() didn't.
148 termios.tcsetattr(sys.stdout,termios.TCSANOW,term_flags)
148 termios.tcsetattr(sys.stdout,termios.TCSANOW,term_flags)
149 # Now we have what we needed: the screen size in rows/columns
149 # Now we have what we needed: the screen size in rows/columns
150 screen_lines += screen_lines_real
150 screen_lines += screen_lines_real
151 #print '***Screen size:',screen_lines_real,'lines x',\
151 #print '***Screen size:',screen_lines_real,'lines x',\
152 #screen_cols,'columns.' # dbg
152 #screen_cols,'columns.' # dbg
153 else:
153 else:
154 screen_lines += screen_lines_def
154 screen_lines += screen_lines_def
155
155
156 #print 'numlines',numlines,'screenlines',screen_lines # dbg
156 #print 'numlines',numlines,'screenlines',screen_lines # dbg
157 if numlines <= screen_lines :
157 if numlines <= screen_lines :
158 #print '*** normal print' # dbg
158 #print '*** normal print' # dbg
159 print >>Term.cout, str_toprint
159 print >>Term.cout, str_toprint
160 else:
160 else:
161 # Try to open pager and default to internal one if that fails.
161 # Try to open pager and default to internal one if that fails.
162 # All failure modes are tagged as 'retval=1', to match the return
162 # All failure modes are tagged as 'retval=1', to match the return
163 # value of a failed system command. If any intermediate attempt
163 # value of a failed system command. If any intermediate attempt
164 # sets retval to 1, at the end we resort to our own page_dumb() pager.
164 # sets retval to 1, at the end we resort to our own page_dumb() pager.
165 pager_cmd = get_pager_cmd(pager_cmd)
165 pager_cmd = get_pager_cmd(pager_cmd)
166 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
166 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
167 if os.name == 'nt':
167 if os.name == 'nt':
168 if pager_cmd.startswith('type'):
168 if pager_cmd.startswith('type'):
169 # The default WinXP 'type' command is failing on complex strings.
169 # The default WinXP 'type' command is failing on complex strings.
170 retval = 1
170 retval = 1
171 else:
171 else:
172 tmpname = tempfile.mktemp('.txt')
172 tmpname = tempfile.mktemp('.txt')
173 tmpfile = file(tmpname,'wt')
173 tmpfile = file(tmpname,'wt')
174 tmpfile.write(strng)
174 tmpfile.write(strng)
175 tmpfile.close()
175 tmpfile.close()
176 cmd = "%s < %s" % (pager_cmd,tmpname)
176 cmd = "%s < %s" % (pager_cmd,tmpname)
177 if os.system(cmd):
177 if os.system(cmd):
178 retval = 1
178 retval = 1
179 else:
179 else:
180 retval = None
180 retval = None
181 os.remove(tmpname)
181 os.remove(tmpname)
182 else:
182 else:
183 try:
183 try:
184 retval = None
184 retval = None
185 # if I use popen4, things hang. No idea why.
185 # if I use popen4, things hang. No idea why.
186 #pager,shell_out = os.popen4(pager_cmd)
186 #pager,shell_out = os.popen4(pager_cmd)
187 pager = os.popen(pager_cmd,'w')
187 pager = os.popen(pager_cmd,'w')
188 pager.write(strng)
188 pager.write(strng)
189 pager.close()
189 pager.close()
190 retval = pager.close() # success returns None
190 retval = pager.close() # success returns None
191 except IOError,msg: # broken pipe when user quits
191 except IOError,msg: # broken pipe when user quits
192 if msg.args == (32,'Broken pipe'):
192 if msg.args == (32,'Broken pipe'):
193 retval = None
193 retval = None
194 else:
194 else:
195 retval = 1
195 retval = 1
196 except OSError:
196 except OSError:
197 # Other strange problems, sometimes seen in Win2k/cygwin
197 # Other strange problems, sometimes seen in Win2k/cygwin
198 retval = 1
198 retval = 1
199 if retval is not None:
199 if retval is not None:
200 page_dumb(strng,screen_lines=screen_lines)
200 page_dumb(strng,screen_lines=screen_lines)
201
201
202 #----------------------------------------------------------------------------
202 #----------------------------------------------------------------------------
203 def page_file(fname,start = 0, pager_cmd = None):
203 def page_file(fname,start = 0, pager_cmd = None):
204 """Page a file, using an optional pager command and starting line.
204 """Page a file, using an optional pager command and starting line.
205 """
205 """
206
206
207 pager_cmd = get_pager_cmd(pager_cmd)
207 pager_cmd = get_pager_cmd(pager_cmd)
208 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
208 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
209
209
210 try:
210 try:
211 if os.environ['TERM'] in ['emacs','dumb']:
211 if os.environ['TERM'] in ['emacs','dumb']:
212 raise EnvironmentError
212 raise EnvironmentError
213 xsys(pager_cmd + ' ' + fname)
213 xsys(pager_cmd + ' ' + fname)
214 except:
214 except:
215 try:
215 try:
216 if start > 0:
216 if start > 0:
217 start -= 1
217 start -= 1
218 page(open(fname).read(),start)
218 page(open(fname).read(),start)
219 except:
219 except:
220 print 'Unable to show file',`fname`
220 print 'Unable to show file',`fname`
221
221
222 #----------------------------------------------------------------------------
222 #----------------------------------------------------------------------------
223 def get_pager_cmd(pager_cmd = None):
223 def get_pager_cmd(pager_cmd = None):
224 """Return a pager command.
224 """Return a pager command.
225
225
226 Makes some attempts at finding an OS-correct one."""
226 Makes some attempts at finding an OS-correct one."""
227
227
228 if os.name == 'posix':
228 if os.name == 'posix':
229 default_pager_cmd = 'less -r' # -r for color control sequences
229 default_pager_cmd = 'less -r' # -r for color control sequences
230 elif os.name in ['nt','dos']:
230 elif os.name in ['nt','dos']:
231 default_pager_cmd = 'type'
231 default_pager_cmd = 'type'
232
232
233 if pager_cmd is None:
233 if pager_cmd is None:
234 try:
234 try:
235 pager_cmd = os.environ['PAGER']
235 pager_cmd = os.environ['PAGER']
236 except:
236 except:
237 pager_cmd = default_pager_cmd
237 pager_cmd = default_pager_cmd
238 return pager_cmd
238 return pager_cmd
239
239
240 #-----------------------------------------------------------------------------
240 #-----------------------------------------------------------------------------
241 def get_pager_start(pager,start):
241 def get_pager_start(pager,start):
242 """Return the string for paging files with an offset.
242 """Return the string for paging files with an offset.
243
243
244 This is the '+N' argument which less and more (under Unix) accept.
244 This is the '+N' argument which less and more (under Unix) accept.
245 """
245 """
246
246
247 if pager in ['less','more']:
247 if pager in ['less','more']:
248 if start:
248 if start:
249 start_string = '+' + str(start)
249 start_string = '+' + str(start)
250 else:
250 else:
251 start_string = ''
251 start_string = ''
252 else:
252 else:
253 start_string = ''
253 start_string = ''
254 return start_string
254 return start_string
255
255
256 #----------------------------------------------------------------------------
256 #----------------------------------------------------------------------------
257 # (X)emacs on W32 doesn't like to be bypassed with msvcrt.getch()
257 # (X)emacs on W32 doesn't like to be bypassed with msvcrt.getch()
258 if os.name == 'nt' and os.environ.get('TERM','dumb') != 'emacs':
258 if os.name == 'nt' and os.environ.get('TERM','dumb') != 'emacs':
259 import msvcrt
259 import msvcrt
260 def page_more():
260 def page_more():
261 """ Smart pausing between pages
261 """ Smart pausing between pages
262
262
263 @return: True if need print more lines, False if quit
263 @return: True if need print more lines, False if quit
264 """
264 """
265 Term.cout.write('---Return to continue, q to quit--- ')
265 Term.cout.write('---Return to continue, q to quit--- ')
266 ans = msvcrt.getch()
266 ans = msvcrt.getch()
267 if ans in ("q", "Q"):
267 if ans in ("q", "Q"):
268 result = False
268 result = False
269 else:
269 else:
270 result = True
270 result = True
271 Term.cout.write("\b"*37 + " "*37 + "\b"*37)
271 Term.cout.write("\b"*37 + " "*37 + "\b"*37)
272 return result
272 return result
273 else:
273 else:
274 def page_more():
274 def page_more():
275 ans = raw_input('---Return to continue, q to quit--- ')
275 ans = raw_input('---Return to continue, q to quit--- ')
276 if ans.lower().startswith('q'):
276 if ans.lower().startswith('q'):
277 return False
277 return False
278 else:
278 else:
279 return True
279 return True
280
280
281 #----------------------------------------------------------------------------
281 #----------------------------------------------------------------------------
282 def snip_print(str,width = 75,print_full = 0,header = ''):
282 def snip_print(str,width = 75,print_full = 0,header = ''):
283 """Print a string snipping the midsection to fit in width.
283 """Print a string snipping the midsection to fit in width.
284
284
285 print_full: mode control:
285 print_full: mode control:
286 - 0: only snip long strings
286 - 0: only snip long strings
287 - 1: send to page() directly.
287 - 1: send to page() directly.
288 - 2: snip long strings and ask for full length viewing with page()
288 - 2: snip long strings and ask for full length viewing with page()
289 Return 1 if snipping was necessary, 0 otherwise."""
289 Return 1 if snipping was necessary, 0 otherwise."""
290
290
291 if print_full == 1:
291 if print_full == 1:
292 page(header+str)
292 page(header+str)
293 return 0
293 return 0
294
294
295 print header,
295 print header,
296 if len(str) < width:
296 if len(str) < width:
297 print str
297 print str
298 snip = 0
298 snip = 0
299 else:
299 else:
300 whalf = int((width -5)/2)
300 whalf = int((width -5)/2)
301 print str[:whalf] + ' <...> ' + str[-whalf:]
301 print str[:whalf] + ' <...> ' + str[-whalf:]
302 snip = 1
302 snip = 1
303 if snip and print_full == 2:
303 if snip and print_full == 2:
304 if raw_input(header+' Snipped. View (y/n)? [N]').lower() == 'y':
304 if raw_input(header+' Snipped. View (y/n)? [N]').lower() == 'y':
305 page(str)
305 page(str)
306 return snip No newline at end of file
306 return snip
@@ -1,28 +1,28 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
2 # -*- coding: utf-8 -*-
3 """IPython -- An enhanced Interactive Python
3 """IPython -- An enhanced Interactive Python
4
4
5 This is just the startup wrapper script, kept deliberately to a minimum.
5 This is just the startup wrapper script, kept deliberately to a minimum.
6
6
7 The shell's mainloop() takes an optional argument, sys_exit (default=0). If
7 The shell's mainloop() takes an optional argument, sys_exit (default=0). If
8 set to 1, it calls sys.exit() at exit time. You can use the following code in
8 set to 1, it calls sys.exit() at exit time. You can use the following code in
9 your PYTHONSTARTUP file:
9 your PYTHONSTARTUP file:
10
10
11 import IPython
11 import IPython
12 IPython.Shell.IPShell().mainloop(sys_exit=1)
12 IPython.Shell.IPShell().mainloop(sys_exit=1)
13
13
14 [or simply IPython.Shell.IPShell().mainloop(1) ]
14 [or simply IPython.Shell.IPShell().mainloop(1) ]
15
15
16 and IPython will be your working environment when you start python. The final
16 and IPython will be your working environment when you start python. The final
17 sys.exit() call will make python exit transparently when IPython finishes, so
17 sys.exit() call will make python exit transparently when IPython finishes, so
18 you don't have an extra prompt to get out of.
18 you don't have an extra prompt to get out of.
19
19
20 This is probably useful to developers who manage multiple Python versions and
20 This is probably useful to developers who manage multiple Python versions and
21 don't want to have correspondingly multiple IPython versions. Note that in
21 don't want to have correspondingly multiple IPython versions. Note that in
22 this mode, there is no way to pass IPython any command-line options, as those
22 this mode, there is no way to pass IPython any command-line options, as those
23 are trapped first by Python itself.
23 are trapped first by Python itself.
24 """
24 """
25
25
26 import IPython.core.ipapi import launch_new_instance
26 from IPython.core.ipapi import launch_new_instance
27
27
28 launch_new_instance()
28 launch_new_instance()
@@ -1,101 +1,109 b''
1 """A Simple wx example to test IPython's event loop integration.
1 """A Simple wx example to test IPython's event loop integration.
2
2
3 To run this do:
3 To run this do:
4
4
5 In [5]: %gui wx
5 In [5]: %gui wx
6
6
7 In [6]: %run gui-wx.py
7 In [6]: %run gui-wx.py
8
8
9 Ref: Modified from wxPython source code wxPython/samples/simple/simple.py
9 Ref: Modified from wxPython source code wxPython/samples/simple/simple.py
10
10
11 This example can only be run once in a given IPython session because when
11 This example can only be run once in a given IPython session because when
12 the frame is closed, wx goes through its shutdown sequence, killing further
12 the frame is closed, wx goes through its shutdown sequence, killing further
13 attempts. I am sure someone who knows wx can fix this issue.
13 attempts. I am sure someone who knows wx can fix this issue.
14
15 Furthermore, once this example is run, the Wx event loop is mostly dead, so
16 even other new uses of Wx may not work correctly. If you know how to better
17 handle this, please contact the ipython developers and let us know.
18
19 Note however that we will work with the Matplotlib and Enthought developers so
20 that the main interactive uses of Wx we are aware of, namely these tools, will
21 continue to work well with IPython interactively.
14 """
22 """
15
23
16 import wx
24 import wx
17
25
18
26
19 class MyFrame(wx.Frame):
27 class MyFrame(wx.Frame):
20 """
28 """
21 This is MyFrame. It just shows a few controls on a wxPanel,
29 This is MyFrame. It just shows a few controls on a wxPanel,
22 and has a simple menu.
30 and has a simple menu.
23 """
31 """
24 def __init__(self, parent, title):
32 def __init__(self, parent, title):
25 wx.Frame.__init__(self, parent, -1, title,
33 wx.Frame.__init__(self, parent, -1, title,
26 pos=(150, 150), size=(350, 200))
34 pos=(150, 150), size=(350, 200))
27
35
28 # Create the menubar
36 # Create the menubar
29 menuBar = wx.MenuBar()
37 menuBar = wx.MenuBar()
30
38
31 # and a menu
39 # and a menu
32 menu = wx.Menu()
40 menu = wx.Menu()
33
41
34 # add an item to the menu, using \tKeyName automatically
42 # add an item to the menu, using \tKeyName automatically
35 # creates an accelerator, the third param is some help text
43 # creates an accelerator, the third param is some help text
36 # that will show up in the statusbar
44 # that will show up in the statusbar
37 menu.Append(wx.ID_EXIT, "E&xit\tAlt-X", "Exit this simple sample")
45 menu.Append(wx.ID_EXIT, "E&xit\tAlt-X", "Exit this simple sample")
38
46
39 # bind the menu event to an event handler
47 # bind the menu event to an event handler
40 self.Bind(wx.EVT_MENU, self.OnTimeToClose, id=wx.ID_EXIT)
48 self.Bind(wx.EVT_MENU, self.OnTimeToClose, id=wx.ID_EXIT)
41
49
42 # and put the menu on the menubar
50 # and put the menu on the menubar
43 menuBar.Append(menu, "&File")
51 menuBar.Append(menu, "&File")
44 self.SetMenuBar(menuBar)
52 self.SetMenuBar(menuBar)
45
53
46 self.CreateStatusBar()
54 self.CreateStatusBar()
47
55
48 # Now create the Panel to put the other controls on.
56 # Now create the Panel to put the other controls on.
49 panel = wx.Panel(self)
57 panel = wx.Panel(self)
50
58
51 # and a few controls
59 # and a few controls
52 text = wx.StaticText(panel, -1, "Hello World!")
60 text = wx.StaticText(panel, -1, "Hello World!")
53 text.SetFont(wx.Font(14, wx.SWISS, wx.NORMAL, wx.BOLD))
61 text.SetFont(wx.Font(14, wx.SWISS, wx.NORMAL, wx.BOLD))
54 text.SetSize(text.GetBestSize())
62 text.SetSize(text.GetBestSize())
55 btn = wx.Button(panel, -1, "Close")
63 btn = wx.Button(panel, -1, "Close")
56 funbtn = wx.Button(panel, -1, "Just for fun...")
64 funbtn = wx.Button(panel, -1, "Just for fun...")
57
65
58 # bind the button events to handlers
66 # bind the button events to handlers
59 self.Bind(wx.EVT_BUTTON, self.OnTimeToClose, btn)
67 self.Bind(wx.EVT_BUTTON, self.OnTimeToClose, btn)
60 self.Bind(wx.EVT_BUTTON, self.OnFunButton, funbtn)
68 self.Bind(wx.EVT_BUTTON, self.OnFunButton, funbtn)
61
69
62 # Use a sizer to layout the controls, stacked vertically and with
70 # Use a sizer to layout the controls, stacked vertically and with
63 # a 10 pixel border around each
71 # a 10 pixel border around each
64 sizer = wx.BoxSizer(wx.VERTICAL)
72 sizer = wx.BoxSizer(wx.VERTICAL)
65 sizer.Add(text, 0, wx.ALL, 10)
73 sizer.Add(text, 0, wx.ALL, 10)
66 sizer.Add(btn, 0, wx.ALL, 10)
74 sizer.Add(btn, 0, wx.ALL, 10)
67 sizer.Add(funbtn, 0, wx.ALL, 10)
75 sizer.Add(funbtn, 0, wx.ALL, 10)
68 panel.SetSizer(sizer)
76 panel.SetSizer(sizer)
69 panel.Layout()
77 panel.Layout()
70
78
71
79
72 def OnTimeToClose(self, evt):
80 def OnTimeToClose(self, evt):
73 """Event handler for the button click."""
81 """Event handler for the button click."""
74 print "See ya later!"
82 print "See ya later!"
75 self.Close()
83 self.Close()
76
84
77 def OnFunButton(self, evt):
85 def OnFunButton(self, evt):
78 """Event handler for the button click."""
86 """Event handler for the button click."""
79 print "Having fun yet?"
87 print "Having fun yet?"
80
88
81
89
82 class MyApp(wx.App):
90 class MyApp(wx.App):
83 def OnInit(self):
91 def OnInit(self):
84 frame = MyFrame(None, "Simple wxPython App")
92 frame = MyFrame(None, "Simple wxPython App")
85 self.SetTopWindow(frame)
93 self.SetTopWindow(frame)
86
94
87 print "Print statements go to this stdout window by default."
95 print "Print statements go to this stdout window by default."
88
96
89 frame.Show(True)
97 frame.Show(True)
90 return True
98 return True
91
99
92 app = wx.GetApp()
100 app = wx.GetApp()
93 if app is None:
101 if app is None:
94 app = MyApp(redirect=False, clearSigInt=False)
102 app = MyApp(redirect=False, clearSigInt=False)
95
103
96 try:
104 try:
97 from IPython.lib.inputhook import appstart_wx
105 from IPython.lib.inputhook import appstart_wx
98 appstart_wx(app)
106 appstart_wx(app)
99 except ImportError:
107 except ImportError:
100 app.MainLoop()
108 app.MainLoop()
101
109
General Comments 0
You need to be logged in to leave comments. Login now