##// END OF EJS Templates
Make "help()" work.
Gael Varoquaux -
Show More
@@ -1,139 +1,141 b''
1 1 """
2 2 Frontend class that uses IPython0 to prefilter the inputs.
3 3
4 4 Using the IPython0 mechanism gives us access to the magics.
5 5 """
6 6 __docformat__ = "restructuredtext en"
7 7
8 8 #-------------------------------------------------------------------------------
9 9 # Copyright (C) 2008 The IPython Development Team
10 10 #
11 11 # Distributed under the terms of the BSD License. The full license is in
12 12 # the file COPYING, distributed as part of this software.
13 13 #-------------------------------------------------------------------------------
14 14
15 15 #-------------------------------------------------------------------------------
16 16 # Imports
17 17 #-------------------------------------------------------------------------------
18 18 import sys
19 19
20 20 from linefrontendbase import LineFrontEndBase, common_prefix
21 21
22 22 from IPython.ipmaker import make_IPython
23 23 from IPython.ipapi import IPApi
24 24 from IPython.kernel.core.sync_output_trap import SyncOutputTrap
25 25
26 26 from IPython.genutils import Term
27 27
28 28 #-------------------------------------------------------------------------------
29 29 # Utility functions (temporary, should be moved out of here)
30 30 #-------------------------------------------------------------------------------
31 31 import os
32 32 def xterm_system(command):
33 33 """ Run a command in a separate console window.
34 34 """
35 35 os.system("""
36 36 xterm -title "%s" -e \'/bin/sh -c "%s ;
37 37 printf \\"\\\\n\\";
38 38 printf \\"press a key to close\\" ;
39 39 printf \\"\x1b]0;%s (finished -- press a key to close)\x07\\" ;
40 40 read foo;"\'
41 41 """ % (command, command, command) )
42 42
43 43 #-------------------------------------------------------------------------------
44 44 # Frontend class using ipython0 to do the prefiltering.
45 45 #-------------------------------------------------------------------------------
46 46 class PrefilterFrontEnd(LineFrontEndBase):
47 47
48 48 def __init__(self, *args, **kwargs):
49 49 LineFrontEndBase.__init__(self, *args, **kwargs)
50 50 # Instanciate an IPython0 interpreter to be able to use the
51 51 # prefiltering.
52 52 self.ipython0 = make_IPython()
53 53 # Set the pager:
54 54 self.ipython0.set_hook('show_in_pager',
55 55 lambda s, string: self.write("\n"+string))
56 56 self.ipython0.write = self.write
57 57 self._ip = _ip = IPApi(self.ipython0)
58 58 # XXX: Hack: mix the two namespaces
59 59 self.shell.user_ns = self.ipython0.user_ns
60 60 self.shell.user_global_ns = self.ipython0.user_global_ns
61 61 # Make sure the raw system call doesn't get called, as we don't
62 62 # have a stdin accessible.
63 63 self._ip.system = xterm_system
64 64 # Redefine a serie of magics to avoid os.system:
65 65 # FIXME: I am redefining way too much magics.
66 66 for alias_name, (_, alias_value) in \
67 67 _ip.IP.shell.alias_table.iteritems():
68 68 magic = lambda s : _ip.magic('sx %s %s' % (alias_value, s))
69 69 setattr(_ip.IP, 'magic_%s' % alias_name, magic)
70 70 # FIXME: I should create a real file-like object dedicated to this
71 71 # terminal
72 72 self.shell.output_trap = SyncOutputTrap(write_out=self.write,
73 73 write_err=self.write)
74 74
75 import pydoc
76 pydoc.help.output = self.shell.output_trap.out
75 77
76 78
77 79 def prefilter_input(self, input_string):
78 80 """ Using IPython0 to prefilter the commands.
79 81 """
80 82 input_string = LineFrontEndBase.prefilter_input(self, input_string)
81 83 filtered_lines = []
82 84 # The IPython0 prefilters sometime produce output. We need to
83 85 # capture it.
84 86 self.capture_output()
85 87 self.last_result = dict(number=self.prompt_number)
86 88 try:
87 89 for line in input_string.split('\n'):
88 90 filtered_lines.append(self.ipython0.prefilter(line, False))
89 91 except:
90 92 # XXX: probably not the right thing to do.
91 93 self.ipython0.showsyntaxerror()
92 94 self.after_execute()
93 95 finally:
94 96 self.release_output()
95 97
96 98 filtered_string = '\n'.join(filtered_lines)
97 99 return filtered_string
98 100
99 101
100 102 def show_traceback(self):
101 103 self.capture_output()
102 104 self.ipython0.showtraceback()
103 105 self.release_output()
104 106
105 107
106 108 def capture_output(self):
107 109 """ Capture all the output mechanism we can think of.
108 110 """
109 111 self.__old_cout_write = Term.cout.write
110 112 self.__old_err_write = Term.cerr.write
111 113 Term.cout.write = self.write
112 114 Term.cerr.write = self.write
113 115 self.__old_stdout = sys.stdout
114 116 self.__old_stderr= sys.stderr
115 117 sys.stdout = Term.cout
116 118 sys.stderr = Term.cerr
117 # FIXME: I still need to provide the writelines method
119
118 120
119 121 def release_output(self):
120 122 """ Release all the different captures we have made,
121 123 and flush the buffers.
122 124 """
123 125 Term.cout.write = self.__old_cout_write
124 126 Term.cerr.write = self.__old_err_write
125 127 sys.stdout = self.__old_stdout
126 128 sys.stderr = self.__old_stderr
127 129
128 130
129 131 def complete(self, line):
130 132 word = line.split('\n')[-1].split(' ')[-1]
131 133 completions = self.ipython0.complete(word)
132 134 key = lambda x: x.replace('_', '')
133 135 completions.sort(key=key)
134 136 if completions:
135 137 prefix = common_prefix(completions)
136 138 line = line[:-len(word)] + prefix
137 139 return line, completions
138 140
139 141
@@ -1,252 +1,254 b''
1 1 # encoding: utf-8 -*- test-case-name:
2 2 # FIXME: Need to add tests.
3 3 # ipython1.frontend.cocoa.tests.test_cocoa_frontend -*-
4 4
5 5 """Classes to provide a Wx frontend to the
6 6 IPython.kernel.core.interpreter.
7 7
8 8 """
9 9
10 10 __docformat__ = "restructuredtext en"
11 11
12 12 #-------------------------------------------------------------------------------
13 13 # Copyright (C) 2008 The IPython Development Team
14 14 #
15 15 # Distributed under the terms of the BSD License. The full license is in
16 16 # the file COPYING, distributed as part of this software.
17 17 #-------------------------------------------------------------------------------
18 18
19 19 #-------------------------------------------------------------------------------
20 20 # Imports
21 21 #-------------------------------------------------------------------------------
22 22
23 23
24 24 import wx
25 25 import re
26 26 from wx import stc
27 27 from console_widget import ConsoleWidget
28 28 import __builtin__
29 29 from time import sleep
30 30
31 31 from IPython.frontend.prefilterfrontend import PrefilterFrontEnd
32 32
33 33 #_COMMAND_BG = '#FAFAF1' # Nice green
34 34 _RUNNING_BUFFER_BG = '#FDFFD3' # Nice yellow
35 35 _ERROR_BG = '#FFF1F1' # Nice red
36 36
37 37 _RUNNING_BUFFER_MARKER = 31
38 38 _ERROR_MARKER = 30
39 39
40 40 #-------------------------------------------------------------------------------
41 41 # Classes to implement the Wx frontend
42 42 #-------------------------------------------------------------------------------
43 43 class WxController(PrefilterFrontEnd, ConsoleWidget):
44 44
45 45 output_prompt = \
46 46 '\x01\x1b[0;31m\x02Out[\x01\x1b[1;31m\x02%i\x01\x1b[0;31m\x02]: \x01\x1b[0m\x02'
47 47
48 48 #--------------------------------------------------------------------------
49 49 # Public API
50 50 #--------------------------------------------------------------------------
51 51
52 52 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
53 53 size=wx.DefaultSize, style=wx.CLIP_CHILDREN,
54 54 *args, **kwds):
55 55 """ Create Shell instance.
56 56 """
57 57 ConsoleWidget.__init__(self, parent, id, pos, size, style)
58 58 PrefilterFrontEnd.__init__(self)
59 59
60 60 # Capture Character keys
61 61 self.Bind(wx.EVT_KEY_DOWN, self._on_key_down)
62 62
63 63 # Marker for running buffer.
64 64 self.MarkerDefine(_RUNNING_BUFFER_MARKER, stc.STC_MARK_BACKGROUND,
65 65 background=_RUNNING_BUFFER_BG)
66 66 # Marker for tracebacks.
67 67 self.MarkerDefine(_ERROR_MARKER, stc.STC_MARK_BACKGROUND,
68 68 background=_ERROR_BG)
69 69
70 70
71 71
72 72 def do_completion(self):
73 73 """ Do code completion.
74 74 """
75 75 line = self.get_current_edit_buffer()
76 76 new_line, completions = self.complete(line)
77 77 if len(completions)>1:
78 78 self.write_completion(completions)
79 79 self.replace_current_edit_buffer(new_line)
80 80
81 81
82 82 def do_calltip(self):
83 83 separators = re.compile('[\s\{\}\[\]\(\)\= ,:]')
84 84 symbol = self.get_current_edit_buffer()
85 85 symbol_string = separators.split(symbol)[-1]
86 86 base_symbol_string = symbol_string.split('.')[0]
87 87 if base_symbol_string in self.shell.user_ns:
88 88 symbol = self.shell.user_ns[base_symbol_string]
89 89 elif base_symbol_string in self.shell.user_global_ns:
90 90 symbol = self.shell.user_global_ns[base_symbol_string]
91 91 elif base_symbol_string in __builtin__.__dict__:
92 92 symbol = __builtin__.__dict__[base_symbol_string]
93 93 else:
94 94 return False
95 95 for name in symbol_string.split('.')[1:] + ['__doc__']:
96 96 symbol = getattr(symbol, name)
97 97 try:
98 98 self.AutoCompCancel()
99 99 wx.Yield()
100 100 self.CallTipShow(self.GetCurrentPos(), symbol)
101 101 except:
102 102 # The retrieve symbol couldn't be converted to a string
103 103 pass
104 104
105 105
106 106 def popup_completion(self, create=False):
107 107 """ Updates the popup completion menu if it exists. If create is
108 108 true, open the menu.
109 109 """
110 110 line = self.get_current_edit_buffer()
111 111 if (self.AutoCompActive() and not line[-1] == '.') \
112 112 or create==True:
113 113 suggestion, completions = self.complete(line)
114 114 offset=0
115 115 if completions:
116 116 complete_sep = re.compile('[\s\{\}\[\]\(\)\= ,:]')
117 117 residual = complete_sep.split(line)[-1]
118 118 offset = len(residual)
119 119 self.pop_completion(completions, offset=offset)
120 120
121 121
122 122 def raw_input(self, prompt):
123 123 """ A replacement from python's raw_input.
124 124 """
125 125 self.new_prompt(prompt)
126 126 self.waiting = True
127 127 self.__old_on_enter = self._on_enter
128 128 def my_on_enter():
129 129 self.waiting = False
130 130 self._on_enter = my_on_enter
131 131 # XXX: Busy waiting, ugly.
132 132 while self.waiting:
133 133 wx.Yield()
134 134 sleep(0.1)
135 135 self._on_enter = self.__old_on_enter
136 136 return self.get_current_edit_buffer().rstrip('\n')
137 137
138 138
139 139 def execute(self, python_string, raw_string=None):
140 140 self.CallTipCancel()
141 141 self._cursor = wx.BusyCursor()
142 142 if raw_string is None:
143 143 raw_string = python_string
144 144 end_line = self.current_prompt_line \
145 145 + max(1, len(raw_string.split('\n'))-1)
146 146 for i in range(self.current_prompt_line, end_line):
147 147 self.MarkerAdd(i, _RUNNING_BUFFER_MARKER)
148 148 # Update the display:
149 149 wx.Yield()
150 150 ## Remove the trailing "\n" for cleaner display
151 151 #self.SetSelection(self.GetLength()-1, self.GetLength())
152 152 #self.ReplaceSelection('')
153 153 self.GotoPos(self.GetLength())
154 154 self.__old_raw_input = __builtin__.raw_input
155 155 __builtin__.raw_input = self.raw_input
156 156 PrefilterFrontEnd.execute(self, python_string, raw_string=raw_string)
157 157 __builtin__.raw_input = self.__old_raw_input
158 158
159 159
160 160 def after_execute(self):
161 161 PrefilterFrontEnd.after_execute(self)
162 162 if hasattr(self, '_cursor'):
163 163 del self._cursor
164 164
165 165
166 166 def show_traceback(self):
167 167 start_line = self.GetCurrentLine()
168 168 PrefilterFrontEnd.show_traceback(self)
169 169 wx.Yield()
170 170 for i in range(start_line, self.GetCurrentLine()):
171 171 self.MarkerAdd(i, _ERROR_MARKER)
172 172
173 173
174 174 #--------------------------------------------------------------------------
175 175 # Private API
176 176 #--------------------------------------------------------------------------
177 177
178 178
179 179 def _on_key_down(self, event, skip=True):
180 180 """ Capture the character events, let the parent
181 181 widget handle them, and put our logic afterward.
182 182 """
183 183 current_line_number = self.GetCurrentLine()
184 # Calltips
184 185 if event.KeyCode == ord('('):
185 186 event.Skip()
186 187 self.do_calltip()
187 188 elif self.AutoCompActive():
188 189 event.Skip()
189 190 if event.KeyCode in (wx.WXK_BACK, wx.WXK_DELETE):
190 191 wx.CallAfter(self.popup_completion, create=True)
191 192 elif not event.KeyCode in (wx.WXK_UP, wx.WXK_DOWN, wx.WXK_LEFT,
192 193 wx.WXK_RIGHT):
193 194 wx.CallAfter(self.popup_completion)
194 195 else:
195 196 # Up history
196 197 if event.KeyCode == wx.WXK_UP and (
197 198 ( current_line_number == self.current_prompt_line and
198 199 event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN) )
199 200 or event.ControlDown() ):
200 201 new_buffer = self.get_history_previous(
201 202 self.get_current_edit_buffer())
202 203 if new_buffer is not None:
203 204 self.replace_current_edit_buffer(new_buffer)
204 205 if self.GetCurrentLine() > self.current_prompt_line:
205 206 # Go to first line, for seemless history up.
206 207 self.GotoPos(self.current_prompt_pos)
207 208 # Down history
208 209 elif event.KeyCode == wx.WXK_DOWN and (
209 210 ( current_line_number == self.LineCount -1 and
210 211 event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN) )
211 212 or event.ControlDown() ):
212 213 new_buffer = self.get_history_next()
213 214 if new_buffer is not None:
214 215 self.replace_current_edit_buffer(new_buffer)
216 # Tab-completion
215 217 elif event.KeyCode == ord('\t'):
216 218 last_line = self.get_current_edit_buffer().split('\n')[-1]
217 219 if not re.match(r'^\s*$', last_line):
218 220 self.do_completion()
219 221 else:
220 222 event.Skip()
221 223 else:
222 224 ConsoleWidget._on_key_down(self, event, skip=skip)
223 225
224 226
225 227 def _on_key_up(self, event, skip=True):
226 228 if event.KeyCode == 59:
227 229 # Intercepting '.'
228 230 event.Skip()
229 231 self.popup_completion(create=True)
230 232 else:
231 233 ConsoleWidget._on_key_up(self, event, skip=skip)
232 234
233 235
234 236 if __name__ == '__main__':
235 237 class MainWindow(wx.Frame):
236 238 def __init__(self, parent, id, title):
237 239 wx.Frame.__init__(self, parent, id, title, size=(300,250))
238 240 self._sizer = wx.BoxSizer(wx.VERTICAL)
239 241 self.shell = WxController(self)
240 242 self._sizer.Add(self.shell, 1, wx.EXPAND)
241 243 self.SetSizer(self._sizer)
242 244 self.SetAutoLayout(1)
243 245 self.Show(True)
244 246
245 247 app = wx.PySimpleApp()
246 248 frame = MainWindow(None, wx.ID_ANY, 'Ipython')
247 249 frame.shell.SetFocus()
248 250 frame.SetSize((680, 460))
249 251 self = frame.shell
250 252
251 253 app.MainLoop()
252 254
General Comments 0
You need to be logged in to leave comments. Login now