##// 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
@@ -15,7 +15,7 b' __docformat__ = "restructuredtext en"'
15 15 #-------------------------------------------------------------------------------
16 16 # Imports
17 17 #-------------------------------------------------------------------------------
18 from killable_process import Popen, PIPE
18 from killableprocess import Popen, PIPE
19 19 from threading import Thread
20 20 from time import sleep
21 21
1 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 19 try:
20 20 from zope.interface import Interface, Attribute, implements, classProvides
21 except ImportError:
22 #zope.interface is not available
23 Interface = object
24 def Attribute(name, doc): pass
25 def implements(interface): pass
26 def classProvides(interface): pass
27
28
21 except ImportError, e:
22 e.message = """%s
23 ________________________________________________________________________________
24 zope.interface is required to run asynchronous frontends.""" % e.message
25 e.args = (e.message, ) + e.args[1:]
29 26
30 27 from frontendbase import FrontEndBase, IFrontEnd, IFrontEndFactory
31 28
@@ -34,9 +31,11 b' from IPython.kernel.core.history import FrontEndHistory'
34 31
35 32 try:
36 33 from twisted.python.failure import Failure
37 except ImportError:
38 #Twisted not available
39 Failure = Exception
34 except ImportError, e:
35 e.message = """%s
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 24 import uuid
25 25 import _ast
26 26
27 try:
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
27 from zopeinterface import Interface, Attribute, implements, classProvides
35 28
36 29 from IPython.kernel.core.history import FrontEndHistory
37 30 from IPython.kernel.core.util import Bunch
@@ -46,6 +39,8 b" rc.prompt_in2 = r'...'"
46 39 rc.prompt_out = r'Out [$number]: '
47 40
48 41 ##############################################################################
42 # Interface definitions
43 ##############################################################################
49 44
50 45 class IFrontEndFactory(Interface):
51 46 """Factory interface for frontends."""
@@ -59,7 +54,6 b' class IFrontEndFactory(Interface):'
59 54 pass
60 55
61 56
62
63 57 class IFrontEnd(Interface):
64 58 """Interface for frontends. All methods return t.i.d.Deferred"""
65 59
@@ -72,9 +66,10 b' class IFrontEnd(Interface):'
72 66
73 67 def update_cell_prompt(result, blockID=None):
74 68 """Subclass may override to update the input prompt for a block.
75 Since this method will be called as a
76 twisted.internet.defer.Deferred's callback/errback,
77 implementations should return result when finished.
69
70 In asynchronous frontends, this method will be called as a
71 twisted.internet.defer.Deferred's callback/errback.
72 Implementations should thus return result when finished.
78 73
79 74 Result is a result dict in case of success, and a
80 75 twisted.python.util.failure.Failure in case of an error
@@ -82,7 +77,6 b' class IFrontEnd(Interface):'
82 77
83 78 pass
84 79
85
86 80 def render_result(result):
87 81 """Render the result of an execute call. Implementors may choose the
88 82 method of rendering.
@@ -100,16 +94,17 b' class IFrontEnd(Interface):'
100 94 pass
101 95
102 96 def render_error(failure):
103 """Subclasses must override to render the failure. Since this method
104 will be called as a twisted.internet.defer.Deferred's callback,
105 implementations should return result when finished.
97 """Subclasses must override to render the failure.
98
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 103 blockID = failure.blockID
108 104 """
109 105
110 106 pass
111 107
112
113 108 def input_prompt(number=''):
114 109 """Returns the input prompt by subsituting into
115 110 self.input_prompt_template
@@ -140,7 +135,6 b' class IFrontEnd(Interface):'
140 135
141 136 pass
142 137
143
144 138 def get_history_previous(current_block):
145 139 """Returns the block previous in the history. Saves currentBlock if
146 140 the history_cursor is currently at the end of the input history"""
@@ -151,6 +145,20 b' class IFrontEnd(Interface):'
151 145
152 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 163 class FrontEndBase(object):
156 164 """
@@ -321,6 +329,8 b' class FrontEndBase(object):'
321 329
322 330 def update_cell_prompt(self, result, blockID=None):
323 331 """Subclass may override to update the input prompt for a block.
332
333 This method only really makes sens in asyncrhonous frontend.
324 334 Since this method will be called as a
325 335 twisted.internet.defer.Deferred's callback, implementations should
326 336 return result when finished.
@@ -330,18 +340,22 b' class FrontEndBase(object):'
330 340
331 341
332 342 def render_result(self, result):
333 """Subclasses must override to render result. Since this method will
334 be called as a twisted.internet.defer.Deferred's callback,
335 implementations should return result when finished.
343 """Subclasses must override to render result.
344
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 350 return result
339 351
340 352
341 353 def render_error(self, failure):
342 """Subclasses must override to render the failure. Since this method
343 will be called as a twisted.internet.defer.Deferred's callback,
344 implementations should return result when finished.
354 """Subclasses must override to render the failure.
355
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 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 5 Currently this focuses on synchronous frontends.
5 6 """
@@ -23,6 +24,9 b' from frontendbase import FrontEndBase'
23 24 from IPython.kernel.core.interpreter import Interpreter
24 25
25 26 def common_prefix(strings):
27 """ Given a list of strings, return the common prefix between all
28 these strings.
29 """
26 30 ref = strings[0]
27 31 prefix = ''
28 32 for size in range(len(ref)):
@@ -38,6 +42,10 b' def common_prefix(strings):'
38 42 # Base class for the line-oriented front ends
39 43 #-------------------------------------------------------------------------------
40 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 50 # We need to keep the prompt number, to be able to increment
43 51 # it when there is an exception.
@@ -47,7 +55,7 b' class LineFrontEndBase(FrontEndBase):'
47 55 last_result = dict(number=0)
48 56
49 57 #--------------------------------------------------------------------------
50 # Public API
58 # FrontEndBase interface
51 59 #--------------------------------------------------------------------------
52 60
53 61 def __init__(self, shell=None, history=None):
@@ -81,6 +89,9 b' class LineFrontEndBase(FrontEndBase):'
81 89
82 90
83 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 95 if 'stdout' in result and result['stdout']:
85 96 self.write('\n' + result['stdout'])
86 97 if 'display' in result and result['display']:
@@ -91,20 +102,25 b' class LineFrontEndBase(FrontEndBase):'
91 102
92 103
93 104 def render_error(self, failure):
105 """ Frontend-specific rendering of error.
106 """
94 107 self.insert_text('\n\n'+str(failure)+'\n\n')
95 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 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 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 124 return True
109 125 elif ( len(self.get_current_edit_buffer().split('\n'))>2
110 126 and not re.findall(r"\n[\t ]*\n[\t ]*$", string)):
@@ -116,8 +132,8 b' class LineFrontEndBase(FrontEndBase):'
116 132
117 133
118 134 def execute(self, python_string, raw_string=None):
119 """ Send the python_string to the interpreter, stores the
120 raw_string in the history and starts a new prompt.
135 """ Stores the raw_string in the history, and sends the
136 python string to the interpreter.
121 137 """
122 138 if raw_string is None:
123 139 raw_string = python_string
@@ -133,6 +149,18 b' class LineFrontEndBase(FrontEndBase):'
133 149 finally:
134 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 165 def after_execute(self):
138 166 """ All the operations required after an execution to put the
@@ -145,6 +173,10 b' class LineFrontEndBase(FrontEndBase):'
145 173 self.history_cursor = len(self.history.input_cache) - 1
146 174
147 175
176 #--------------------------------------------------------------------------
177 # Private API
178 #--------------------------------------------------------------------------
179
148 180 def _on_enter(self):
149 181 """ Called when the return key is pressed in a line editing
150 182 buffer.
@@ -160,11 +192,10 b' class LineFrontEndBase(FrontEndBase):'
160 192 self.write('\t')
161 193
162 194
163 #--------------------------------------------------------------------------
164 # Private API
165 #--------------------------------------------------------------------------
166
167 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 199 string = string.replace('\t', ' '*4)
169 200 string = string.split('\n')[-1]
170 201 indent_chars = len(string) - len(string.lstrip())
@@ -2,6 +2,12 b''
2 2 Frontend class that uses IPython0 to prefilter the inputs.
3 3
4 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 12 __docformat__ = "restructuredtext en"
7 13
@@ -27,6 +33,8 b' from IPython.kernel.core.sync_traceback_trap import SyncTracebackTrap'
27 33
28 34 from IPython.genutils import Term
29 35 import pydoc
36 import os
37
30 38
31 39 def mk_system_call(system_call_function, command):
32 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 49 # Frontend class using ipython0 to do the prefiltering.
42 50 #-------------------------------------------------------------------------------
43 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 61 def __init__(self, *args, **kwargs):
46 62 LineFrontEndBase.__init__(self, *args, **kwargs)
@@ -67,38 +83,20 b' class PrefilterFrontEnd(LineFrontEndBase):'
67 83 err_callback=self.write,
68 84 )
69 85 self.shell.traceback_trap = SyncTracebackTrap(
70 formatters=self.shell.traceback_trap.formatters
86 formatters=self.shell.traceback_trap.formatters,
71 87 )
72 88 # Capture and release the outputs, to make sure all the
73 89 # shadow variables are set
74 90 self.capture_output()
75 91 self.release_output()
76 92
77
78 def prefilter_input(self, input_string):
79 """ Using IPython0 to prefilter the commands.
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
93 #--------------------------------------------------------------------------
94 # FrontEndBase interface
95 #--------------------------------------------------------------------------
100 96
101 97 def show_traceback(self):
98 """ Use ipython0 to capture the last traceback and display it.
99 """
102 100 self.capture_output()
103 101 self.ipython0.showtraceback()
104 102 self.release_output()
@@ -111,13 +109,6 b' class PrefilterFrontEnd(LineFrontEndBase):'
111 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 112 def capture_output(self):
122 113 """ Capture all the output mechanisms we can think of.
123 114 """
@@ -154,6 +145,45 b' class PrefilterFrontEnd(LineFrontEndBase):'
154 145 line = line[:-len(word)] + prefix
155 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 188 def do_exit(self):
159 189 """ Exit the shell, cleanup and save the history.
@@ -76,6 +76,8 b' class ConsoleWidget(editwindow.EditWindow):'
76 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 81 title = 'Console'
80 82
81 83 style = _DEFAULT_STYLE.copy()
@@ -102,7 +104,7 b' class ConsoleWidget(editwindow.EditWindow):'
102 104 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
103 105 size=wx.DefaultSize, style=0, ):
104 106 editwindow.EditWindow.__init__(self, parent, id, pos, size, style)
105 self.configure_scintilla()
107 self._configure_scintilla()
106 108
107 109 # FIXME: we need to retrieve this from the interpreter.
108 110 self.prompt = \
@@ -113,87 +115,6 b' class ConsoleWidget(editwindow.EditWindow):'
113 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 118 def write(self, text, refresh=True):
198 119 """ Write given text to buffer, while translating the ansi escape
199 120 sequences.
@@ -270,24 +191,20 b' class ConsoleWidget(editwindow.EditWindow):'
270 191 return current_edit_buffer
271 192
272 193
273 #--------------------------------------------------------------------------
274 # Private API
275 #--------------------------------------------------------------------------
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)
194 def scroll_to_bottom(self):
195 maxrange = self.GetScrollRange(wx.VERTICAL)
196 self.ScrollLines(maxrange)
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():
290 self.StyleSetSpec(style[0], "bold,fore:%s" % style[1])
199 def pop_completion(self, possibilities, offset=0):
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 210 def write_completion(self, possibilities):
@@ -315,21 +232,105 b' class ConsoleWidget(editwindow.EditWindow):'
315 232 self.new_prompt(self.prompt % (self.last_result['number'] + 1))
316 233 self.replace_current_edit_buffer(current_buffer)
317 234
318
319 def pop_completion(self, possibilities, offset=0):
320 """ Pops up an autocompletion menu. Offset is the offset
321 in characters of the position at which the menu should
322 appear, relativ to the cursor.
235 #--------------------------------------------------------------------------
236 # Private API
237 #--------------------------------------------------------------------------
238
239 def _apply_style(self):
240 """ Applies the colors for the different text elements and the
241 carret.
323 242 """
324 self.AutoCompSetIgnoreCase(False)
325 self.AutoCompSetAutoHide(False)
326 self.AutoCompSetMaxHeight(len(possibilities))
327 self.AutoCompShow(offset, " ".join(possibilities))
243 self.SetCaretForeground(self.carret_color)
328 244
329
330 def scroll_to_bottom(self):
331 maxrange = self.GetScrollRange(wx.VERTICAL)
332 self.ScrollLines(maxrange)
245 #self.StyleClearAll()
246 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT,
247 "fore:#FF0000,back:#0000FF,bold")
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 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 422 if __name__ == '__main__':
423 423 # Some simple code to test the console widget.
424 424 class MainWindow(wx.Frame):
@@ -5,6 +5,8 b''
5 5 """Classes to provide a Wx frontend to the
6 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 12 __docformat__ = "restructuredtext en"
@@ -20,21 +22,25 b' __docformat__ = "restructuredtext en"'
20 22 # Imports
21 23 #-------------------------------------------------------------------------------
22 24
23
24 import wx
25 # Major library imports
25 26 import re
26 from wx import stc
27 from console_widget import ConsoleWidget
28 27 import __builtin__
29 28 from time import sleep
30 29 import sys
31 import signal
32
33 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 38 from IPython.frontend.prefilterfrontend import PrefilterFrontEnd
37 39
40 #-------------------------------------------------------------------------------
41 # Constants
42 #-------------------------------------------------------------------------------
43
38 44 #_COMMAND_BG = '#FAFAF1' # Nice green
39 45 _RUNNING_BUFFER_BG = '#FDFFD3' # Nice yellow
40 46 _ERROR_BG = '#FFF1F1' # Nice red
@@ -46,7 +52,14 b' _ERROR_MARKER = 30'
46 52 # Classes to implement the Wx frontend
47 53 #-------------------------------------------------------------------------------
48 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 63 output_prompt = \
51 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 69 # The title of the terminal, as captured through the ANSI escape
57 70 # sequences.
58
59 71 def _set_title(self, title):
60 72 return self.Parent.SetTitle(title)
61 73
@@ -114,8 +126,43 b' class WxController(PrefilterFrontEnd, ConsoleWidget):'
114 126 self._buffer_flush_timer = wx.Timer(self, BUFFER_FLUSH_TIMER_ID)
115 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 164 def do_completion(self):
118 """ Do code completion.
165 """ Do code completion on current line.
119 166 """
120 167 if self.debug:
121 168 print >>sys.__stdout__, "do_completion",
@@ -129,6 +176,8 b' class WxController(PrefilterFrontEnd, ConsoleWidget):'
129 176
130 177
131 178 def do_calltip(self):
179 """ Analyse current and displays useful calltip for it.
180 """
132 181 if self.debug:
133 182 print >>sys.__stdout__, "do_calltip"
134 183 separators = re.compile('[\s\{\}\[\]\(\)\= ,:]')
@@ -154,12 +203,12 b' class WxController(PrefilterFrontEnd, ConsoleWidget):'
154 203 pass
155 204
156 205
157 def popup_completion(self, create=False):
206 def _popup_completion(self, create=False):
158 207 """ Updates the popup completion menu if it exists. If create is
159 208 true, open the menu.
160 209 """
161 210 if self.debug:
162 print >>sys.__stdout__, "popup_completion",
211 print >>sys.__stdout__, "_popup_completion",
163 212 line = self.get_current_edit_buffer()
164 213 if (self.AutoCompActive() and not line[-1] == '.') \
165 214 or create==True:
@@ -174,28 +223,23 b' class WxController(PrefilterFrontEnd, ConsoleWidget):'
174 223 print >>sys.__stdout__, completions
175 224
176 225
177 def new_prompt(self, prompt):
178 self._input_state = 'readline'
179 ConsoleWidget.new_prompt(self, prompt)
180
226 def buffered_write(self, text):
227 """ A write method for streams, that caches the stream in order
228 to avoid flooding the event loop.
181 229
182 def raw_input(self, prompt):
183 """ A replacement from python's raw_input.
230 This can be called outside of the main loop, in separate
231 threads.
184 232 """
185 self.new_prompt(prompt)
186 self.waiting = True
187 self.__old_on_enter = self._on_enter
188 def my_on_enter():
189 self.waiting = False
190 self._on_enter = my_on_enter
191 # XXX: Busy waiting, ugly.
192 while self.waiting:
193 wx.Yield()
194 sleep(0.1)
195 self._on_enter = self.__old_on_enter
196 self._input_state = 'buffering'
197 return self.get_current_edit_buffer().rstrip('\n')
198
233 self._out_buffer_lock.acquire()
234 self._out_buffer.append(text)
235 self._out_buffer_lock.release()
236 if not self._buffer_flush_timer.IsRunning():
237 wx.CallAfter(self._buffer_flush_timer.Start, 100) # milliseconds
238
239
240 #--------------------------------------------------------------------------
241 # LineFrontEnd interface
242 #--------------------------------------------------------------------------
199 243
200 244 def execute(self, python_string, raw_string=None):
201 245 self._input_state = 'buffering'
@@ -226,39 +270,10 b' class WxController(PrefilterFrontEnd, ConsoleWidget):'
226 270
227 271 def after_execute(self):
228 272 PrefilterFrontEnd.after_execute(self)
273 # Clear the wait cursor
229 274 if hasattr(self, '_cursor'):
230 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 278 def show_traceback(self):
264 279 start_line = self.GetCurrentLine()
@@ -266,12 +281,19 b' class WxController(PrefilterFrontEnd, ConsoleWidget):'
266 281 wx.Yield()
267 282 for i in range(start_line, self.GetCurrentLine()):
268 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 297 def _on_key_down(self, event, skip=True):
276 298 """ Capture the character events, let the parent
277 299 widget handle them, and put our logic afterward.
@@ -286,8 +308,8 b' class WxController(PrefilterFrontEnd, ConsoleWidget):'
286 308 self._running_process.process.kill()
287 309 elif self._input_state == 'buffering':
288 310 if self.debug:
289 print >>sys.__stderr__, 'Raising KeyboardException'
290 raise KeyboardException
311 print >>sys.__stderr__, 'Raising KeyboardInterrupt'
312 raise KeyboardInterrupt
291 313 # XXX: We need to make really sure we
292 314 # get back to a prompt.
293 315 elif self._input_state == 'subprocess' and (
@@ -315,10 +337,10 b' class WxController(PrefilterFrontEnd, ConsoleWidget):'
315 337 elif self.AutoCompActive():
316 338 event.Skip()
317 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 341 elif not event.KeyCode in (wx.WXK_UP, wx.WXK_DOWN, wx.WXK_LEFT,
320 342 wx.WXK_RIGHT):
321 wx.CallAfter(self.popup_completion)
343 wx.CallAfter(self._popup_completion)
322 344 else:
323 345 # Up history
324 346 if event.KeyCode == wx.WXK_UP and (
@@ -352,20 +374,28 b' class WxController(PrefilterFrontEnd, ConsoleWidget):'
352 374
353 375
354 376 def _on_key_up(self, event, skip=True):
377 """ Called when any key is released.
378 """
355 379 if event.KeyCode in (59, ord('.')):
356 380 # Intercepting '.'
357 381 event.Skip()
358 self.popup_completion(create=True)
382 self._popup_completion(create=True)
359 383 else:
360 384 ConsoleWidget._on_key_up(self, event, skip=skip)
361 385
362 386
363 387 def _on_enter(self):
388 """ Called on return key down, in readline input_state.
389 """
364 390 if self.debug:
365 391 print >>sys.__stdout__, repr(self.get_current_edit_buffer())
366 392 PrefilterFrontEnd._on_enter(self)
367 393
368 394
395 #--------------------------------------------------------------------------
396 # Private API
397 #--------------------------------------------------------------------------
398
369 399 def _end_system_call(self):
370 400 """ Called at the end of a system call.
371 401 """
@@ -22,19 +22,23 b' from IPython.ultraTB import ColorTB'
22 22
23 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 27 TracebackTrap.__init__(self, formatters=formatters)
27 28 if sync_formatter is None:
28 29 sync_formatter = ColorTB(color_scheme='LightBG')
29 30 self.sync_formatter = sync_formatter
31 self.raiseException = raiseException
30 32
31 33
32 34 def hook(self, *args):
33 35 """ This method actually implements the hook.
34 36 """
35 37 self.args = args
36
37 print self.sync_formatter(*self.args)
38 if not self.raiseException:
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