##// END OF EJS Templates
Better fonts on MacOSX....
gvaroquaux -
Show More
@@ -1,208 +1,212 b''
1 """
1 """
2 Frontend class that uses IPython0 to prefilter the inputs.
2 Frontend class that uses IPython0 to prefilter the inputs.
3
3
4 Using the IPython0 mechanism gives us access to the magics.
4 Using the IPython0 mechanism gives us access to the magics.
5
5
6 This is a transitory class, used here to do the transition between
6 This is a transitory class, used here to do the transition between
7 ipython0 and ipython1. This class is meant to be short-lived as more
7 ipython0 and ipython1. This class is meant to be short-lived as more
8 functionnality is abstracted out of ipython0 in reusable functions and
8 functionnality is abstracted out of ipython0 in reusable functions and
9 is added on the interpreter. This class can be a used to guide this
9 is added on the interpreter. This class can be a used to guide this
10 refactoring.
10 refactoring.
11 """
11 """
12 __docformat__ = "restructuredtext en"
12 __docformat__ = "restructuredtext en"
13
13
14 #-------------------------------------------------------------------------------
14 #-------------------------------------------------------------------------------
15 # Copyright (C) 2008 The IPython Development Team
15 # Copyright (C) 2008 The IPython Development Team
16 #
16 #
17 # Distributed under the terms of the BSD License. The full license is in
17 # Distributed under the terms of the BSD License. The full license is in
18 # the file COPYING, distributed as part of this software.
18 # the file COPYING, distributed as part of this software.
19 #-------------------------------------------------------------------------------
19 #-------------------------------------------------------------------------------
20
20
21 #-------------------------------------------------------------------------------
21 #-------------------------------------------------------------------------------
22 # Imports
22 # Imports
23 #-------------------------------------------------------------------------------
23 #-------------------------------------------------------------------------------
24 import sys
24 import sys
25
25
26 from linefrontendbase import LineFrontEndBase, common_prefix
26 from linefrontendbase import LineFrontEndBase, common_prefix
27
27
28 from IPython.ipmaker import make_IPython
28 from IPython.ipmaker import make_IPython
29 from IPython.ipapi import IPApi
29 from IPython.ipapi import IPApi
30 from IPython.kernel.core.redirector_output_trap import RedirectorOutputTrap
30 from IPython.kernel.core.redirector_output_trap import RedirectorOutputTrap
31
31
32 from IPython.kernel.core.sync_traceback_trap import SyncTracebackTrap
32 from IPython.kernel.core.sync_traceback_trap import SyncTracebackTrap
33
33
34 from IPython.genutils import Term
34 from IPython.genutils import Term
35 import pydoc
35 import pydoc
36 import os
36 import os
37
37
38
38
39 def mk_system_call(system_call_function, command):
39 def mk_system_call(system_call_function, command):
40 """ given a os.system replacement, and a leading string command,
40 """ given a os.system replacement, and a leading string command,
41 returns a function that will execute the command with the given
41 returns a function that will execute the command with the given
42 argument string.
42 argument string.
43 """
43 """
44 def my_system_call(args):
44 def my_system_call(args):
45 system_call_function("%s %s" % (command, args))
45 system_call_function("%s %s" % (command, args))
46 return my_system_call
46 return my_system_call
47
47
48 #-------------------------------------------------------------------------------
48 #-------------------------------------------------------------------------------
49 # Frontend class using ipython0 to do the prefiltering.
49 # Frontend class using ipython0 to do the prefiltering.
50 #-------------------------------------------------------------------------------
50 #-------------------------------------------------------------------------------
51 class PrefilterFrontEnd(LineFrontEndBase):
51 class PrefilterFrontEnd(LineFrontEndBase):
52 """ Class that uses ipython0 to do prefilter the input, do the
52 """ Class that uses ipython0 to do prefilter the input, do the
53 completion and the magics.
53 completion and the magics.
54
54
55 The core trick is to use an ipython0 instance to prefilter the
55 The core trick is to use an ipython0 instance to prefilter the
56 input, and share the namespace between the interpreter instance used
56 input, and share the namespace between the interpreter instance used
57 to execute the statements and the ipython0 used for code
57 to execute the statements and the ipython0 used for code
58 completion...
58 completion...
59 """
59 """
60
60
61 def __init__(self, *args, **kwargs):
61 def __init__(self, *args, **kwargs):
62 self.save_output_hooks()
62 self.save_output_hooks()
63 # Instanciate an IPython0 interpreter to be able to use the
63 # Instanciate an IPython0 interpreter to be able to use the
64 # prefiltering.
64 # prefiltering.
65 self.ipython0 = make_IPython()
65 self.ipython0 = make_IPython()
66 # Set the pager:
66 # Set the pager:
67 self.ipython0.set_hook('show_in_pager',
67 self.ipython0.set_hook('show_in_pager',
68 lambda s, string: self.write("\n"+string))
68 lambda s, string: self.write("\n"+string))
69 self.ipython0.write = self.write
69 self.ipython0.write = self.write
70 self._ip = _ip = IPApi(self.ipython0)
70 self._ip = _ip = IPApi(self.ipython0)
71 # Make sure the raw system call doesn't get called, as we don't
71 # Make sure the raw system call doesn't get called, as we don't
72 # have a stdin accessible.
72 # have a stdin accessible.
73 self._ip.system = self.system_call
73 self._ip.system = self.system_call
74 # XXX: Muck around with magics so that they work better
74 # XXX: Muck around with magics so that they work better
75 # in our environment
75 # in our environment
76 self.ipython0.magic_ls = mk_system_call(self.system_call,
76 self.ipython0.magic_ls = mk_system_call(self.system_call,
77 'ls -CF')
77 'ls -CF')
78 # And now clean up the mess created by ipython0
78 # And now clean up the mess created by ipython0
79 self.release_output()
79 self.release_output()
80 if not 'banner' in kwargs:
80 if not 'banner' in kwargs:
81 kwargs['banner'] = self.ipython0.BANNER + """
81 kwargs['banner'] = self.ipython0.BANNER + """
82 This is the wx frontend, by Gael Varoquaux. This is EXPERIMENTAL code."""
82 This is the wx frontend, by Gael Varoquaux. This is EXPERIMENTAL code."""
83
83
84 LineFrontEndBase.__init__(self, *args, **kwargs)
84 LineFrontEndBase.__init__(self, *args, **kwargs)
85 # XXX: Hack: mix the two namespaces
85 # XXX: Hack: mix the two namespaces
86 self.shell.user_ns = self.ipython0.user_ns
86 self.shell.user_ns = self.ipython0.user_ns
87 self.shell.user_global_ns = self.ipython0.user_global_ns
87 self.shell.user_global_ns = self.ipython0.user_global_ns
88
88
89 self.shell.output_trap = RedirectorOutputTrap(
89 self.shell.output_trap = RedirectorOutputTrap(
90 out_callback=self.write,
90 out_callback=self.write,
91 err_callback=self.write,
91 err_callback=self.write,
92 )
92 )
93 self.shell.traceback_trap = SyncTracebackTrap(
93 self.shell.traceback_trap = SyncTracebackTrap(
94 formatters=self.shell.traceback_trap.formatters,
94 formatters=self.shell.traceback_trap.formatters,
95 )
95 )
96
96
97 #--------------------------------------------------------------------------
97 #--------------------------------------------------------------------------
98 # FrontEndBase interface
98 # FrontEndBase interface
99 #--------------------------------------------------------------------------
99 #--------------------------------------------------------------------------
100
100
101 def show_traceback(self):
101 def show_traceback(self):
102 """ Use ipython0 to capture the last traceback and display it.
102 """ Use ipython0 to capture the last traceback and display it.
103 """
103 """
104 self.capture_output()
104 self.capture_output()
105 self.ipython0.showtraceback()
105 self.ipython0.showtraceback()
106 self.release_output()
106 self.release_output()
107
107
108
108
109 def execute(self, python_string, raw_string=None):
109 def execute(self, python_string, raw_string=None):
110 if self.debug:
111 print 'Executing Python code:', repr(python_string)
110 self.capture_output()
112 self.capture_output()
111 LineFrontEndBase.execute(self, python_string,
113 LineFrontEndBase.execute(self, python_string,
112 raw_string=raw_string)
114 raw_string=raw_string)
113 self.release_output()
115 self.release_output()
114
116
115
117
116 def save_output_hooks(self):
118 def save_output_hooks(self):
117 """ Store all the output hooks we can think of, to be able to
119 """ Store all the output hooks we can think of, to be able to
118 restore them.
120 restore them.
119
121
120 We need to do this early, as starting the ipython0 instance will
122 We need to do this early, as starting the ipython0 instance will
121 screw ouput hooks.
123 screw ouput hooks.
122 """
124 """
123 self.__old_cout_write = Term.cout.write
125 self.__old_cout_write = Term.cout.write
124 self.__old_cerr_write = Term.cerr.write
126 self.__old_cerr_write = Term.cerr.write
125 self.__old_stdout = sys.stdout
127 self.__old_stdout = sys.stdout
126 self.__old_stderr= sys.stderr
128 self.__old_stderr= sys.stderr
127 self.__old_help_output = pydoc.help.output
129 self.__old_help_output = pydoc.help.output
128 self.__old_display_hook = sys.displayhook
130 self.__old_display_hook = sys.displayhook
129
131
130
132
131 def capture_output(self):
133 def capture_output(self):
132 """ Capture all the output mechanisms we can think of.
134 """ Capture all the output mechanisms we can think of.
133 """
135 """
134 self.save_output_hooks()
136 self.save_output_hooks()
135 Term.cout.write = self.write
137 Term.cout.write = self.write
136 Term.cerr.write = self.write
138 Term.cerr.write = self.write
137 sys.stdout = Term.cout
139 sys.stdout = Term.cout
138 sys.stderr = Term.cerr
140 sys.stderr = Term.cerr
139 pydoc.help.output = self.shell.output_trap.out
141 pydoc.help.output = self.shell.output_trap.out
140
142
141
143
142 def release_output(self):
144 def release_output(self):
143 """ Release all the different captures we have made.
145 """ Release all the different captures we have made.
144 """
146 """
145 Term.cout.write = self.__old_cout_write
147 Term.cout.write = self.__old_cout_write
146 Term.cerr.write = self.__old_cerr_write
148 Term.cerr.write = self.__old_cerr_write
147 sys.stdout = self.__old_stdout
149 sys.stdout = self.__old_stdout
148 sys.stderr = self.__old_stderr
150 sys.stderr = self.__old_stderr
149 pydoc.help.output = self.__old_help_output
151 pydoc.help.output = self.__old_help_output
150 sys.displayhook = self.__old_display_hook
152 sys.displayhook = self.__old_display_hook
151
153
152
154
153 def complete(self, line):
155 def complete(self, line):
154 word = line.split('\n')[-1].split(' ')[-1]
156 word = line.split('\n')[-1].split(' ')[-1]
155 completions = self.ipython0.complete(word)
157 completions = self.ipython0.complete(word)
156 # FIXME: The proper sort should be done in the complete method.
158 # FIXME: The proper sort should be done in the complete method.
157 key = lambda x: x.replace('_', '')
159 key = lambda x: x.replace('_', '')
158 completions.sort(key=key)
160 completions.sort(key=key)
159 if completions:
161 if completions:
160 prefix = common_prefix(completions)
162 prefix = common_prefix(completions)
161 line = line[:-len(word)] + prefix
163 line = line[:-len(word)] + prefix
162 return line, completions
164 return line, completions
163
165
164
166
165 #--------------------------------------------------------------------------
167 #--------------------------------------------------------------------------
166 # LineFrontEndBase interface
168 # LineFrontEndBase interface
167 #--------------------------------------------------------------------------
169 #--------------------------------------------------------------------------
168
170
169 def prefilter_input(self, input_string):
171 def prefilter_input(self, input_string):
170 """ Using IPython0 to prefilter the commands to turn them
172 """ Using IPython0 to prefilter the commands to turn them
171 in executable statements that are valid Python strings.
173 in executable statements that are valid Python strings.
172 """
174 """
173 input_string = LineFrontEndBase.prefilter_input(self, input_string)
175 input_string = LineFrontEndBase.prefilter_input(self, input_string)
174 filtered_lines = []
176 filtered_lines = []
175 # The IPython0 prefilters sometime produce output. We need to
177 # The IPython0 prefilters sometime produce output. We need to
176 # capture it.
178 # capture it.
177 self.capture_output()
179 self.capture_output()
178 self.last_result = dict(number=self.prompt_number)
180 self.last_result = dict(number=self.prompt_number)
179 try:
181 try:
180 for line in input_string.split('\n'):
182 for line in input_string.split('\n'):
181 filtered_lines.append(self.ipython0.prefilter(line, False))
183 filtered_lines.append(
184 self.ipython0.prefilter(line, False).rstrip())
182 except:
185 except:
183 # XXX: probably not the right thing to do.
186 # XXX: probably not the right thing to do.
184 self.ipython0.showsyntaxerror()
187 self.ipython0.showsyntaxerror()
185 self.after_execute()
188 self.after_execute()
186 finally:
189 finally:
187 self.release_output()
190 self.release_output()
188
191
192 # Clean up the trailing whitespace, to avoid indentation errors
189 filtered_string = '\n'.join(filtered_lines)
193 filtered_string = '\n'.join(filtered_lines)
190 return filtered_string
194 return filtered_string
191
195
192
196
193 #--------------------------------------------------------------------------
197 #--------------------------------------------------------------------------
194 # PrefilterFrontEnd interface
198 # PrefilterFrontEnd interface
195 #--------------------------------------------------------------------------
199 #--------------------------------------------------------------------------
196
200
197 def system_call(self, command_string):
201 def system_call(self, command_string):
198 """ Allows for frontend to define their own system call, to be
202 """ Allows for frontend to define their own system call, to be
199 able capture output and redirect input.
203 able capture output and redirect input.
200 """
204 """
201 return os.system(command_string)
205 return os.system(command_string)
202
206
203
207
204 def do_exit(self):
208 def do_exit(self):
205 """ Exit the shell, cleanup and save the history.
209 """ Exit the shell, cleanup and save the history.
206 """
210 """
207 self.ipython0.atexit_operations()
211 self.ipython0.atexit_operations()
208
212
@@ -1,415 +1,417 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 A Wx widget to act as a console and input commands.
3 A Wx widget to act as a console and input commands.
4
4
5 This widget deals with prompts and provides an edit buffer
5 This widget deals with prompts and provides an edit buffer
6 restricted to after the last prompt.
6 restricted to after the last prompt.
7 """
7 """
8
8
9 __docformat__ = "restructuredtext en"
9 __docformat__ = "restructuredtext en"
10
10
11 #-------------------------------------------------------------------------------
11 #-------------------------------------------------------------------------------
12 # Copyright (C) 2008 The IPython Development Team
12 # Copyright (C) 2008 The IPython Development Team
13 #
13 #
14 # Distributed under the terms of the BSD License. The full license is
14 # Distributed under the terms of the BSD License. The full license is
15 # in the file COPYING, distributed as part of this software.
15 # in the file COPYING, distributed as part of this software.
16 #-------------------------------------------------------------------------------
16 #-------------------------------------------------------------------------------
17
17
18 #-------------------------------------------------------------------------------
18 #-------------------------------------------------------------------------------
19 # Imports
19 # Imports
20 #-------------------------------------------------------------------------------
20 #-------------------------------------------------------------------------------
21
21
22 import wx
22 import wx
23 import wx.stc as stc
23 import wx.stc as stc
24
24
25 from wx.py import editwindow
25 from wx.py import editwindow
26 import sys
26 import sys
27 LINESEP = '\n'
27 LINESEP = '\n'
28 if sys.platform == 'win32':
28 if sys.platform == 'win32':
29 LINESEP = '\n\r'
29 LINESEP = '\n\r'
30
30
31 import re
31 import re
32
32
33 # FIXME: Need to provide an API for non user-generated display on the
33 # FIXME: Need to provide an API for non user-generated display on the
34 # screen: this should not be editable by the user.
34 # screen: this should not be editable by the user.
35
35
36 _DEFAULT_SIZE = 10
36 _DEFAULT_SIZE = 10
37 if sys.platform == 'darwin':
38 _DEFAULT_STYLE = 12
37
39
38 _DEFAULT_STYLE = {
40 _DEFAULT_STYLE = {
39 'stdout' : 'fore:#0000FF',
41 'stdout' : 'fore:#0000FF',
40 'stderr' : 'fore:#007f00',
42 'stderr' : 'fore:#007f00',
41 'trace' : 'fore:#FF0000',
43 'trace' : 'fore:#FF0000',
42
44
43 'default' : 'size:%d' % _DEFAULT_SIZE,
45 'default' : 'size:%d' % _DEFAULT_SIZE,
44 'bracegood' : 'fore:#00AA00,back:#000000,bold',
46 'bracegood' : 'fore:#00AA00,back:#000000,bold',
45 'bracebad' : 'fore:#FF0000,back:#000000,bold',
47 'bracebad' : 'fore:#FF0000,back:#000000,bold',
46
48
47 # properties for the various Python lexer styles
49 # properties for the various Python lexer styles
48 'comment' : 'fore:#007F00',
50 'comment' : 'fore:#007F00',
49 'number' : 'fore:#007F7F',
51 'number' : 'fore:#007F7F',
50 'string' : 'fore:#7F007F,italic',
52 'string' : 'fore:#7F007F,italic',
51 'char' : 'fore:#7F007F,italic',
53 'char' : 'fore:#7F007F,italic',
52 'keyword' : 'fore:#00007F,bold',
54 'keyword' : 'fore:#00007F,bold',
53 'triple' : 'fore:#7F0000',
55 'triple' : 'fore:#7F0000',
54 'tripledouble' : 'fore:#7F0000',
56 'tripledouble' : 'fore:#7F0000',
55 'class' : 'fore:#0000FF,bold,underline',
57 'class' : 'fore:#0000FF,bold,underline',
56 'def' : 'fore:#007F7F,bold',
58 'def' : 'fore:#007F7F,bold',
57 'operator' : 'bold'
59 'operator' : 'bold'
58 }
60 }
59
61
60 # new style numbers
62 # new style numbers
61 _STDOUT_STYLE = 15
63 _STDOUT_STYLE = 15
62 _STDERR_STYLE = 16
64 _STDERR_STYLE = 16
63 _TRACE_STYLE = 17
65 _TRACE_STYLE = 17
64
66
65
67
66 # system colors
68 # system colors
67 #SYS_COLOUR_BACKGROUND = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BACKGROUND)
69 #SYS_COLOUR_BACKGROUND = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BACKGROUND)
68
70
69 #-------------------------------------------------------------------------------
71 #-------------------------------------------------------------------------------
70 # The console widget class
72 # The console widget class
71 #-------------------------------------------------------------------------------
73 #-------------------------------------------------------------------------------
72 class ConsoleWidget(editwindow.EditWindow):
74 class ConsoleWidget(editwindow.EditWindow):
73 """ Specialized styled text control view for console-like workflow.
75 """ Specialized styled text control view for console-like workflow.
74
76
75 This widget is mainly interested in dealing with the prompt and
77 This widget is mainly interested in dealing with the prompt and
76 keeping the cursor inside the editing line.
78 keeping the cursor inside the editing line.
77 """
79 """
78
80
79 # This is where the title captured from the ANSI escape sequences are
81 # This is where the title captured from the ANSI escape sequences are
80 # stored.
82 # stored.
81 title = 'Console'
83 title = 'Console'
82
84
83 # The buffer being edited.
85 # The buffer being edited.
84 def _set_input_buffer(self, string):
86 def _set_input_buffer(self, string):
85 self.SetSelection(self.current_prompt_pos, self.GetLength())
87 self.SetSelection(self.current_prompt_pos, self.GetLength())
86 self.ReplaceSelection(string)
88 self.ReplaceSelection(string)
87 self.GotoPos(self.GetLength())
89 self.GotoPos(self.GetLength())
88
90
89 def _get_input_buffer(self):
91 def _get_input_buffer(self):
90 """ Returns the text in current edit buffer.
92 """ Returns the text in current edit buffer.
91 """
93 """
92 input_buffer = self.GetTextRange(self.current_prompt_pos,
94 input_buffer = self.GetTextRange(self.current_prompt_pos,
93 self.GetLength())
95 self.GetLength())
94 input_buffer = input_buffer.replace(LINESEP, '\n')
96 input_buffer = input_buffer.replace(LINESEP, '\n')
95 return input_buffer
97 return input_buffer
96
98
97 input_buffer = property(_get_input_buffer, _set_input_buffer)
99 input_buffer = property(_get_input_buffer, _set_input_buffer)
98
100
99 style = _DEFAULT_STYLE.copy()
101 style = _DEFAULT_STYLE.copy()
100
102
101 # Translation table from ANSI escape sequences to color. Override
103 # Translation table from ANSI escape sequences to color. Override
102 # this to specify your colors.
104 # this to specify your colors.
103 ANSI_STYLES = {'0;30': [0, 'BLACK'], '0;31': [1, 'RED'],
105 ANSI_STYLES = {'0;30': [0, 'BLACK'], '0;31': [1, 'RED'],
104 '0;32': [2, 'GREEN'], '0;33': [3, 'BROWN'],
106 '0;32': [2, 'GREEN'], '0;33': [3, 'BROWN'],
105 '0;34': [4, 'BLUE'], '0;35': [5, 'PURPLE'],
107 '0;34': [4, 'BLUE'], '0;35': [5, 'PURPLE'],
106 '0;36': [6, 'CYAN'], '0;37': [7, 'LIGHT GREY'],
108 '0;36': [6, 'CYAN'], '0;37': [7, 'LIGHT GREY'],
107 '1;30': [8, 'DARK GREY'], '1;31': [9, 'RED'],
109 '1;30': [8, 'DARK GREY'], '1;31': [9, 'RED'],
108 '1;32': [10, 'SEA GREEN'], '1;33': [11, 'YELLOW'],
110 '1;32': [10, 'SEA GREEN'], '1;33': [11, 'YELLOW'],
109 '1;34': [12, 'LIGHT BLUE'], '1;35':
111 '1;34': [12, 'LIGHT BLUE'], '1;35':
110 [13, 'MEDIUM VIOLET RED'],
112 [13, 'MEDIUM VIOLET RED'],
111 '1;36': [14, 'LIGHT STEEL BLUE'], '1;37': [15, 'YELLOW']}
113 '1;36': [14, 'LIGHT STEEL BLUE'], '1;37': [15, 'YELLOW']}
112
114
113 # The color of the carret (call _apply_style() after setting)
115 # The color of the carret (call _apply_style() after setting)
114 carret_color = 'BLACK'
116 carret_color = 'BLACK'
115
117
116 #--------------------------------------------------------------------------
118 #--------------------------------------------------------------------------
117 # Public API
119 # Public API
118 #--------------------------------------------------------------------------
120 #--------------------------------------------------------------------------
119
121
120 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
122 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
121 size=wx.DefaultSize, style=0, ):
123 size=wx.DefaultSize, style=0, ):
122 editwindow.EditWindow.__init__(self, parent, id, pos, size, style)
124 editwindow.EditWindow.__init__(self, parent, id, pos, size, style)
123 self._configure_scintilla()
125 self._configure_scintilla()
124
126
125 self.Bind(wx.EVT_KEY_DOWN, self._on_key_down)
127 self.Bind(wx.EVT_KEY_DOWN, self._on_key_down)
126 self.Bind(wx.EVT_KEY_UP, self._on_key_up)
128 self.Bind(wx.EVT_KEY_UP, self._on_key_up)
127
129
128
130
129 def write(self, text, refresh=True):
131 def write(self, text, refresh=True):
130 """ Write given text to buffer, while translating the ansi escape
132 """ Write given text to buffer, while translating the ansi escape
131 sequences.
133 sequences.
132 """
134 """
133 # XXX: do not put print statements to sys.stdout/sys.stderr in
135 # XXX: do not put print statements to sys.stdout/sys.stderr in
134 # this method, the print statements will call this method, as
136 # this method, the print statements will call this method, as
135 # you will end up with an infinit loop
137 # you will end up with an infinit loop
136 title = self.title_pat.split(text)
138 title = self.title_pat.split(text)
137 if len(title)>1:
139 if len(title)>1:
138 self.title = title[-2]
140 self.title = title[-2]
139
141
140 text = self.title_pat.sub('', text)
142 text = self.title_pat.sub('', text)
141 segments = self.color_pat.split(text)
143 segments = self.color_pat.split(text)
142 segment = segments.pop(0)
144 segment = segments.pop(0)
143 self.GotoPos(self.GetLength())
145 self.GotoPos(self.GetLength())
144 self.StartStyling(self.GetLength(), 0xFF)
146 self.StartStyling(self.GetLength(), 0xFF)
145 try:
147 try:
146 self.AppendText(segment)
148 self.AppendText(segment)
147 except UnicodeDecodeError:
149 except UnicodeDecodeError:
148 # XXX: Do I really want to skip the exception?
150 # XXX: Do I really want to skip the exception?
149 pass
151 pass
150
152
151 if segments:
153 if segments:
152 for ansi_tag, text in zip(segments[::2], segments[1::2]):
154 for ansi_tag, text in zip(segments[::2], segments[1::2]):
153 self.StartStyling(self.GetLength(), 0xFF)
155 self.StartStyling(self.GetLength(), 0xFF)
154 try:
156 try:
155 self.AppendText(text)
157 self.AppendText(text)
156 except UnicodeDecodeError:
158 except UnicodeDecodeError:
157 # XXX: Do I really want to skip the exception?
159 # XXX: Do I really want to skip the exception?
158 pass
160 pass
159
161
160 if ansi_tag not in self.ANSI_STYLES:
162 if ansi_tag not in self.ANSI_STYLES:
161 style = 0
163 style = 0
162 else:
164 else:
163 style = self.ANSI_STYLES[ansi_tag][0]
165 style = self.ANSI_STYLES[ansi_tag][0]
164
166
165 self.SetStyling(len(text), style)
167 self.SetStyling(len(text), style)
166
168
167 self.GotoPos(self.GetLength())
169 self.GotoPos(self.GetLength())
168 if refresh:
170 if refresh:
169 wx.Yield()
171 wx.Yield()
170
172
171
173
172 def new_prompt(self, prompt):
174 def new_prompt(self, prompt):
173 """ Prints a prompt at start of line, and move the start of the
175 """ Prints a prompt at start of line, and move the start of the
174 current block there.
176 current block there.
175
177
176 The prompt can be given with ascii escape sequences.
178 The prompt can be given with ascii escape sequences.
177 """
179 """
178 self.write(prompt, refresh=False)
180 self.write(prompt, refresh=False)
179 # now we update our cursor giving end of prompt
181 # now we update our cursor giving end of prompt
180 self.current_prompt_pos = self.GetLength()
182 self.current_prompt_pos = self.GetLength()
181 self.current_prompt_line = self.GetCurrentLine()
183 self.current_prompt_line = self.GetCurrentLine()
182 wx.Yield()
184 wx.Yield()
183 self.EnsureCaretVisible()
185 self.EnsureCaretVisible()
184
186
185
187
186 def scroll_to_bottom(self):
188 def scroll_to_bottom(self):
187 maxrange = self.GetScrollRange(wx.VERTICAL)
189 maxrange = self.GetScrollRange(wx.VERTICAL)
188 self.ScrollLines(maxrange)
190 self.ScrollLines(maxrange)
189
191
190
192
191 def pop_completion(self, possibilities, offset=0):
193 def pop_completion(self, possibilities, offset=0):
192 """ Pops up an autocompletion menu. Offset is the offset
194 """ Pops up an autocompletion menu. Offset is the offset
193 in characters of the position at which the menu should
195 in characters of the position at which the menu should
194 appear, relativ to the cursor.
196 appear, relativ to the cursor.
195 """
197 """
196 self.AutoCompSetIgnoreCase(False)
198 self.AutoCompSetIgnoreCase(False)
197 self.AutoCompSetAutoHide(False)
199 self.AutoCompSetAutoHide(False)
198 self.AutoCompSetMaxHeight(len(possibilities))
200 self.AutoCompSetMaxHeight(len(possibilities))
199 self.AutoCompShow(offset, " ".join(possibilities))
201 self.AutoCompShow(offset, " ".join(possibilities))
200
202
201
203
202 def get_line_width(self):
204 def get_line_width(self):
203 """ Return the width of the line in characters.
205 """ Return the width of the line in characters.
204 """
206 """
205 return self.GetSize()[0]/self.GetCharWidth()
207 return self.GetSize()[0]/self.GetCharWidth()
206
208
207
209
208 #--------------------------------------------------------------------------
210 #--------------------------------------------------------------------------
209 # Private API
211 # Private API
210 #--------------------------------------------------------------------------
212 #--------------------------------------------------------------------------
211
213
212 def _apply_style(self):
214 def _apply_style(self):
213 """ Applies the colors for the different text elements and the
215 """ Applies the colors for the different text elements and the
214 carret.
216 carret.
215 """
217 """
216 self.SetCaretForeground(self.carret_color)
218 self.SetCaretForeground(self.carret_color)
217
219
218 #self.StyleClearAll()
220 #self.StyleClearAll()
219 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT,
221 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT,
220 "fore:#FF0000,back:#0000FF,bold")
222 "fore:#FF0000,back:#0000FF,bold")
221 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD,
223 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD,
222 "fore:#000000,back:#FF0000,bold")
224 "fore:#000000,back:#FF0000,bold")
223
225
224 for style in self.ANSI_STYLES.values():
226 for style in self.ANSI_STYLES.values():
225 self.StyleSetSpec(style[0], "bold,fore:%s" % style[1])
227 self.StyleSetSpec(style[0], "bold,fore:%s" % style[1])
226
228
227
229
228 def _configure_scintilla(self):
230 def _configure_scintilla(self):
229 self.SetEOLMode(stc.STC_EOL_LF)
231 self.SetEOLMode(stc.STC_EOL_LF)
230
232
231 # Ctrl"+" or Ctrl "-" can be used to zoomin/zoomout the text inside
233 # Ctrl"+" or Ctrl "-" can be used to zoomin/zoomout the text inside
232 # the widget
234 # the widget
233 self.CmdKeyAssign(ord('+'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
235 self.CmdKeyAssign(ord('+'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
234 self.CmdKeyAssign(ord('-'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
236 self.CmdKeyAssign(ord('-'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
235 # Also allow Ctrl Shift "=" for poor non US keyboard users.
237 # Also allow Ctrl Shift "=" for poor non US keyboard users.
236 self.CmdKeyAssign(ord('='), stc.STC_SCMOD_CTRL|stc.STC_SCMOD_SHIFT,
238 self.CmdKeyAssign(ord('='), stc.STC_SCMOD_CTRL|stc.STC_SCMOD_SHIFT,
237 stc.STC_CMD_ZOOMIN)
239 stc.STC_CMD_ZOOMIN)
238
240
239 # Keys: we need to clear some of the keys the that don't play
241 # Keys: we need to clear some of the keys the that don't play
240 # well with a console.
242 # well with a console.
241 self.CmdKeyClear(ord('D'), stc.STC_SCMOD_CTRL)
243 self.CmdKeyClear(ord('D'), stc.STC_SCMOD_CTRL)
242 self.CmdKeyClear(ord('L'), stc.STC_SCMOD_CTRL)
244 self.CmdKeyClear(ord('L'), stc.STC_SCMOD_CTRL)
243 self.CmdKeyClear(ord('T'), stc.STC_SCMOD_CTRL)
245 self.CmdKeyClear(ord('T'), stc.STC_SCMOD_CTRL)
244 self.CmdKeyClear(ord('A'), stc.STC_SCMOD_CTRL)
246 self.CmdKeyClear(ord('A'), stc.STC_SCMOD_CTRL)
245
247
246 self.SetEOLMode(stc.STC_EOL_CRLF)
248 self.SetEOLMode(stc.STC_EOL_CRLF)
247 self.SetWrapMode(stc.STC_WRAP_CHAR)
249 self.SetWrapMode(stc.STC_WRAP_CHAR)
248 self.SetWrapMode(stc.STC_WRAP_WORD)
250 self.SetWrapMode(stc.STC_WRAP_WORD)
249 self.SetBufferedDraw(True)
251 self.SetBufferedDraw(True)
250 self.SetUseAntiAliasing(True)
252 self.SetUseAntiAliasing(True)
251 self.SetLayoutCache(stc.STC_CACHE_PAGE)
253 self.SetLayoutCache(stc.STC_CACHE_PAGE)
252 self.SetUndoCollection(False)
254 self.SetUndoCollection(False)
253 self.SetUseTabs(True)
255 self.SetUseTabs(True)
254 self.SetIndent(4)
256 self.SetIndent(4)
255 self.SetTabWidth(4)
257 self.SetTabWidth(4)
256
258
257 # we don't want scintilla's autocompletion to choose
259 # we don't want scintilla's autocompletion to choose
258 # automaticaly out of a single choice list, as we pop it up
260 # automaticaly out of a single choice list, as we pop it up
259 # automaticaly
261 # automaticaly
260 self.AutoCompSetChooseSingle(False)
262 self.AutoCompSetChooseSingle(False)
261 self.AutoCompSetMaxHeight(10)
263 self.AutoCompSetMaxHeight(10)
262 # XXX: this doesn't seem to have an effect.
264 # XXX: this doesn't seem to have an effect.
263 self.AutoCompSetFillUps('\n')
265 self.AutoCompSetFillUps('\n')
264
266
265 self.SetMargins(3, 3) #text is moved away from border with 3px
267 self.SetMargins(3, 3) #text is moved away from border with 3px
266 # Suppressing Scintilla margins
268 # Suppressing Scintilla margins
267 self.SetMarginWidth(0, 0)
269 self.SetMarginWidth(0, 0)
268 self.SetMarginWidth(1, 0)
270 self.SetMarginWidth(1, 0)
269 self.SetMarginWidth(2, 0)
271 self.SetMarginWidth(2, 0)
270
272
271 self._apply_style()
273 self._apply_style()
272
274
273 # Xterm escape sequences
275 # Xterm escape sequences
274 self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?')
276 self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?')
275 self.title_pat = re.compile('\x1b]0;(.*?)\x07')
277 self.title_pat = re.compile('\x1b]0;(.*?)\x07')
276
278
277 #self.SetEdgeMode(stc.STC_EDGE_LINE)
279 #self.SetEdgeMode(stc.STC_EDGE_LINE)
278 #self.SetEdgeColumn(80)
280 #self.SetEdgeColumn(80)
279
281
280 # styles
282 # styles
281 p = self.style
283 p = self.style
282 self.StyleSetSpec(stc.STC_STYLE_DEFAULT, p['default'])
284 self.StyleSetSpec(stc.STC_STYLE_DEFAULT, p['default'])
283 self.StyleClearAll()
285 self.StyleClearAll()
284 self.StyleSetSpec(_STDOUT_STYLE, p['stdout'])
286 self.StyleSetSpec(_STDOUT_STYLE, p['stdout'])
285 self.StyleSetSpec(_STDERR_STYLE, p['stderr'])
287 self.StyleSetSpec(_STDERR_STYLE, p['stderr'])
286 self.StyleSetSpec(_TRACE_STYLE, p['trace'])
288 self.StyleSetSpec(_TRACE_STYLE, p['trace'])
287
289
288 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, p['bracegood'])
290 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, p['bracegood'])
289 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, p['bracebad'])
291 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, p['bracebad'])
290 self.StyleSetSpec(stc.STC_P_COMMENTLINE, p['comment'])
292 self.StyleSetSpec(stc.STC_P_COMMENTLINE, p['comment'])
291 self.StyleSetSpec(stc.STC_P_NUMBER, p['number'])
293 self.StyleSetSpec(stc.STC_P_NUMBER, p['number'])
292 self.StyleSetSpec(stc.STC_P_STRING, p['string'])
294 self.StyleSetSpec(stc.STC_P_STRING, p['string'])
293 self.StyleSetSpec(stc.STC_P_CHARACTER, p['char'])
295 self.StyleSetSpec(stc.STC_P_CHARACTER, p['char'])
294 self.StyleSetSpec(stc.STC_P_WORD, p['keyword'])
296 self.StyleSetSpec(stc.STC_P_WORD, p['keyword'])
295 self.StyleSetSpec(stc.STC_P_WORD2, p['keyword'])
297 self.StyleSetSpec(stc.STC_P_WORD2, p['keyword'])
296 self.StyleSetSpec(stc.STC_P_TRIPLE, p['triple'])
298 self.StyleSetSpec(stc.STC_P_TRIPLE, p['triple'])
297 self.StyleSetSpec(stc.STC_P_TRIPLEDOUBLE, p['tripledouble'])
299 self.StyleSetSpec(stc.STC_P_TRIPLEDOUBLE, p['tripledouble'])
298 self.StyleSetSpec(stc.STC_P_CLASSNAME, p['class'])
300 self.StyleSetSpec(stc.STC_P_CLASSNAME, p['class'])
299 self.StyleSetSpec(stc.STC_P_DEFNAME, p['def'])
301 self.StyleSetSpec(stc.STC_P_DEFNAME, p['def'])
300 self.StyleSetSpec(stc.STC_P_OPERATOR, p['operator'])
302 self.StyleSetSpec(stc.STC_P_OPERATOR, p['operator'])
301 self.StyleSetSpec(stc.STC_P_COMMENTBLOCK, p['comment'])
303 self.StyleSetSpec(stc.STC_P_COMMENTBLOCK, p['comment'])
302
304
303 def _on_key_down(self, event, skip=True):
305 def _on_key_down(self, event, skip=True):
304 """ Key press callback used for correcting behavior for
306 """ Key press callback used for correcting behavior for
305 console-like interfaces: the cursor is constraint to be after
307 console-like interfaces: the cursor is constraint to be after
306 the last prompt.
308 the last prompt.
307
309
308 Return True if event as been catched.
310 Return True if event as been catched.
309 """
311 """
310 catched = True
312 catched = True
311 # Intercept some specific keys.
313 # Intercept some specific keys.
312 if event.KeyCode == ord('L') and event.ControlDown() :
314 if event.KeyCode == ord('L') and event.ControlDown() :
313 self.scroll_to_bottom()
315 self.scroll_to_bottom()
314 elif event.KeyCode == ord('K') and event.ControlDown() :
316 elif event.KeyCode == ord('K') and event.ControlDown() :
315 self.input_buffer = ''
317 self.input_buffer = ''
316 elif event.KeyCode == ord('A') and event.ControlDown() :
318 elif event.KeyCode == ord('A') and event.ControlDown() :
317 self.GotoPos(self.GetLength())
319 self.GotoPos(self.GetLength())
318 self.SetSelectionStart(self.current_prompt_pos)
320 self.SetSelectionStart(self.current_prompt_pos)
319 self.SetSelectionEnd(self.GetCurrentPos())
321 self.SetSelectionEnd(self.GetCurrentPos())
320 catched = True
322 catched = True
321 elif event.KeyCode == ord('E') and event.ControlDown() :
323 elif event.KeyCode == ord('E') and event.ControlDown() :
322 self.GotoPos(self.GetLength())
324 self.GotoPos(self.GetLength())
323 catched = True
325 catched = True
324 elif event.KeyCode == wx.WXK_PAGEUP:
326 elif event.KeyCode == wx.WXK_PAGEUP:
325 self.ScrollPages(-1)
327 self.ScrollPages(-1)
326 elif event.KeyCode == wx.WXK_PAGEDOWN:
328 elif event.KeyCode == wx.WXK_PAGEDOWN:
327 self.ScrollPages(1)
329 self.ScrollPages(1)
328 elif event.KeyCode == wx.WXK_UP and event.ShiftDown():
330 elif event.KeyCode == wx.WXK_UP and event.ShiftDown():
329 self.ScrollLines(-1)
331 self.ScrollLines(-1)
330 elif event.KeyCode == wx.WXK_DOWN and event.ShiftDown():
332 elif event.KeyCode == wx.WXK_DOWN and event.ShiftDown():
331 self.ScrollLines(1)
333 self.ScrollLines(1)
332 else:
334 else:
333 catched = False
335 catched = False
334
336
335 if self.AutoCompActive():
337 if self.AutoCompActive():
336 event.Skip()
338 event.Skip()
337 else:
339 else:
338 if event.KeyCode in (13, wx.WXK_NUMPAD_ENTER) and \
340 if event.KeyCode in (13, wx.WXK_NUMPAD_ENTER) and \
339 event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN):
341 event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN):
340 catched = True
342 catched = True
341 self.CallTipCancel()
343 self.CallTipCancel()
342 self.write('\n', refresh=False)
344 self.write('\n', refresh=False)
343 # Under windows scintilla seems to be doing funny stuff to the
345 # Under windows scintilla seems to be doing funny stuff to the
344 # line returns here, but the getter for input_buffer filters
346 # line returns here, but the getter for input_buffer filters
345 # this out.
347 # this out.
346 if sys.platform == 'win32':
348 if sys.platform == 'win32':
347 self.input_buffer = self.input_buffer
349 self.input_buffer = self.input_buffer
348 self._on_enter()
350 self._on_enter()
349
351
350 elif event.KeyCode == wx.WXK_HOME:
352 elif event.KeyCode == wx.WXK_HOME:
351 if event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN):
353 if event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN):
352 self.GotoPos(self.current_prompt_pos)
354 self.GotoPos(self.current_prompt_pos)
353 catched = True
355 catched = True
354
356
355 elif event.Modifiers == wx.MOD_SHIFT:
357 elif event.Modifiers == wx.MOD_SHIFT:
356 # FIXME: This behavior is not ideal: if the selection
358 # FIXME: This behavior is not ideal: if the selection
357 # is already started, it will jump.
359 # is already started, it will jump.
358 self.SetSelectionStart(self.current_prompt_pos)
360 self.SetSelectionStart(self.current_prompt_pos)
359 self.SetSelectionEnd(self.GetCurrentPos())
361 self.SetSelectionEnd(self.GetCurrentPos())
360 catched = True
362 catched = True
361
363
362 elif event.KeyCode == wx.WXK_UP:
364 elif event.KeyCode == wx.WXK_UP:
363 if self.GetCurrentLine() > self.current_prompt_line:
365 if self.GetCurrentLine() > self.current_prompt_line:
364 if self.GetCurrentLine() == self.current_prompt_line + 1 \
366 if self.GetCurrentLine() == self.current_prompt_line + 1 \
365 and self.GetColumn(self.GetCurrentPos()) < \
367 and self.GetColumn(self.GetCurrentPos()) < \
366 self.GetColumn(self.current_prompt_pos):
368 self.GetColumn(self.current_prompt_pos):
367 self.GotoPos(self.current_prompt_pos)
369 self.GotoPos(self.current_prompt_pos)
368 else:
370 else:
369 event.Skip()
371 event.Skip()
370 catched = True
372 catched = True
371
373
372 elif event.KeyCode in (wx.WXK_LEFT, wx.WXK_BACK):
374 elif event.KeyCode in (wx.WXK_LEFT, wx.WXK_BACK):
373 if self.GetCurrentPos() > self.current_prompt_pos:
375 if self.GetCurrentPos() > self.current_prompt_pos:
374 event.Skip()
376 event.Skip()
375 catched = True
377 catched = True
376
378
377 if skip and not catched:
379 if skip and not catched:
378 # Put the cursor back in the edit region
380 # Put the cursor back in the edit region
379 if self.GetCurrentPos() < self.current_prompt_pos:
381 if self.GetCurrentPos() < self.current_prompt_pos:
380 self.GotoPos(self.current_prompt_pos)
382 self.GotoPos(self.current_prompt_pos)
381 else:
383 else:
382 event.Skip()
384 event.Skip()
383
385
384 return catched
386 return catched
385
387
386
388
387 def _on_key_up(self, event, skip=True):
389 def _on_key_up(self, event, skip=True):
388 """ If cursor is outside the editing region, put it back.
390 """ If cursor is outside the editing region, put it back.
389 """
391 """
390 event.Skip()
392 event.Skip()
391 if self.GetCurrentPos() < self.current_prompt_pos:
393 if self.GetCurrentPos() < self.current_prompt_pos:
392 self.GotoPos(self.current_prompt_pos)
394 self.GotoPos(self.current_prompt_pos)
393
395
394
396
395
397
396 if __name__ == '__main__':
398 if __name__ == '__main__':
397 # Some simple code to test the console widget.
399 # Some simple code to test the console widget.
398 class MainWindow(wx.Frame):
400 class MainWindow(wx.Frame):
399 def __init__(self, parent, id, title):
401 def __init__(self, parent, id, title):
400 wx.Frame.__init__(self, parent, id, title, size=(300,250))
402 wx.Frame.__init__(self, parent, id, title, size=(300,250))
401 self._sizer = wx.BoxSizer(wx.VERTICAL)
403 self._sizer = wx.BoxSizer(wx.VERTICAL)
402 self.console_widget = ConsoleWidget(self)
404 self.console_widget = ConsoleWidget(self)
403 self._sizer.Add(self.console_widget, 1, wx.EXPAND)
405 self._sizer.Add(self.console_widget, 1, wx.EXPAND)
404 self.SetSizer(self._sizer)
406 self.SetSizer(self._sizer)
405 self.SetAutoLayout(1)
407 self.SetAutoLayout(1)
406 self.Show(True)
408 self.Show(True)
407
409
408 app = wx.PySimpleApp()
410 app = wx.PySimpleApp()
409 w = MainWindow(None, wx.ID_ANY, 'ConsoleWidget')
411 w = MainWindow(None, wx.ID_ANY, 'ConsoleWidget')
410 w.SetSize((780, 460))
412 w.SetSize((780, 460))
411 w.Show()
413 w.Show()
412
414
413 app.MainLoop()
415 app.MainLoop()
414
416
415
417
@@ -1,107 +1,110 b''
1 """
1 """
2 Entry point for a simple application giving a graphical frontend to
2 Entry point for a simple application giving a graphical frontend to
3 ipython.
3 ipython.
4 """
4 """
5
5
6 try:
6 try:
7 import wx
7 import wx
8 except ImportError, e:
8 except ImportError, e:
9 e.message = """%s
9 e.message = """%s
10 ________________________________________________________________________________
10 ________________________________________________________________________________
11 You need wxPython to run this application.
11 You need wxPython to run this application.
12 """ % e.message
12 """ % e.message
13 e.args = (e.message, ) + e.args[1:]
13 e.args = (e.message, ) + e.args[1:]
14 raise e
14 raise e
15
15
16 from wx_frontend import WxController
16 from wx_frontend import WxController
17 import __builtin__
17 import __builtin__
18
18
19
19
20 class IPythonXController(WxController):
20 class IPythonXController(WxController):
21 """ Sub class of WxController that adds some application-specific
21 """ Sub class of WxController that adds some application-specific
22 bindings.
22 bindings.
23 """
23 """
24
24
25 debug = False
25 debug = False
26
26
27 def __init__(self, *args, **kwargs):
27 def __init__(self, *args, **kwargs):
28 WxController.__init__(self, *args, **kwargs)
28 WxController.__init__(self, *args, **kwargs)
29 self.ipython0.ask_exit = self.do_exit
29 self.ipython0.ask_exit = self.do_exit
30 # Scroll to top
30 # Scroll to top
31 maxrange = self.GetScrollRange(wx.VERTICAL)
31 maxrange = self.GetScrollRange(wx.VERTICAL)
32 self.ScrollLines(-maxrange)
32 self.ScrollLines(-maxrange)
33
33
34
34
35 def _on_key_down(self, event, skip=True):
35 def _on_key_down(self, event, skip=True):
36 # Intercept Ctrl-D to quit
36 # Intercept Ctrl-D to quit
37 if event.KeyCode == ord('D') and event.ControlDown() and \
37 if event.KeyCode == ord('D') and event.ControlDown() and \
38 self.input_buffer == '' and \
38 self.input_buffer == '' and \
39 self._input_state == 'readline':
39 self._input_state == 'readline':
40 wx.CallAfter(self.ask_exit)
40 wx.CallAfter(self.ask_exit)
41 else:
41 else:
42 WxController._on_key_down(self, event, skip=skip)
42 WxController._on_key_down(self, event, skip=skip)
43
43
44
44
45 def ask_exit(self):
45 def ask_exit(self):
46 """ Ask the user whether to exit.
46 """ Ask the user whether to exit.
47 """
47 """
48 self._input_state = 'subprocess'
48 self._input_state = 'subprocess'
49 self.write('\n', refresh=False)
49 self.write('\n', refresh=False)
50 self.capture_output()
50 self.capture_output()
51 self.ipython0.shell.exit()
51 self.ipython0.shell.exit()
52 self.release_output()
52 self.release_output()
53 if not self.ipython0.exit_now:
53 if not self.ipython0.exit_now:
54 wx.CallAfter(self.new_prompt,
54 wx.CallAfter(self.new_prompt,
55 self.input_prompt_template.substitute(
55 self.input_prompt_template.substitute(
56 number=self.last_result['number'] + 1))
56 number=self.last_result['number'] + 1))
57 else:
58 wx.CallAfter(wx.GetApp().Exit)
59 self.write('Exiting ...', refresh=False)
57
60
58
61
59 def do_exit(self):
62 def do_exit(self):
60 """ Exits the interpreter, kills the windows.
63 """ Exits the interpreter, kills the windows.
61 """
64 """
62 WxController.do_exit(self)
65 WxController.do_exit(self)
63 self.release_output()
66 self.release_output()
64 wx.CallAfter(wx.Exit)
67 wx.CallAfter(wx.Exit)
65
68
66
69
67
70
68 class IPythonX(wx.Frame):
71 class IPythonX(wx.Frame):
69 """ Main frame of the IPythonX app.
72 """ Main frame of the IPythonX app.
70 """
73 """
71
74
72 def __init__(self, parent, id, title, debug=False):
75 def __init__(self, parent, id, title, debug=False):
73 wx.Frame.__init__(self, parent, id, title, size=(300,250))
76 wx.Frame.__init__(self, parent, id, title, size=(300,250))
74 self._sizer = wx.BoxSizer(wx.VERTICAL)
77 self._sizer = wx.BoxSizer(wx.VERTICAL)
75 self.shell = IPythonXController(self, debug=debug)
78 self.shell = IPythonXController(self, debug=debug)
76 self._sizer.Add(self.shell, 1, wx.EXPAND)
79 self._sizer.Add(self.shell, 1, wx.EXPAND)
77 self.SetSizer(self._sizer)
80 self.SetSizer(self._sizer)
78 self.SetAutoLayout(1)
81 self.SetAutoLayout(1)
79 self.Show(True)
82 self.Show(True)
80
83
81
84
82 def main():
85 def main():
83 from optparse import OptionParser
86 from optparse import OptionParser
84 usage = """usage: %prog [options]
87 usage = """usage: %prog [options]
85
88
86 Simple graphical frontend to IPython, using WxWidgets."""
89 Simple graphical frontend to IPython, using WxWidgets."""
87 parser = OptionParser(usage=usage)
90 parser = OptionParser(usage=usage)
88 parser.add_option("-d", "--debug",
91 parser.add_option("-d", "--debug",
89 action="store_true", dest="debug", default=False,
92 action="store_true", dest="debug", default=False,
90 help="Enable debug message for the wx frontend.")
93 help="Enable debug message for the wx frontend.")
91
94
92 options, args = parser.parse_args()
95 options, args = parser.parse_args()
93
96
94 # Clear the options, to avoid having the ipython0 instance complain
97 # Clear the options, to avoid having the ipython0 instance complain
95 import sys
98 import sys
96 sys.argv = sys.argv[:1]
99 sys.argv = sys.argv[:1]
97
100
98 app = wx.PySimpleApp()
101 app = wx.PySimpleApp()
99 frame = IPythonX(None, wx.ID_ANY, 'IPythonX', debug=options.debug)
102 frame = IPythonX(None, wx.ID_ANY, 'IPythonX', debug=options.debug)
100 frame.shell.SetFocus()
103 frame.shell.SetFocus()
101 frame.shell.app = app
104 frame.shell.app = app
102 frame.SetSize((680, 460))
105 frame.SetSize((680, 460))
103
106
104 app.MainLoop()
107 app.MainLoop()
105
108
106 if __name__ == '__main__':
109 if __name__ == '__main__':
107 main()
110 main()
General Comments 0
You need to be logged in to leave comments. Login now