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