##// END OF EJS Templates
Nice background color for already entered code....
Gael Varoquaux -
Show More
@@ -1,162 +1,162 b''
1 """
1 """
2 Base front end class for all line-oriented frontends.
2 Base front end class for all line-oriented frontends.
3
3
4 Currently this focuses on synchronous frontends.
4 Currently this focuses on synchronous frontends.
5 """
5 """
6 __docformat__ = "restructuredtext en"
6 __docformat__ = "restructuredtext en"
7
7
8 #-------------------------------------------------------------------------------
8 #-------------------------------------------------------------------------------
9 # Copyright (C) 2008 The IPython Development Team
9 # Copyright (C) 2008 The IPython Development Team
10 #
10 #
11 # Distributed under the terms of the BSD License. The full license is in
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
12 # the file COPYING, distributed as part of this software.
13 #-------------------------------------------------------------------------------
13 #-------------------------------------------------------------------------------
14
14
15 #-------------------------------------------------------------------------------
15 #-------------------------------------------------------------------------------
16 # Imports
16 # Imports
17 #-------------------------------------------------------------------------------
17 #-------------------------------------------------------------------------------
18 import re
18 import re
19
19
20 import IPython
20 import IPython
21
21
22
22
23 from frontendbase import FrontEndBase
23 from frontendbase import FrontEndBase
24 from IPython.kernel.core.interpreter import Interpreter
24 from IPython.kernel.core.interpreter import Interpreter
25
25
26 #-------------------------------------------------------------------------------
26 #-------------------------------------------------------------------------------
27 # Base class for the line-oriented front ends
27 # Base class for the line-oriented front ends
28 #-------------------------------------------------------------------------------
28 #-------------------------------------------------------------------------------
29 class LineFrontEndBase(FrontEndBase):
29 class LineFrontEndBase(FrontEndBase):
30
30
31 # We need to keep the prompt number, to be able to increment
31 # We need to keep the prompt number, to be able to increment
32 # it when there is an exception.
32 # it when there is an exception.
33 prompt_number = 1
33 prompt_number = 1
34
34
35 # To bootstrap
35 # To bootstrap
36 last_result = dict(number=0)
36 last_result = dict(number=0)
37
37
38 #--------------------------------------------------------------------------
38 #--------------------------------------------------------------------------
39 # Public API
39 # Public API
40 #--------------------------------------------------------------------------
40 #--------------------------------------------------------------------------
41
41
42 def __init__(self, shell=None, history=None):
42 def __init__(self, shell=None, history=None):
43 if shell is None:
43 if shell is None:
44 shell = Interpreter()
44 shell = Interpreter()
45 FrontEndBase.__init__(self, shell=shell, history=history)
45 FrontEndBase.__init__(self, shell=shell, history=history)
46
46
47 #FIXME: print banner.
47 #FIXME: print banner.
48 banner = """IPython1 %s -- An enhanced Interactive Python.""" \
48 banner = """IPython1 %s -- An enhanced Interactive Python.""" \
49 % IPython.__version__
49 % IPython.__version__
50
50
51
51
52 def complete(self, token):
52 def complete(self, token):
53 """Complete token in engine's user_ns
53 """Complete token in engine's user_ns
54
54
55 Parameters
55 Parameters
56 ----------
56 ----------
57 token : string
57 token : string
58
58
59 Result
59 Result
60 ------
60 ------
61 Deferred result of
61 Deferred result of
62 IPython.kernel.engineservice.IEngineBase.complete
62 IPython.kernel.engineservice.IEngineBase.complete
63 """
63 """
64
64
65 return self.shell.complete(token)
65 return self.shell.complete(token)
66
66
67
67
68 def render_result(self, result):
68 def render_result(self, result):
69 if 'stdout' in result and result['stdout']:
69 if 'stdout' in result and result['stdout']:
70 self.write('\n' + result['stdout'])
70 self.write('\n' + result['stdout'])
71 if 'display' in result and result['display']:
71 if 'display' in result and result['display']:
72 self.write("%s%s\n" % (
72 self.write("%s%s\n" % (
73 self.output_prompt % result['number'],
73 self.output_prompt % result['number'],
74 result['display']['pprint']
74 result['display']['pprint']
75 ) )
75 ) )
76
76
77
77
78 def render_error(self, failure):
78 def render_error(self, failure):
79 self.insert_text('\n\n'+str(failure)+'\n\n')
79 self.insert_text('\n\n'+str(failure)+'\n\n')
80 return failure
80 return failure
81
81
82
82
83 def prefilter_input(self, string):
83 def prefilter_input(self, string):
84 string = string.replace('\r\n', '\n')
84 string = string.replace('\r\n', '\n')
85 string = string.replace('\t', 4*' ')
85 string = string.replace('\t', 4*' ')
86 # Clean the trailing whitespace
86 # Clean the trailing whitespace
87 string = '\n'.join(l.rstrip() for l in string.split('\n'))
87 string = '\n'.join(l.rstrip() for l in string.split('\n'))
88 return string
88 return string
89
89
90
90
91 def is_complete(self, string):
91 def is_complete(self, string):
92 if string in ('', '\n'):
92 if string in ('', '\n'):
93 return True
93 return True
94 elif ( len(self.get_current_edit_buffer().split('\n'))>2
94 elif ( len(self.get_current_edit_buffer().split('\n'))>2
95 and not re.findall(r"\n[\t ]*\n[\t ]*$", string)):
95 and not re.findall(r"\n[\t ]*\n[\t ]*$", string)):
96 return False
96 return False
97 else:
97 else:
98 # Add line returns here, to make sure that the statement is
98 # Add line returns here, to make sure that the statement is
99 # complete.
99 # complete.
100 return FrontEndBase.is_complete(self, string.rstrip() + '\n\n')
100 return FrontEndBase.is_complete(self, string.rstrip() + '\n\n')
101
101
102
102
103 def execute(self, python_string, raw_string=None):
103 def execute(self, python_string, raw_string=None):
104 """ Send the python_string to the interpreter, stores the
104 """ Send the python_string to the interpreter, stores the
105 raw_string in the history and starts a new prompt.
105 raw_string in the history and starts a new prompt.
106 """
106 """
107 if raw_string is None:
107 if raw_string is None:
108 raw_string = string
108 raw_string = python_string
109 # Create a false result, in case there is an exception
109 # Create a false result, in case there is an exception
110 self.last_result = dict(number=self.prompt_number)
110 self.last_result = dict(number=self.prompt_number)
111 try:
111 try:
112 self.history.input_cache[-1] = raw_string.rstrip()
112 self.history.input_cache[-1] = raw_string.rstrip()
113 result = self.shell.execute(python_string)
113 result = self.shell.execute(python_string)
114 self.last_result = result
114 self.last_result = result
115 self.render_result(result)
115 self.render_result(result)
116 except:
116 except:
117 self.show_traceback()
117 self.show_traceback()
118 finally:
118 finally:
119 self.after_execute()
119 self.after_execute()
120
120
121
121
122 def after_execute(self):
122 def after_execute(self):
123 """ All the operations required after an execution to put the
123 """ All the operations required after an execution to put the
124 terminal back in a shape where it is usable.
124 terminal back in a shape where it is usable.
125 """
125 """
126 self.prompt_number += 1
126 self.prompt_number += 1
127 self.new_prompt(self.prompt % (self.last_result['number'] + 1))
127 self.new_prompt(self.prompt % (self.last_result['number'] + 1))
128 # Start a new empty history entry
128 # Start a new empty history entry
129 self._add_history(None, '')
129 self._add_history(None, '')
130 self.history_cursor = len(self.history.input_cache) - 1
130 self.history_cursor = len(self.history.input_cache) - 1
131
131
132
132
133 def _on_enter(self):
133 def _on_enter(self):
134 """ Called when the return key is pressed in a line editing
134 """ Called when the return key is pressed in a line editing
135 buffer.
135 buffer.
136 """
136 """
137 current_buffer = self.get_current_edit_buffer()
137 current_buffer = self.get_current_edit_buffer()
138 cleaned_buffer = self.prefilter_input(current_buffer)
138 cleaned_buffer = self.prefilter_input(current_buffer)
139 if self.is_complete(cleaned_buffer):
139 if self.is_complete(cleaned_buffer):
140 self.execute(cleaned_buffer, raw_string=current_buffer)
140 self.execute(cleaned_buffer, raw_string=current_buffer)
141 else:
141 else:
142 if len(current_buffer.split('\n'))>2:
142 if len(current_buffer.split('\n'))>2:
143 # We need to clean the trailing '\n'
143 # We need to clean the trailing '\n'
144 self.write(self._get_indent_string(current_buffer[:-1]))
144 self.write(self._get_indent_string(current_buffer[:-1]))
145 else:
145 else:
146 self.write('\t')
146 self.write('\t')
147
147
148
148
149 #--------------------------------------------------------------------------
149 #--------------------------------------------------------------------------
150 # Private API
150 # Private API
151 #--------------------------------------------------------------------------
151 #--------------------------------------------------------------------------
152
152
153 def _get_indent_string(self, string):
153 def _get_indent_string(self, string):
154 string = string.replace('\t', ' '*4)
154 string = string.replace('\t', ' '*4)
155 string = string.split('\n')[-1]
155 string = string.split('\n')[-1]
156 indent_chars = len(string) - len(string.lstrip())
156 indent_chars = len(string) - len(string.lstrip())
157 indent_string = '\t'*(indent_chars // 4) + \
157 indent_string = '\t'*(indent_chars // 4) + \
158 ' '*(indent_chars % 4)
158 ' '*(indent_chars % 4)
159
159
160 return indent_string
160 return indent_string
161
161
162
162
@@ -1,406 +1,406 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
26
27 import re
27 import re
28
28
29 # FIXME: Need to provide an API for non user-generated display on the
29 # FIXME: Need to provide an API for non user-generated display on the
30 # screen: this should not be editable by the user.
30 # screen: this should not be editable by the user.
31
31
32 if wx.Platform == '__WXMSW__':
32 if wx.Platform == '__WXMSW__':
33 _DEFAULT_SIZE = 80
33 _DEFAULT_SIZE = 80
34 else:
34 else:
35 _DEFAULT_SIZE = 10
35 _DEFAULT_SIZE = 10
36
36
37 _DEFAULT_STYLE = {
37 _DEFAULT_STYLE = {
38 'stdout' : 'fore:#0000FF',
38 'stdout' : 'fore:#0000FF',
39 'stderr' : 'fore:#007f00',
39 'stderr' : 'fore:#007f00',
40 'trace' : 'fore:#FF0000',
40 'trace' : 'fore:#FF0000',
41
41
42 'default' : 'size:%d' % _DEFAULT_SIZE,
42 'default' : 'size:%d' % _DEFAULT_SIZE,
43 'bracegood' : 'fore:#FFFFFF,back:#0000FF,bold',
43 'bracegood' : 'fore:#FFFFFF,back:#0000FF,bold',
44 'bracebad' : 'fore:#000000,back:#FF0000,bold',
44 'bracebad' : 'fore:#000000,back:#FF0000,bold',
45
45
46 # properties for the various Python lexer styles
46 # properties for the various Python lexer styles
47 'comment' : 'fore:#007F00',
47 'comment' : 'fore:#007F00',
48 'number' : 'fore:#007F7F',
48 'number' : 'fore:#007F7F',
49 'string' : 'fore:#7F007F,italic',
49 'string' : 'fore:#7F007F,italic',
50 'char' : 'fore:#7F007F,italic',
50 'char' : 'fore:#7F007F,italic',
51 'keyword' : 'fore:#00007F,bold',
51 'keyword' : 'fore:#00007F,bold',
52 'triple' : 'fore:#7F0000',
52 'triple' : 'fore:#7F0000',
53 'tripledouble': 'fore:#7F0000',
53 'tripledouble' : 'fore:#7F0000',
54 'class' : 'fore:#0000FF,bold,underline',
54 'class' : 'fore:#0000FF,bold,underline',
55 'def' : 'fore:#007F7F,bold',
55 'def' : 'fore:#007F7F,bold',
56 'operator' : 'bold',
56 'operator' : 'bold'
57
58 }
57 }
59
58
60 # new style numbers
59 # new style numbers
61 _STDOUT_STYLE = 15
60 _STDOUT_STYLE = 15
62 _STDERR_STYLE = 16
61 _STDERR_STYLE = 16
63 _TRACE_STYLE = 17
62 _TRACE_STYLE = 17
64
63
65
64
66 # system colors
65 # system colors
67 SYS_COLOUR_BACKGROUND = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BACKGROUND)
66 SYS_COLOUR_BACKGROUND = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BACKGROUND)
68
67
69 #-------------------------------------------------------------------------------
68 #-------------------------------------------------------------------------------
70 # The console widget class
69 # The console widget class
71 #-------------------------------------------------------------------------------
70 #-------------------------------------------------------------------------------
72 class ConsoleWidget(editwindow.EditWindow):
71 class ConsoleWidget(editwindow.EditWindow):
73 """ Specialized styled text control view for console-like workflow.
72 """ Specialized styled text control view for console-like workflow.
74
73
75 This widget is mainly interested in dealing with the prompt and
74 This widget is mainly interested in dealing with the prompt and
76 keeping the cursor inside the editing line.
75 keeping the cursor inside the editing line.
77 """
76 """
78
77
79 title = 'Console'
78 title = 'Console'
80
79
81 style = _DEFAULT_STYLE.copy()
80 style = _DEFAULT_STYLE.copy()
82
81
83 # Translation table from ANSI escape sequences to color. Override
82 # Translation table from ANSI escape sequences to color. Override
84 # this to specify your colors.
83 # this to specify your colors.
85 ANSI_STYLES = {'0;30': [0, 'BLACK'], '0;31': [1, 'RED'],
84 ANSI_STYLES = {'0;30': [0, 'BLACK'], '0;31': [1, 'RED'],
86 '0;32': [2, 'GREEN'], '0;33': [3, 'BROWN'],
85 '0;32': [2, 'GREEN'], '0;33': [3, 'BROWN'],
87 '0;34': [4, 'BLUE'], '0;35': [5, 'PURPLE'],
86 '0;34': [4, 'BLUE'], '0;35': [5, 'PURPLE'],
88 '0;36': [6, 'CYAN'], '0;37': [7, 'LIGHT GREY'],
87 '0;36': [6, 'CYAN'], '0;37': [7, 'LIGHT GREY'],
89 '1;30': [8, 'DARK GREY'], '1;31': [9, 'RED'],
88 '1;30': [8, 'DARK GREY'], '1;31': [9, 'RED'],
90 '1;32': [10, 'SEA GREEN'], '1;33': [11, 'YELLOW'],
89 '1;32': [10, 'SEA GREEN'], '1;33': [11, 'YELLOW'],
91 '1;34': [12, 'LIGHT BLUE'], '1;35':
90 '1;34': [12, 'LIGHT BLUE'], '1;35':
92 [13, 'MEDIUM VIOLET RED'],
91 [13, 'MEDIUM VIOLET RED'],
93 '1;36': [14, 'LIGHT STEEL BLUE'], '1;37': [15, 'YELLOW']}
92 '1;36': [14, 'LIGHT STEEL BLUE'], '1;37': [15, 'YELLOW']}
94
93
95 # The color of the carret (call _apply_style() after setting)
94 # The color of the carret (call _apply_style() after setting)
96 carret_color = 'BLACK'
95 carret_color = 'BLACK'
97
96
98
97
99 #--------------------------------------------------------------------------
98 #--------------------------------------------------------------------------
100 # Public API
99 # Public API
101 #--------------------------------------------------------------------------
100 #--------------------------------------------------------------------------
102
101
103 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
102 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
104 size=wx.DefaultSize, style=0,
103 size=wx.DefaultSize, style=0,
105 autocomplete_mode='popup'):
104 autocomplete_mode='popup'):
106 """ Autocomplete_mode: Can be 'popup' or 'text'
105 """ Autocomplete_mode: Can be 'popup' or 'text'
107 'text' show autocompletion in the text buffer
106 'text' show autocompletion in the text buffer
108 'popup' show it with a dropdown popup
107 'popup' show it with a dropdown popup
109 """
108 """
110 editwindow.EditWindow.__init__(self, parent, id, pos, size, style)
109 editwindow.EditWindow.__init__(self, parent, id, pos, size, style)
111 self.configure_scintilla()
110 self.configure_scintilla()
112
111
113 # FIXME: we need to retrieve this from the interpreter.
112 # FIXME: we need to retrieve this from the interpreter.
114 self.prompt = \
113 self.prompt = \
115 '\n\x01\x1b[0;34m\x02In [\x01\x1b[1;34m\x02%i\x01\x1b[0;34m\x02]: \x01\x1b[0m\x02'
114 '\n\x01\x1b[0;34m\x02In [\x01\x1b[1;34m\x02%i\x01\x1b[0;34m\x02]: \x01\x1b[0m\x02'
116 self.new_prompt(self.prompt % 1)
115 self.new_prompt(self.prompt % 1)
117
116
118 self.autocomplete_mode = autocomplete_mode
117 self.autocomplete_mode = autocomplete_mode
119
118
120 self.Bind(wx.EVT_KEY_DOWN, self._on_key_down)
119 self.Bind(wx.EVT_KEY_DOWN, self._on_key_down)
121 self.Bind(wx.EVT_KEY_UP, self._on_key_up)
120 self.Bind(wx.EVT_KEY_UP, self._on_key_up)
122
121
123
122
124 def configure_scintilla(self):
123 def configure_scintilla(self):
125 # Ctrl"+" or Ctrl "-" can be used to zoomin/zoomout the text inside
124 # Ctrl"+" or Ctrl "-" can be used to zoomin/zoomout the text inside
126 # the widget
125 # the widget
127 self.CmdKeyAssign(ord('+'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
126 self.CmdKeyAssign(ord('+'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
128 self.CmdKeyAssign(ord('-'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
127 self.CmdKeyAssign(ord('-'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
129 # Also allow Ctrl Shift "=" for poor non US keyboard users.
128 # Also allow Ctrl Shift "=" for poor non US keyboard users.
130 self.CmdKeyAssign(ord('='), stc.STC_SCMOD_CTRL|stc.STC_SCMOD_SHIFT,
129 self.CmdKeyAssign(ord('='), stc.STC_SCMOD_CTRL|stc.STC_SCMOD_SHIFT,
131 stc.STC_CMD_ZOOMIN)
130 stc.STC_CMD_ZOOMIN)
132
131
133 #self.CmdKeyAssign(stc.STC_KEY_PRIOR, stc.STC_SCMOD_SHIFT,
132 #self.CmdKeyAssign(stc.STC_KEY_PRIOR, stc.STC_SCMOD_SHIFT,
134 # stc.STC_CMD_PAGEUP)
133 # stc.STC_CMD_PAGEUP)
135
134
136 #self.CmdKeyAssign(stc.STC_KEY_NEXT, stc.STC_SCMOD_SHIFT,
135 #self.CmdKeyAssign(stc.STC_KEY_NEXT, stc.STC_SCMOD_SHIFT,
137 # stc.STC_CMD_PAGEDOWN)
136 # stc.STC_CMD_PAGEDOWN)
138
137
139 # Keys: we need to clear some of the keys the that don't play
138 # Keys: we need to clear some of the keys the that don't play
140 # well with a console.
139 # well with a console.
141 self.CmdKeyClear(ord('D'), stc.STC_SCMOD_CTRL)
140 self.CmdKeyClear(ord('D'), stc.STC_SCMOD_CTRL)
142 self.CmdKeyClear(ord('L'), stc.STC_SCMOD_CTRL)
141 self.CmdKeyClear(ord('L'), stc.STC_SCMOD_CTRL)
143 self.CmdKeyClear(ord('T'), stc.STC_SCMOD_CTRL)
142 self.CmdKeyClear(ord('T'), stc.STC_SCMOD_CTRL)
144
143
145
144
146 self.SetEOLMode(stc.STC_EOL_CRLF)
145 self.SetEOLMode(stc.STC_EOL_CRLF)
147 self.SetWrapMode(stc.STC_WRAP_CHAR)
146 self.SetWrapMode(stc.STC_WRAP_CHAR)
148 self.SetWrapMode(stc.STC_WRAP_WORD)
147 self.SetWrapMode(stc.STC_WRAP_WORD)
149 self.SetBufferedDraw(True)
148 self.SetBufferedDraw(True)
150 self.SetUseAntiAliasing(True)
149 self.SetUseAntiAliasing(True)
151 self.SetLayoutCache(stc.STC_CACHE_PAGE)
150 self.SetLayoutCache(stc.STC_CACHE_PAGE)
152 self.SetUndoCollection(False)
151 self.SetUndoCollection(False)
153 self.SetUseTabs(True)
152 self.SetUseTabs(True)
154 self.SetIndent(4)
153 self.SetIndent(4)
155 self.SetTabWidth(4)
154 self.SetTabWidth(4)
156
155
157 self.EnsureCaretVisible()
156 self.EnsureCaretVisible()
158 # Tell autocompletion to choose automaticaly out of a single
157 # Tell autocompletion to choose automaticaly out of a single
159 # choice list
158 # choice list
160 self.AutoCompSetChooseSingle(True)
159 self.AutoCompSetChooseSingle(True)
161 self.AutoCompSetMaxHeight(10)
160 self.AutoCompSetMaxHeight(10)
162
161
163 self.SetMargins(3, 3) #text is moved away from border with 3px
162 self.SetMargins(3, 3) #text is moved away from border with 3px
164 # Suppressing Scintilla margins
163 # Suppressing Scintilla margins
165 self.SetMarginWidth(0, 0)
164 self.SetMarginWidth(0, 0)
166 self.SetMarginWidth(1, 0)
165 self.SetMarginWidth(1, 0)
167 self.SetMarginWidth(2, 0)
166 self.SetMarginWidth(2, 0)
168
167
169 self._apply_style()
168 self._apply_style()
170
169
171 # Xterm escape sequences
170 # Xterm escape sequences
172 self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?')
171 self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?')
173 self.title_pat = re.compile('\x1b]0;(.*?)\x07')
172 self.title_pat = re.compile('\x1b]0;(.*?)\x07')
174
173
175 #self.SetEdgeMode(stc.STC_EDGE_LINE)
174 #self.SetEdgeMode(stc.STC_EDGE_LINE)
176 #self.SetEdgeColumn(80)
175 #self.SetEdgeColumn(80)
177
176
178 # styles
177 # styles
179 p = self.style
178 p = self.style
180 self.StyleSetSpec(stc.STC_STYLE_DEFAULT, p['default'])
179 self.StyleSetSpec(stc.STC_STYLE_DEFAULT, p['default'])
181 self.StyleClearAll()
180 self.StyleClearAll()
182 self.StyleSetSpec(_STDOUT_STYLE, p['stdout'])
181 self.StyleSetSpec(_STDOUT_STYLE, p['stdout'])
183 self.StyleSetSpec(_STDERR_STYLE, p['stderr'])
182 self.StyleSetSpec(_STDERR_STYLE, p['stderr'])
184 self.StyleSetSpec(_TRACE_STYLE, p['trace'])
183 self.StyleSetSpec(_TRACE_STYLE, p['trace'])
185
184
186 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, p['bracegood'])
185 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, p['bracegood'])
187 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, p['bracebad'])
186 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, p['bracebad'])
188 self.StyleSetSpec(stc.STC_P_COMMENTLINE, p['comment'])
187 self.StyleSetSpec(stc.STC_P_COMMENTLINE, p['comment'])
189 self.StyleSetSpec(stc.STC_P_NUMBER, p['number'])
188 self.StyleSetSpec(stc.STC_P_NUMBER, p['number'])
190 self.StyleSetSpec(stc.STC_P_STRING, p['string'])
189 self.StyleSetSpec(stc.STC_P_STRING, p['string'])
191 self.StyleSetSpec(stc.STC_P_CHARACTER, p['char'])
190 self.StyleSetSpec(stc.STC_P_CHARACTER, p['char'])
192 self.StyleSetSpec(stc.STC_P_WORD, p['keyword'])
191 self.StyleSetSpec(stc.STC_P_WORD, p['keyword'])
192 self.StyleSetSpec(stc.STC_P_WORD2, p['keyword'])
193 self.StyleSetSpec(stc.STC_P_TRIPLE, p['triple'])
193 self.StyleSetSpec(stc.STC_P_TRIPLE, p['triple'])
194 self.StyleSetSpec(stc.STC_P_TRIPLEDOUBLE, p['tripledouble'])
194 self.StyleSetSpec(stc.STC_P_TRIPLEDOUBLE, p['tripledouble'])
195 self.StyleSetSpec(stc.STC_P_CLASSNAME, p['class'])
195 self.StyleSetSpec(stc.STC_P_CLASSNAME, p['class'])
196 self.StyleSetSpec(stc.STC_P_DEFNAME, p['def'])
196 self.StyleSetSpec(stc.STC_P_DEFNAME, p['def'])
197 self.StyleSetSpec(stc.STC_P_OPERATOR, p['operator'])
197 self.StyleSetSpec(stc.STC_P_OPERATOR, p['operator'])
198 self.StyleSetSpec(stc.STC_P_COMMENTBLOCK, p['comment'])
198 self.StyleSetSpec(stc.STC_P_COMMENTBLOCK, p['comment'])
199
199
200
200
201 def write(self, text):
201 def write(self, text):
202 """ Write given text to buffer, while translating the ansi escape
202 """ Write given text to buffer, while translating the ansi escape
203 sequences.
203 sequences.
204 """
204 """
205 title = self.title_pat.split(text)
205 title = self.title_pat.split(text)
206 if len(title)>0:
206 if len(title)>0:
207 self.title = title[-1]
207 self.title = title[-1]
208
208
209 text = self.title_pat.sub('', text)
209 text = self.title_pat.sub('', text)
210 segments = self.color_pat.split(text)
210 segments = self.color_pat.split(text)
211 segment = segments.pop(0)
211 segment = segments.pop(0)
212 self.StartStyling(self.GetLength(), 0xFF)
212 self.StartStyling(self.GetLength(), 0xFF)
213 self.AppendText(segment)
213 self.AppendText(segment)
214
214
215 if segments:
215 if segments:
216 ansi_tags = self.color_pat.findall(text)
216 ansi_tags = self.color_pat.findall(text)
217
217
218 for tag in ansi_tags:
218 for tag in ansi_tags:
219 i = segments.index(tag)
219 i = segments.index(tag)
220 self.StartStyling(self.GetLength(), 0xFF)
220 self.StartStyling(self.GetLength(), 0xFF)
221 self.AppendText(segments[i+1])
221 self.AppendText(segments[i+1])
222
222
223 if tag != '0':
223 if tag != '0':
224 self.SetStyling(len(segments[i+1]),
224 self.SetStyling(len(segments[i+1]),
225 self.ANSI_STYLES[tag][0])
225 self.ANSI_STYLES[tag][0])
226
226
227 segments.pop(i)
227 segments.pop(i)
228
228
229 self.GotoPos(self.GetLength())
229 self.GotoPos(self.GetLength())
230
230
231
231
232 def new_prompt(self, prompt):
232 def new_prompt(self, prompt):
233 """ Prints a prompt at start of line, and move the start of the
233 """ Prints a prompt at start of line, and move the start of the
234 current block there.
234 current block there.
235
235
236 The prompt can be give with ascii escape sequences.
236 The prompt can be give with ascii escape sequences.
237 """
237 """
238 self.write(prompt)
238 self.write(prompt)
239 # now we update our cursor giving end of prompt
239 # now we update our cursor giving end of prompt
240 self.current_prompt_pos = self.GetLength()
240 self.current_prompt_pos = self.GetLength()
241 self.current_prompt_line = self.GetCurrentLine()
241 self.current_prompt_line = self.GetCurrentLine()
242 wx.Yield()
242 wx.Yield()
243 self.EnsureCaretVisible()
243 self.EnsureCaretVisible()
244
244
245
245
246 def replace_current_edit_buffer(self, text):
246 def replace_current_edit_buffer(self, text):
247 """ Replace currently entered command line with given text.
247 """ Replace currently entered command line with given text.
248 """
248 """
249 self.SetSelection(self.current_prompt_pos, self.GetLength())
249 self.SetSelection(self.current_prompt_pos, self.GetLength())
250 self.ReplaceSelection(text)
250 self.ReplaceSelection(text)
251 self.GotoPos(self.GetLength())
251 self.GotoPos(self.GetLength())
252
252
253
253
254 def get_current_edit_buffer(self):
254 def get_current_edit_buffer(self):
255 """ Returns the text in current edit buffer.
255 """ Returns the text in current edit buffer.
256 """
256 """
257 return self.GetTextRange(self.current_prompt_pos,
257 return self.GetTextRange(self.current_prompt_pos,
258 self.GetLength())
258 self.GetLength())
259
259
260
260
261 #--------------------------------------------------------------------------
261 #--------------------------------------------------------------------------
262 # Private API
262 # Private API
263 #--------------------------------------------------------------------------
263 #--------------------------------------------------------------------------
264
264
265 def _apply_style(self):
265 def _apply_style(self):
266 """ Applies the colors for the different text elements and the
266 """ Applies the colors for the different text elements and the
267 carret.
267 carret.
268 """
268 """
269 self.SetCaretForeground(self.carret_color)
269 self.SetCaretForeground(self.carret_color)
270
270
271 #self.StyleClearAll()
271 #self.StyleClearAll()
272 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT,
272 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT,
273 "fore:#FF0000,back:#0000FF,bold")
273 "fore:#FF0000,back:#0000FF,bold")
274 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD,
274 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD,
275 "fore:#000000,back:#FF0000,bold")
275 "fore:#000000,back:#FF0000,bold")
276
276
277 for style in self.ANSI_STYLES.values():
277 for style in self.ANSI_STYLES.values():
278 self.StyleSetSpec(style[0], "bold,fore:%s" % style[1])
278 self.StyleSetSpec(style[0], "bold,fore:%s" % style[1])
279
279
280
280
281 def write_completion(self, possibilities, mode=None):
281 def write_completion(self, possibilities, mode=None):
282 if mode=='text' or self.autocomplete_mode == 'text':
282 if mode=='text' or self.autocomplete_mode == 'text':
283 max_len = len(max(possibilities, key=len))
283 max_len = len(max(possibilities, key=len))
284 current_buffer = self.get_current_edit_buffer()
284 current_buffer = self.get_current_edit_buffer()
285
285
286 self.write('\n')
286 self.write('\n')
287 for symbol in possibilities:
287 for symbol in possibilities:
288 self.write(symbol.ljust(max_len))
288 self.write(symbol.ljust(max_len))
289 self.new_prompt(self.prompt % (self.last_result['number'] + 1))
289 self.new_prompt(self.prompt % (self.last_result['number'] + 1))
290 self.replace_current_edit_buffer(current_buffer)
290 self.replace_current_edit_buffer(current_buffer)
291 else:
291 else:
292 #possibilities.sort() # Python sorts are case sensitive
292 #possibilities.sort() # Python sorts are case sensitive
293 self.AutoCompSetIgnoreCase(False)
293 self.AutoCompSetIgnoreCase(False)
294 self.AutoCompSetAutoHide(False)
294 self.AutoCompSetAutoHide(False)
295 #let compute the length ot text)last word
295 #let compute the length ot text)last word
296 splitter = [' ', '(', '[', '{']
296 splitter = [' ', '(', '[', '{']
297 last_word = self.get_current_edit_buffer()
297 last_word = self.get_current_edit_buffer()
298 for breaker in splitter:
298 for breaker in splitter:
299 last_word = last_word.split(breaker)[-1]
299 last_word = last_word.split(breaker)[-1]
300 self.AutoCompSetMaxHeight(len(possibilities))
300 self.AutoCompSetMaxHeight(len(possibilities))
301 self.AutoCompShow(len(last_word), " ".join(possibilities))
301 self.AutoCompShow(len(last_word), " ".join(possibilities))
302
302
303
303
304 def scroll_to_bottom(self):
304 def scroll_to_bottom(self):
305 maxrange = self.GetScrollRange(wx.VERTICAL)
305 maxrange = self.GetScrollRange(wx.VERTICAL)
306 self.ScrollLines(maxrange)
306 self.ScrollLines(maxrange)
307
307
308
308
309 def _on_enter(self):
309 def _on_enter(self):
310 """ Called when the return key is hit.
310 """ Called when the return key is hit.
311 """
311 """
312 pass
312 pass
313
313
314
314
315 def _on_key_down(self, event, skip=True):
315 def _on_key_down(self, event, skip=True):
316 """ Key press callback used for correcting behavior for
316 """ Key press callback used for correcting behavior for
317 console-like interfaces: the cursor is constraint to be after
317 console-like interfaces: the cursor is constraint to be after
318 the last prompt.
318 the last prompt.
319
319
320 Return True if event as been catched.
320 Return True if event as been catched.
321 """
321 """
322 catched = True
322 catched = True
323 # Intercept some specific keys.
323 # Intercept some specific keys.
324 if event.KeyCode == ord('L') and event.ControlDown() :
324 if event.KeyCode == ord('L') and event.ControlDown() :
325 self.scroll_to_bottom()
325 self.scroll_to_bottom()
326 elif event.KeyCode == ord('K') and event.ControlDown() :
326 elif event.KeyCode == ord('K') and event.ControlDown() :
327 self.replace_current_edit_buffer('')
327 self.replace_current_edit_buffer('')
328 elif event.KeyCode == wx.WXK_PAGEUP and event.ShiftDown():
328 elif event.KeyCode == wx.WXK_PAGEUP and event.ShiftDown():
329 self.ScrollPages(-1)
329 self.ScrollPages(-1)
330 elif event.KeyCode == wx.WXK_PAGEDOWN and event.ShiftDown():
330 elif event.KeyCode == wx.WXK_PAGEDOWN and event.ShiftDown():
331 self.ScrollPages(1)
331 self.ScrollPages(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.write('\n')
341 self.write('\n')
342 self._on_enter()
342 self._on_enter()
343
343
344 elif event.KeyCode == wx.WXK_HOME:
344 elif event.KeyCode == wx.WXK_HOME:
345 if event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN):
345 if event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN):
346 self.GotoPos(self.current_prompt_pos)
346 self.GotoPos(self.current_prompt_pos)
347 catched = True
347 catched = True
348
348
349 elif event.Modifiers in (wx.MOD_SHIFT, wx.MOD_WIN) :
349 elif event.Modifiers in (wx.MOD_SHIFT, wx.MOD_WIN) :
350 # FIXME: This behavior is not ideal: if the selection
350 # FIXME: This behavior is not ideal: if the selection
351 # is already started, it will jump.
351 # is already started, it will jump.
352 self.SetSelectionStart(self.current_prompt_pos)
352 self.SetSelectionStart(self.current_prompt_pos)
353 self.SetSelectionEnd(self.GetCurrentPos())
353 self.SetSelectionEnd(self.GetCurrentPos())
354 catched = True
354 catched = True
355
355
356 elif event.KeyCode == wx.WXK_UP:
356 elif event.KeyCode == wx.WXK_UP:
357 if self.GetCurrentLine() > self.current_prompt_line:
357 if self.GetCurrentLine() > self.current_prompt_line:
358 if self.GetCurrentLine() == self.current_prompt_line + 1 \
358 if self.GetCurrentLine() == self.current_prompt_line + 1 \
359 and self.GetColumn(self.GetCurrentPos()) < \
359 and self.GetColumn(self.GetCurrentPos()) < \
360 self.GetColumn(self.current_prompt_pos):
360 self.GetColumn(self.current_prompt_pos):
361 self.GotoPos(self.current_prompt_pos)
361 self.GotoPos(self.current_prompt_pos)
362 else:
362 else:
363 event.Skip()
363 event.Skip()
364 catched = True
364 catched = True
365
365
366 elif event.KeyCode in (wx.WXK_LEFT, wx.WXK_BACK):
366 elif event.KeyCode in (wx.WXK_LEFT, wx.WXK_BACK):
367 if self.GetCurrentPos() > self.current_prompt_pos:
367 if self.GetCurrentPos() > self.current_prompt_pos:
368 event.Skip()
368 event.Skip()
369 catched = True
369 catched = True
370
370
371 if skip and not catched:
371 if skip and not catched:
372 event.Skip()
372 event.Skip()
373
373
374 return catched
374 return catched
375
375
376
376
377 def _on_key_up(self, event, skip=True):
377 def _on_key_up(self, event, skip=True):
378 """ If cursor is outside the editing region, put it back.
378 """ If cursor is outside the editing region, put it back.
379 """
379 """
380 event.Skip()
380 event.Skip()
381 if self.GetCurrentPos() < self.current_prompt_pos:
381 if self.GetCurrentPos() < self.current_prompt_pos:
382 self.GotoPos(self.current_prompt_pos)
382 self.GotoPos(self.current_prompt_pos)
383
383
384
384
385
385
386
386
387 if __name__ == '__main__':
387 if __name__ == '__main__':
388 # Some simple code to test the console widget.
388 # Some simple code to test the console widget.
389 class MainWindow(wx.Frame):
389 class MainWindow(wx.Frame):
390 def __init__(self, parent, id, title):
390 def __init__(self, parent, id, title):
391 wx.Frame.__init__(self, parent, id, title, size=(300,250))
391 wx.Frame.__init__(self, parent, id, title, size=(300,250))
392 self._sizer = wx.BoxSizer(wx.VERTICAL)
392 self._sizer = wx.BoxSizer(wx.VERTICAL)
393 self.console_widget = ConsoleWidget(self)
393 self.console_widget = ConsoleWidget(self)
394 self._sizer.Add(self.console_widget, 1, wx.EXPAND)
394 self._sizer.Add(self.console_widget, 1, wx.EXPAND)
395 self.SetSizer(self._sizer)
395 self.SetSizer(self._sizer)
396 self.SetAutoLayout(1)
396 self.SetAutoLayout(1)
397 self.Show(True)
397 self.Show(True)
398
398
399 app = wx.PySimpleApp()
399 app = wx.PySimpleApp()
400 w = MainWindow(None, wx.ID_ANY, 'ConsoleWidget')
400 w = MainWindow(None, wx.ID_ANY, 'ConsoleWidget')
401 w.SetSize((780, 460))
401 w.SetSize((780, 460))
402 w.Show()
402 w.Show()
403
403
404 app.MainLoop()
404 app.MainLoop()
405
405
406
406
@@ -1,159 +1,178 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 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 console_widget import ConsoleWidget
27 from console_widget import ConsoleWidget
27
28
28 from IPython.frontend.prefilterfrontend import PrefilterFrontEnd
29 from IPython.frontend.prefilterfrontend import PrefilterFrontEnd
29
30
31 #_COMMAND_BG = '#FAFAF1' # Nice green
32 _RUNNING_BUFFER_BG = '#FDFFBE' # Nice yellow
33
34 _RUNNING_BUFFER_MARKER = 31
35
36
30 #-------------------------------------------------------------------------------
37 #-------------------------------------------------------------------------------
31 # Classes to implement the Wx frontend
38 # Classes to implement the Wx frontend
32 #-------------------------------------------------------------------------------
39 #-------------------------------------------------------------------------------
33 class IPythonWxController(PrefilterFrontEnd, ConsoleWidget):
40 class IPythonWxController(PrefilterFrontEnd, ConsoleWidget):
34
41
35 output_prompt = \
42 output_prompt = \
36 '\x01\x1b[0;31m\x02Out[\x01\x1b[1;31m\x02%i\x01\x1b[0;31m\x02]: \x01\x1b[0m\x02'
43 '\x01\x1b[0;31m\x02Out[\x01\x1b[1;31m\x02%i\x01\x1b[0;31m\x02]: \x01\x1b[0m\x02'
37
44
38 #--------------------------------------------------------------------------
45 #--------------------------------------------------------------------------
39 # Public API
46 # Public API
40 #--------------------------------------------------------------------------
47 #--------------------------------------------------------------------------
41
48
42 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
49 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
43 size=wx.DefaultSize, style=wx.CLIP_CHILDREN,
50 size=wx.DefaultSize, style=wx.CLIP_CHILDREN,
44 *args, **kwds):
51 *args, **kwds):
45 """ Create Shell instance.
52 """ Create Shell instance.
46 """
53 """
47 ConsoleWidget.__init__(self, parent, id, pos, size, style)
54 ConsoleWidget.__init__(self, parent, id, pos, size, style)
48 PrefilterFrontEnd.__init__(self)
55 PrefilterFrontEnd.__init__(self)
49
56
50 # Capture Character keys
57 # Capture Character keys
51 self.Bind(wx.EVT_KEY_DOWN, self._on_key_down)
58 self.Bind(wx.EVT_KEY_DOWN, self._on_key_down)
52
59
60 # Marker for running buffer.
61 self.MarkerDefine(_RUNNING_BUFFER_MARKER, stc.STC_MARK_BACKGROUND,
62 background=_RUNNING_BUFFER_BG)
63
64
53
65
54 def do_completion(self, mode=None):
66 def do_completion(self, mode=None):
55 """ Do code completion.
67 """ Do code completion.
56 mode can be 'text', 'popup' or 'none' to use default.
68 mode can be 'text', 'popup' or 'none' to use default.
57 """
69 """
58 line = self.get_current_edit_buffer()
70 line = self.get_current_edit_buffer()
59 completions = self.complete(line)
71 completions = self.complete(line)
60 self.write_completion(completions, mode=mode)
72 if len(completions)>0:
73 self.write_completion(completions, mode=mode)
61
74
62
75
63 def update_completion(self):
76 def update_completion(self):
64 line = self.get_current_edit_buffer()
77 line = self.get_current_edit_buffer()
65 if self.AutoCompActive() and not line[-1] == '.':
78 if self.AutoCompActive() and not line[-1] == '.':
66 line = line[:-1]
79 line = line[:-1]
67 completions = self.complete(line)
80 completions = self.complete(line)
68 choose_single = self.AutoCompGetChooseSingle()
81 choose_single = self.AutoCompGetChooseSingle()
69 self.AutoCompSetChooseSingle(False)
82 self.AutoCompSetChooseSingle(False)
70 self.write_completion(completions, mode='popup')
83 self.write_completion(completions, mode='popup')
71 self.AutoCompSetChooseSingle(choose_single)
84 self.AutoCompSetChooseSingle(choose_single)
72
85
73
86
74 def execute(self, *args, **kwargs):
87 def execute(self, python_string, raw_string=None):
75 self._cursor = wx.BusyCursor()
88 self._cursor = wx.BusyCursor()
76 PrefilterFrontEnd.execute(self, *args, **kwargs)
89 if raw_string is None:
90 raw_string = python_string
91 end_line = self.current_prompt_line \
92 + max(1, len(raw_string.split('\n'))-1)
93 for i in range(self.current_prompt_line, end_line):
94 self.MarkerAdd(i, 31)
95 PrefilterFrontEnd.execute(self, python_string, raw_string=raw_string)
96
77
97
78
79 def after_execute(self):
98 def after_execute(self):
80 PrefilterFrontEnd.after_execute(self)
99 PrefilterFrontEnd.after_execute(self)
81 if hasattr(self, '_cursor'):
100 if hasattr(self, '_cursor'):
82 del self._cursor
101 del self._cursor
83
102
84 #--------------------------------------------------------------------------
103 #--------------------------------------------------------------------------
85 # Private API
104 # Private API
86 #--------------------------------------------------------------------------
105 #--------------------------------------------------------------------------
87
106
88
107
89 def _on_key_down(self, event, skip=True):
108 def _on_key_down(self, event, skip=True):
90 """ Capture the character events, let the parent
109 """ Capture the character events, let the parent
91 widget handle them, and put our logic afterward.
110 widget handle them, and put our logic afterward.
92 """
111 """
93 current_line_number = self.GetCurrentLine()
112 current_line_number = self.GetCurrentLine()
94 if self.AutoCompActive():
113 if self.AutoCompActive():
95 event.Skip()
114 event.Skip()
96 if event.KeyCode in (wx.WXK_BACK, wx.WXK_DELETE):
115 if event.KeyCode in (wx.WXK_BACK, wx.WXK_DELETE):
97 wx.CallAfter(self.do_completion)
116 wx.CallAfter(self.do_completion)
98 elif not event.KeyCode in (wx.WXK_UP, wx.WXK_DOWN, wx.WXK_LEFT,
117 elif not event.KeyCode in (wx.WXK_UP, wx.WXK_DOWN, wx.WXK_LEFT,
99 wx.WXK_RIGHT):
118 wx.WXK_RIGHT):
100 wx.CallAfter(self.update_completion)
119 wx.CallAfter(self.update_completion)
101 else:
120 else:
102 # Up history
121 # Up history
103 if event.KeyCode == wx.WXK_UP and (
122 if event.KeyCode == wx.WXK_UP and (
104 ( current_line_number == self.current_prompt_line and
123 ( current_line_number == self.current_prompt_line and
105 event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN) )
124 event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN) )
106 or event.ControlDown() ):
125 or event.ControlDown() ):
107 new_buffer = self.get_history_previous(
126 new_buffer = self.get_history_previous(
108 self.get_current_edit_buffer())
127 self.get_current_edit_buffer())
109 if new_buffer is not None:
128 if new_buffer is not None:
110 self.replace_current_edit_buffer(new_buffer)
129 self.replace_current_edit_buffer(new_buffer)
111 if self.GetCurrentLine() > self.current_prompt_line:
130 if self.GetCurrentLine() > self.current_prompt_line:
112 # Go to first line, for seemless history up.
131 # Go to first line, for seemless history up.
113 self.GotoPos(self.current_prompt_pos)
132 self.GotoPos(self.current_prompt_pos)
114 # Down history
133 # Down history
115 elif event.KeyCode == wx.WXK_DOWN and (
134 elif event.KeyCode == wx.WXK_DOWN and (
116 ( current_line_number == self.LineCount -1 and
135 ( current_line_number == self.LineCount -1 and
117 event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN) )
136 event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN) )
118 or event.ControlDown() ):
137 or event.ControlDown() ):
119 new_buffer = self.get_history_next()
138 new_buffer = self.get_history_next()
120 if new_buffer is not None:
139 if new_buffer is not None:
121 self.replace_current_edit_buffer(new_buffer)
140 self.replace_current_edit_buffer(new_buffer)
122 elif event.KeyCode == ord('\t'):
141 elif event.KeyCode == ord('\t'):
123 last_line = self.get_current_edit_buffer().split('\n')[-1]
142 last_line = self.get_current_edit_buffer().split('\n')[-1]
124 if not re.match(r'^\s*$', last_line):
143 if not re.match(r'^\s*$', last_line):
125 self.do_completion(mode='text')
144 self.do_completion(mode='text')
126 else:
145 else:
127 event.Skip()
146 event.Skip()
128 else:
147 else:
129 ConsoleWidget._on_key_down(self, event, skip=skip)
148 ConsoleWidget._on_key_down(self, event, skip=skip)
130
149
131
150
132 def _on_key_up(self, event, skip=True):
151 def _on_key_up(self, event, skip=True):
133 if event.KeyCode == 59:
152 if event.KeyCode == 59:
134 # Intercepting '.'
153 # Intercepting '.'
135 event.Skip()
154 event.Skip()
136 self.do_completion(mode='popup')
155 #self.do_completion(mode='popup')
137 else:
156 else:
138 ConsoleWidget._on_key_up(self, event, skip=skip)
157 ConsoleWidget._on_key_up(self, event, skip=skip)
139
158
140
159
141 if __name__ == '__main__':
160 if __name__ == '__main__':
142 class MainWindow(wx.Frame):
161 class MainWindow(wx.Frame):
143 def __init__(self, parent, id, title):
162 def __init__(self, parent, id, title):
144 wx.Frame.__init__(self, parent, id, title, size=(300,250))
163 wx.Frame.__init__(self, parent, id, title, size=(300,250))
145 self._sizer = wx.BoxSizer(wx.VERTICAL)
164 self._sizer = wx.BoxSizer(wx.VERTICAL)
146 self.shell = IPythonWxController(self)
165 self.shell = IPythonWxController(self)
147 self._sizer.Add(self.shell, 1, wx.EXPAND)
166 self._sizer.Add(self.shell, 1, wx.EXPAND)
148 self.SetSizer(self._sizer)
167 self.SetSizer(self._sizer)
149 self.SetAutoLayout(1)
168 self.SetAutoLayout(1)
150 self.Show(True)
169 self.Show(True)
151
170
152 app = wx.PySimpleApp()
171 app = wx.PySimpleApp()
153 frame = MainWindow(None, wx.ID_ANY, 'Ipython')
172 frame = MainWindow(None, wx.ID_ANY, 'Ipython')
154 frame.shell.SetFocus()
173 frame.shell.SetFocus()
155 frame.SetSize((660, 460))
174 frame.SetSize((660, 460))
156 self = frame.shell
175 self = frame.shell
157
176
158 app.MainLoop()
177 app.MainLoop()
159
178
General Comments 0
You need to be logged in to leave comments. Login now