##// END OF EJS Templates
Spelling
gvaroquaux -
Show More
@@ -1,415 +1,415 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 A Wx widget to act as a console and input commands.
3 A Wx widget to act as a console and input commands.
4
4
5 This widget deals with prompts and provides an edit buffer
5 This widget deals with prompts and provides an edit buffer
6 restricted to after the last prompt.
6 restricted to after the last prompt.
7 """
7 """
8
8
9 __docformat__ = "restructuredtext en"
9 __docformat__ = "restructuredtext en"
10
10
11 #-------------------------------------------------------------------------------
11 #-------------------------------------------------------------------------------
12 # Copyright (C) 2008 The IPython Development Team
12 # Copyright (C) 2008 The IPython Development Team
13 #
13 #
14 # Distributed under the terms of the BSD License. The full license is
14 # Distributed under the terms of the BSD License. The full license is
15 # in the file COPYING, distributed as part of this software.
15 # in the file COPYING, distributed as part of this software.
16 #-------------------------------------------------------------------------------
16 #-------------------------------------------------------------------------------
17
17
18 #-------------------------------------------------------------------------------
18 #-------------------------------------------------------------------------------
19 # Imports
19 # Imports
20 #-------------------------------------------------------------------------------
20 #-------------------------------------------------------------------------------
21
21
22 import wx
22 import wx
23 import wx.stc as stc
23 import wx.stc as stc
24
24
25 from wx.py import editwindow
25 from wx.py import editwindow
26 import sys
26 import sys
27 LINESEP = '\n'
27 LINESEP = '\n'
28 if sys.platform == 'win32':
28 if sys.platform == 'win32':
29 LINESEP = '\n\r'
29 LINESEP = '\n\r'
30
30
31 import re
31 import re
32
32
33 # FIXME: Need to provide an API for non user-generated display on the
33 # FIXME: Need to provide an API for non user-generated display on the
34 # screen: this should not be editable by the user.
34 # screen: this should not be editable by the user.
35
35
36 _DEFAULT_SIZE = 10
36 _DEFAULT_SIZE = 10
37
37
38 _DEFAULT_STYLE = {
38 _DEFAULT_STYLE = {
39 'stdout' : 'fore:#0000FF',
39 'stdout' : 'fore:#0000FF',
40 'stderr' : 'fore:#007f00',
40 'stderr' : 'fore:#007f00',
41 'trace' : 'fore:#FF0000',
41 'trace' : 'fore:#FF0000',
42
42
43 'default' : 'size:%d' % _DEFAULT_SIZE,
43 'default' : 'size:%d' % _DEFAULT_SIZE,
44 'bracegood' : 'fore:#FFFFFF,back:#0000FF,bold',
44 'bracegood' : 'fore:#FFFFFF,back:#0000FF,bold',
45 'bracebad' : 'fore:#000000,back:#FF0000,bold',
45 'bracebad' : 'fore:#000000,back:#FF0000,bold',
46
46
47 # properties for the various Python lexer styles
47 # properties for the various Python lexer styles
48 'comment' : 'fore:#007F00',
48 'comment' : 'fore:#007F00',
49 'number' : 'fore:#007F7F',
49 'number' : 'fore:#007F7F',
50 'string' : 'fore:#7F007F,italic',
50 'string' : 'fore:#7F007F,italic',
51 'char' : 'fore:#7F007F,italic',
51 'char' : 'fore:#7F007F,italic',
52 'keyword' : 'fore:#00007F,bold',
52 'keyword' : 'fore:#00007F,bold',
53 'triple' : 'fore:#7F0000',
53 'triple' : 'fore:#7F0000',
54 'tripledouble' : 'fore:#7F0000',
54 'tripledouble' : 'fore:#7F0000',
55 'class' : 'fore:#0000FF,bold,underline',
55 'class' : 'fore:#0000FF,bold,underline',
56 'def' : 'fore:#007F7F,bold',
56 'def' : 'fore:#007F7F,bold',
57 'operator' : 'bold'
57 'operator' : 'bold'
58 }
58 }
59
59
60 # new style numbers
60 # new style numbers
61 _STDOUT_STYLE = 15
61 _STDOUT_STYLE = 15
62 _STDERR_STYLE = 16
62 _STDERR_STYLE = 16
63 _TRACE_STYLE = 17
63 _TRACE_STYLE = 17
64
64
65
65
66 # system colors
66 # system colors
67 #SYS_COLOUR_BACKGROUND = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BACKGROUND)
67 #SYS_COLOUR_BACKGROUND = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BACKGROUND)
68
68
69 #-------------------------------------------------------------------------------
69 #-------------------------------------------------------------------------------
70 # The console widget class
70 # The console widget class
71 #-------------------------------------------------------------------------------
71 #-------------------------------------------------------------------------------
72 class ConsoleWidget(editwindow.EditWindow):
72 class ConsoleWidget(editwindow.EditWindow):
73 """ Specialized styled text control view for console-like workflow.
73 """ Specialized styled text control view for console-like workflow.
74
74
75 This widget is mainly interested in dealing with the prompt and
75 This widget is mainly interested in dealing with the prompt and
76 keeping the cursor inside the editing line.
76 keeping the cursor inside the editing line.
77 """
77 """
78
78
79 # This is where the title captured from the ANSI escape sequences are
79 # This is where the title captured from the ANSI escape sequences are
80 # stored.
80 # stored.
81 title = 'Console'
81 title = 'Console'
82
82
83 # The buffer being edited.
83 # The buffer being edited.
84 def _set_input_buffer(self, string):
84 def _set_input_buffer(self, string):
85 self.SetSelection(self.current_prompt_pos, self.GetLength())
85 self.SetSelection(self.current_prompt_pos, self.GetLength())
86 self.ReplaceSelection(string)
86 self.ReplaceSelection(string)
87 self.GotoPos(self.GetLength())
87 self.GotoPos(self.GetLength())
88
88
89 def _get_input_buffer(self):
89 def _get_input_buffer(self):
90 """ Returns the text in current edit buffer.
90 """ Returns the text in current edit buffer.
91 """
91 """
92 input_buffer = self.GetTextRange(self.current_prompt_pos,
92 input_buffer = self.GetTextRange(self.current_prompt_pos,
93 self.GetLength())
93 self.GetLength())
94 input_buffer = input_buffer.replace(LINESEP, '\n')
94 input_buffer = input_buffer.replace(LINESEP, '\n')
95 return input_buffer
95 return input_buffer
96
96
97 input_buffer = property(_get_input_buffer, _set_input_buffer)
97 input_buffer = property(_get_input_buffer, _set_input_buffer)
98
98
99 style = _DEFAULT_STYLE.copy()
99 style = _DEFAULT_STYLE.copy()
100
100
101 # Translation table from ANSI escape sequences to color. Override
101 # Translation table from ANSI escape sequences to color. Override
102 # this to specify your colors.
102 # this to specify your colors.
103 ANSI_STYLES = {'0;30': [0, 'BLACK'], '0;31': [1, 'RED'],
103 ANSI_STYLES = {'0;30': [0, 'BLACK'], '0;31': [1, 'RED'],
104 '0;32': [2, 'GREEN'], '0;33': [3, 'BROWN'],
104 '0;32': [2, 'GREEN'], '0;33': [3, 'BROWN'],
105 '0;34': [4, 'BLUE'], '0;35': [5, 'PURPLE'],
105 '0;34': [4, 'BLUE'], '0;35': [5, 'PURPLE'],
106 '0;36': [6, 'CYAN'], '0;37': [7, 'LIGHT GREY'],
106 '0;36': [6, 'CYAN'], '0;37': [7, 'LIGHT GREY'],
107 '1;30': [8, 'DARK GREY'], '1;31': [9, 'RED'],
107 '1;30': [8, 'DARK GREY'], '1;31': [9, 'RED'],
108 '1;32': [10, 'SEA GREEN'], '1;33': [11, 'YELLOW'],
108 '1;32': [10, 'SEA GREEN'], '1;33': [11, 'YELLOW'],
109 '1;34': [12, 'LIGHT BLUE'], '1;35':
109 '1;34': [12, 'LIGHT BLUE'], '1;35':
110 [13, 'MEDIUM VIOLET RED'],
110 [13, 'MEDIUM VIOLET RED'],
111 '1;36': [14, 'LIGHT STEEL BLUE'], '1;37': [15, 'YELLOW']}
111 '1;36': [14, 'LIGHT STEEL BLUE'], '1;37': [15, 'YELLOW']}
112
112
113 # The color of the carret (call _apply_style() after setting)
113 # The color of the carret (call _apply_style() after setting)
114 carret_color = 'BLACK'
114 carret_color = 'BLACK'
115
115
116 #--------------------------------------------------------------------------
116 #--------------------------------------------------------------------------
117 # Public API
117 # Public API
118 #--------------------------------------------------------------------------
118 #--------------------------------------------------------------------------
119
119
120 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
120 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
121 size=wx.DefaultSize, style=0, ):
121 size=wx.DefaultSize, style=0, ):
122 editwindow.EditWindow.__init__(self, parent, id, pos, size, style)
122 editwindow.EditWindow.__init__(self, parent, id, pos, size, style)
123 self._configure_scintilla()
123 self._configure_scintilla()
124
124
125 self.Bind(wx.EVT_KEY_DOWN, self._on_key_down)
125 self.Bind(wx.EVT_KEY_DOWN, self._on_key_down)
126 self.Bind(wx.EVT_KEY_UP, self._on_key_up)
126 self.Bind(wx.EVT_KEY_UP, self._on_key_up)
127
127
128
128
129 def write(self, text, refresh=True):
129 def write(self, text, refresh=True):
130 """ Write given text to buffer, while translating the ansi escape
130 """ Write given text to buffer, while translating the ansi escape
131 sequences.
131 sequences.
132 """
132 """
133 # XXX: do not put print statements to sys.stdout/sys.stderr in
133 # XXX: do not put print statements to sys.stdout/sys.stderr in
134 # this method, the print statements will call this method, as
134 # this method, the print statements will call this method, as
135 # you will end up with an infinit loop
135 # you will end up with an infinit loop
136 if self.debug:
136 if self.debug:
137 print >>sys.__stderr__, text
137 print >>sys.__stderr__, text
138 title = self.title_pat.split(text)
138 title = self.title_pat.split(text)
139 if len(title)>1:
139 if len(title)>1:
140 self.title = title[-2]
140 self.title = title[-2]
141
141
142 text = self.title_pat.sub('', text)
142 text = self.title_pat.sub('', text)
143 segments = self.color_pat.split(text)
143 segments = self.color_pat.split(text)
144 segment = segments.pop(0)
144 segment = segments.pop(0)
145 self.GotoPos(self.GetLength())
145 self.GotoPos(self.GetLength())
146 self.StartStyling(self.GetLength(), 0xFF)
146 self.StartStyling(self.GetLength(), 0xFF)
147 try:
147 try:
148 self.AppendText(segment)
148 self.AppendText(segment)
149 except UnicodeDecodeError:
149 except UnicodeDecodeError:
150 # XXX: Do I really want to skip the exception?
150 # XXX: Do I really want to skip the exception?
151 pass
151 pass
152
152
153 if segments:
153 if segments:
154 for ansi_tag, text in zip(segments[::2], segments[1::2]):
154 for ansi_tag, text in zip(segments[::2], segments[1::2]):
155 self.StartStyling(self.GetLength(), 0xFF)
155 self.StartStyling(self.GetLength(), 0xFF)
156 try:
156 try:
157 self.AppendText(text)
157 self.AppendText(text)
158 except UnicodeDecodeError:
158 except UnicodeDecodeError:
159 # XXX: Do I really want to skip the exception?
159 # XXX: Do I really want to skip the exception?
160 pass
160 pass
161
161
162 if ansi_tag not in self.ANSI_STYLES:
162 if ansi_tag not in self.ANSI_STYLES:
163 style = 0
163 style = 0
164 else:
164 else:
165 style = self.ANSI_STYLES[ansi_tag][0]
165 style = self.ANSI_STYLES[ansi_tag][0]
166
166
167 self.SetStyling(len(text), style)
167 self.SetStyling(len(text), style)
168
168
169 self.GotoPos(self.GetLength())
169 self.GotoPos(self.GetLength())
170 if refresh:
170 if refresh:
171 wx.Yield()
171 wx.Yield()
172
172
173
173
174 def new_prompt(self, prompt):
174 def new_prompt(self, prompt):
175 """ Prints a prompt at start of line, and move the start of the
175 """ Prints a prompt at start of line, and move the start of the
176 current block there.
176 current block there.
177
177
178 The prompt can be give with ascii escape sequences.
178 The prompt can be given with ascii escape sequences.
179 """
179 """
180 self.write(prompt)
180 self.write(prompt)
181 # now we update our cursor giving end of prompt
181 # now we update our cursor giving end of prompt
182 self.current_prompt_pos = self.GetLength()
182 self.current_prompt_pos = self.GetLength()
183 self.current_prompt_line = self.GetCurrentLine()
183 self.current_prompt_line = self.GetCurrentLine()
184 wx.Yield()
184 wx.Yield()
185 self.EnsureCaretVisible()
185 self.EnsureCaretVisible()
186
186
187
187
188 def scroll_to_bottom(self):
188 def scroll_to_bottom(self):
189 maxrange = self.GetScrollRange(wx.VERTICAL)
189 maxrange = self.GetScrollRange(wx.VERTICAL)
190 self.ScrollLines(maxrange)
190 self.ScrollLines(maxrange)
191
191
192
192
193 def pop_completion(self, possibilities, offset=0):
193 def pop_completion(self, possibilities, offset=0):
194 """ Pops up an autocompletion menu. Offset is the offset
194 """ Pops up an autocompletion menu. Offset is the offset
195 in characters of the position at which the menu should
195 in characters of the position at which the menu should
196 appear, relativ to the cursor.
196 appear, relativ to the cursor.
197 """
197 """
198 self.AutoCompSetIgnoreCase(False)
198 self.AutoCompSetIgnoreCase(False)
199 self.AutoCompSetAutoHide(False)
199 self.AutoCompSetAutoHide(False)
200 self.AutoCompSetMaxHeight(len(possibilities))
200 self.AutoCompSetMaxHeight(len(possibilities))
201 self.AutoCompShow(offset, " ".join(possibilities))
201 self.AutoCompShow(offset, " ".join(possibilities))
202
202
203
203
204 def get_line_width(self):
204 def get_line_width(self):
205 """ Return the width of the line in characters.
205 """ Return the width of the line in characters.
206 """
206 """
207 return self.GetSize()[0]/self.GetCharWidth()
207 return self.GetSize()[0]/self.GetCharWidth()
208
208
209
209
210 #--------------------------------------------------------------------------
210 #--------------------------------------------------------------------------
211 # Private API
211 # Private API
212 #--------------------------------------------------------------------------
212 #--------------------------------------------------------------------------
213
213
214 def _apply_style(self):
214 def _apply_style(self):
215 """ Applies the colors for the different text elements and the
215 """ Applies the colors for the different text elements and the
216 carret.
216 carret.
217 """
217 """
218 self.SetCaretForeground(self.carret_color)
218 self.SetCaretForeground(self.carret_color)
219
219
220 #self.StyleClearAll()
220 #self.StyleClearAll()
221 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT,
221 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT,
222 "fore:#FF0000,back:#0000FF,bold")
222 "fore:#FF0000,back:#0000FF,bold")
223 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD,
223 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD,
224 "fore:#000000,back:#FF0000,bold")
224 "fore:#000000,back:#FF0000,bold")
225
225
226 for style in self.ANSI_STYLES.values():
226 for style in self.ANSI_STYLES.values():
227 self.StyleSetSpec(style[0], "bold,fore:%s" % style[1])
227 self.StyleSetSpec(style[0], "bold,fore:%s" % style[1])
228
228
229
229
230 def _configure_scintilla(self):
230 def _configure_scintilla(self):
231 self.SetEOLMode(stc.STC_EOL_LF)
231 self.SetEOLMode(stc.STC_EOL_LF)
232
232
233 # Ctrl"+" or Ctrl "-" can be used to zoomin/zoomout the text inside
233 # Ctrl"+" or Ctrl "-" can be used to zoomin/zoomout the text inside
234 # the widget
234 # the widget
235 self.CmdKeyAssign(ord('+'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
235 self.CmdKeyAssign(ord('+'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
236 self.CmdKeyAssign(ord('-'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
236 self.CmdKeyAssign(ord('-'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
237 # Also allow Ctrl Shift "=" for poor non US keyboard users.
237 # Also allow Ctrl Shift "=" for poor non US keyboard users.
238 self.CmdKeyAssign(ord('='), stc.STC_SCMOD_CTRL|stc.STC_SCMOD_SHIFT,
238 self.CmdKeyAssign(ord('='), stc.STC_SCMOD_CTRL|stc.STC_SCMOD_SHIFT,
239 stc.STC_CMD_ZOOMIN)
239 stc.STC_CMD_ZOOMIN)
240
240
241 #self.CmdKeyAssign(stc.STC_KEY_PRIOR, stc.STC_SCMOD_SHIFT,
241 #self.CmdKeyAssign(stc.STC_KEY_PRIOR, stc.STC_SCMOD_SHIFT,
242 # stc.STC_CMD_PAGEUP)
242 # stc.STC_CMD_PAGEUP)
243
243
244 #self.CmdKeyAssign(stc.STC_KEY_NEXT, stc.STC_SCMOD_SHIFT,
244 #self.CmdKeyAssign(stc.STC_KEY_NEXT, stc.STC_SCMOD_SHIFT,
245 # stc.STC_CMD_PAGEDOWN)
245 # stc.STC_CMD_PAGEDOWN)
246
246
247 # Keys: we need to clear some of the keys the that don't play
247 # Keys: we need to clear some of the keys the that don't play
248 # well with a console.
248 # well with a console.
249 self.CmdKeyClear(ord('D'), stc.STC_SCMOD_CTRL)
249 self.CmdKeyClear(ord('D'), stc.STC_SCMOD_CTRL)
250 self.CmdKeyClear(ord('L'), stc.STC_SCMOD_CTRL)
250 self.CmdKeyClear(ord('L'), stc.STC_SCMOD_CTRL)
251 self.CmdKeyClear(ord('T'), stc.STC_SCMOD_CTRL)
251 self.CmdKeyClear(ord('T'), stc.STC_SCMOD_CTRL)
252
252
253
253
254 self.SetEOLMode(stc.STC_EOL_CRLF)
254 self.SetEOLMode(stc.STC_EOL_CRLF)
255 self.SetWrapMode(stc.STC_WRAP_CHAR)
255 self.SetWrapMode(stc.STC_WRAP_CHAR)
256 self.SetWrapMode(stc.STC_WRAP_WORD)
256 self.SetWrapMode(stc.STC_WRAP_WORD)
257 self.SetBufferedDraw(True)
257 self.SetBufferedDraw(True)
258 self.SetUseAntiAliasing(True)
258 self.SetUseAntiAliasing(True)
259 self.SetLayoutCache(stc.STC_CACHE_PAGE)
259 self.SetLayoutCache(stc.STC_CACHE_PAGE)
260 self.SetUndoCollection(False)
260 self.SetUndoCollection(False)
261 self.SetUseTabs(True)
261 self.SetUseTabs(True)
262 self.SetIndent(4)
262 self.SetIndent(4)
263 self.SetTabWidth(4)
263 self.SetTabWidth(4)
264
264
265 self.EnsureCaretVisible()
265 self.EnsureCaretVisible()
266 # we don't want scintilla's autocompletion to choose
266 # we don't want scintilla's autocompletion to choose
267 # automaticaly out of a single choice list, as we pop it up
267 # automaticaly out of a single choice list, as we pop it up
268 # automaticaly
268 # automaticaly
269 self.AutoCompSetChooseSingle(False)
269 self.AutoCompSetChooseSingle(False)
270 self.AutoCompSetMaxHeight(10)
270 self.AutoCompSetMaxHeight(10)
271
271
272 self.SetMargins(3, 3) #text is moved away from border with 3px
272 self.SetMargins(3, 3) #text is moved away from border with 3px
273 # Suppressing Scintilla margins
273 # Suppressing Scintilla margins
274 self.SetMarginWidth(0, 0)
274 self.SetMarginWidth(0, 0)
275 self.SetMarginWidth(1, 0)
275 self.SetMarginWidth(1, 0)
276 self.SetMarginWidth(2, 0)
276 self.SetMarginWidth(2, 0)
277
277
278 self._apply_style()
278 self._apply_style()
279
279
280 # Xterm escape sequences
280 # Xterm escape sequences
281 self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?')
281 self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?')
282 self.title_pat = re.compile('\x1b]0;(.*?)\x07')
282 self.title_pat = re.compile('\x1b]0;(.*?)\x07')
283
283
284 #self.SetEdgeMode(stc.STC_EDGE_LINE)
284 #self.SetEdgeMode(stc.STC_EDGE_LINE)
285 #self.SetEdgeColumn(80)
285 #self.SetEdgeColumn(80)
286
286
287 # styles
287 # styles
288 p = self.style
288 p = self.style
289 self.StyleSetSpec(stc.STC_STYLE_DEFAULT, p['default'])
289 self.StyleSetSpec(stc.STC_STYLE_DEFAULT, p['default'])
290 self.StyleClearAll()
290 self.StyleClearAll()
291 self.StyleSetSpec(_STDOUT_STYLE, p['stdout'])
291 self.StyleSetSpec(_STDOUT_STYLE, p['stdout'])
292 self.StyleSetSpec(_STDERR_STYLE, p['stderr'])
292 self.StyleSetSpec(_STDERR_STYLE, p['stderr'])
293 self.StyleSetSpec(_TRACE_STYLE, p['trace'])
293 self.StyleSetSpec(_TRACE_STYLE, p['trace'])
294
294
295 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, p['bracegood'])
295 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, p['bracegood'])
296 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, p['bracebad'])
296 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, p['bracebad'])
297 self.StyleSetSpec(stc.STC_P_COMMENTLINE, p['comment'])
297 self.StyleSetSpec(stc.STC_P_COMMENTLINE, p['comment'])
298 self.StyleSetSpec(stc.STC_P_NUMBER, p['number'])
298 self.StyleSetSpec(stc.STC_P_NUMBER, p['number'])
299 self.StyleSetSpec(stc.STC_P_STRING, p['string'])
299 self.StyleSetSpec(stc.STC_P_STRING, p['string'])
300 self.StyleSetSpec(stc.STC_P_CHARACTER, p['char'])
300 self.StyleSetSpec(stc.STC_P_CHARACTER, p['char'])
301 self.StyleSetSpec(stc.STC_P_WORD, p['keyword'])
301 self.StyleSetSpec(stc.STC_P_WORD, p['keyword'])
302 self.StyleSetSpec(stc.STC_P_WORD2, p['keyword'])
302 self.StyleSetSpec(stc.STC_P_WORD2, p['keyword'])
303 self.StyleSetSpec(stc.STC_P_TRIPLE, p['triple'])
303 self.StyleSetSpec(stc.STC_P_TRIPLE, p['triple'])
304 self.StyleSetSpec(stc.STC_P_TRIPLEDOUBLE, p['tripledouble'])
304 self.StyleSetSpec(stc.STC_P_TRIPLEDOUBLE, p['tripledouble'])
305 self.StyleSetSpec(stc.STC_P_CLASSNAME, p['class'])
305 self.StyleSetSpec(stc.STC_P_CLASSNAME, p['class'])
306 self.StyleSetSpec(stc.STC_P_DEFNAME, p['def'])
306 self.StyleSetSpec(stc.STC_P_DEFNAME, p['def'])
307 self.StyleSetSpec(stc.STC_P_OPERATOR, p['operator'])
307 self.StyleSetSpec(stc.STC_P_OPERATOR, p['operator'])
308 self.StyleSetSpec(stc.STC_P_COMMENTBLOCK, p['comment'])
308 self.StyleSetSpec(stc.STC_P_COMMENTBLOCK, p['comment'])
309
309
310
310
311 def _on_key_down(self, event, skip=True):
311 def _on_key_down(self, event, skip=True):
312 """ Key press callback used for correcting behavior for
312 """ Key press callback used for correcting behavior for
313 console-like interfaces: the cursor is constraint to be after
313 console-like interfaces: the cursor is constraint to be after
314 the last prompt.
314 the last prompt.
315
315
316 Return True if event as been catched.
316 Return True if event as been catched.
317 """
317 """
318 catched = True
318 catched = True
319 # Intercept some specific keys.
319 # Intercept some specific keys.
320 if event.KeyCode == ord('L') and event.ControlDown() :
320 if event.KeyCode == ord('L') and event.ControlDown() :
321 self.scroll_to_bottom()
321 self.scroll_to_bottom()
322 elif event.KeyCode == ord('K') and event.ControlDown() :
322 elif event.KeyCode == ord('K') and event.ControlDown() :
323 self.input_buffer = ''
323 self.input_buffer = ''
324 elif event.KeyCode == wx.WXK_PAGEUP and event.ShiftDown():
324 elif event.KeyCode == wx.WXK_PAGEUP and event.ShiftDown():
325 self.ScrollPages(-1)
325 self.ScrollPages(-1)
326 elif event.KeyCode == wx.WXK_PAGEDOWN and event.ShiftDown():
326 elif event.KeyCode == wx.WXK_PAGEDOWN and event.ShiftDown():
327 self.ScrollPages(1)
327 self.ScrollPages(1)
328 elif event.KeyCode == wx.WXK_UP and event.ShiftDown():
328 elif event.KeyCode == wx.WXK_UP and event.ShiftDown():
329 self.ScrollLines(-1)
329 self.ScrollLines(-1)
330 elif event.KeyCode == wx.WXK_DOWN and event.ShiftDown():
330 elif event.KeyCode == wx.WXK_DOWN and event.ShiftDown():
331 self.ScrollLines(1)
331 self.ScrollLines(1)
332 else:
332 else:
333 catched = False
333 catched = False
334
334
335 if self.AutoCompActive():
335 if self.AutoCompActive():
336 event.Skip()
336 event.Skip()
337 else:
337 else:
338 if event.KeyCode in (13, wx.WXK_NUMPAD_ENTER) and \
338 if event.KeyCode in (13, wx.WXK_NUMPAD_ENTER) and \
339 event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN):
339 event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN):
340 catched = True
340 catched = True
341 self.CallTipCancel()
341 self.CallTipCancel()
342 self.write('\n')
342 self.write('\n')
343 # Under windows scintilla seems to be doing funny stuff to the
343 # Under windows scintilla seems to be doing funny stuff to the
344 # line returns here, but the getter for input_buffer filters
344 # line returns here, but the getter for input_buffer filters
345 # this out.
345 # this out.
346 if sys.platform == 'win32':
346 if sys.platform == 'win32':
347 self.input_buffer = self.input_buffer
347 self.input_buffer = self.input_buffer
348 self._on_enter()
348 self._on_enter()
349
349
350 elif event.KeyCode == wx.WXK_HOME:
350 elif event.KeyCode == wx.WXK_HOME:
351 if event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN):
351 if event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN):
352 self.GotoPos(self.current_prompt_pos)
352 self.GotoPos(self.current_prompt_pos)
353 catched = True
353 catched = True
354
354
355 elif event.Modifiers in (wx.MOD_SHIFT, wx.MOD_WIN) :
355 elif event.Modifiers in (wx.MOD_SHIFT, wx.MOD_WIN) :
356 # FIXME: This behavior is not ideal: if the selection
356 # FIXME: This behavior is not ideal: if the selection
357 # is already started, it will jump.
357 # is already started, it will jump.
358 self.SetSelectionStart(self.current_prompt_pos)
358 self.SetSelectionStart(self.current_prompt_pos)
359 self.SetSelectionEnd(self.GetCurrentPos())
359 self.SetSelectionEnd(self.GetCurrentPos())
360 catched = True
360 catched = True
361
361
362 elif event.KeyCode == wx.WXK_UP:
362 elif event.KeyCode == wx.WXK_UP:
363 if self.GetCurrentLine() > self.current_prompt_line:
363 if self.GetCurrentLine() > self.current_prompt_line:
364 if self.GetCurrentLine() == self.current_prompt_line + 1 \
364 if self.GetCurrentLine() == self.current_prompt_line + 1 \
365 and self.GetColumn(self.GetCurrentPos()) < \
365 and self.GetColumn(self.GetCurrentPos()) < \
366 self.GetColumn(self.current_prompt_pos):
366 self.GetColumn(self.current_prompt_pos):
367 self.GotoPos(self.current_prompt_pos)
367 self.GotoPos(self.current_prompt_pos)
368 else:
368 else:
369 event.Skip()
369 event.Skip()
370 catched = True
370 catched = True
371
371
372 elif event.KeyCode in (wx.WXK_LEFT, wx.WXK_BACK):
372 elif event.KeyCode in (wx.WXK_LEFT, wx.WXK_BACK):
373 if self.GetCurrentPos() > self.current_prompt_pos:
373 if self.GetCurrentPos() > self.current_prompt_pos:
374 event.Skip()
374 event.Skip()
375 catched = True
375 catched = True
376
376
377 if skip and not catched:
377 if skip and not catched:
378 # Put the cursor back in the edit region
378 # Put the cursor back in the edit region
379 if self.GetCurrentPos() < self.current_prompt_pos:
379 if self.GetCurrentPos() < self.current_prompt_pos:
380 self.GotoPos(self.current_prompt_pos)
380 self.GotoPos(self.current_prompt_pos)
381 else:
381 else:
382 event.Skip()
382 event.Skip()
383
383
384 return catched
384 return catched
385
385
386
386
387 def _on_key_up(self, event, skip=True):
387 def _on_key_up(self, event, skip=True):
388 """ If cursor is outside the editing region, put it back.
388 """ If cursor is outside the editing region, put it back.
389 """
389 """
390 event.Skip()
390 event.Skip()
391 if self.GetCurrentPos() < self.current_prompt_pos:
391 if self.GetCurrentPos() < self.current_prompt_pos:
392 self.GotoPos(self.current_prompt_pos)
392 self.GotoPos(self.current_prompt_pos)
393
393
394
394
395
395
396 if __name__ == '__main__':
396 if __name__ == '__main__':
397 # Some simple code to test the console widget.
397 # Some simple code to test the console widget.
398 class MainWindow(wx.Frame):
398 class MainWindow(wx.Frame):
399 def __init__(self, parent, id, title):
399 def __init__(self, parent, id, title):
400 wx.Frame.__init__(self, parent, id, title, size=(300,250))
400 wx.Frame.__init__(self, parent, id, title, size=(300,250))
401 self._sizer = wx.BoxSizer(wx.VERTICAL)
401 self._sizer = wx.BoxSizer(wx.VERTICAL)
402 self.console_widget = ConsoleWidget(self)
402 self.console_widget = ConsoleWidget(self)
403 self._sizer.Add(self.console_widget, 1, wx.EXPAND)
403 self._sizer.Add(self.console_widget, 1, wx.EXPAND)
404 self.SetSizer(self._sizer)
404 self.SetSizer(self._sizer)
405 self.SetAutoLayout(1)
405 self.SetAutoLayout(1)
406 self.Show(True)
406 self.Show(True)
407
407
408 app = wx.PySimpleApp()
408 app = wx.PySimpleApp()
409 w = MainWindow(None, wx.ID_ANY, 'ConsoleWidget')
409 w = MainWindow(None, wx.ID_ANY, 'ConsoleWidget')
410 w.SetSize((780, 460))
410 w.SetSize((780, 460))
411 w.Show()
411 w.Show()
412
412
413 app.MainLoop()
413 app.MainLoop()
414
414
415
415
General Comments 0
You need to be logged in to leave comments. Login now