##// END OF EJS Templates
Tracebacks in red.
Gael Varoquaux -
Show More
@@ -1,218 +1,231 b''
1 # encoding: utf-8 -*- test-case-name:
1 # encoding: utf-8 -*- test-case-name:
2 # FIXME: Need to add tests.
2 # FIXME: Need to add tests.
3 # ipython1.frontend.cocoa.tests.test_cocoa_frontend -*-
3 # ipython1.frontend.cocoa.tests.test_cocoa_frontend -*-
4
4
5 """Classes to provide a Wx frontend to the
5 """Classes to provide a Wx frontend to the
6 IPython.kernel.core.interpreter.
6 IPython.kernel.core.interpreter.
7
7
8 """
8 """
9
9
10 __docformat__ = "restructuredtext en"
10 __docformat__ = "restructuredtext en"
11
11
12 #-------------------------------------------------------------------------------
12 #-------------------------------------------------------------------------------
13 # Copyright (C) 2008 The IPython Development Team
13 # Copyright (C) 2008 The IPython Development Team
14 #
14 #
15 # Distributed under the terms of the BSD License. The full license is in
15 # Distributed under the terms of the BSD License. The full license is in
16 # the file COPYING, distributed as part of this software.
16 # the file COPYING, distributed as part of this software.
17 #-------------------------------------------------------------------------------
17 #-------------------------------------------------------------------------------
18
18
19 #-------------------------------------------------------------------------------
19 #-------------------------------------------------------------------------------
20 # Imports
20 # Imports
21 #-------------------------------------------------------------------------------
21 #-------------------------------------------------------------------------------
22
22
23
23
24 import wx
24 import wx
25 import re
25 import re
26 from wx import stc
26 from wx import stc
27 from console_widget import ConsoleWidget
27 from console_widget import ConsoleWidget
28 import __builtin__
28 import __builtin__
29
29
30 from IPython.frontend.prefilterfrontend import PrefilterFrontEnd
30 from IPython.frontend.prefilterfrontend import PrefilterFrontEnd
31
31
32 #_COMMAND_BG = '#FAFAF1' # Nice green
32 #_COMMAND_BG = '#FAFAF1' # Nice green
33 _RUNNING_BUFFER_BG = '#FDFFD3' # Nice yellow
33 _RUNNING_BUFFER_BG = '#FDFFD3' # Nice yellow
34 _ERROR_BG = '#FFF1F1' # Nice red
34
35
35 _RUNNING_BUFFER_MARKER = 31
36 _RUNNING_BUFFER_MARKER = 31
36
37 _ERROR_MARKER = 30
37
38
38 #-------------------------------------------------------------------------------
39 #-------------------------------------------------------------------------------
39 # Classes to implement the Wx frontend
40 # Classes to implement the Wx frontend
40 #-------------------------------------------------------------------------------
41 #-------------------------------------------------------------------------------
41 class IPythonWxController(PrefilterFrontEnd, ConsoleWidget):
42 class IPythonWxController(PrefilterFrontEnd, ConsoleWidget):
42
43
43 output_prompt = \
44 output_prompt = \
44 '\x01\x1b[0;31m\x02Out[\x01\x1b[1;31m\x02%i\x01\x1b[0;31m\x02]: \x01\x1b[0m\x02'
45 '\x01\x1b[0;31m\x02Out[\x01\x1b[1;31m\x02%i\x01\x1b[0;31m\x02]: \x01\x1b[0m\x02'
45
46
46 #--------------------------------------------------------------------------
47 #--------------------------------------------------------------------------
47 # Public API
48 # Public API
48 #--------------------------------------------------------------------------
49 #--------------------------------------------------------------------------
49
50
50 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
51 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
51 size=wx.DefaultSize, style=wx.CLIP_CHILDREN,
52 size=wx.DefaultSize, style=wx.CLIP_CHILDREN,
52 *args, **kwds):
53 *args, **kwds):
53 """ Create Shell instance.
54 """ Create Shell instance.
54 """
55 """
55 ConsoleWidget.__init__(self, parent, id, pos, size, style)
56 ConsoleWidget.__init__(self, parent, id, pos, size, style)
56 PrefilterFrontEnd.__init__(self)
57 PrefilterFrontEnd.__init__(self)
57
58
58 # Capture Character keys
59 # Capture Character keys
59 self.Bind(wx.EVT_KEY_DOWN, self._on_key_down)
60 self.Bind(wx.EVT_KEY_DOWN, self._on_key_down)
60
61
61 # Marker for running buffer.
62 # Marker for running buffer.
62 self.MarkerDefine(_RUNNING_BUFFER_MARKER, stc.STC_MARK_BACKGROUND,
63 self.MarkerDefine(_RUNNING_BUFFER_MARKER, stc.STC_MARK_BACKGROUND,
63 background=_RUNNING_BUFFER_BG)
64 background=_RUNNING_BUFFER_BG)
65 # Marker for tracebacks.
66 self.MarkerDefine(_ERROR_MARKER, stc.STC_MARK_BACKGROUND,
67 background=_ERROR_BG)
64
68
65
69
66
70
67 def do_completion(self):
71 def do_completion(self):
68 """ Do code completion.
72 """ Do code completion.
69 """
73 """
70 line = self.get_current_edit_buffer()
74 line = self.get_current_edit_buffer()
71 new_line, completions = self.complete(line)
75 new_line, completions = self.complete(line)
72 if len(completions)>1:
76 if len(completions)>1:
73 self.write_completion(completions)
77 self.write_completion(completions)
74 self.replace_current_edit_buffer(new_line)
78 self.replace_current_edit_buffer(new_line)
75
79
76
80
77 def do_calltip(self):
81 def do_calltip(self):
78 separators = re.compile('[\s\{\}\[\]\(\)\= ,:]')
82 separators = re.compile('[\s\{\}\[\]\(\)\= ,:]')
79 symbol = self.get_current_edit_buffer()
83 symbol = self.get_current_edit_buffer()
80 symbol_string = separators.split(symbol)[-1]
84 symbol_string = separators.split(symbol)[-1]
81 base_symbol_string = symbol_string.split('.')[0]
85 base_symbol_string = symbol_string.split('.')[0]
82 if base_symbol_string in self.shell.user_ns:
86 if base_symbol_string in self.shell.user_ns:
83 symbol = self.shell.user_ns[base_symbol_string]
87 symbol = self.shell.user_ns[base_symbol_string]
84 elif base_symbol_string in self.shell.user_global_ns:
88 elif base_symbol_string in self.shell.user_global_ns:
85 symbol = self.shell.user_global_ns[base_symbol_string]
89 symbol = self.shell.user_global_ns[base_symbol_string]
86 elif base_symbol_string in __builtin__.__dict__:
90 elif base_symbol_string in __builtin__.__dict__:
87 symbol = __builtin__.__dict__[base_symbol_string]
91 symbol = __builtin__.__dict__[base_symbol_string]
88 else:
92 else:
89 return False
93 return False
90 for name in symbol_string.split('.')[1:] + ['__doc__']:
94 for name in symbol_string.split('.')[1:] + ['__doc__']:
91 symbol = getattr(symbol, name)
95 symbol = getattr(symbol, name)
92 try:
96 try:
93 self.AutoCompCancel()
97 self.AutoCompCancel()
94 wx.Yield()
98 wx.Yield()
95 self.CallTipShow(self.GetCurrentPos(), symbol)
99 self.CallTipShow(self.GetCurrentPos(), symbol)
96 except:
100 except:
97 # The retrieve symbol couldn't be converted to a string
101 # The retrieve symbol couldn't be converted to a string
98 pass
102 pass
99
103
100
104
101 def popup_completion(self, create=False):
105 def popup_completion(self, create=False):
102 """ Updates the popup completion menu if it exists. If create is
106 """ Updates the popup completion menu if it exists. If create is
103 true, open the menu.
107 true, open the menu.
104 """
108 """
105 line = self.get_current_edit_buffer()
109 line = self.get_current_edit_buffer()
106 if (self.AutoCompActive() and not line[-1] == '.') \
110 if (self.AutoCompActive() and not line[-1] == '.') \
107 or create==True:
111 or create==True:
108 suggestion, completions = self.complete(line)
112 suggestion, completions = self.complete(line)
109 offset=0
113 offset=0
110 if completions:
114 if completions:
111 complete_sep = re.compile('[\s\{\}\[\]\(\)\= ,:]')
115 complete_sep = re.compile('[\s\{\}\[\]\(\)\= ,:]')
112 residual = complete_sep.split(line)[-1]
116 residual = complete_sep.split(line)[-1]
113 offset = len(residual)
117 offset = len(residual)
114 self.pop_completion(completions, offset=offset)
118 self.pop_completion(completions, offset=offset)
115
119
116
120
117 def execute(self, python_string, raw_string=None):
121 def execute(self, python_string, raw_string=None):
118 self.CallTipCancel()
122 self.CallTipCancel()
119 self._cursor = wx.BusyCursor()
123 self._cursor = wx.BusyCursor()
120 if raw_string is None:
124 if raw_string is None:
121 raw_string = python_string
125 raw_string = python_string
122 end_line = self.current_prompt_line \
126 end_line = self.current_prompt_line \
123 + max(1, len(raw_string.split('\n'))-1)
127 + max(1, len(raw_string.split('\n'))-1)
124 for i in range(self.current_prompt_line, end_line):
128 for i in range(self.current_prompt_line, end_line):
125 self.MarkerAdd(i, 31)
129 self.MarkerAdd(i, _RUNNING_BUFFER_MARKER)
126 # Update the display:
130 # Update the display:
127 wx.Yield()
131 wx.Yield()
128 ## Remove the trailing "\n" for cleaner display
132 ## Remove the trailing "\n" for cleaner display
129 #self.SetSelection(self.GetLength()-1, self.GetLength())
133 #self.SetSelection(self.GetLength()-1, self.GetLength())
130 #self.ReplaceSelection('')
134 #self.ReplaceSelection('')
131 self.GotoPos(self.GetLength())
135 self.GotoPos(self.GetLength())
132 PrefilterFrontEnd.execute(self, python_string, raw_string=raw_string)
136 PrefilterFrontEnd.execute(self, python_string, raw_string=raw_string)
133
137
134
138
135 def after_execute(self):
139 def after_execute(self):
136 PrefilterFrontEnd.after_execute(self)
140 PrefilterFrontEnd.after_execute(self)
137 if hasattr(self, '_cursor'):
141 if hasattr(self, '_cursor'):
138 del self._cursor
142 del self._cursor
139
143
144
145 def show_traceback(self):
146 start_line = self.GetCurrentLine()
147 PrefilterFrontEnd.show_traceback(self)
148 wx.Yield()
149 for i in range(start_line, self.GetCurrentLine()):
150 self.MarkerAdd(i, _ERROR_MARKER)
151
152
140 #--------------------------------------------------------------------------
153 #--------------------------------------------------------------------------
141 # Private API
154 # Private API
142 #--------------------------------------------------------------------------
155 #--------------------------------------------------------------------------
143
156
144
157
145 def _on_key_down(self, event, skip=True):
158 def _on_key_down(self, event, skip=True):
146 """ Capture the character events, let the parent
159 """ Capture the character events, let the parent
147 widget handle them, and put our logic afterward.
160 widget handle them, and put our logic afterward.
148 """
161 """
149 current_line_number = self.GetCurrentLine()
162 current_line_number = self.GetCurrentLine()
150 if event.KeyCode == ord('('):
163 if event.KeyCode == ord('('):
151 event.Skip()
164 event.Skip()
152 self.do_calltip()
165 self.do_calltip()
153 elif self.AutoCompActive():
166 elif self.AutoCompActive():
154 event.Skip()
167 event.Skip()
155 if event.KeyCode in (wx.WXK_BACK, wx.WXK_DELETE):
168 if event.KeyCode in (wx.WXK_BACK, wx.WXK_DELETE):
156 wx.CallAfter(self.popup_completion, create=True)
169 wx.CallAfter(self.popup_completion, create=True)
157 elif not event.KeyCode in (wx.WXK_UP, wx.WXK_DOWN, wx.WXK_LEFT,
170 elif not event.KeyCode in (wx.WXK_UP, wx.WXK_DOWN, wx.WXK_LEFT,
158 wx.WXK_RIGHT):
171 wx.WXK_RIGHT):
159 wx.CallAfter(self.popup_completion)
172 wx.CallAfter(self.popup_completion)
160 else:
173 else:
161 # Up history
174 # Up history
162 if event.KeyCode == wx.WXK_UP and (
175 if event.KeyCode == wx.WXK_UP and (
163 ( current_line_number == self.current_prompt_line and
176 ( current_line_number == self.current_prompt_line and
164 event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN) )
177 event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN) )
165 or event.ControlDown() ):
178 or event.ControlDown() ):
166 new_buffer = self.get_history_previous(
179 new_buffer = self.get_history_previous(
167 self.get_current_edit_buffer())
180 self.get_current_edit_buffer())
168 if new_buffer is not None:
181 if new_buffer is not None:
169 self.replace_current_edit_buffer(new_buffer)
182 self.replace_current_edit_buffer(new_buffer)
170 if self.GetCurrentLine() > self.current_prompt_line:
183 if self.GetCurrentLine() > self.current_prompt_line:
171 # Go to first line, for seemless history up.
184 # Go to first line, for seemless history up.
172 self.GotoPos(self.current_prompt_pos)
185 self.GotoPos(self.current_prompt_pos)
173 # Down history
186 # Down history
174 elif event.KeyCode == wx.WXK_DOWN and (
187 elif event.KeyCode == wx.WXK_DOWN and (
175 ( current_line_number == self.LineCount -1 and
188 ( current_line_number == self.LineCount -1 and
176 event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN) )
189 event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN) )
177 or event.ControlDown() ):
190 or event.ControlDown() ):
178 new_buffer = self.get_history_next()
191 new_buffer = self.get_history_next()
179 if new_buffer is not None:
192 if new_buffer is not None:
180 self.replace_current_edit_buffer(new_buffer)
193 self.replace_current_edit_buffer(new_buffer)
181 elif event.KeyCode == ord('\t'):
194 elif event.KeyCode == ord('\t'):
182 last_line = self.get_current_edit_buffer().split('\n')[-1]
195 last_line = self.get_current_edit_buffer().split('\n')[-1]
183 if not re.match(r'^\s*$', last_line):
196 if not re.match(r'^\s*$', last_line):
184 self.do_completion()
197 self.do_completion()
185 else:
198 else:
186 event.Skip()
199 event.Skip()
187 else:
200 else:
188 ConsoleWidget._on_key_down(self, event, skip=skip)
201 ConsoleWidget._on_key_down(self, event, skip=skip)
189
202
190
203
191 def _on_key_up(self, event, skip=True):
204 def _on_key_up(self, event, skip=True):
192 if event.KeyCode == 59:
205 if event.KeyCode == 59:
193 # Intercepting '.'
206 # Intercepting '.'
194 event.Skip()
207 event.Skip()
195 self.popup_completion(create=True)
208 self.popup_completion(create=True)
196 else:
209 else:
197 ConsoleWidget._on_key_up(self, event, skip=skip)
210 ConsoleWidget._on_key_up(self, event, skip=skip)
198
211
199
212
200 if __name__ == '__main__':
213 if __name__ == '__main__':
201 class MainWindow(wx.Frame):
214 class MainWindow(wx.Frame):
202 def __init__(self, parent, id, title):
215 def __init__(self, parent, id, title):
203 wx.Frame.__init__(self, parent, id, title, size=(300,250))
216 wx.Frame.__init__(self, parent, id, title, size=(300,250))
204 self._sizer = wx.BoxSizer(wx.VERTICAL)
217 self._sizer = wx.BoxSizer(wx.VERTICAL)
205 self.shell = IPythonWxController(self)
218 self.shell = IPythonWxController(self)
206 self._sizer.Add(self.shell, 1, wx.EXPAND)
219 self._sizer.Add(self.shell, 1, wx.EXPAND)
207 self.SetSizer(self._sizer)
220 self.SetSizer(self._sizer)
208 self.SetAutoLayout(1)
221 self.SetAutoLayout(1)
209 self.Show(True)
222 self.Show(True)
210
223
211 app = wx.PySimpleApp()
224 app = wx.PySimpleApp()
212 frame = MainWindow(None, wx.ID_ANY, 'Ipython')
225 frame = MainWindow(None, wx.ID_ANY, 'Ipython')
213 frame.shell.SetFocus()
226 frame.shell.SetFocus()
214 frame.SetSize((680, 460))
227 frame.SetSize((680, 460))
215 self = frame.shell
228 self = frame.shell
216
229
217 app.MainLoop()
230 app.MainLoop()
218
231
General Comments 0
You need to be logged in to leave comments. Login now