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