##// END OF EJS Templates
Correct styling of ANSI patterns.
Gael Varoquaux -
Show More
@@ -1,143 +1,139 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 __docformat__ = "restructuredtext en"
6 __docformat__ = "restructuredtext en"
7
7
8 #-------------------------------------------------------------------------------
8 #-------------------------------------------------------------------------------
9 # Copyright (C) 2008 The IPython Development Team
9 # Copyright (C) 2008 The IPython Development Team
10 #
10 #
11 # Distributed under the terms of the BSD License. The full license is in
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
12 # the file COPYING, distributed as part of this software.
13 #-------------------------------------------------------------------------------
13 #-------------------------------------------------------------------------------
14
14
15 #-------------------------------------------------------------------------------
15 #-------------------------------------------------------------------------------
16 # Imports
16 # Imports
17 #-------------------------------------------------------------------------------
17 #-------------------------------------------------------------------------------
18 import sys
18 import sys
19
19
20 from linefrontendbase import LineFrontEndBase, common_prefix
20 from linefrontendbase import LineFrontEndBase, common_prefix
21
21
22 from IPython.ipmaker import make_IPython
22 from IPython.ipmaker import make_IPython
23 from IPython.ipapi import IPApi
23 from IPython.ipapi import IPApi
24 from IPython.kernel.core.sync_output_trap import SyncOutputTrap
24 from IPython.kernel.core.sync_output_trap import SyncOutputTrap
25
25
26 from IPython.genutils import Term
26 from IPython.genutils import Term
27
27
28 #-------------------------------------------------------------------------------
28 #-------------------------------------------------------------------------------
29 # Utility functions (temporary, should be moved out of here)
29 # Utility functions (temporary, should be moved out of here)
30 #-------------------------------------------------------------------------------
30 #-------------------------------------------------------------------------------
31 import os
31 import os
32 def xterm_system(command):
32 def xterm_system(command):
33 """ Run a command in a separate console window.
33 """ Run a command in a separate console window.
34 """
34 """
35 os.system("""
35 os.system("""
36 xterm -title "%s" -e \'/bin/sh -c "%s ;
36 xterm -title "%s" -e \'/bin/sh -c "%s ;
37 printf \\"\\\\n\\";
37 printf \\"\\\\n\\";
38 printf \\"press a key to close\\" ;
38 printf \\"press a key to close\\" ;
39 printf \\"\x1b]0;%s (finished -- press a key to close)\x07\\" ;
39 printf \\"\x1b]0;%s (finished -- press a key to close)\x07\\" ;
40 read foo;"\'
40 read foo;"\'
41 """ % (command, command, command) )
41 """ % (command, command, command) )
42
42
43 #-------------------------------------------------------------------------------
43 #-------------------------------------------------------------------------------
44 # Frontend class using ipython0 to do the prefiltering.
44 # Frontend class using ipython0 to do the prefiltering.
45 #-------------------------------------------------------------------------------
45 #-------------------------------------------------------------------------------
46 class PrefilterFrontEnd(LineFrontEndBase):
46 class PrefilterFrontEnd(LineFrontEndBase):
47
47
48 def __init__(self, *args, **kwargs):
48 def __init__(self, *args, **kwargs):
49 LineFrontEndBase.__init__(self, *args, **kwargs)
49 LineFrontEndBase.__init__(self, *args, **kwargs)
50 # Instanciate an IPython0 interpreter to be able to use the
50 # Instanciate an IPython0 interpreter to be able to use the
51 # prefiltering.
51 # prefiltering.
52 self.ipython0 = make_IPython()
52 self.ipython0 = make_IPython()
53 # Set the pager:
53 # Set the pager:
54 self.ipython0.set_hook('show_in_pager',
54 self.ipython0.set_hook('show_in_pager',
55 lambda s, string: self.write("\n"+string))
55 lambda s, string: self.write("\n"+string))
56 self.ipython0.write = self.write
56 self.ipython0.write = self.write
57 self._ip = _ip = IPApi(self.ipython0)
57 self._ip = _ip = IPApi(self.ipython0)
58 # XXX: Hack: mix the two namespaces
58 # XXX: Hack: mix the two namespaces
59 self.shell.user_ns = self.ipython0.user_ns
59 self.shell.user_ns = self.ipython0.user_ns
60 self.shell.user_global_ns = self.ipython0.user_global_ns
60 self.shell.user_global_ns = self.ipython0.user_global_ns
61 # Make sure the raw system call doesn't get called, as we don't
61 # Make sure the raw system call doesn't get called, as we don't
62 # have a stdin accessible.
62 # have a stdin accessible.
63 self._ip.system = xterm_system
63 self._ip.system = xterm_system
64 # Redefine a serie of magics to avoid os.system:
64 # Redefine a serie of magics to avoid os.system:
65 # FIXME: I am redefining way too much magics.
65 # FIXME: I am redefining way too much magics.
66 for alias_name, (_, alias_value) in \
66 for alias_name, (_, alias_value) in \
67 _ip.IP.shell.alias_table.iteritems():
67 _ip.IP.shell.alias_table.iteritems():
68 magic = lambda s : _ip.magic('sx %s %s' % (alias_value, s))
68 magic = lambda s : _ip.magic('sx %s %s' % (alias_value, s))
69 setattr(_ip.IP, 'magic_%s' % alias_name, magic)
69 setattr(_ip.IP, 'magic_%s' % alias_name, magic)
70 # FIXME: I should create a real file-like object dedicated to this
70 # FIXME: I should create a real file-like object dedicated to this
71 # terminal
71 # terminal
72 Term.cout.flush = lambda : None
73 Term.cout.getvalue = lambda : ''
74 Term.cerr.flush = lambda : None
75 Term.cerr.getvalue = lambda : ''
76 self.shell.output_trap = SyncOutputTrap(write_out=self.write,
72 self.shell.output_trap = SyncOutputTrap(write_out=self.write,
77 write_err=self.write)
73 write_err=self.write)
78
74
79
75
80
76
81 def prefilter_input(self, input_string):
77 def prefilter_input(self, input_string):
82 """ Using IPython0 to prefilter the commands.
78 """ Using IPython0 to prefilter the commands.
83 """
79 """
84 input_string = LineFrontEndBase.prefilter_input(self, input_string)
80 input_string = LineFrontEndBase.prefilter_input(self, input_string)
85 filtered_lines = []
81 filtered_lines = []
86 # The IPython0 prefilters sometime produce output. We need to
82 # The IPython0 prefilters sometime produce output. We need to
87 # capture it.
83 # capture it.
88 self.capture_output()
84 self.capture_output()
89 self.last_result = dict(number=self.prompt_number)
85 self.last_result = dict(number=self.prompt_number)
90 try:
86 try:
91 for line in input_string.split('\n'):
87 for line in input_string.split('\n'):
92 filtered_lines.append(self.ipython0.prefilter(line, False))
88 filtered_lines.append(self.ipython0.prefilter(line, False))
93 except:
89 except:
94 # XXX: probably not the right thing to do.
90 # XXX: probably not the right thing to do.
95 self.ipython0.showsyntaxerror()
91 self.ipython0.showsyntaxerror()
96 self.after_execute()
92 self.after_execute()
97 finally:
93 finally:
98 self.release_output()
94 self.release_output()
99
95
100 filtered_string = '\n'.join(filtered_lines)
96 filtered_string = '\n'.join(filtered_lines)
101 return filtered_string
97 return filtered_string
102
98
103
99
104 def show_traceback(self):
100 def show_traceback(self):
105 self.capture_output()
101 self.capture_output()
106 self.ipython0.showtraceback()
102 self.ipython0.showtraceback()
107 self.release_output()
103 self.release_output()
108
104
109
105
110 def capture_output(self):
106 def capture_output(self):
111 """ Capture all the output mechanism we can think of.
107 """ Capture all the output mechanism we can think of.
112 """
108 """
113 self.__old_cout_write = Term.cout.write
109 self.__old_cout_write = Term.cout.write
114 self.__old_err_write = Term.cerr.write
110 self.__old_err_write = Term.cerr.write
115 Term.cout.write = self.write
111 Term.cout.write = self.write
116 Term.cerr.write = self.write
112 Term.cerr.write = self.write
117 self.__old_stdout = sys.stdout
113 self.__old_stdout = sys.stdout
118 self.__old_stderr= sys.stderr
114 self.__old_stderr= sys.stderr
119 sys.stdout = Term.cout
115 sys.stdout = Term.cout
120 sys.stderr = Term.cerr
116 sys.stderr = Term.cerr
121 # FIXME: I still need to provide the writelines method
117 # FIXME: I still need to provide the writelines method
122
118
123 def release_output(self):
119 def release_output(self):
124 """ Release all the different captures we have made,
120 """ Release all the different captures we have made,
125 and flush the buffers.
121 and flush the buffers.
126 """
122 """
127 Term.cout.write = self.__old_cout_write
123 Term.cout.write = self.__old_cout_write
128 Term.cerr.write = self.__old_err_write
124 Term.cerr.write = self.__old_err_write
129 sys.stdout = self.__old_stdout
125 sys.stdout = self.__old_stdout
130 sys.stderr = self.__old_stderr
126 sys.stderr = self.__old_stderr
131
127
132
128
133 def complete(self, line):
129 def complete(self, line):
134 word = line.split('\n')[-1].split(' ')[-1]
130 word = line.split('\n')[-1].split(' ')[-1]
135 completions = self.ipython0.complete(word)
131 completions = self.ipython0.complete(word)
136 key = lambda x: x.replace('_', '')
132 key = lambda x: x.replace('_', '')
137 completions.sort(key=key)
133 completions.sort(key=key)
138 if completions:
134 if completions:
139 prefix = common_prefix(completions)
135 prefix = common_prefix(completions)
140 line = line[:-len(word)] + prefix
136 line = line[:-len(word)] + prefix
141 return line, completions
137 return line, completions
142
138
143
139
@@ -1,420 +1,418 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 A Wx widget to act as a console and input commands.
3 A Wx widget to act as a console and input commands.
4
4
5 This widget deals with prompts and provides an edit buffer
5 This widget deals with prompts and provides an edit buffer
6 restricted to after the last prompt.
6 restricted to after the last prompt.
7 """
7 """
8
8
9 __docformat__ = "restructuredtext en"
9 __docformat__ = "restructuredtext en"
10
10
11 #-------------------------------------------------------------------------------
11 #-------------------------------------------------------------------------------
12 # Copyright (C) 2008 The IPython Development Team
12 # Copyright (C) 2008 The IPython Development Team
13 #
13 #
14 # Distributed under the terms of the BSD License. The full license is
14 # Distributed under the terms of the BSD License. The full license is
15 # in the file COPYING, distributed as part of this software.
15 # in the file COPYING, distributed as part of this software.
16 #-------------------------------------------------------------------------------
16 #-------------------------------------------------------------------------------
17
17
18 #-------------------------------------------------------------------------------
18 #-------------------------------------------------------------------------------
19 # Imports
19 # Imports
20 #-------------------------------------------------------------------------------
20 #-------------------------------------------------------------------------------
21
21
22 import wx
22 import wx
23 import wx.stc as stc
23 import wx.stc as stc
24
24
25 from wx.py import editwindow
25 from wx.py import editwindow
26
26
27 import re
27 import re
28
28
29 # FIXME: Need to provide an API for non user-generated display on the
29 # FIXME: Need to provide an API for non user-generated display on the
30 # screen: this should not be editable by the user.
30 # screen: this should not be editable by the user.
31
31
32 if wx.Platform == '__WXMSW__':
32 if wx.Platform == '__WXMSW__':
33 _DEFAULT_SIZE = 80
33 _DEFAULT_SIZE = 80
34 else:
34 else:
35 _DEFAULT_SIZE = 10
35 _DEFAULT_SIZE = 10
36
36
37 _DEFAULT_STYLE = {
37 _DEFAULT_STYLE = {
38 'stdout' : 'fore:#0000FF',
38 'stdout' : 'fore:#0000FF',
39 'stderr' : 'fore:#007f00',
39 'stderr' : 'fore:#007f00',
40 'trace' : 'fore:#FF0000',
40 'trace' : 'fore:#FF0000',
41
41
42 'default' : 'size:%d' % _DEFAULT_SIZE,
42 'default' : 'size:%d' % _DEFAULT_SIZE,
43 'bracegood' : 'fore:#FFFFFF,back:#0000FF,bold',
43 'bracegood' : 'fore:#FFFFFF,back:#0000FF,bold',
44 'bracebad' : 'fore:#000000,back:#FF0000,bold',
44 'bracebad' : 'fore:#000000,back:#FF0000,bold',
45
45
46 # properties for the various Python lexer styles
46 # properties for the various Python lexer styles
47 'comment' : 'fore:#007F00',
47 'comment' : 'fore:#007F00',
48 'number' : 'fore:#007F7F',
48 'number' : 'fore:#007F7F',
49 'string' : 'fore:#7F007F,italic',
49 'string' : 'fore:#7F007F,italic',
50 'char' : 'fore:#7F007F,italic',
50 'char' : 'fore:#7F007F,italic',
51 'keyword' : 'fore:#00007F,bold',
51 'keyword' : 'fore:#00007F,bold',
52 'triple' : 'fore:#7F0000',
52 'triple' : 'fore:#7F0000',
53 'tripledouble' : 'fore:#7F0000',
53 'tripledouble' : 'fore:#7F0000',
54 'class' : 'fore:#0000FF,bold,underline',
54 'class' : 'fore:#0000FF,bold,underline',
55 'def' : 'fore:#007F7F,bold',
55 'def' : 'fore:#007F7F,bold',
56 'operator' : 'bold'
56 'operator' : 'bold'
57 }
57 }
58
58
59 # new style numbers
59 # new style numbers
60 _STDOUT_STYLE = 15
60 _STDOUT_STYLE = 15
61 _STDERR_STYLE = 16
61 _STDERR_STYLE = 16
62 _TRACE_STYLE = 17
62 _TRACE_STYLE = 17
63
63
64
64
65 # system colors
65 # system colors
66 #SYS_COLOUR_BACKGROUND = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BACKGROUND)
66 #SYS_COLOUR_BACKGROUND = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BACKGROUND)
67
67
68 #-------------------------------------------------------------------------------
68 #-------------------------------------------------------------------------------
69 # The console widget class
69 # The console widget class
70 #-------------------------------------------------------------------------------
70 #-------------------------------------------------------------------------------
71 class ConsoleWidget(editwindow.EditWindow):
71 class ConsoleWidget(editwindow.EditWindow):
72 """ Specialized styled text control view for console-like workflow.
72 """ Specialized styled text control view for console-like workflow.
73
73
74 This widget is mainly interested in dealing with the prompt and
74 This widget is mainly interested in dealing with the prompt and
75 keeping the cursor inside the editing line.
75 keeping the cursor inside the editing line.
76 """
76 """
77
77
78 title = 'Console'
78 title = 'Console'
79
79
80 style = _DEFAULT_STYLE.copy()
80 style = _DEFAULT_STYLE.copy()
81
81
82 # Translation table from ANSI escape sequences to color. Override
82 # Translation table from ANSI escape sequences to color. Override
83 # this to specify your colors.
83 # this to specify your colors.
84 ANSI_STYLES = {'0;30': [0, 'BLACK'], '0;31': [1, 'RED'],
84 ANSI_STYLES = {'0;30': [0, 'BLACK'], '0;31': [1, 'RED'],
85 '0;32': [2, 'GREEN'], '0;33': [3, 'BROWN'],
85 '0;32': [2, 'GREEN'], '0;33': [3, 'BROWN'],
86 '0;34': [4, 'BLUE'], '0;35': [5, 'PURPLE'],
86 '0;34': [4, 'BLUE'], '0;35': [5, 'PURPLE'],
87 '0;36': [6, 'CYAN'], '0;37': [7, 'LIGHT GREY'],
87 '0;36': [6, 'CYAN'], '0;37': [7, 'LIGHT GREY'],
88 '1;30': [8, 'DARK GREY'], '1;31': [9, 'RED'],
88 '1;30': [8, 'DARK GREY'], '1;31': [9, 'RED'],
89 '1;32': [10, 'SEA GREEN'], '1;33': [11, 'YELLOW'],
89 '1;32': [10, 'SEA GREEN'], '1;33': [11, 'YELLOW'],
90 '1;34': [12, 'LIGHT BLUE'], '1;35':
90 '1;34': [12, 'LIGHT BLUE'], '1;35':
91 [13, 'MEDIUM VIOLET RED'],
91 [13, 'MEDIUM VIOLET RED'],
92 '1;36': [14, 'LIGHT STEEL BLUE'], '1;37': [15, 'YELLOW']}
92 '1;36': [14, 'LIGHT STEEL BLUE'], '1;37': [15, 'YELLOW']}
93
93
94 # The color of the carret (call _apply_style() after setting)
94 # The color of the carret (call _apply_style() after setting)
95 carret_color = 'BLACK'
95 carret_color = 'BLACK'
96
96
97
97
98 #--------------------------------------------------------------------------
98 #--------------------------------------------------------------------------
99 # Public API
99 # Public API
100 #--------------------------------------------------------------------------
100 #--------------------------------------------------------------------------
101
101
102 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
102 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
103 size=wx.DefaultSize, style=0, ):
103 size=wx.DefaultSize, style=0, ):
104 editwindow.EditWindow.__init__(self, parent, id, pos, size, style)
104 editwindow.EditWindow.__init__(self, parent, id, pos, size, style)
105 self.configure_scintilla()
105 self.configure_scintilla()
106
106
107 # FIXME: we need to retrieve this from the interpreter.
107 # FIXME: we need to retrieve this from the interpreter.
108 self.prompt = \
108 self.prompt = \
109 '\n\x01\x1b[0;34m\x02In [\x01\x1b[1;34m\x02%i\x01\x1b[0;34m\x02]: \x01\x1b[0m\x02'
109 '\n\x01\x1b[0;34m\x02In [\x01\x1b[1;34m\x02%i\x01\x1b[0;34m\x02]: \x01\x1b[0m\x02'
110 self.new_prompt(self.prompt % 1)
110 self.new_prompt(self.prompt % 1)
111
111
112 self.Bind(wx.EVT_KEY_DOWN, self._on_key_down)
112 self.Bind(wx.EVT_KEY_DOWN, self._on_key_down)
113 self.Bind(wx.EVT_KEY_UP, self._on_key_up)
113 self.Bind(wx.EVT_KEY_UP, self._on_key_up)
114
114
115
115
116 def configure_scintilla(self):
116 def configure_scintilla(self):
117 # Ctrl"+" or Ctrl "-" can be used to zoomin/zoomout the text inside
117 # Ctrl"+" or Ctrl "-" can be used to zoomin/zoomout the text inside
118 # the widget
118 # the widget
119 self.CmdKeyAssign(ord('+'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
119 self.CmdKeyAssign(ord('+'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
120 self.CmdKeyAssign(ord('-'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
120 self.CmdKeyAssign(ord('-'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
121 # Also allow Ctrl Shift "=" for poor non US keyboard users.
121 # Also allow Ctrl Shift "=" for poor non US keyboard users.
122 self.CmdKeyAssign(ord('='), stc.STC_SCMOD_CTRL|stc.STC_SCMOD_SHIFT,
122 self.CmdKeyAssign(ord('='), stc.STC_SCMOD_CTRL|stc.STC_SCMOD_SHIFT,
123 stc.STC_CMD_ZOOMIN)
123 stc.STC_CMD_ZOOMIN)
124
124
125 #self.CmdKeyAssign(stc.STC_KEY_PRIOR, stc.STC_SCMOD_SHIFT,
125 #self.CmdKeyAssign(stc.STC_KEY_PRIOR, stc.STC_SCMOD_SHIFT,
126 # stc.STC_CMD_PAGEUP)
126 # stc.STC_CMD_PAGEUP)
127
127
128 #self.CmdKeyAssign(stc.STC_KEY_NEXT, stc.STC_SCMOD_SHIFT,
128 #self.CmdKeyAssign(stc.STC_KEY_NEXT, stc.STC_SCMOD_SHIFT,
129 # stc.STC_CMD_PAGEDOWN)
129 # stc.STC_CMD_PAGEDOWN)
130
130
131 # Keys: we need to clear some of the keys the that don't play
131 # Keys: we need to clear some of the keys the that don't play
132 # well with a console.
132 # well with a console.
133 self.CmdKeyClear(ord('D'), stc.STC_SCMOD_CTRL)
133 self.CmdKeyClear(ord('D'), stc.STC_SCMOD_CTRL)
134 self.CmdKeyClear(ord('L'), stc.STC_SCMOD_CTRL)
134 self.CmdKeyClear(ord('L'), stc.STC_SCMOD_CTRL)
135 self.CmdKeyClear(ord('T'), stc.STC_SCMOD_CTRL)
135 self.CmdKeyClear(ord('T'), stc.STC_SCMOD_CTRL)
136
136
137
137
138 self.SetEOLMode(stc.STC_EOL_CRLF)
138 self.SetEOLMode(stc.STC_EOL_CRLF)
139 self.SetWrapMode(stc.STC_WRAP_CHAR)
139 self.SetWrapMode(stc.STC_WRAP_CHAR)
140 self.SetWrapMode(stc.STC_WRAP_WORD)
140 self.SetWrapMode(stc.STC_WRAP_WORD)
141 self.SetBufferedDraw(True)
141 self.SetBufferedDraw(True)
142 self.SetUseAntiAliasing(True)
142 self.SetUseAntiAliasing(True)
143 self.SetLayoutCache(stc.STC_CACHE_PAGE)
143 self.SetLayoutCache(stc.STC_CACHE_PAGE)
144 self.SetUndoCollection(False)
144 self.SetUndoCollection(False)
145 self.SetUseTabs(True)
145 self.SetUseTabs(True)
146 self.SetIndent(4)
146 self.SetIndent(4)
147 self.SetTabWidth(4)
147 self.SetTabWidth(4)
148
148
149 self.EnsureCaretVisible()
149 self.EnsureCaretVisible()
150 # we don't want scintilla's autocompletion to choose
150 # we don't want scintilla's autocompletion to choose
151 # automaticaly out of a single choice list, as we pop it up
151 # automaticaly out of a single choice list, as we pop it up
152 # automaticaly
152 # automaticaly
153 self.AutoCompSetChooseSingle(False)
153 self.AutoCompSetChooseSingle(False)
154 self.AutoCompSetMaxHeight(10)
154 self.AutoCompSetMaxHeight(10)
155
155
156 self.SetMargins(3, 3) #text is moved away from border with 3px
156 self.SetMargins(3, 3) #text is moved away from border with 3px
157 # Suppressing Scintilla margins
157 # Suppressing Scintilla margins
158 self.SetMarginWidth(0, 0)
158 self.SetMarginWidth(0, 0)
159 self.SetMarginWidth(1, 0)
159 self.SetMarginWidth(1, 0)
160 self.SetMarginWidth(2, 0)
160 self.SetMarginWidth(2, 0)
161
161
162 self._apply_style()
162 self._apply_style()
163
163
164 # Xterm escape sequences
164 # Xterm escape sequences
165 self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?')
165 self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?')
166 self.title_pat = re.compile('\x1b]0;(.*?)\x07')
166 self.title_pat = re.compile('\x1b]0;(.*?)\x07')
167
167
168 #self.SetEdgeMode(stc.STC_EDGE_LINE)
168 #self.SetEdgeMode(stc.STC_EDGE_LINE)
169 #self.SetEdgeColumn(80)
169 #self.SetEdgeColumn(80)
170
170
171 # styles
171 # styles
172 p = self.style
172 p = self.style
173 self.StyleSetSpec(stc.STC_STYLE_DEFAULT, p['default'])
173 self.StyleSetSpec(stc.STC_STYLE_DEFAULT, p['default'])
174 self.StyleClearAll()
174 self.StyleClearAll()
175 self.StyleSetSpec(_STDOUT_STYLE, p['stdout'])
175 self.StyleSetSpec(_STDOUT_STYLE, p['stdout'])
176 self.StyleSetSpec(_STDERR_STYLE, p['stderr'])
176 self.StyleSetSpec(_STDERR_STYLE, p['stderr'])
177 self.StyleSetSpec(_TRACE_STYLE, p['trace'])
177 self.StyleSetSpec(_TRACE_STYLE, p['trace'])
178
178
179 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, p['bracegood'])
179 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, p['bracegood'])
180 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, p['bracebad'])
180 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, p['bracebad'])
181 self.StyleSetSpec(stc.STC_P_COMMENTLINE, p['comment'])
181 self.StyleSetSpec(stc.STC_P_COMMENTLINE, p['comment'])
182 self.StyleSetSpec(stc.STC_P_NUMBER, p['number'])
182 self.StyleSetSpec(stc.STC_P_NUMBER, p['number'])
183 self.StyleSetSpec(stc.STC_P_STRING, p['string'])
183 self.StyleSetSpec(stc.STC_P_STRING, p['string'])
184 self.StyleSetSpec(stc.STC_P_CHARACTER, p['char'])
184 self.StyleSetSpec(stc.STC_P_CHARACTER, p['char'])
185 self.StyleSetSpec(stc.STC_P_WORD, p['keyword'])
185 self.StyleSetSpec(stc.STC_P_WORD, p['keyword'])
186 self.StyleSetSpec(stc.STC_P_WORD2, p['keyword'])
186 self.StyleSetSpec(stc.STC_P_WORD2, p['keyword'])
187 self.StyleSetSpec(stc.STC_P_TRIPLE, p['triple'])
187 self.StyleSetSpec(stc.STC_P_TRIPLE, p['triple'])
188 self.StyleSetSpec(stc.STC_P_TRIPLEDOUBLE, p['tripledouble'])
188 self.StyleSetSpec(stc.STC_P_TRIPLEDOUBLE, p['tripledouble'])
189 self.StyleSetSpec(stc.STC_P_CLASSNAME, p['class'])
189 self.StyleSetSpec(stc.STC_P_CLASSNAME, p['class'])
190 self.StyleSetSpec(stc.STC_P_DEFNAME, p['def'])
190 self.StyleSetSpec(stc.STC_P_DEFNAME, p['def'])
191 self.StyleSetSpec(stc.STC_P_OPERATOR, p['operator'])
191 self.StyleSetSpec(stc.STC_P_OPERATOR, p['operator'])
192 self.StyleSetSpec(stc.STC_P_COMMENTBLOCK, p['comment'])
192 self.StyleSetSpec(stc.STC_P_COMMENTBLOCK, p['comment'])
193
193
194
194
195 def write(self, text):
195 def write(self, text):
196 """ Write given text to buffer, while translating the ansi escape
196 """ Write given text to buffer, while translating the ansi escape
197 sequences.
197 sequences.
198 """
198 """
199 title = self.title_pat.split(text)
199 title = self.title_pat.split(text)
200 if len(title)>0:
200 if len(title)>0:
201 self.title = title[-1]
201 self.title = title[-1]
202
202
203 text = self.title_pat.sub('', text)
203 text = self.title_pat.sub('', text)
204 segments = self.color_pat.split(text)
204 segments = self.color_pat.split(text)
205 segment = segments.pop(0)
205 segment = segments.pop(0)
206 self.StartStyling(self.GetLength(), 0xFF)
206 self.StartStyling(self.GetLength(), 0xFF)
207 self.AppendText(segment)
207 self.AppendText(segment)
208
208
209 if segments:
209 if segments:
210 ansi_tags = self.color_pat.findall(text)
210 for ansi_tag, text in zip(segments[::2], segments[1::2]):
211
212 for tag in ansi_tags:
213 i = segments.index(tag)
214 self.StartStyling(self.GetLength(), 0xFF)
211 self.StartStyling(self.GetLength(), 0xFF)
215 self.AppendText(segments[i+1])
212 self.AppendText(text)
216
213
217 if tag != '0':
214 if ansi_tag == '0':
218 self.SetStyling(len(segments[i+1]),
215 style = 0
219 self.ANSI_STYLES[tag][0])
216 else:
217 style = self.ANSI_STYLES[ansi_tag][0]
220
218
221 segments.pop(i)
219 self.SetStyling(len(text), style)
222
220
223 self.GotoPos(self.GetLength())
221 self.GotoPos(self.GetLength())
224 wx.Yield()
222 wx.Yield()
225
223
226
224
227 def new_prompt(self, prompt):
225 def new_prompt(self, prompt):
228 """ Prints a prompt at start of line, and move the start of the
226 """ Prints a prompt at start of line, and move the start of the
229 current block there.
227 current block there.
230
228
231 The prompt can be give with ascii escape sequences.
229 The prompt can be give with ascii escape sequences.
232 """
230 """
233 self.write(prompt)
231 self.write(prompt)
234 # now we update our cursor giving end of prompt
232 # now we update our cursor giving end of prompt
235 self.current_prompt_pos = self.GetLength()
233 self.current_prompt_pos = self.GetLength()
236 self.current_prompt_line = self.GetCurrentLine()
234 self.current_prompt_line = self.GetCurrentLine()
237 wx.Yield()
235 wx.Yield()
238 self.EnsureCaretVisible()
236 self.EnsureCaretVisible()
239
237
240
238
241 def replace_current_edit_buffer(self, text):
239 def replace_current_edit_buffer(self, text):
242 """ Replace currently entered command line with given text.
240 """ Replace currently entered command line with given text.
243 """
241 """
244 self.SetSelection(self.current_prompt_pos, self.GetLength())
242 self.SetSelection(self.current_prompt_pos, self.GetLength())
245 self.ReplaceSelection(text)
243 self.ReplaceSelection(text)
246 self.GotoPos(self.GetLength())
244 self.GotoPos(self.GetLength())
247
245
248
246
249 def get_current_edit_buffer(self):
247 def get_current_edit_buffer(self):
250 """ Returns the text in current edit buffer.
248 """ Returns the text in current edit buffer.
251 """
249 """
252 return self.GetTextRange(self.current_prompt_pos,
250 return self.GetTextRange(self.current_prompt_pos,
253 self.GetLength())
251 self.GetLength())
254
252
255
253
256 #--------------------------------------------------------------------------
254 #--------------------------------------------------------------------------
257 # Private API
255 # Private API
258 #--------------------------------------------------------------------------
256 #--------------------------------------------------------------------------
259
257
260 def _apply_style(self):
258 def _apply_style(self):
261 """ Applies the colors for the different text elements and the
259 """ Applies the colors for the different text elements and the
262 carret.
260 carret.
263 """
261 """
264 self.SetCaretForeground(self.carret_color)
262 self.SetCaretForeground(self.carret_color)
265
263
266 #self.StyleClearAll()
264 #self.StyleClearAll()
267 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT,
265 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT,
268 "fore:#FF0000,back:#0000FF,bold")
266 "fore:#FF0000,back:#0000FF,bold")
269 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD,
267 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD,
270 "fore:#000000,back:#FF0000,bold")
268 "fore:#000000,back:#FF0000,bold")
271
269
272 for style in self.ANSI_STYLES.values():
270 for style in self.ANSI_STYLES.values():
273 self.StyleSetSpec(style[0], "bold,fore:%s" % style[1])
271 self.StyleSetSpec(style[0], "bold,fore:%s" % style[1])
274
272
275
273
276 def write_completion(self, possibilities):
274 def write_completion(self, possibilities):
277 # FIXME: This is non Wx specific and needs to be moved into
275 # FIXME: This is non Wx specific and needs to be moved into
278 # the base class.
276 # the base class.
279 current_buffer = self.get_current_edit_buffer()
277 current_buffer = self.get_current_edit_buffer()
280
278
281 self.write('\n')
279 self.write('\n')
282 max_len = len(max(possibilities, key=len)) + 1
280 max_len = len(max(possibilities, key=len)) + 1
283
281
284 #now we check how much symbol we can put on a line...
282 #now we check how much symbol we can put on a line...
285 chars_per_line = self.GetSize()[0]/self.GetCharWidth()
283 chars_per_line = self.GetSize()[0]/self.GetCharWidth()
286 symbols_per_line = max(1, chars_per_line/max_len)
284 symbols_per_line = max(1, chars_per_line/max_len)
287
285
288 pos = 1
286 pos = 1
289 buf = []
287 buf = []
290 for symbol in possibilities:
288 for symbol in possibilities:
291 if pos < symbols_per_line:
289 if pos < symbols_per_line:
292 buf.append(symbol.ljust(max_len))
290 buf.append(symbol.ljust(max_len))
293 pos += 1
291 pos += 1
294 else:
292 else:
295 buf.append(symbol.rstrip() +'\n')
293 buf.append(symbol.rstrip() +'\n')
296 pos = 1
294 pos = 1
297 self.write(''.join(buf))
295 self.write(''.join(buf))
298 self.new_prompt(self.prompt % (self.last_result['number'] + 1))
296 self.new_prompt(self.prompt % (self.last_result['number'] + 1))
299 self.replace_current_edit_buffer(current_buffer)
297 self.replace_current_edit_buffer(current_buffer)
300
298
301
299
302 def pop_completion(self, possibilities, offset=0):
300 def pop_completion(self, possibilities, offset=0):
303 """ Pops up an autocompletion menu. Offset is the offset
301 """ Pops up an autocompletion menu. Offset is the offset
304 in characters of the position at which the menu should
302 in characters of the position at which the menu should
305 appear, relativ to the cursor.
303 appear, relativ to the cursor.
306 """
304 """
307 self.AutoCompSetIgnoreCase(False)
305 self.AutoCompSetIgnoreCase(False)
308 self.AutoCompSetAutoHide(False)
306 self.AutoCompSetAutoHide(False)
309 self.AutoCompSetMaxHeight(len(possibilities))
307 self.AutoCompSetMaxHeight(len(possibilities))
310 self.AutoCompShow(offset, " ".join(possibilities))
308 self.AutoCompShow(offset, " ".join(possibilities))
311
309
312
310
313 def scroll_to_bottom(self):
311 def scroll_to_bottom(self):
314 maxrange = self.GetScrollRange(wx.VERTICAL)
312 maxrange = self.GetScrollRange(wx.VERTICAL)
315 self.ScrollLines(maxrange)
313 self.ScrollLines(maxrange)
316
314
317
315
318 def _on_enter(self):
316 def _on_enter(self):
319 """ Called when the return key is hit.
317 """ Called when the return key is hit.
320 """
318 """
321 pass
319 pass
322
320
323
321
324 def _on_key_down(self, event, skip=True):
322 def _on_key_down(self, event, skip=True):
325 """ Key press callback used for correcting behavior for
323 """ Key press callback used for correcting behavior for
326 console-like interfaces: the cursor is constraint to be after
324 console-like interfaces: the cursor is constraint to be after
327 the last prompt.
325 the last prompt.
328
326
329 Return True if event as been catched.
327 Return True if event as been catched.
330 """
328 """
331 catched = True
329 catched = True
332 # Intercept some specific keys.
330 # Intercept some specific keys.
333 if event.KeyCode == ord('L') and event.ControlDown() :
331 if event.KeyCode == ord('L') and event.ControlDown() :
334 self.scroll_to_bottom()
332 self.scroll_to_bottom()
335 elif event.KeyCode == ord('K') and event.ControlDown() :
333 elif event.KeyCode == ord('K') and event.ControlDown() :
336 self.replace_current_edit_buffer('')
334 self.replace_current_edit_buffer('')
337 elif event.KeyCode == wx.WXK_PAGEUP and event.ShiftDown():
335 elif event.KeyCode == wx.WXK_PAGEUP and event.ShiftDown():
338 self.ScrollPages(-1)
336 self.ScrollPages(-1)
339 elif event.KeyCode == wx.WXK_PAGEDOWN and event.ShiftDown():
337 elif event.KeyCode == wx.WXK_PAGEDOWN and event.ShiftDown():
340 self.ScrollPages(1)
338 self.ScrollPages(1)
341 elif event.KeyCode == wx.WXK_UP and event.ShiftDown():
339 elif event.KeyCode == wx.WXK_UP and event.ShiftDown():
342 self.ScrollLines(-1)
340 self.ScrollLines(-1)
343 elif event.KeyCode == wx.WXK_DOWN and event.ShiftDown():
341 elif event.KeyCode == wx.WXK_DOWN and event.ShiftDown():
344 self.ScrollLinees(1)
342 self.ScrollLinees(1)
345 else:
343 else:
346 catched = False
344 catched = False
347
345
348 if self.AutoCompActive():
346 if self.AutoCompActive():
349 event.Skip()
347 event.Skip()
350 else:
348 else:
351 if event.KeyCode in (13, wx.WXK_NUMPAD_ENTER) and \
349 if event.KeyCode in (13, wx.WXK_NUMPAD_ENTER) and \
352 event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN):
350 event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN):
353 catched = True
351 catched = True
354 self.CallTipCancel()
352 self.CallTipCancel()
355 self.write('\n')
353 self.write('\n')
356 self._on_enter()
354 self._on_enter()
357
355
358 elif event.KeyCode == wx.WXK_HOME:
356 elif event.KeyCode == wx.WXK_HOME:
359 if event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN):
357 if event.Modifiers in (wx.MOD_NONE, wx.MOD_WIN):
360 self.GotoPos(self.current_prompt_pos)
358 self.GotoPos(self.current_prompt_pos)
361 catched = True
359 catched = True
362
360
363 elif event.Modifiers in (wx.MOD_SHIFT, wx.MOD_WIN) :
361 elif event.Modifiers in (wx.MOD_SHIFT, wx.MOD_WIN) :
364 # FIXME: This behavior is not ideal: if the selection
362 # FIXME: This behavior is not ideal: if the selection
365 # is already started, it will jump.
363 # is already started, it will jump.
366 self.SetSelectionStart(self.current_prompt_pos)
364 self.SetSelectionStart(self.current_prompt_pos)
367 self.SetSelectionEnd(self.GetCurrentPos())
365 self.SetSelectionEnd(self.GetCurrentPos())
368 catched = True
366 catched = True
369
367
370 elif event.KeyCode == wx.WXK_UP:
368 elif event.KeyCode == wx.WXK_UP:
371 if self.GetCurrentLine() > self.current_prompt_line:
369 if self.GetCurrentLine() > self.current_prompt_line:
372 if self.GetCurrentLine() == self.current_prompt_line + 1 \
370 if self.GetCurrentLine() == self.current_prompt_line + 1 \
373 and self.GetColumn(self.GetCurrentPos()) < \
371 and self.GetColumn(self.GetCurrentPos()) < \
374 self.GetColumn(self.current_prompt_pos):
372 self.GetColumn(self.current_prompt_pos):
375 self.GotoPos(self.current_prompt_pos)
373 self.GotoPos(self.current_prompt_pos)
376 else:
374 else:
377 event.Skip()
375 event.Skip()
378 catched = True
376 catched = True
379
377
380 elif event.KeyCode in (wx.WXK_LEFT, wx.WXK_BACK):
378 elif event.KeyCode in (wx.WXK_LEFT, wx.WXK_BACK):
381 if self.GetCurrentPos() > self.current_prompt_pos:
379 if self.GetCurrentPos() > self.current_prompt_pos:
382 event.Skip()
380 event.Skip()
383 catched = True
381 catched = True
384
382
385 if skip and not catched:
383 if skip and not catched:
386 event.Skip()
384 event.Skip()
387
385
388 return catched
386 return catched
389
387
390
388
391 def _on_key_up(self, event, skip=True):
389 def _on_key_up(self, event, skip=True):
392 """ If cursor is outside the editing region, put it back.
390 """ If cursor is outside the editing region, put it back.
393 """
391 """
394 event.Skip()
392 event.Skip()
395 if self.GetCurrentPos() < self.current_prompt_pos:
393 if self.GetCurrentPos() < self.current_prompt_pos:
396 self.GotoPos(self.current_prompt_pos)
394 self.GotoPos(self.current_prompt_pos)
397
395
398
396
399
397
400
398
401 if __name__ == '__main__':
399 if __name__ == '__main__':
402 # Some simple code to test the console widget.
400 # Some simple code to test the console widget.
403 class MainWindow(wx.Frame):
401 class MainWindow(wx.Frame):
404 def __init__(self, parent, id, title):
402 def __init__(self, parent, id, title):
405 wx.Frame.__init__(self, parent, id, title, size=(300,250))
403 wx.Frame.__init__(self, parent, id, title, size=(300,250))
406 self._sizer = wx.BoxSizer(wx.VERTICAL)
404 self._sizer = wx.BoxSizer(wx.VERTICAL)
407 self.console_widget = ConsoleWidget(self)
405 self.console_widget = ConsoleWidget(self)
408 self._sizer.Add(self.console_widget, 1, wx.EXPAND)
406 self._sizer.Add(self.console_widget, 1, wx.EXPAND)
409 self.SetSizer(self._sizer)
407 self.SetSizer(self._sizer)
410 self.SetAutoLayout(1)
408 self.SetAutoLayout(1)
411 self.Show(True)
409 self.Show(True)
412
410
413 app = wx.PySimpleApp()
411 app = wx.PySimpleApp()
414 w = MainWindow(None, wx.ID_ANY, 'ConsoleWidget')
412 w = MainWindow(None, wx.ID_ANY, 'ConsoleWidget')
415 w.SetSize((780, 460))
413 w.SetSize((780, 460))
416 w.Show()
414 w.Show()
417
415
418 app.MainLoop()
416 app.MainLoop()
419
417
420
418
General Comments 0
You need to be logged in to leave comments. Login now