##// END OF EJS Templates
Sync with upstream. Make the wx frontend work without any twisted...
Gael Varoquaux -
Show More
@@ -1,207 +1,201 b''
1 # encoding: utf-8 -*- test-case-name:
1 # encoding: utf-8 -*- test-case-name:
2 # FIXME: Need to add tests.
2 # ipython1.frontend.cocoa.tests.test_cocoa_frontend -*-
3 # ipython1.frontend.cocoa.tests.test_cocoa_frontend -*-
3
4
4 """Classes to provide a Wx frontend to the
5 """Classes to provide a Wx frontend to the
5 ipython1.kernel.engineservice.EngineService.
6 ipython1.kernel.engineservice.EngineService.
6
7
7 """
8 """
8
9
9 __docformat__ = "restructuredtext en"
10 __docformat__ = "restructuredtext en"
10
11
11 #-------------------------------------------------------------------------------
12 #-------------------------------------------------------------------------------
12 # Copyright (C) 2008 The IPython Development Team
13 # Copyright (C) 2008 The IPython Development Team
13 #
14 #
14 # 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
15 # the file COPYING, distributed as part of this software.
16 # the file COPYING, distributed as part of this software.
16 #-------------------------------------------------------------------------------
17 #-------------------------------------------------------------------------------
17
18
18 #-------------------------------------------------------------------------------
19 #-------------------------------------------------------------------------------
19 # Imports
20 # Imports
20 #-------------------------------------------------------------------------------
21 #-------------------------------------------------------------------------------
21
22
22
23
23 import wx
24 import wx
24 from console_widget import ConsoleWidget
25 from console_widget import ConsoleWidget
25 import re
26 import re
26
27
27 import IPython
28 import IPython
28 from IPython.kernel.engineservice import EngineService
29 from IPython.kernel.core.interpreter import Interpreter
29 from IPython.kernel.core.history import FrontEndHistory
30 from IPython.frontend.frontendbase import FrontEndBase
30 from IPython.frontend.frontendbase import FrontEndBase
31
31
32 #-------------------------------------------------------------------------------
32 #-------------------------------------------------------------------------------
33 # Classes to implement the Wx frontend
33 # Classes to implement the Wx frontend
34 #-------------------------------------------------------------------------------
34 #-------------------------------------------------------------------------------
35
35
36
36
37
37
38
38
39 class IPythonWxController(FrontEndBase, ConsoleWidget):
39 class IPythonWxController(FrontEndBase, ConsoleWidget):
40
40
41 output_prompt = \
41 output_prompt = \
42 '\n\x01\x1b[0;31m\x02Out[\x01\x1b[1;31m\x02%i\x01\x1b[0;31m\x02]: \x01\x1b[0m\x02'
42 '\n\x01\x1b[0;31m\x02Out[\x01\x1b[1;31m\x02%i\x01\x1b[0;31m\x02]: \x01\x1b[0m\x02'
43
43
44 # Are we entering multi line input?
44 # Are we entering multi line input?
45 multi_line_input = False
45 multi_line_input = False
46
46
47 # The added tab stop to the string. It may, for instance, come from
47 # The added tab stop to the string. It may, for instance, come from
48 # copy and pasting something with tabs.
48 # copy and pasting something with tabs.
49 tab_stop = 0
49 tab_stop = 0
50 # FIXME: We still have to deal with this.
50 # FIXME: We still have to deal with this.
51
51
52 #--------------------------------------------------------------------------
52 #--------------------------------------------------------------------------
53 # Public API
53 # Public API
54 #--------------------------------------------------------------------------
54 #--------------------------------------------------------------------------
55
55
56 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
56 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
57 size=wx.DefaultSize, style=wx.CLIP_CHILDREN,
57 size=wx.DefaultSize, style=wx.CLIP_CHILDREN,
58 *args, **kwds):
58 *args, **kwds):
59 """ Create Shell instance.
59 """ Create Shell instance.
60 """
60 """
61 ConsoleWidget.__init__(self, parent, id, pos, size, style)
61 ConsoleWidget.__init__(self, parent, id, pos, size, style)
62 FrontEndBase.__init__(self, engine=EngineService(),
62 FrontEndBase.__init__(self, shell=Interpreter(),
63 )
63 )
64
64
65 # FIXME: Something is wrong with the history, I instanciate it
65 # FIXME: Something is wrong with the history, I instanciate it
66 # with an empty cache, but this is not the way to do.
66 # with an empty cache, but this is not the way to do.
67 self.lines = {}
67 self.lines = {}
68
68
69 # Start the IPython engine
69 # Start the IPython engine
70 self.engine.startService()
70 self.shell
71
71
72 # Capture Character keys
72 # Capture Character keys
73 self.Bind(wx.EVT_KEY_DOWN, self._on_key_down)
73 self.Bind(wx.EVT_KEY_DOWN, self._on_key_down)
74
74
75 #FIXME: print banner.
75 #FIXME: print banner.
76 banner = """IPython1 %s -- An enhanced Interactive Python.""" \
76 banner = """IPython1 %s -- An enhanced Interactive Python.""" \
77 % IPython.__version__
77 % IPython.__version__
78
78
79
79
80 def appWillTerminate_(self, notification):
81 """appWillTerminate"""
82
83 self.engine.stopService()
84
85
86 def complete(self, token):
80 def complete(self, token):
87 """Complete token in engine's user_ns
81 """Complete token in engine's user_ns
88
82
89 Parameters
83 Parameters
90 ----------
84 ----------
91 token : string
85 token : string
92
86
93 Result
87 Result
94 ------
88 ------
95 Deferred result of
89 Deferred result of
96 IPython.kernel.engineservice.IEngineBase.complete
90 IPython.kernel.engineservice.IEngineBase.complete
97 """
91 """
98
92
99 return self.engine.complete(token)
93 return self.shell.complete(token)
100
94
101
95
102 def render_result(self, result):
96 def render_result(self, result):
103 if 'stdout' in result and result['stdout']:
97 if 'stdout' in result and result['stdout']:
104 self.write('\n' + result['stdout'])
98 self.write('\n' + result['stdout'])
105 if 'display' in result and result['display']:
99 if 'display' in result and result['display']:
106 self.write("%s%s\n" % (
100 self.write("%s%s\n" % (
107 self.output_prompt % result['number'],
101 self.output_prompt % result['number'],
108 result['display']['pprint']
102 result['display']['pprint']
109 ) )
103 ) )
110
104
111
105
112 def render_error(self, failure):
106 def render_error(self, failure):
113 self.insert_text('\n\n'+str(failure)+'\n\n')
107 self.insert_text('\n\n'+str(failure)+'\n\n')
114 return failure
108 return failure
115
109
116
110
117 #--------------------------------------------------------------------------
111 #--------------------------------------------------------------------------
118 # Private API
112 # Private API
119 #--------------------------------------------------------------------------
113 #--------------------------------------------------------------------------
120
114
121
115
122 def _on_key_down(self, event, skip=True):
116 def _on_key_down(self, event, skip=True):
123 """ Capture the character events, let the parent
117 """ Capture the character events, let the parent
124 widget handle them, and put our logic afterward.
118 widget handle them, and put our logic afterward.
125 """
119 """
126 current_line_number = self.GetCurrentLine()
120 current_line_number = self.GetCurrentLine()
127 # Capture enter
121 # Capture enter
128 if event.KeyCode in (13, wx.WXK_NUMPAD_ENTER) and \
122 if event.KeyCode in (13, wx.WXK_NUMPAD_ENTER) and \
129 event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN):
123 event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN):
130 self._on_enter()
124 self._on_enter()
131 # Up history
125 # Up history
132 elif event.KeyCode == wx.WXK_UP and (
126 elif event.KeyCode == wx.WXK_UP and (
133 ( current_line_number == self.current_prompt_line and
127 ( current_line_number == self.current_prompt_line and
134 event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN) )
128 event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN) )
135 or event.ControlDown() ):
129 or event.ControlDown() ):
136 new_buffer = self.get_history_previous(
130 new_buffer = self.get_history_previous(
137 self.get_current_edit_buffer())
131 self.get_current_edit_buffer())
138 if new_buffer is not None:
132 if new_buffer is not None:
139 self.replace_current_edit_buffer(new_buffer)
133 self.replace_current_edit_buffer(new_buffer)
140 # Down history
134 # Down history
141 elif event.KeyCode == wx.WXK_DOWN and (
135 elif event.KeyCode == wx.WXK_DOWN and (
142 ( current_line_number == self.LineCount -1 and
136 ( current_line_number == self.LineCount -1 and
143 event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN) )
137 event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN) )
144 or event.ControlDown() ):
138 or event.ControlDown() ):
145 new_buffer = self.get_history_next()
139 new_buffer = self.get_history_next()
146 if new_buffer is not None:
140 if new_buffer is not None:
147 self.replace_current_edit_buffer(new_buffer)
141 self.replace_current_edit_buffer(new_buffer)
148 else:
142 else:
149 ConsoleWidget._on_key_down(self, event, skip=True)
143 ConsoleWidget._on_key_down(self, event, skip=True)
150
144
151
145
152 def _on_enter(self):
146 def _on_enter(self):
153 """ Called when the return key is pressed in a line editing
147 """ Called when the return key is pressed in a line editing
154 buffer.
148 buffer.
155 """
149 """
156 current_buffer = self.get_current_edit_buffer()
150 current_buffer = self.get_current_edit_buffer()
157 current_buffer = current_buffer.replace('\r\n', '\n')
151 current_buffer = current_buffer.replace('\r\n', '\n')
158 current_buffer = current_buffer.replace('\t', 4*' ')
152 current_buffer = current_buffer.replace('\t', 4*' ')
159 cleaned_buffer = '\n'.join(l.rstrip()
153 cleaned_buffer = '\n'.join(l.rstrip()
160 for l in current_buffer.split('\n'))
154 for l in current_buffer.split('\n'))
161 if ( not self.multi_line_input
155 if ( not self.multi_line_input
162 or re.findall(r"\n[\t ]*$", cleaned_buffer)):
156 or re.findall(r"\n[\t ]*$", cleaned_buffer)):
163 if self.is_complete(cleaned_buffer):
157 if self.is_complete(cleaned_buffer):
164 self._add_history(None, cleaned_buffer.rstrip())
158 self._add_history(None, cleaned_buffer.rstrip())
165 result = self.engine.shell.execute(cleaned_buffer)
159 result = self.shell.execute(cleaned_buffer)
166 self.render_result(result)
160 self.render_result(result)
167 self.new_prompt(self.prompt % (result['number'] + 1))
161 self.new_prompt(self.prompt % (result['number'] + 1))
168 self.multi_line_input = False
162 self.multi_line_input = False
169 else:
163 else:
170 if self.multi_line_input:
164 if self.multi_line_input:
171 self.write('\n' + self._get_indent_string(current_buffer))
165 self.write('\n' + self._get_indent_string(current_buffer))
172 else:
166 else:
173 self.multi_line_input = True
167 self.multi_line_input = True
174 self.write('\n\t')
168 self.write('\n\t')
175 else:
169 else:
176 self.write('\n'+self._get_indent_string(current_buffer))
170 self.write('\n'+self._get_indent_string(current_buffer))
177
171
178
172
179 def _get_indent_string(self, string):
173 def _get_indent_string(self, string):
180 string = string.split('\n')[-1]
174 string = string.split('\n')[-1]
181 indent_chars = len(string) - len(string.lstrip())
175 indent_chars = len(string) - len(string.lstrip())
182 indent_string = '\t'*(indent_chars // 4) + \
176 indent_string = '\t'*(indent_chars // 4) + \
183 ' '*(indent_chars % 4)
177 ' '*(indent_chars % 4)
184
178
185 return indent_string
179 return indent_string
186
180
187
181
188
182
189 if __name__ == '__main__':
183 if __name__ == '__main__':
190 class MainWindow(wx.Frame):
184 class MainWindow(wx.Frame):
191 def __init__(self, parent, id, title):
185 def __init__(self, parent, id, title):
192 wx.Frame.__init__(self, parent, id, title, size=(300,250))
186 wx.Frame.__init__(self, parent, id, title, size=(300,250))
193 self._sizer = wx.BoxSizer(wx.VERTICAL)
187 self._sizer = wx.BoxSizer(wx.VERTICAL)
194 self.shell = IPythonWxController(self)
188 self.shell = IPythonWxController(self)
195 self._sizer.Add(self.shell, 1, wx.EXPAND)
189 self._sizer.Add(self.shell, 1, wx.EXPAND)
196 self.SetSizer(self._sizer)
190 self.SetSizer(self._sizer)
197 self.SetAutoLayout(1)
191 self.SetAutoLayout(1)
198 self.Show(True)
192 self.Show(True)
199
193
200 app = wx.PySimpleApp()
194 app = wx.PySimpleApp()
201 frame = MainWindow(None, wx.ID_ANY, 'Ipython')
195 frame = MainWindow(None, wx.ID_ANY, 'Ipython')
202 frame.shell.SetFocus()
196 frame.shell.SetFocus()
203 frame.SetSize((660, 460))
197 frame.SetSize((660, 460))
204 self = frame.shell
198 self = frame.shell
205
199
206 app.MainLoop()
200 app.MainLoop()
207
201
General Comments 0
You need to be logged in to leave comments. Login now