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