##// END OF EJS Templates
Clean up code, names, and docstrings.
gvaroquaux -
Show More
@@ -0,0 +1,19 b''
1 """
2 Package for dealing for process execution in a callback environment, in a
3 portable way.
4
5 killable_process.py is a wrapper of subprocess.Popen that allows the
6 subprocess and its children to be killed in a reliable way, including
7 under windows.
8
9 winprocess.py is required by killable_process.py to kill processes under
10 windows.
11
12 piped_process.py wraps process execution with callbacks to print output,
13 in a non-blocking way. It can be used to interact with a subprocess in eg
14 a GUI event loop.
15 """
16
17 from pipedprocess import PipedProcess
18
19
@@ -0,0 +1,34 b''
1 # encoding: utf-8
2 # -*- test-case-name: IPython.frontend.tests.test_frontendbase -*-
3 """
4 zope.interface mock. If zope is installed, this module provides a zope
5 interface classes, if not it provides mocks for them.
6
7 Classes provided:
8 Interface, Attribute, implements, classProvides
9 """
10 __docformat__ = "restructuredtext en"
11
12 #-------------------------------------------------------------------------------
13 # Copyright (C) 2008 The IPython Development Team
14 #
15 # Distributed under the terms of the BSD License. The full license is in
16 # the file COPYING, distributed as part of this software.
17 #-------------------------------------------------------------------------------
18
19 #-------------------------------------------------------------------------------
20 # Imports
21 #-------------------------------------------------------------------------------
22 import string
23 import uuid
24 import _ast
25
26 try:
27 from zope.interface import Interface, Attribute, implements, classProvides
28 except ImportError:
29 #zope.interface is not available
30 Interface = object
31 def Attribute(name, doc): pass
32 def implements(interface): pass
33 def classProvides(interface): pass
34
1 NO CONTENT: file renamed from IPython/frontend/killable_process.py to IPython/frontend/_process/killableprocess.py
NO CONTENT: file renamed from IPython/frontend/killable_process.py to IPython/frontend/_process/killableprocess.py
@@ -15,7 +15,7 b' __docformat__ = "restructuredtext en"'
15 #-------------------------------------------------------------------------------
15 #-------------------------------------------------------------------------------
16 # Imports
16 # Imports
17 #-------------------------------------------------------------------------------
17 #-------------------------------------------------------------------------------
18 from killable_process import Popen, PIPE
18 from killableprocess import Popen, PIPE
19 from threading import Thread
19 from threading import Thread
20 from time import sleep
20 from time import sleep
21
21
1 NO CONTENT: file renamed from IPython/frontend/winprocess.py to IPython/frontend/_process/winprocess.py
NO CONTENT: file renamed from IPython/frontend/winprocess.py to IPython/frontend/_process/winprocess.py
@@ -18,14 +18,11 b' import uuid'
18
18
19 try:
19 try:
20 from zope.interface import Interface, Attribute, implements, classProvides
20 from zope.interface import Interface, Attribute, implements, classProvides
21 except ImportError:
21 except ImportError, e:
22 #zope.interface is not available
22 e.message = """%s
23 Interface = object
23 ________________________________________________________________________________
24 def Attribute(name, doc): pass
24 zope.interface is required to run asynchronous frontends.""" % e.message
25 def implements(interface): pass
25 e.args = (e.message, ) + e.args[1:]
26 def classProvides(interface): pass
27
28
29
26
30 from frontendbase import FrontEndBase, IFrontEnd, IFrontEndFactory
27 from frontendbase import FrontEndBase, IFrontEnd, IFrontEndFactory
31
28
@@ -34,9 +31,11 b' from IPython.kernel.core.history import FrontEndHistory'
34
31
35 try:
32 try:
36 from twisted.python.failure import Failure
33 from twisted.python.failure import Failure
37 except ImportError:
34 except ImportError, e:
38 #Twisted not available
35 e.message = """%s
39 Failure = Exception
36 ________________________________________________________________________________
37 twisted is required to run asynchronous frontends.""" % e.message
38 e.args = (e.message, ) + e.args[1:]
40
39
41
40
42
41
@@ -24,14 +24,7 b' import string'
24 import uuid
24 import uuid
25 import _ast
25 import _ast
26
26
27 try:
27 from zopeinterface import Interface, Attribute, implements, classProvides
28 from zope.interface import Interface, Attribute, implements, classProvides
29 except ImportError:
30 #zope.interface is not available
31 Interface = object
32 def Attribute(name, doc): pass
33 def implements(interface): pass
34 def classProvides(interface): pass
35
28
36 from IPython.kernel.core.history import FrontEndHistory
29 from IPython.kernel.core.history import FrontEndHistory
37 from IPython.kernel.core.util import Bunch
30 from IPython.kernel.core.util import Bunch
@@ -46,6 +39,8 b" rc.prompt_in2 = r'...'"
46 rc.prompt_out = r'Out [$number]: '
39 rc.prompt_out = r'Out [$number]: '
47
40
48 ##############################################################################
41 ##############################################################################
42 # Interface definitions
43 ##############################################################################
49
44
50 class IFrontEndFactory(Interface):
45 class IFrontEndFactory(Interface):
51 """Factory interface for frontends."""
46 """Factory interface for frontends."""
@@ -59,7 +54,6 b' class IFrontEndFactory(Interface):'
59 pass
54 pass
60
55
61
56
62
63 class IFrontEnd(Interface):
57 class IFrontEnd(Interface):
64 """Interface for frontends. All methods return t.i.d.Deferred"""
58 """Interface for frontends. All methods return t.i.d.Deferred"""
65
59
@@ -72,9 +66,10 b' class IFrontEnd(Interface):'
72
66
73 def update_cell_prompt(result, blockID=None):
67 def update_cell_prompt(result, blockID=None):
74 """Subclass may override to update the input prompt for a block.
68 """Subclass may override to update the input prompt for a block.
75 Since this method will be called as a
69
76 twisted.internet.defer.Deferred's callback/errback,
70 In asynchronous frontends, this method will be called as a
77 implementations should return result when finished.
71 twisted.internet.defer.Deferred's callback/errback.
72 Implementations should thus return result when finished.
78
73
79 Result is a result dict in case of success, and a
74 Result is a result dict in case of success, and a
80 twisted.python.util.failure.Failure in case of an error
75 twisted.python.util.failure.Failure in case of an error
@@ -82,7 +77,6 b' class IFrontEnd(Interface):'
82
77
83 pass
78 pass
84
79
85
86 def render_result(result):
80 def render_result(result):
87 """Render the result of an execute call. Implementors may choose the
81 """Render the result of an execute call. Implementors may choose the
88 method of rendering.
82 method of rendering.
@@ -100,16 +94,17 b' class IFrontEnd(Interface):'
100 pass
94 pass
101
95
102 def render_error(failure):
96 def render_error(failure):
103 """Subclasses must override to render the failure. Since this method
97 """Subclasses must override to render the failure.
104 will be called as a twisted.internet.defer.Deferred's callback,
98
105 implementations should return result when finished.
99 In asynchronous frontend, since this method will be called as a
100 twisted.internet.defer.Deferred's callback. Implementations
101 should thus return result when finished.
106
102
107 blockID = failure.blockID
103 blockID = failure.blockID
108 """
104 """
109
105
110 pass
106 pass
111
107
112
113 def input_prompt(number=''):
108 def input_prompt(number=''):
114 """Returns the input prompt by subsituting into
109 """Returns the input prompt by subsituting into
115 self.input_prompt_template
110 self.input_prompt_template
@@ -140,7 +135,6 b' class IFrontEnd(Interface):'
140
135
141 pass
136 pass
142
137
143
144 def get_history_previous(current_block):
138 def get_history_previous(current_block):
145 """Returns the block previous in the history. Saves currentBlock if
139 """Returns the block previous in the history. Saves currentBlock if
146 the history_cursor is currently at the end of the input history"""
140 the history_cursor is currently at the end of the input history"""
@@ -151,6 +145,20 b' class IFrontEnd(Interface):'
151
145
152 pass
146 pass
153
147
148 def complete(self, line):
149 """Returns the list of possible completions, and the completed
150 line.
151
152 The input argument is the full line to be completed. This method
153 returns both the line completed as much as possible, and the list
154 of further possible completions (full words).
155 """
156 pass
157
158
159 ##############################################################################
160 # Base class for all the frontends.
161 ##############################################################################
154
162
155 class FrontEndBase(object):
163 class FrontEndBase(object):
156 """
164 """
@@ -321,6 +329,8 b' class FrontEndBase(object):'
321
329
322 def update_cell_prompt(self, result, blockID=None):
330 def update_cell_prompt(self, result, blockID=None):
323 """Subclass may override to update the input prompt for a block.
331 """Subclass may override to update the input prompt for a block.
332
333 This method only really makes sens in asyncrhonous frontend.
324 Since this method will be called as a
334 Since this method will be called as a
325 twisted.internet.defer.Deferred's callback, implementations should
335 twisted.internet.defer.Deferred's callback, implementations should
326 return result when finished.
336 return result when finished.
@@ -330,18 +340,22 b' class FrontEndBase(object):'
330
340
331
341
332 def render_result(self, result):
342 def render_result(self, result):
333 """Subclasses must override to render result. Since this method will
343 """Subclasses must override to render result.
334 be called as a twisted.internet.defer.Deferred's callback,
344
335 implementations should return result when finished.
345 In asynchronous frontends, this method will be called as a
346 twisted.internet.defer.Deferred's callback. Implementations
347 should thus return result when finished.
336 """
348 """
337
349
338 return result
350 return result
339
351
340
352
341 def render_error(self, failure):
353 def render_error(self, failure):
342 """Subclasses must override to render the failure. Since this method
354 """Subclasses must override to render the failure.
343 will be called as a twisted.internet.defer.Deferred's callback,
355
344 implementations should return result when finished.
356 In asynchronous frontends, this method will be called as a
357 twisted.internet.defer.Deferred's callback. Implementations
358 should thus return result when finished.
345 """
359 """
346
360
347 return failure
361 return failure
@@ -1,5 +1,6 b''
1 """
1 """
2 Base front end class for all line-oriented frontends.
2 Base front end class for all line-oriented frontends, rather than
3 block-oriented.
3
4
4 Currently this focuses on synchronous frontends.
5 Currently this focuses on synchronous frontends.
5 """
6 """
@@ -23,6 +24,9 b' from frontendbase import FrontEndBase'
23 from IPython.kernel.core.interpreter import Interpreter
24 from IPython.kernel.core.interpreter import Interpreter
24
25
25 def common_prefix(strings):
26 def common_prefix(strings):
27 """ Given a list of strings, return the common prefix between all
28 these strings.
29 """
26 ref = strings[0]
30 ref = strings[0]
27 prefix = ''
31 prefix = ''
28 for size in range(len(ref)):
32 for size in range(len(ref)):
@@ -38,6 +42,10 b' def common_prefix(strings):'
38 # Base class for the line-oriented front ends
42 # Base class for the line-oriented front ends
39 #-------------------------------------------------------------------------------
43 #-------------------------------------------------------------------------------
40 class LineFrontEndBase(FrontEndBase):
44 class LineFrontEndBase(FrontEndBase):
45 """ Concrete implementation of the FrontEndBase class. This is meant
46 to be the base class behind all the frontend that are line-oriented,
47 rather than block-oriented.
48 """
41
49
42 # We need to keep the prompt number, to be able to increment
50 # We need to keep the prompt number, to be able to increment
43 # it when there is an exception.
51 # it when there is an exception.
@@ -47,7 +55,7 b' class LineFrontEndBase(FrontEndBase):'
47 last_result = dict(number=0)
55 last_result = dict(number=0)
48
56
49 #--------------------------------------------------------------------------
57 #--------------------------------------------------------------------------
50 # Public API
58 # FrontEndBase interface
51 #--------------------------------------------------------------------------
59 #--------------------------------------------------------------------------
52
60
53 def __init__(self, shell=None, history=None):
61 def __init__(self, shell=None, history=None):
@@ -81,6 +89,9 b' class LineFrontEndBase(FrontEndBase):'
81
89
82
90
83 def render_result(self, result):
91 def render_result(self, result):
92 """ Frontend-specific rendering of the result of a calculation
93 that has been sent to an engine.
94 """
84 if 'stdout' in result and result['stdout']:
95 if 'stdout' in result and result['stdout']:
85 self.write('\n' + result['stdout'])
96 self.write('\n' + result['stdout'])
86 if 'display' in result and result['display']:
97 if 'display' in result and result['display']:
@@ -91,20 +102,25 b' class LineFrontEndBase(FrontEndBase):'
91
102
92
103
93 def render_error(self, failure):
104 def render_error(self, failure):
105 """ Frontend-specific rendering of error.
106 """
94 self.insert_text('\n\n'+str(failure)+'\n\n')
107 self.insert_text('\n\n'+str(failure)+'\n\n')
95 return failure
108 return failure
96
109
97
110
98 def prefilter_input(self, string):
99 string = string.replace('\r\n', '\n')
100 string = string.replace('\t', 4*' ')
101 # Clean the trailing whitespace
102 string = '\n'.join(l.rstrip() for l in string.split('\n'))
103 return string
104
105
106 def is_complete(self, string):
111 def is_complete(self, string):
112 """ Check if a string forms a complete, executable set of
113 commands.
114
115 For the line-oriented frontend, multi-line code is not executed
116 as soon as it is complete: the users has to enter two line
117 returns.
118 """
107 if string in ('', '\n'):
119 if string in ('', '\n'):
120 # Prefiltering, eg through ipython0, may return an empty
121 # string although some operations have been accomplished. We
122 # thus want to consider an empty string as a complete
123 # statement.
108 return True
124 return True
109 elif ( len(self.get_current_edit_buffer().split('\n'))>2
125 elif ( len(self.get_current_edit_buffer().split('\n'))>2
110 and not re.findall(r"\n[\t ]*\n[\t ]*$", string)):
126 and not re.findall(r"\n[\t ]*\n[\t ]*$", string)):
@@ -116,8 +132,8 b' class LineFrontEndBase(FrontEndBase):'
116
132
117
133
118 def execute(self, python_string, raw_string=None):
134 def execute(self, python_string, raw_string=None):
119 """ Send the python_string to the interpreter, stores the
135 """ Stores the raw_string in the history, and sends the
120 raw_string in the history and starts a new prompt.
136 python string to the interpreter.
121 """
137 """
122 if raw_string is None:
138 if raw_string is None:
123 raw_string = python_string
139 raw_string = python_string
@@ -133,6 +149,18 b' class LineFrontEndBase(FrontEndBase):'
133 finally:
149 finally:
134 self.after_execute()
150 self.after_execute()
135
151
152 #--------------------------------------------------------------------------
153 # LineFrontEndBase interface
154 #--------------------------------------------------------------------------
155
156 def prefilter_input(self, string):
157 """ Priflter the input to turn it in valid python.
158 """
159 string = string.replace('\r\n', '\n')
160 string = string.replace('\t', 4*' ')
161 # Clean the trailing whitespace
162 string = '\n'.join(l.rstrip() for l in string.split('\n'))
163 return string
136
164
137 def after_execute(self):
165 def after_execute(self):
138 """ All the operations required after an execution to put the
166 """ All the operations required after an execution to put the
@@ -145,6 +173,10 b' class LineFrontEndBase(FrontEndBase):'
145 self.history_cursor = len(self.history.input_cache) - 1
173 self.history_cursor = len(self.history.input_cache) - 1
146
174
147
175
176 #--------------------------------------------------------------------------
177 # Private API
178 #--------------------------------------------------------------------------
179
148 def _on_enter(self):
180 def _on_enter(self):
149 """ Called when the return key is pressed in a line editing
181 """ Called when the return key is pressed in a line editing
150 buffer.
182 buffer.
@@ -160,11 +192,10 b' class LineFrontEndBase(FrontEndBase):'
160 self.write('\t')
192 self.write('\t')
161
193
162
194
163 #--------------------------------------------------------------------------
164 # Private API
165 #--------------------------------------------------------------------------
166
167 def _get_indent_string(self, string):
195 def _get_indent_string(self, string):
196 """ Return the string of whitespace that prefixes a line. Used to
197 add the right amount of indendation when creating a new line.
198 """
168 string = string.replace('\t', ' '*4)
199 string = string.replace('\t', ' '*4)
169 string = string.split('\n')[-1]
200 string = string.split('\n')[-1]
170 indent_chars = len(string) - len(string.lstrip())
201 indent_chars = len(string) - len(string.lstrip())
@@ -2,6 +2,12 b''
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
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
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
10 refactoring.
5 """
11 """
6 __docformat__ = "restructuredtext en"
12 __docformat__ = "restructuredtext en"
7
13
@@ -27,6 +33,8 b' from IPython.kernel.core.sync_traceback_trap import SyncTracebackTrap'
27
33
28 from IPython.genutils import Term
34 from IPython.genutils import Term
29 import pydoc
35 import pydoc
36 import os
37
30
38
31 def mk_system_call(system_call_function, command):
39 def mk_system_call(system_call_function, command):
32 """ given a os.system replacement, and a leading string command,
40 """ given a os.system replacement, and a leading string command,
@@ -41,6 +49,14 b' def mk_system_call(system_call_function, command):'
41 # Frontend class using ipython0 to do the prefiltering.
49 # Frontend class using ipython0 to do the prefiltering.
42 #-------------------------------------------------------------------------------
50 #-------------------------------------------------------------------------------
43 class PrefilterFrontEnd(LineFrontEndBase):
51 class PrefilterFrontEnd(LineFrontEndBase):
52 """ Class that uses ipython0 to do prefilter the input, do the
53 completion and the magics.
54
55 The core trick is to use an ipython0 instance to prefilter the
56 input, and share the namespace between the interpreter instance used
57 to execute the statements and the ipython0 used for code
58 completion...
59 """
44
60
45 def __init__(self, *args, **kwargs):
61 def __init__(self, *args, **kwargs):
46 LineFrontEndBase.__init__(self, *args, **kwargs)
62 LineFrontEndBase.__init__(self, *args, **kwargs)
@@ -67,38 +83,20 b' class PrefilterFrontEnd(LineFrontEndBase):'
67 err_callback=self.write,
83 err_callback=self.write,
68 )
84 )
69 self.shell.traceback_trap = SyncTracebackTrap(
85 self.shell.traceback_trap = SyncTracebackTrap(
70 formatters=self.shell.traceback_trap.formatters
86 formatters=self.shell.traceback_trap.formatters,
71 )
87 )
72 # Capture and release the outputs, to make sure all the
88 # Capture and release the outputs, to make sure all the
73 # shadow variables are set
89 # shadow variables are set
74 self.capture_output()
90 self.capture_output()
75 self.release_output()
91 self.release_output()
76
92
77
93 #--------------------------------------------------------------------------
78 def prefilter_input(self, input_string):
94 # FrontEndBase interface
79 """ Using IPython0 to prefilter the commands.
95 #--------------------------------------------------------------------------
80 """
81 input_string = LineFrontEndBase.prefilter_input(self, input_string)
82 filtered_lines = []
83 # The IPython0 prefilters sometime produce output. We need to
84 # capture it.
85 self.capture_output()
86 self.last_result = dict(number=self.prompt_number)
87 try:
88 for line in input_string.split('\n'):
89 filtered_lines.append(self.ipython0.prefilter(line, False))
90 except:
91 # XXX: probably not the right thing to do.
92 self.ipython0.showsyntaxerror()
93 self.after_execute()
94 finally:
95 self.release_output()
96
97 filtered_string = '\n'.join(filtered_lines)
98 return filtered_string
99
100
96
101 def show_traceback(self):
97 def show_traceback(self):
98 """ Use ipython0 to capture the last traceback and display it.
99 """
102 self.capture_output()
100 self.capture_output()
103 self.ipython0.showtraceback()
101 self.ipython0.showtraceback()
104 self.release_output()
102 self.release_output()
@@ -111,13 +109,6 b' class PrefilterFrontEnd(LineFrontEndBase):'
111 self.release_output()
109 self.release_output()
112
110
113
111
114 def system_call(self, command):
115 """ Allows for frontend to define their own system call, to be
116 able capture output and redirect input.
117 """
118 return os.system(command, args)
119
120
121 def capture_output(self):
112 def capture_output(self):
122 """ Capture all the output mechanisms we can think of.
113 """ Capture all the output mechanisms we can think of.
123 """
114 """
@@ -154,6 +145,45 b' class PrefilterFrontEnd(LineFrontEndBase):'
154 line = line[:-len(word)] + prefix
145 line = line[:-len(word)] + prefix
155 return line, completions
146 return line, completions
156
147
148
149 #--------------------------------------------------------------------------
150 # LineFrontEndBase interface
151 #--------------------------------------------------------------------------
152
153 def prefilter_input(self, input_string):
154 """ Using IPython0 to prefilter the commands to turn them
155 in executable statements that are valid Python strings.
156 """
157 input_string = LineFrontEndBase.prefilter_input(self, input_string)
158 filtered_lines = []
159 # The IPython0 prefilters sometime produce output. We need to
160 # capture it.
161 self.capture_output()
162 self.last_result = dict(number=self.prompt_number)
163 try:
164 for line in input_string.split('\n'):
165 filtered_lines.append(self.ipython0.prefilter(line, False))
166 except:
167 # XXX: probably not the right thing to do.
168 self.ipython0.showsyntaxerror()
169 self.after_execute()
170 finally:
171 self.release_output()
172
173 filtered_string = '\n'.join(filtered_lines)
174 return filtered_string
175
176
177 #--------------------------------------------------------------------------
178 # PrefilterLineFrontEnd interface
179 #--------------------------------------------------------------------------
180
181 def system_call(self, command_string):
182 """ Allows for frontend to define their own system call, to be
183 able capture output and redirect input.
184 """
185 return os.system(command_string)
186
157
187
158 def do_exit(self):
188 def do_exit(self):
159 """ Exit the shell, cleanup and save the history.
189 """ Exit the shell, cleanup and save the history.
@@ -76,6 +76,8 b' class ConsoleWidget(editwindow.EditWindow):'
76 keeping the cursor inside the editing line.
76 keeping the cursor inside the editing line.
77 """
77 """
78
78
79 # This is where the title captured from the ANSI escape sequences are
80 # stored.
79 title = 'Console'
81 title = 'Console'
80
82
81 style = _DEFAULT_STYLE.copy()
83 style = _DEFAULT_STYLE.copy()
@@ -102,7 +104,7 b' class ConsoleWidget(editwindow.EditWindow):'
102 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
104 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
103 size=wx.DefaultSize, style=0, ):
105 size=wx.DefaultSize, style=0, ):
104 editwindow.EditWindow.__init__(self, parent, id, pos, size, style)
106 editwindow.EditWindow.__init__(self, parent, id, pos, size, style)
105 self.configure_scintilla()
107 self._configure_scintilla()
106
108
107 # FIXME: we need to retrieve this from the interpreter.
109 # FIXME: we need to retrieve this from the interpreter.
108 self.prompt = \
110 self.prompt = \
@@ -113,87 +115,6 b' class ConsoleWidget(editwindow.EditWindow):'
113 self.Bind(wx.EVT_KEY_UP, self._on_key_up)
115 self.Bind(wx.EVT_KEY_UP, self._on_key_up)
114
116
115
117
116 def configure_scintilla(self):
117 self.SetEOLMode(stc.STC_EOL_LF)
118
119 # Ctrl"+" or Ctrl "-" can be used to zoomin/zoomout the text inside
120 # the widget
121 self.CmdKeyAssign(ord('+'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
122 self.CmdKeyAssign(ord('-'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
123 # Also allow Ctrl Shift "=" for poor non US keyboard users.
124 self.CmdKeyAssign(ord('='), stc.STC_SCMOD_CTRL|stc.STC_SCMOD_SHIFT,
125 stc.STC_CMD_ZOOMIN)
126
127 #self.CmdKeyAssign(stc.STC_KEY_PRIOR, stc.STC_SCMOD_SHIFT,
128 # stc.STC_CMD_PAGEUP)
129
130 #self.CmdKeyAssign(stc.STC_KEY_NEXT, stc.STC_SCMOD_SHIFT,
131 # stc.STC_CMD_PAGEDOWN)
132
133 # Keys: we need to clear some of the keys the that don't play
134 # well with a console.
135 self.CmdKeyClear(ord('D'), stc.STC_SCMOD_CTRL)
136 self.CmdKeyClear(ord('L'), stc.STC_SCMOD_CTRL)
137 self.CmdKeyClear(ord('T'), stc.STC_SCMOD_CTRL)
138
139
140 self.SetEOLMode(stc.STC_EOL_CRLF)
141 self.SetWrapMode(stc.STC_WRAP_CHAR)
142 self.SetWrapMode(stc.STC_WRAP_WORD)
143 self.SetBufferedDraw(True)
144 self.SetUseAntiAliasing(True)
145 self.SetLayoutCache(stc.STC_CACHE_PAGE)
146 self.SetUndoCollection(False)
147 self.SetUseTabs(True)
148 self.SetIndent(4)
149 self.SetTabWidth(4)
150
151 self.EnsureCaretVisible()
152 # we don't want scintilla's autocompletion to choose
153 # automaticaly out of a single choice list, as we pop it up
154 # automaticaly
155 self.AutoCompSetChooseSingle(False)
156 self.AutoCompSetMaxHeight(10)
157
158 self.SetMargins(3, 3) #text is moved away from border with 3px
159 # Suppressing Scintilla margins
160 self.SetMarginWidth(0, 0)
161 self.SetMarginWidth(1, 0)
162 self.SetMarginWidth(2, 0)
163
164 self._apply_style()
165
166 # Xterm escape sequences
167 self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?')
168 self.title_pat = re.compile('\x1b]0;(.*?)\x07')
169
170 #self.SetEdgeMode(stc.STC_EDGE_LINE)
171 #self.SetEdgeColumn(80)
172
173 # styles
174 p = self.style
175 self.StyleSetSpec(stc.STC_STYLE_DEFAULT, p['default'])
176 self.StyleClearAll()
177 self.StyleSetSpec(_STDOUT_STYLE, p['stdout'])
178 self.StyleSetSpec(_STDERR_STYLE, p['stderr'])
179 self.StyleSetSpec(_TRACE_STYLE, p['trace'])
180
181 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, p['bracegood'])
182 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, p['bracebad'])
183 self.StyleSetSpec(stc.STC_P_COMMENTLINE, p['comment'])
184 self.StyleSetSpec(stc.STC_P_NUMBER, p['number'])
185 self.StyleSetSpec(stc.STC_P_STRING, p['string'])
186 self.StyleSetSpec(stc.STC_P_CHARACTER, p['char'])
187 self.StyleSetSpec(stc.STC_P_WORD, p['keyword'])
188 self.StyleSetSpec(stc.STC_P_WORD2, p['keyword'])
189 self.StyleSetSpec(stc.STC_P_TRIPLE, p['triple'])
190 self.StyleSetSpec(stc.STC_P_TRIPLEDOUBLE, p['tripledouble'])
191 self.StyleSetSpec(stc.STC_P_CLASSNAME, p['class'])
192 self.StyleSetSpec(stc.STC_P_DEFNAME, p['def'])
193 self.StyleSetSpec(stc.STC_P_OPERATOR, p['operator'])
194 self.StyleSetSpec(stc.STC_P_COMMENTBLOCK, p['comment'])
195
196
197 def write(self, text, refresh=True):
118 def write(self, text, refresh=True):
198 """ Write given text to buffer, while translating the ansi escape
119 """ Write given text to buffer, while translating the ansi escape
199 sequences.
120 sequences.
@@ -270,24 +191,20 b' class ConsoleWidget(editwindow.EditWindow):'
270 return current_edit_buffer
191 return current_edit_buffer
271
192
272
193
273 #--------------------------------------------------------------------------
194 def scroll_to_bottom(self):
274 # Private API
195 maxrange = self.GetScrollRange(wx.VERTICAL)
275 #--------------------------------------------------------------------------
196 self.ScrollLines(maxrange)
276
277 def _apply_style(self):
278 """ Applies the colors for the different text elements and the
279 carret.
280 """
281 self.SetCaretForeground(self.carret_color)
282
197
283 #self.StyleClearAll()
284 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT,
285 "fore:#FF0000,back:#0000FF,bold")
286 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD,
287 "fore:#000000,back:#FF0000,bold")
288
198
289 for style in self.ANSI_STYLES.values():
199 def pop_completion(self, possibilities, offset=0):
290 self.StyleSetSpec(style[0], "bold,fore:%s" % style[1])
200 """ Pops up an autocompletion menu. Offset is the offset
201 in characters of the position at which the menu should
202 appear, relativ to the cursor.
203 """
204 self.AutoCompSetIgnoreCase(False)
205 self.AutoCompSetAutoHide(False)
206 self.AutoCompSetMaxHeight(len(possibilities))
207 self.AutoCompShow(offset, " ".join(possibilities))
291
208
292
209
293 def write_completion(self, possibilities):
210 def write_completion(self, possibilities):
@@ -315,21 +232,105 b' class ConsoleWidget(editwindow.EditWindow):'
315 self.new_prompt(self.prompt % (self.last_result['number'] + 1))
232 self.new_prompt(self.prompt % (self.last_result['number'] + 1))
316 self.replace_current_edit_buffer(current_buffer)
233 self.replace_current_edit_buffer(current_buffer)
317
234
318
235 #--------------------------------------------------------------------------
319 def pop_completion(self, possibilities, offset=0):
236 # Private API
320 """ Pops up an autocompletion menu. Offset is the offset
237 #--------------------------------------------------------------------------
321 in characters of the position at which the menu should
238
322 appear, relativ to the cursor.
239 def _apply_style(self):
240 """ Applies the colors for the different text elements and the
241 carret.
323 """
242 """
324 self.AutoCompSetIgnoreCase(False)
243 self.SetCaretForeground(self.carret_color)
325 self.AutoCompSetAutoHide(False)
326 self.AutoCompSetMaxHeight(len(possibilities))
327 self.AutoCompShow(offset, " ".join(possibilities))
328
244
329
245 #self.StyleClearAll()
330 def scroll_to_bottom(self):
246 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT,
331 maxrange = self.GetScrollRange(wx.VERTICAL)
247 "fore:#FF0000,back:#0000FF,bold")
332 self.ScrollLines(maxrange)
248 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD,
249 "fore:#000000,back:#FF0000,bold")
250
251 for style in self.ANSI_STYLES.values():
252 self.StyleSetSpec(style[0], "bold,fore:%s" % style[1])
253
254
255 def _configure_scintilla(self):
256 self.SetEOLMode(stc.STC_EOL_LF)
257
258 # Ctrl"+" or Ctrl "-" can be used to zoomin/zoomout the text inside
259 # the widget
260 self.CmdKeyAssign(ord('+'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
261 self.CmdKeyAssign(ord('-'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
262 # Also allow Ctrl Shift "=" for poor non US keyboard users.
263 self.CmdKeyAssign(ord('='), stc.STC_SCMOD_CTRL|stc.STC_SCMOD_SHIFT,
264 stc.STC_CMD_ZOOMIN)
265
266 #self.CmdKeyAssign(stc.STC_KEY_PRIOR, stc.STC_SCMOD_SHIFT,
267 # stc.STC_CMD_PAGEUP)
268
269 #self.CmdKeyAssign(stc.STC_KEY_NEXT, stc.STC_SCMOD_SHIFT,
270 # stc.STC_CMD_PAGEDOWN)
271
272 # Keys: we need to clear some of the keys the that don't play
273 # well with a console.
274 self.CmdKeyClear(ord('D'), stc.STC_SCMOD_CTRL)
275 self.CmdKeyClear(ord('L'), stc.STC_SCMOD_CTRL)
276 self.CmdKeyClear(ord('T'), stc.STC_SCMOD_CTRL)
277
278
279 self.SetEOLMode(stc.STC_EOL_CRLF)
280 self.SetWrapMode(stc.STC_WRAP_CHAR)
281 self.SetWrapMode(stc.STC_WRAP_WORD)
282 self.SetBufferedDraw(True)
283 self.SetUseAntiAliasing(True)
284 self.SetLayoutCache(stc.STC_CACHE_PAGE)
285 self.SetUndoCollection(False)
286 self.SetUseTabs(True)
287 self.SetIndent(4)
288 self.SetTabWidth(4)
289
290 self.EnsureCaretVisible()
291 # we don't want scintilla's autocompletion to choose
292 # automaticaly out of a single choice list, as we pop it up
293 # automaticaly
294 self.AutoCompSetChooseSingle(False)
295 self.AutoCompSetMaxHeight(10)
296
297 self.SetMargins(3, 3) #text is moved away from border with 3px
298 # Suppressing Scintilla margins
299 self.SetMarginWidth(0, 0)
300 self.SetMarginWidth(1, 0)
301 self.SetMarginWidth(2, 0)
302
303 self._apply_style()
304
305 # Xterm escape sequences
306 self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?')
307 self.title_pat = re.compile('\x1b]0;(.*?)\x07')
308
309 #self.SetEdgeMode(stc.STC_EDGE_LINE)
310 #self.SetEdgeColumn(80)
311
312 # styles
313 p = self.style
314 self.StyleSetSpec(stc.STC_STYLE_DEFAULT, p['default'])
315 self.StyleClearAll()
316 self.StyleSetSpec(_STDOUT_STYLE, p['stdout'])
317 self.StyleSetSpec(_STDERR_STYLE, p['stderr'])
318 self.StyleSetSpec(_TRACE_STYLE, p['trace'])
319
320 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, p['bracegood'])
321 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, p['bracebad'])
322 self.StyleSetSpec(stc.STC_P_COMMENTLINE, p['comment'])
323 self.StyleSetSpec(stc.STC_P_NUMBER, p['number'])
324 self.StyleSetSpec(stc.STC_P_STRING, p['string'])
325 self.StyleSetSpec(stc.STC_P_CHARACTER, p['char'])
326 self.StyleSetSpec(stc.STC_P_WORD, p['keyword'])
327 self.StyleSetSpec(stc.STC_P_WORD2, p['keyword'])
328 self.StyleSetSpec(stc.STC_P_TRIPLE, p['triple'])
329 self.StyleSetSpec(stc.STC_P_TRIPLEDOUBLE, p['tripledouble'])
330 self.StyleSetSpec(stc.STC_P_CLASSNAME, p['class'])
331 self.StyleSetSpec(stc.STC_P_DEFNAME, p['def'])
332 self.StyleSetSpec(stc.STC_P_OPERATOR, p['operator'])
333 self.StyleSetSpec(stc.STC_P_COMMENTBLOCK, p['comment'])
333
334
334
335
335 def _on_key_down(self, event, skip=True):
336 def _on_key_down(self, event, skip=True):
@@ -418,7 +419,6 b' class ConsoleWidget(editwindow.EditWindow):'
418
419
419
420
420
421
421
422 if __name__ == '__main__':
422 if __name__ == '__main__':
423 # Some simple code to test the console widget.
423 # Some simple code to test the console widget.
424 class MainWindow(wx.Frame):
424 class MainWindow(wx.Frame):
@@ -5,6 +5,8 b''
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 This class inherits from ConsoleWidget, that provides a console-like
9 widget to provide a text-rendering widget suitable for a terminal.
8 """
10 """
9
11
10 __docformat__ = "restructuredtext en"
12 __docformat__ = "restructuredtext en"
@@ -20,21 +22,25 b' __docformat__ = "restructuredtext en"'
20 # Imports
22 # Imports
21 #-------------------------------------------------------------------------------
23 #-------------------------------------------------------------------------------
22
24
23
25 # Major library imports
24 import wx
25 import re
26 import re
26 from wx import stc
27 from console_widget import ConsoleWidget
28 import __builtin__
27 import __builtin__
29 from time import sleep
28 from time import sleep
30 import sys
29 import sys
31 import signal
32
33 from threading import Lock
30 from threading import Lock
34
31
35 from IPython.frontend.piped_process import PipedProcess
32 import wx
33 from wx import stc
34
35 # Ipython-specific imports.
36 from IPython.frontend._process import PipedProcess
37 from console_widget import ConsoleWidget
36 from IPython.frontend.prefilterfrontend import PrefilterFrontEnd
38 from IPython.frontend.prefilterfrontend import PrefilterFrontEnd
37
39
40 #-------------------------------------------------------------------------------
41 # Constants
42 #-------------------------------------------------------------------------------
43
38 #_COMMAND_BG = '#FAFAF1' # Nice green
44 #_COMMAND_BG = '#FAFAF1' # Nice green
39 _RUNNING_BUFFER_BG = '#FDFFD3' # Nice yellow
45 _RUNNING_BUFFER_BG = '#FDFFD3' # Nice yellow
40 _ERROR_BG = '#FFF1F1' # Nice red
46 _ERROR_BG = '#FFF1F1' # Nice red
@@ -46,7 +52,14 b' _ERROR_MARKER = 30'
46 # Classes to implement the Wx frontend
52 # Classes to implement the Wx frontend
47 #-------------------------------------------------------------------------------
53 #-------------------------------------------------------------------------------
48 class WxController(PrefilterFrontEnd, ConsoleWidget):
54 class WxController(PrefilterFrontEnd, ConsoleWidget):
55 """Classes to provide a Wx frontend to the
56 IPython.kernel.core.interpreter.
57
58 This class inherits from ConsoleWidget, that provides a console-like
59 widget to provide a text-rendering widget suitable for a terminal.
60 """
49
61
62 # FIXME: this shouldn't be there.
50 output_prompt = \
63 output_prompt = \
51 '\x01\x1b[0;31m\x02Out[\x01\x1b[1;31m\x02%i\x01\x1b[0;31m\x02]: \x01\x1b[0m\x02'
64 '\x01\x1b[0;31m\x02Out[\x01\x1b[1;31m\x02%i\x01\x1b[0;31m\x02]: \x01\x1b[0m\x02'
52
65
@@ -55,7 +68,6 b' class WxController(PrefilterFrontEnd, ConsoleWidget):'
55
68
56 # The title of the terminal, as captured through the ANSI escape
69 # The title of the terminal, as captured through the ANSI escape
57 # sequences.
70 # sequences.
58
59 def _set_title(self, title):
71 def _set_title(self, title):
60 return self.Parent.SetTitle(title)
72 return self.Parent.SetTitle(title)
61
73
@@ -114,8 +126,43 b' class WxController(PrefilterFrontEnd, ConsoleWidget):'
114 self._buffer_flush_timer = wx.Timer(self, BUFFER_FLUSH_TIMER_ID)
126 self._buffer_flush_timer = wx.Timer(self, BUFFER_FLUSH_TIMER_ID)
115 wx.EVT_TIMER(self, BUFFER_FLUSH_TIMER_ID, self._buffer_flush)
127 wx.EVT_TIMER(self, BUFFER_FLUSH_TIMER_ID, self._buffer_flush)
116
128
129
130 def raw_input(self, prompt):
131 """ A replacement from python's raw_input.
132 """
133 self.new_prompt(prompt)
134 self.waiting = True
135 self.__old_on_enter = self._on_enter
136 def my_on_enter():
137 self.waiting = False
138 self._on_enter = my_on_enter
139 # XXX: Busy waiting, ugly.
140 while self.waiting:
141 wx.Yield()
142 sleep(0.1)
143 self._on_enter = self.__old_on_enter
144 self._input_state = 'buffering'
145 return self.get_current_edit_buffer().rstrip('\n')
146
147
148 def system_call(self, command_string):
149 self._input_state = 'subprocess'
150 self._running_process = PipedProcess(command_string,
151 out_callback=self.buffered_write,
152 end_callback = self._end_system_call)
153 self._running_process.start()
154 # XXX: another one of these polling loops to have a blocking
155 # call
156 wx.Yield()
157 while self._running_process:
158 wx.Yield()
159 sleep(0.1)
160 # Be sure to flush the buffer.
161 self._buffer_flush(event=None)
162
163
117 def do_completion(self):
164 def do_completion(self):
118 """ Do code completion.
165 """ Do code completion on current line.
119 """
166 """
120 if self.debug:
167 if self.debug:
121 print >>sys.__stdout__, "do_completion",
168 print >>sys.__stdout__, "do_completion",
@@ -129,6 +176,8 b' class WxController(PrefilterFrontEnd, ConsoleWidget):'
129
176
130
177
131 def do_calltip(self):
178 def do_calltip(self):
179 """ Analyse current and displays useful calltip for it.
180 """
132 if self.debug:
181 if self.debug:
133 print >>sys.__stdout__, "do_calltip"
182 print >>sys.__stdout__, "do_calltip"
134 separators = re.compile('[\s\{\}\[\]\(\)\= ,:]')
183 separators = re.compile('[\s\{\}\[\]\(\)\= ,:]')
@@ -154,12 +203,12 b' class WxController(PrefilterFrontEnd, ConsoleWidget):'
154 pass
203 pass
155
204
156
205
157 def popup_completion(self, create=False):
206 def _popup_completion(self, create=False):
158 """ Updates the popup completion menu if it exists. If create is
207 """ Updates the popup completion menu if it exists. If create is
159 true, open the menu.
208 true, open the menu.
160 """
209 """
161 if self.debug:
210 if self.debug:
162 print >>sys.__stdout__, "popup_completion",
211 print >>sys.__stdout__, "_popup_completion",
163 line = self.get_current_edit_buffer()
212 line = self.get_current_edit_buffer()
164 if (self.AutoCompActive() and not line[-1] == '.') \
213 if (self.AutoCompActive() and not line[-1] == '.') \
165 or create==True:
214 or create==True:
@@ -174,28 +223,23 b' class WxController(PrefilterFrontEnd, ConsoleWidget):'
174 print >>sys.__stdout__, completions
223 print >>sys.__stdout__, completions
175
224
176
225
177 def new_prompt(self, prompt):
226 def buffered_write(self, text):
178 self._input_state = 'readline'
227 """ A write method for streams, that caches the stream in order
179 ConsoleWidget.new_prompt(self, prompt)
228 to avoid flooding the event loop.
180
181
229
182 def raw_input(self, prompt):
230 This can be called outside of the main loop, in separate
183 """ A replacement from python's raw_input.
231 threads.
184 """
232 """
185 self.new_prompt(prompt)
233 self._out_buffer_lock.acquire()
186 self.waiting = True
234 self._out_buffer.append(text)
187 self.__old_on_enter = self._on_enter
235 self._out_buffer_lock.release()
188 def my_on_enter():
236 if not self._buffer_flush_timer.IsRunning():
189 self.waiting = False
237 wx.CallAfter(self._buffer_flush_timer.Start, 100) # milliseconds
190 self._on_enter = my_on_enter
238
191 # XXX: Busy waiting, ugly.
239
192 while self.waiting:
240 #--------------------------------------------------------------------------
193 wx.Yield()
241 # LineFrontEnd interface
194 sleep(0.1)
242 #--------------------------------------------------------------------------
195 self._on_enter = self.__old_on_enter
196 self._input_state = 'buffering'
197 return self.get_current_edit_buffer().rstrip('\n')
198
199
243
200 def execute(self, python_string, raw_string=None):
244 def execute(self, python_string, raw_string=None):
201 self._input_state = 'buffering'
245 self._input_state = 'buffering'
@@ -226,39 +270,10 b' class WxController(PrefilterFrontEnd, ConsoleWidget):'
226
270
227 def after_execute(self):
271 def after_execute(self):
228 PrefilterFrontEnd.after_execute(self)
272 PrefilterFrontEnd.after_execute(self)
273 # Clear the wait cursor
229 if hasattr(self, '_cursor'):
274 if hasattr(self, '_cursor'):
230 del self._cursor
275 del self._cursor
231
276
232
233 def system_call(self, command_string):
234 self._input_state = 'subprocess'
235 self._running_process = PipedProcess(command_string,
236 out_callback=self.buffered_write,
237 end_callback = self._end_system_call)
238 self._running_process.start()
239 # XXX: another one of these polling loops to have a blocking
240 # call
241 wx.Yield()
242 while self._running_process:
243 wx.Yield()
244 sleep(0.1)
245 # Be sure to flush the buffer.
246 self._buffer_flush(event=None)
247
248
249 def buffered_write(self, text):
250 """ A write method for streams, that caches the stream in order
251 to avoid flooding the event loop.
252
253 This can be called outside of the main loop, in separate
254 threads.
255 """
256 self._out_buffer_lock.acquire()
257 self._out_buffer.append(text)
258 self._out_buffer_lock.release()
259 if not self._buffer_flush_timer.IsRunning():
260 wx.CallAfter(self._buffer_flush_timer.Start, 100) # milliseconds
261
262
277
263 def show_traceback(self):
278 def show_traceback(self):
264 start_line = self.GetCurrentLine()
279 start_line = self.GetCurrentLine()
@@ -266,12 +281,19 b' class WxController(PrefilterFrontEnd, ConsoleWidget):'
266 wx.Yield()
281 wx.Yield()
267 for i in range(start_line, self.GetCurrentLine()):
282 for i in range(start_line, self.GetCurrentLine()):
268 self.MarkerAdd(i, _ERROR_MARKER)
283 self.MarkerAdd(i, _ERROR_MARKER)
269
270
284
285
271 #--------------------------------------------------------------------------
286 #--------------------------------------------------------------------------
272 # Private API
287 # ConsoleWidget interface
273 #--------------------------------------------------------------------------
288 #--------------------------------------------------------------------------
274
289
290 def new_prompt(self, prompt):
291 """ Display a new prompt, and start a new input buffer.
292 """
293 self._input_state = 'readline'
294 ConsoleWidget.new_prompt(self, prompt)
295
296
275 def _on_key_down(self, event, skip=True):
297 def _on_key_down(self, event, skip=True):
276 """ Capture the character events, let the parent
298 """ Capture the character events, let the parent
277 widget handle them, and put our logic afterward.
299 widget handle them, and put our logic afterward.
@@ -286,8 +308,8 b' class WxController(PrefilterFrontEnd, ConsoleWidget):'
286 self._running_process.process.kill()
308 self._running_process.process.kill()
287 elif self._input_state == 'buffering':
309 elif self._input_state == 'buffering':
288 if self.debug:
310 if self.debug:
289 print >>sys.__stderr__, 'Raising KeyboardException'
311 print >>sys.__stderr__, 'Raising KeyboardInterrupt'
290 raise KeyboardException
312 raise KeyboardInterrupt
291 # XXX: We need to make really sure we
313 # XXX: We need to make really sure we
292 # get back to a prompt.
314 # get back to a prompt.
293 elif self._input_state == 'subprocess' and (
315 elif self._input_state == 'subprocess' and (
@@ -315,10 +337,10 b' class WxController(PrefilterFrontEnd, ConsoleWidget):'
315 elif self.AutoCompActive():
337 elif self.AutoCompActive():
316 event.Skip()
338 event.Skip()
317 if event.KeyCode in (wx.WXK_BACK, wx.WXK_DELETE):
339 if event.KeyCode in (wx.WXK_BACK, wx.WXK_DELETE):
318 wx.CallAfter(self.popup_completion, create=True)
340 wx.CallAfter(self._popup_completion, create=True)
319 elif not event.KeyCode in (wx.WXK_UP, wx.WXK_DOWN, wx.WXK_LEFT,
341 elif not event.KeyCode in (wx.WXK_UP, wx.WXK_DOWN, wx.WXK_LEFT,
320 wx.WXK_RIGHT):
342 wx.WXK_RIGHT):
321 wx.CallAfter(self.popup_completion)
343 wx.CallAfter(self._popup_completion)
322 else:
344 else:
323 # Up history
345 # Up history
324 if event.KeyCode == wx.WXK_UP and (
346 if event.KeyCode == wx.WXK_UP and (
@@ -352,20 +374,28 b' class WxController(PrefilterFrontEnd, ConsoleWidget):'
352
374
353
375
354 def _on_key_up(self, event, skip=True):
376 def _on_key_up(self, event, skip=True):
377 """ Called when any key is released.
378 """
355 if event.KeyCode in (59, ord('.')):
379 if event.KeyCode in (59, ord('.')):
356 # Intercepting '.'
380 # Intercepting '.'
357 event.Skip()
381 event.Skip()
358 self.popup_completion(create=True)
382 self._popup_completion(create=True)
359 else:
383 else:
360 ConsoleWidget._on_key_up(self, event, skip=skip)
384 ConsoleWidget._on_key_up(self, event, skip=skip)
361
385
362
386
363 def _on_enter(self):
387 def _on_enter(self):
388 """ Called on return key down, in readline input_state.
389 """
364 if self.debug:
390 if self.debug:
365 print >>sys.__stdout__, repr(self.get_current_edit_buffer())
391 print >>sys.__stdout__, repr(self.get_current_edit_buffer())
366 PrefilterFrontEnd._on_enter(self)
392 PrefilterFrontEnd._on_enter(self)
367
393
368
394
395 #--------------------------------------------------------------------------
396 # Private API
397 #--------------------------------------------------------------------------
398
369 def _end_system_call(self):
399 def _end_system_call(self):
370 """ Called at the end of a system call.
400 """ Called at the end of a system call.
371 """
401 """
@@ -22,19 +22,23 b' from IPython.ultraTB import ColorTB'
22
22
23 class SyncTracebackTrap(TracebackTrap):
23 class SyncTracebackTrap(TracebackTrap):
24
24
25 def __init__(self, sync_formatter=None, formatters=None):
25 def __init__(self, sync_formatter=None, formatters=None,
26 raiseException=True):
26 TracebackTrap.__init__(self, formatters=formatters)
27 TracebackTrap.__init__(self, formatters=formatters)
27 if sync_formatter is None:
28 if sync_formatter is None:
28 sync_formatter = ColorTB(color_scheme='LightBG')
29 sync_formatter = ColorTB(color_scheme='LightBG')
29 self.sync_formatter = sync_formatter
30 self.sync_formatter = sync_formatter
31 self.raiseException = raiseException
30
32
31
33
32 def hook(self, *args):
34 def hook(self, *args):
33 """ This method actually implements the hook.
35 """ This method actually implements the hook.
34 """
36 """
35 self.args = args
37 self.args = args
36
38 if not self.raiseException:
37 print self.sync_formatter(*self.args)
39 print self.sync_formatter(*self.args)
40 else:
41 raise
38
42
39
43
40
44
General Comments 0
You need to be logged in to leave comments. Login now