Show More
@@ -27,6 +27,40 b' import re' | |||||
27 | # FIXME: Need to provide an API for non user-generated display on the |
|
27 | # FIXME: Need to provide an API for non user-generated display on the | |
28 | # screen: this should not be editable by the user. |
|
28 | # screen: this should not be editable by the user. | |
29 |
|
29 | |||
|
30 | if wx.Platform == '__WXMSW__': | |||
|
31 | _DEFAULT_SIZE = 80 | |||
|
32 | else: | |||
|
33 | _DEFAULT_SIZE = 10 | |||
|
34 | ||||
|
35 | _DEFAULT_STYLE = { | |||
|
36 | 'stdout' : 'fore:#0000FF', | |||
|
37 | 'stderr' : 'fore:#007f00', | |||
|
38 | 'trace' : 'fore:#FF0000', | |||
|
39 | ||||
|
40 | 'default' : 'size:%d' % _DEFAULT_SIZE, | |||
|
41 | 'bracegood' : 'fore:#FFFFFF,back:#0000FF,bold', | |||
|
42 | 'bracebad' : 'fore:#000000,back:#FF0000,bold', | |||
|
43 | ||||
|
44 | # properties for the various Python lexer styles | |||
|
45 | 'comment' : 'fore:#007F00', | |||
|
46 | 'number' : 'fore:#007F7F', | |||
|
47 | 'string' : 'fore:#7F007F,italic', | |||
|
48 | 'char' : 'fore:#7F007F,italic', | |||
|
49 | 'keyword' : 'fore:#00007F,bold', | |||
|
50 | 'triple' : 'fore:#7F0000', | |||
|
51 | 'tripledouble': 'fore:#7F0000', | |||
|
52 | 'class' : 'fore:#0000FF,bold,underline', | |||
|
53 | 'def' : 'fore:#007F7F,bold', | |||
|
54 | 'operator' : 'bold', | |||
|
55 | ||||
|
56 | } | |||
|
57 | ||||
|
58 | # new style numbers | |||
|
59 | _STDOUT_STYLE = 15 | |||
|
60 | _STDERR_STYLE = 16 | |||
|
61 | _TRACE_STYLE = 17 | |||
|
62 | ||||
|
63 | ||||
30 | #------------------------------------------------------------------------------- |
|
64 | #------------------------------------------------------------------------------- | |
31 | # The console widget class |
|
65 | # The console widget class | |
32 | #------------------------------------------------------------------------------- |
|
66 | #------------------------------------------------------------------------------- | |
@@ -37,6 +71,8 b' class ConsoleWidget(stc.StyledTextCtrl):' | |||||
37 | keeping the cursor inside the editing line. |
|
71 | keeping the cursor inside the editing line. | |
38 | """ |
|
72 | """ | |
39 |
|
73 | |||
|
74 | style = _DEFAULT_STYLE.copy() | |||
|
75 | ||||
40 | # Translation table from ANSI escape sequences to color. Override |
|
76 | # Translation table from ANSI escape sequences to color. Override | |
41 | # this to specify your colors. |
|
77 | # this to specify your colors. | |
42 | ANSI_STYLES = {'0;30': [0, 'BLACK'], '0;31': [1, 'RED'], |
|
78 | ANSI_STYLES = {'0;30': [0, 'BLACK'], '0;31': [1, 'RED'], | |
@@ -57,6 +93,88 b' class ConsoleWidget(stc.StyledTextCtrl):' | |||||
57 | # Public API |
|
93 | # Public API | |
58 | #-------------------------------------------------------------------------- |
|
94 | #-------------------------------------------------------------------------- | |
59 |
|
95 | |||
|
96 | def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, | |||
|
97 | size=wx.DefaultSize, style=0, | |||
|
98 | autocomplete_mode='IPYTHON'): | |||
|
99 | """ Autocomplete_mode: Can be 'IPYTHON' or 'STC' | |||
|
100 | 'IPYTHON' show autocompletion the ipython way | |||
|
101 | 'STC" show it scintilla text control way | |||
|
102 | """ | |||
|
103 | stc.StyledTextCtrl.__init__(self, parent, id, pos, size, style) | |||
|
104 | self.configure_scintilla() | |||
|
105 | ||||
|
106 | # FIXME: we need to retrieve this from the interpreter. | |||
|
107 | self.prompt = \ | |||
|
108 | '\n\x01\x1b[0;34m\x02In [\x01\x1b[1;34m\x02%i\x01\x1b[0;34m\x02]: \x01\x1b[0m\x02' | |||
|
109 | self.new_prompt(self.prompt % 1) | |||
|
110 | ||||
|
111 | self.autocomplete_mode = autocomplete_mode | |||
|
112 | ||||
|
113 | self.Bind(wx.EVT_KEY_DOWN, self._onKeypress) | |||
|
114 | ||||
|
115 | ||||
|
116 | def configure_scintilla(self): | |||
|
117 | # Ctrl"+" or Ctrl "-" can be used to zoomin/zoomout the text inside | |||
|
118 | # the widget | |||
|
119 | self.CmdKeyAssign(ord('+'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN) | |||
|
120 | self.CmdKeyAssign(ord('-'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT) | |||
|
121 | # Also allow Ctrl Shift "=" for poor non US keyboard users. | |||
|
122 | self.CmdKeyAssign(ord('='), stc.STC_SCMOD_CTRL|stc.STC_SCMOD_SHIFT, | |||
|
123 | stc.STC_CMD_ZOOMIN) | |||
|
124 | ||||
|
125 | self.SetEOLMode(stc.STC_EOL_CRLF) | |||
|
126 | self.SetWrapMode(stc.STC_WRAP_CHAR) | |||
|
127 | self.SetWrapMode(stc.STC_WRAP_WORD) | |||
|
128 | self.SetBufferedDraw(True) | |||
|
129 | self.SetUseAntiAliasing(True) | |||
|
130 | self.SetLayoutCache(stc.STC_CACHE_PAGE) | |||
|
131 | self.SetUndoCollection(False) | |||
|
132 | self.SetUseTabs(True) | |||
|
133 | self.SetIndent(4) | |||
|
134 | self.SetTabWidth(4) | |||
|
135 | ||||
|
136 | self.EnsureCaretVisible() | |||
|
137 | ||||
|
138 | self.SetMargins(3, 3) #text is moved away from border with 3px | |||
|
139 | # Suppressing Scintilla margins | |||
|
140 | self.SetMarginWidth(0, 0) | |||
|
141 | self.SetMarginWidth(1, 0) | |||
|
142 | self.SetMarginWidth(2, 0) | |||
|
143 | ||||
|
144 | self._apply_style() | |||
|
145 | ||||
|
146 | self.indent = 0 | |||
|
147 | self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?') | |||
|
148 | ||||
|
149 | #self.SetEdgeMode(stc.STC_EDGE_LINE) | |||
|
150 | #self.SetEdgeColumn(80) | |||
|
151 | ||||
|
152 | # styles | |||
|
153 | p = self.style | |||
|
154 | self.StyleSetSpec(stc.STC_STYLE_DEFAULT, p['default']) | |||
|
155 | self.StyleClearAll() | |||
|
156 | self.StyleSetSpec(_STDOUT_STYLE, p['stdout']) | |||
|
157 | self.StyleSetSpec(_STDERR_STYLE, p['stderr']) | |||
|
158 | self.StyleSetSpec(_TRACE_STYLE, p['trace']) | |||
|
159 | ||||
|
160 | self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, p['bracegood']) | |||
|
161 | self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, p['bracebad']) | |||
|
162 | self.StyleSetSpec(stc.STC_P_COMMENTLINE, p['comment']) | |||
|
163 | self.StyleSetSpec(stc.STC_P_NUMBER, p['number']) | |||
|
164 | self.StyleSetSpec(stc.STC_P_STRING, p['string']) | |||
|
165 | self.StyleSetSpec(stc.STC_P_CHARACTER, p['char']) | |||
|
166 | self.StyleSetSpec(stc.STC_P_WORD, p['keyword']) | |||
|
167 | self.StyleSetSpec(stc.STC_P_TRIPLE, p['triple']) | |||
|
168 | self.StyleSetSpec(stc.STC_P_TRIPLEDOUBLE, p['tripledouble']) | |||
|
169 | self.StyleSetSpec(stc.STC_P_CLASSNAME, p['class']) | |||
|
170 | self.StyleSetSpec(stc.STC_P_DEFNAME, p['def']) | |||
|
171 | self.StyleSetSpec(stc.STC_P_OPERATOR, p['operator']) | |||
|
172 | self.StyleSetSpec(stc.STC_P_COMMENTBLOCK, p['comment']) | |||
|
173 | ||||
|
174 | ||||
|
175 | ||||
|
176 | ||||
|
177 | ||||
60 | def write(self, text): |
|
178 | def write(self, text): | |
61 | """ Write given text to buffer, while translating the ansi escape |
|
179 | """ Write given text to buffer, while translating the ansi escape | |
62 | sequences. |
|
180 | sequences. | |
@@ -118,59 +236,6 b' class ConsoleWidget(stc.StyledTextCtrl):' | |||||
118 | # Private API |
|
236 | # Private API | |
119 | #-------------------------------------------------------------------------- |
|
237 | #-------------------------------------------------------------------------- | |
120 |
|
238 | |||
121 | def __init__(self, parent, pos=wx.DefaultPosition, ID=-1, |
|
|||
122 | size=wx.DefaultSize, style=0, |
|
|||
123 | autocomplete_mode='IPYTHON'): |
|
|||
124 | """ Autocomplete_mode: Can be 'IPYTHON' or 'STC' |
|
|||
125 | 'IPYTHON' show autocompletion the ipython way |
|
|||
126 | 'STC" show it scintilla text control way |
|
|||
127 | """ |
|
|||
128 | stc.StyledTextCtrl.__init__(self, parent, ID, pos, size, style) |
|
|||
129 |
|
||||
130 | #------ Scintilla configuration ----------------------------------- |
|
|||
131 |
|
||||
132 | # Ctrl"+" or Ctrl "-" can be used to zoomin/zoomout the text inside |
|
|||
133 | # the widget |
|
|||
134 | self.CmdKeyAssign(ord('+'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN) |
|
|||
135 | self.CmdKeyAssign(ord('-'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT) |
|
|||
136 | # Also allow Ctrl Shift "=" for poor non US keyboard users. |
|
|||
137 | self.CmdKeyAssign(ord('='), stc.STC_SCMOD_CTRL|stc.STC_SCMOD_SHIFT, |
|
|||
138 | stc.STC_CMD_ZOOMIN) |
|
|||
139 |
|
||||
140 | self.SetEOLMode(stc.STC_EOL_CRLF) |
|
|||
141 | self.SetWrapMode(stc.STC_WRAP_CHAR) |
|
|||
142 | self.SetWrapMode(stc.STC_WRAP_WORD) |
|
|||
143 | self.SetBufferedDraw(True) |
|
|||
144 | self.SetUseAntiAliasing(True) |
|
|||
145 | self.SetLayoutCache(stc.STC_CACHE_PAGE) |
|
|||
146 | self.SetUndoCollection(False) |
|
|||
147 | self.SetUseTabs(True) |
|
|||
148 | self.SetIndent(4) |
|
|||
149 | self.SetTabWidth(4) |
|
|||
150 |
|
||||
151 | self.EnsureCaretVisible() |
|
|||
152 |
|
||||
153 | self.SetMargins(3, 3) #text is moved away from border with 3px |
|
|||
154 | # Suppressing Scintilla margins |
|
|||
155 | self.SetMarginWidth(0, 0) |
|
|||
156 | self.SetMarginWidth(1, 0) |
|
|||
157 | self.SetMarginWidth(2, 0) |
|
|||
158 |
|
||||
159 | self._apply_style() |
|
|||
160 |
|
||||
161 | self.indent = 0 |
|
|||
162 | self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?') |
|
|||
163 |
|
||||
164 | # FIXME: we need to retrieve this from the interpreter. |
|
|||
165 | self.prompt = \ |
|
|||
166 | '\n\x01\x1b[0;34m\x02In [\x01\x1b[1;34m\x026\x01\x1b[0;34m\x02]: \x01\x1b[0m\x02' |
|
|||
167 | self.new_prompt(self.prompt) |
|
|||
168 |
|
||||
169 | self.autocomplete_mode = autocomplete_mode |
|
|||
170 |
|
||||
171 | self.Bind(wx.EVT_KEY_DOWN, self._onKeypress) |
|
|||
172 |
|
||||
173 |
|
||||
174 | def _apply_style(self): |
|
239 | def _apply_style(self): | |
175 | """ Applies the colors for the different text elements and the |
|
240 | """ Applies the colors for the different text elements and the | |
176 | carret. |
|
241 | carret. | |
@@ -220,7 +285,7 b' class ConsoleWidget(stc.StyledTextCtrl):' | |||||
220 | self.StyleSetSpec(style[0], "bold,fore:%s" % style[1]) |
|
285 | self.StyleSetSpec(style[0], "bold,fore:%s" % style[1]) | |
221 |
|
286 | |||
222 |
|
287 | |||
223 |
|
|
288 | def removeFromTo(self, from_pos, to_pos): | |
224 | if from_pos < to_pos: |
|
289 | if from_pos < to_pos: | |
225 | self.SetSelection(from_pos, to_pos) |
|
290 | self.SetSelection(from_pos, to_pos) | |
226 | self.DeleteBack() |
|
291 | self.DeleteBack() | |
@@ -278,7 +343,7 b' class ConsoleWidget(stc.StyledTextCtrl):' | |||||
278 | if self.AutoCompActive(): |
|
343 | if self.AutoCompActive(): | |
279 | event.Skip() |
|
344 | event.Skip() | |
280 | else: |
|
345 | else: | |
281 |
if event. |
|
346 | if event.KeyCode == wx.WXK_HOME: | |
282 | if event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN): |
|
347 | if event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN): | |
283 | self.GotoPos(self.current_prompt_pos) |
|
348 | self.GotoPos(self.current_prompt_pos) | |
284 | catched = True |
|
349 | catched = True | |
@@ -288,7 +353,7 b' class ConsoleWidget(stc.StyledTextCtrl):' | |||||
288 | self.GetCurrentPos()) |
|
353 | self.GetCurrentPos()) | |
289 | catched = True |
|
354 | catched = True | |
290 |
|
355 | |||
291 |
elif event. |
|
356 | elif event.KeyCode == wx.WXK_UP: | |
292 | if self.GetCurrentLine() > self.current_prompt_line: |
|
357 | if self.GetCurrentLine() > self.current_prompt_line: | |
293 | if self.GetCurrentLine() == self.current_prompt_line + 1 \ |
|
358 | if self.GetCurrentLine() == self.current_prompt_line + 1 \ | |
294 | and self.GetColumn(self.GetCurrentPos()) < \ |
|
359 | and self.GetColumn(self.GetCurrentPos()) < \ | |
@@ -298,7 +363,7 b' class ConsoleWidget(stc.StyledTextCtrl):' | |||||
298 | event.Skip() |
|
363 | event.Skip() | |
299 | catched = True |
|
364 | catched = True | |
300 |
|
365 | |||
301 |
elif event. |
|
366 | elif event.KeyCode in (wx.WXK_LEFT, wx.WXK_BACK): | |
302 | if self.GetCurrentPos() > self.current_prompt_pos: |
|
367 | if self.GetCurrentPos() > self.current_prompt_pos: | |
303 | event.Skip() |
|
368 | event.Skip() | |
304 | catched = True |
|
369 | catched = True | |
@@ -306,7 +371,7 b' class ConsoleWidget(stc.StyledTextCtrl):' | |||||
306 | if skip and not catched: |
|
371 | if skip and not catched: | |
307 | event.Skip() |
|
372 | event.Skip() | |
308 |
|
373 | |||
309 |
if event. |
|
374 | if event.KeyCode not in (wx.WXK_PAGEUP, wx.WXK_PAGEDOWN)\ | |
310 | and event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN, |
|
375 | and event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN, | |
311 | wx.MOD_SHIFT): |
|
376 | wx.MOD_SHIFT): | |
312 | # If cursor is outside the editing region, put it back. |
|
377 | # If cursor is outside the editing region, put it back. |
@@ -25,42 +25,45 b' from console_widget import ConsoleWidget' | |||||
25 |
|
25 | |||
26 |
|
26 | |||
27 | import IPython |
|
27 | import IPython | |
28 |
from IPython.kernel.engineservice import EngineService |
|
28 | from IPython.kernel.engineservice import EngineService | |
29 | from IPython.frontend.frontendbase import FrontEndBase |
|
29 | from IPython.frontend.frontendbase import FrontEndBase | |
30 |
|
30 | |||
31 |
|
31 | |||
32 | from twisted.internet.threads import blockingCallFromThread |
|
|||
33 |
|
||||
34 | #------------------------------------------------------------------------------- |
|
32 | #------------------------------------------------------------------------------- | |
35 | # Classes to implement the Wx frontend |
|
33 | # Classes to implement the Wx frontend | |
36 | #------------------------------------------------------------------------------- |
|
34 | #------------------------------------------------------------------------------- | |
37 |
|
35 | |||
38 | # TODO: |
|
36 | ||
39 | # 1. Remove any multithreading. |
|
|||
40 |
|
||||
41 |
|
37 | |||
42 |
|
38 | |||
43 | class IPythonWxController(FrontEndBase, ConsoleWidget): |
|
39 | class IPythonWxController(FrontEndBase, ConsoleWidget): | |
44 | userNS = dict() #mirror of engine.user_ns (key=>str(value)) |
|
40 | ||
45 | waiting_for_engine = False |
|
41 | output_prompt = \ | |
46 | textView = False |
|
42 | '\n\x01\x1b[0;31m\x02Out[\x01\x1b[1;31m\x02%i\x01\x1b[0;31m\x02]: \x01\x1b[0m\x02' | |
47 |
|
43 | |||
|
44 | #-------------------------------------------------------------------------- | |||
|
45 | # Public API | |||
|
46 | #-------------------------------------------------------------------------- | |||
|
47 | ||||
48 | def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, |
|
48 | def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, | |
49 | size=wx.DefaultSize, style=wx.CLIP_CHILDREN, |
|
49 | size=wx.DefaultSize, style=wx.CLIP_CHILDREN, | |
50 | *args, **kwds): |
|
50 | *args, **kwds): | |
51 | """ Create Shell instance. |
|
51 | """ Create Shell instance. | |
52 | """ |
|
52 | """ | |
53 | ConsoleWidget.__init__(self, parent, id, pos, size, style) |
|
53 | ConsoleWidget.__init__(self, parent, id, pos, size, style) | |
54 |
FrontEndBase.__init__(self, engine= |
|
54 | FrontEndBase.__init__(self, engine=EngineService()) | |
55 |
|
55 | |||
56 | self.lines = {} |
|
56 | self.lines = {} | |
57 |
|
57 | |||
58 | # Start the IPython engine |
|
58 | # Start the IPython engine | |
59 | self.engine.startService() |
|
59 | self.engine.startService() | |
60 |
|
60 | |||
|
61 | # Capture Character keys | |||
|
62 | self.Bind(wx.EVT_KEY_UP, self._on_key_up) | |||
61 |
|
63 | |||
62 | #FIXME: print banner. |
|
64 | #FIXME: print banner. | |
63 |
banner = """IPython1 %s -- An enhanced Interactive Python.""" |
|
65 | banner = """IPython1 %s -- An enhanced Interactive Python.""" \ | |
|
66 | % IPython.__version__ | |||
64 |
|
67 | |||
65 |
|
68 | |||
66 | def appWillTerminate_(self, notification): |
|
69 | def appWillTerminate_(self, notification): | |
@@ -85,168 +88,12 b' class IPythonWxController(FrontEndBase, ConsoleWidget):' | |||||
85 | return self.engine.complete(token) |
|
88 | return self.engine.complete(token) | |
86 |
|
89 | |||
87 |
|
90 | |||
88 | def execute(self, block, blockID=None): |
|
|||
89 | self.waiting_for_engine = True |
|
|||
90 | self.willChangeValueForKey_('commandHistory') |
|
|||
91 | d = FrontEndBase.execute(block, blockID) |
|
|||
92 | d.addBoth(self._engine_done) |
|
|||
93 |
|
||||
94 | return d |
|
|||
95 |
|
||||
96 |
|
||||
97 | def _engine_done(self, x): |
|
|||
98 | self.waiting_for_engine = False |
|
|||
99 | self.didChangeValueForKey_('commandHistory') |
|
|||
100 | return x |
|
|||
101 |
|
||||
102 |
|
||||
103 | def _store_engine_namespace_values(self, values, keys=[]): |
|
|||
104 | assert(len(values) == len(keys)) |
|
|||
105 | self.willChangeValueForKey_('userNS') |
|
|||
106 | for (k,v) in zip(keys,values): |
|
|||
107 | self.userNS[k] = saferepr(v) |
|
|||
108 | self.didChangeValueForKey_('userNS') |
|
|||
109 |
|
||||
110 |
|
||||
111 | def textView_doCommandBySelector_(self, textView, selector): |
|
|||
112 | assert(textView == self.textView) |
|
|||
113 | NSLog("textView_doCommandBySelector_: "+selector) |
|
|||
114 |
|
||||
115 |
|
||||
116 | if(selector == 'insertNewline:'): |
|
|||
117 | indent = self.current_indent_string() |
|
|||
118 | if(indent): |
|
|||
119 | line = indent + self.current_line() |
|
|||
120 | else: |
|
|||
121 | line = self.current_line() |
|
|||
122 |
|
||||
123 | if(self.is_complete(self.current_block())): |
|
|||
124 | self.execute(self.current_block(), |
|
|||
125 | blockID=self.currentBlockID) |
|
|||
126 | self.start_new_block() |
|
|||
127 |
|
||||
128 | return True |
|
|||
129 |
|
||||
130 | return False |
|
|||
131 |
|
||||
132 | elif(selector == 'moveUp:'): |
|
|||
133 | prevBlock = self.get_history_previous(self.current_block()) |
|
|||
134 | if(prevBlock != None): |
|
|||
135 | self.replace_current_block_with_string(textView, prevBlock) |
|
|||
136 | else: |
|
|||
137 | NSBeep() |
|
|||
138 | return True |
|
|||
139 |
|
||||
140 | elif(selector == 'moveDown:'): |
|
|||
141 | nextBlock = self.get_history_next() |
|
|||
142 | if(nextBlock != None): |
|
|||
143 | self.replace_current_block_with_string(textView, nextBlock) |
|
|||
144 | else: |
|
|||
145 | NSBeep() |
|
|||
146 | return True |
|
|||
147 |
|
||||
148 | elif(selector == 'moveToBeginningOfParagraph:'): |
|
|||
149 | textView.setSelectedRange_(NSMakeRange( |
|
|||
150 | self.current_block_range().location, |
|
|||
151 | 0)) |
|
|||
152 | return True |
|
|||
153 | elif(selector == 'moveToEndOfParagraph:'): |
|
|||
154 | textView.setSelectedRange_(NSMakeRange( |
|
|||
155 | self.current_block_range().location + \ |
|
|||
156 | self.current_block_range().length, 0)) |
|
|||
157 | return True |
|
|||
158 | elif(selector == 'deleteToEndOfParagraph:'): |
|
|||
159 | if(textView.selectedRange().location <= \ |
|
|||
160 | self.current_block_range().location): |
|
|||
161 | # Intersect the selected range with the current line range |
|
|||
162 | if(self.current_block_range().length < 0): |
|
|||
163 | self.blockRanges[self.currentBlockID].length = 0 |
|
|||
164 |
|
||||
165 | r = NSIntersectionRange(textView.rangesForUserTextChange()[0], |
|
|||
166 | self.current_block_range()) |
|
|||
167 |
|
||||
168 | if(r.length > 0): #no intersection |
|
|||
169 | textView.setSelectedRange_(r) |
|
|||
170 |
|
||||
171 | return False # don't actually handle the delete |
|
|||
172 |
|
||||
173 | elif(selector == 'insertTab:'): |
|
|||
174 | if(len(self.current_line().strip()) == 0): #only white space |
|
|||
175 | return False |
|
|||
176 | else: |
|
|||
177 | self.textView.complete_(self) |
|
|||
178 | return True |
|
|||
179 |
|
||||
180 | elif(selector == 'deleteBackward:'): |
|
|||
181 | #if we're at the beginning of the current block, ignore |
|
|||
182 | if(textView.selectedRange().location == \ |
|
|||
183 | self.current_block_range().location): |
|
|||
184 | return True |
|
|||
185 | else: |
|
|||
186 | self.current_block_range().length-=1 |
|
|||
187 | return False |
|
|||
188 | return False |
|
|||
189 |
|
||||
190 |
|
||||
191 | def textView_shouldChangeTextInRanges_replacementStrings_(self, |
|
|||
192 | textView, ranges, replacementStrings): |
|
|||
193 | """ |
|
|||
194 | Delegate method for NSTextView. |
|
|||
195 |
|
||||
196 | Refuse change text in ranges not at end, but make those changes at |
|
|||
197 | end. |
|
|||
198 | """ |
|
|||
199 |
|
||||
200 | assert(len(ranges) == len(replacementStrings)) |
|
|||
201 | allow = True |
|
|||
202 | for r,s in zip(ranges, replacementStrings): |
|
|||
203 | r = r.rangeValue() |
|
|||
204 | if(textView.textStorage().length() > 0 and |
|
|||
205 | r.location < self.current_block_range().location): |
|
|||
206 | self.insert_text(s) |
|
|||
207 | allow = False |
|
|||
208 |
|
||||
209 |
|
||||
210 | self.blockRanges.setdefault(self.currentBlockID, |
|
|||
211 | self.current_block_range()).length +=\ |
|
|||
212 | len(s) |
|
|||
213 |
|
||||
214 | return allow |
|
|||
215 |
|
||||
216 |
|
||||
217 | def textView_completions_forPartialWordRange_indexOfSelectedItem_(self, |
|
|||
218 | textView, words, charRange, index): |
|
|||
219 | try: |
|
|||
220 | ts = textView.textStorage() |
|
|||
221 | token = ts.string().substringWithRange_(charRange) |
|
|||
222 | completions = blockingCallFromThread(self.complete, token) |
|
|||
223 | except: |
|
|||
224 | completions = objc.nil |
|
|||
225 | NSBeep() |
|
|||
226 |
|
||||
227 | return (completions,0) |
|
|||
228 |
|
||||
229 |
|
||||
230 | def currentLine(self): |
|
|||
231 | block = self.textForRange(self.currentBlockRange()) |
|
|||
232 | block = block.split('\n') |
|
|||
233 | return block[-1] |
|
|||
234 |
|
||||
235 | def update_cell_prompt(self, result): |
|
|||
236 | blockID = result['blockID'] |
|
|||
237 | self.insert_text(self.inputPrompt(result=result), |
|
|||
238 | scrollToVisible=False |
|
|||
239 | ) |
|
|||
240 |
|
||||
241 | return result |
|
|||
242 |
|
||||
243 |
|
||||
244 | def render_result(self, result): |
|
91 | def render_result(self, result): | |
245 | self.insert_text('\n' + |
|
92 | if 'stdout' in result: | |
246 | self.outputPrompt(result) + |
|
93 | self.write(result['stdout']) | |
247 | result.get('display',{}).get('pprint','') + |
|
94 | if 'display' in result: | |
248 | '\n\n') |
|
95 | self.write(self.output_prompt % result['number'] | |
249 | return result |
|
96 | + result['display']['pprint']) | |
250 |
|
97 | |||
251 |
|
98 | |||
252 | def render_error(self, failure): |
|
99 | def render_error(self, failure): | |
@@ -254,26 +101,30 b' class IPythonWxController(FrontEndBase, ConsoleWidget):' | |||||
254 | return failure |
|
101 | return failure | |
255 |
|
102 | |||
256 |
|
103 | |||
257 | def insert_text(self, string, scrollToVisible=True): |
|
104 | #-------------------------------------------------------------------------- | |
258 | """Insert text into console_widget""" |
|
105 | # Private API | |
259 | self.write(string) |
|
106 | #-------------------------------------------------------------------------- | |
260 |
|
107 | |||
261 |
|
108 | |||
262 | def currentIndentString(self): |
|
109 | def _on_key_up(self, event, skip=True): | |
263 | """returns string for indent or None if no indent""" |
|
110 | """ Capture the character events, let the parent | |
264 |
|
111 | widget handle them, and put our logic afterward. | ||
265 | if(len(self.currentBlock()) > 0): |
|
112 | """ | |
266 | lines = self.currentBlock().split('\n') |
|
113 | event.Skip() | |
267 | currentIndent = len(lines[-1]) - len(lines[-1].lstrip()) |
|
114 | # Capture enter | |
268 | if(currentIndent == 0): |
|
115 | if event.KeyCode == 13 and \ | |
269 | currentIndent = 4 |
|
116 | event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN): | |
270 |
|
117 | self._on_enter() | ||
271 | result = ' ' * currentIndent |
|
118 | ||
272 | else: |
|
|||
273 | result = None |
|
|||
274 |
|
||||
275 | return result |
|
|||
276 |
|
119 | |||
|
120 | def _on_enter(self): | |||
|
121 | """ Called when the return key is pressed in a line editing | |||
|
122 | buffer. | |||
|
123 | """ | |||
|
124 | result = self.engine.shell.execute(self.get_current_edit_buffer()) | |||
|
125 | self.render_result(result) | |||
|
126 | self.new_prompt(self.prompt % result['number']) | |||
|
127 | ||||
277 |
|
128 | |||
278 | if __name__ == '__main__': |
|
129 | if __name__ == '__main__': | |
279 | class MainWindow(wx.Frame): |
|
130 | class MainWindow(wx.Frame): | |
@@ -288,8 +139,9 b" if __name__ == '__main__':" | |||||
288 |
|
139 | |||
289 | app = wx.PySimpleApp() |
|
140 | app = wx.PySimpleApp() | |
290 | frame = MainWindow(None, wx.ID_ANY, 'Ipython') |
|
141 | frame = MainWindow(None, wx.ID_ANY, 'Ipython') | |
|
142 | frame.shell.SetFocus() | |||
291 | frame.SetSize((780, 460)) |
|
143 | frame.SetSize((780, 460)) | |
292 | shell = frame.shell |
|
144 | shell = frame.shell | |
293 |
|
145 | |||
294 | app.MainLoop() |
|
146 | #app.MainLoop() | |
295 |
|
147 |
General Comments 0
You need to be logged in to leave comments.
Login now