##// END OF EJS Templates
Merge pull request #1089 from mdboom/qtconsole-carriage-return...
Fernando Perez -
r5641:21c436b6 merge
parent child Browse files
Show More
@@ -26,12 +26,19 b" MoveAction = namedtuple('MoveAction', ['action', 'dir', 'unit', 'count'])"
26 # An action for scroll requests (SU and ST) and form feeds.
26 # An action for scroll requests (SU and ST) and form feeds.
27 ScrollAction = namedtuple('ScrollAction', ['action', 'dir', 'unit', 'count'])
27 ScrollAction = namedtuple('ScrollAction', ['action', 'dir', 'unit', 'count'])
28
28
29 # An action for the carriage return character
30 CarriageReturnAction = namedtuple('CarriageReturnAction', ['action'])
31
32 # An action for the beep character
33 BeepAction = namedtuple('BeepAction', ['action'])
34
29 # Regular expressions.
35 # Regular expressions.
30 CSI_COMMANDS = 'ABCDEFGHJKSTfmnsu'
36 CSI_COMMANDS = 'ABCDEFGHJKSTfmnsu'
31 CSI_SUBPATTERN = '\[(.*?)([%s])' % CSI_COMMANDS
37 CSI_SUBPATTERN = '\[(.*?)([%s])' % CSI_COMMANDS
32 OSC_SUBPATTERN = '\](.*?)[\x07\x1b]'
38 OSC_SUBPATTERN = '\](.*?)[\x07\x1b]'
33 ANSI_PATTERN = re.compile('\x01?\x1b(%s|%s)\x02?' % \
39 ANSI_PATTERN = ('\x01?\x1b(%s|%s)\x02?' % \
34 (CSI_SUBPATTERN, OSC_SUBPATTERN))
40 (CSI_SUBPATTERN, OSC_SUBPATTERN))
41 ANSI_OR_SPECIAL_PATTERN = re.compile('(\b|\r)|(?:%s)' % ANSI_PATTERN)
35 SPECIAL_PATTERN = re.compile('([\f])')
42 SPECIAL_PATTERN = re.compile('([\f])')
36
43
37 #-----------------------------------------------------------------------------
44 #-----------------------------------------------------------------------------
@@ -76,7 +83,7 b' class AnsiCodeProcessor(object):'
76 self.actions = []
83 self.actions = []
77 start = 0
84 start = 0
78
85
79 for match in ANSI_PATTERN.finditer(string):
86 for match in ANSI_OR_SPECIAL_PATTERN.finditer(string):
80 raw = string[start:match.start()]
87 raw = string[start:match.start()]
81 substring = SPECIAL_PATTERN.sub(self._replace_special, raw)
88 substring = SPECIAL_PATTERN.sub(self._replace_special, raw)
82 if substring or self.actions:
89 if substring or self.actions:
@@ -85,20 +92,27 b' class AnsiCodeProcessor(object):'
85
92
86 self.actions = []
93 self.actions = []
87 groups = filter(lambda x: x is not None, match.groups())
94 groups = filter(lambda x: x is not None, match.groups())
88 params = [ param for param in groups[1].split(';') if param ]
95 if groups[0] == '\r':
89 if groups[0].startswith('['):
96 self.actions.append(CarriageReturnAction('carriage-return'))
90 # Case 1: CSI code.
97 yield ''
91 try:
98 elif groups[0] == '\b':
92 params = map(int, params)
99 self.actions.append(BeepAction('beep'))
93 except ValueError:
100 yield ''
94 # Silently discard badly formed codes.
101 else:
95 pass
102 params = [ param for param in groups[1].split(';') if param ]
96 else:
103 if groups[0].startswith('['):
97 self.set_csi_code(groups[2], params)
104 # Case 1: CSI code.
98
105 try:
99 elif groups[0].startswith(']'):
106 params = map(int, params)
100 # Case 2: OSC code.
107 except ValueError:
101 self.set_osc_code(params)
108 # Silently discard badly formed codes.
109 pass
110 else:
111 self.set_csi_code(groups[2], params)
112
113 elif groups[0].startswith(']'):
114 # Case 2: OSC code.
115 self.set_osc_code(params)
102
116
103 raw = string[start:]
117 raw = string[start:]
104 substring = SPECIAL_PATTERN.sub(self._replace_special, raw)
118 substring = SPECIAL_PATTERN.sub(self._replace_special, raw)
@@ -1513,6 +1513,13 b' class ConsoleWidget(LoggingConfigurable, QtGui.QWidget):'
1513 cursor.joinPreviousEditBlock()
1513 cursor.joinPreviousEditBlock()
1514 cursor.deletePreviousChar()
1514 cursor.deletePreviousChar()
1515
1515
1516 elif act.action == 'carriage-return':
1517 cursor.movePosition(
1518 cursor.StartOfLine, cursor.KeepAnchor)
1519
1520 elif act.action == 'beep':
1521 QtGui.qApp.beep()
1522
1516 format = self._ansi_processor.get_format()
1523 format = self._ansi_processor.get_format()
1517 cursor.insertText(substring, format)
1524 cursor.insertText(substring, format)
1518 else:
1525 else:
@@ -90,8 +90,8 b' class TestAnsiCodeProcessor(unittest.TestCase):'
90 self.fail('Too many substrings.')
90 self.fail('Too many substrings.')
91 self.assertEquals(i, 1, 'Too few substrings.')
91 self.assertEquals(i, 1, 'Too few substrings.')
92
92
93 def test_specials(self):
93 def test_formfeed(self):
94 """ Are special characters processed correctly?
94 """ Are formfeed characters processed correctly?
95 """
95 """
96 string = '\f' # form feed
96 string = '\f' # form feed
97 self.assertEquals(list(self.processor.split_string(string)), [''])
97 self.assertEquals(list(self.processor.split_string(string)), [''])
@@ -102,6 +102,26 b' class TestAnsiCodeProcessor(unittest.TestCase):'
102 self.assertEquals(action.unit, 'page')
102 self.assertEquals(action.unit, 'page')
103 self.assertEquals(action.count, 1)
103 self.assertEquals(action.count, 1)
104
104
105 def test_carriage_return(self):
106 """ Are carriage return characters processed correctly?
107 """
108 string = 'foo\rbar' # form feed
109 self.assertEquals(list(self.processor.split_string(string)), ['foo', '', 'bar'])
110 self.assertEquals(len(self.processor.actions), 1)
111 action = self.processor.actions[0]
112 self.assertEquals(action.action, 'carriage-return')
113 self.assertEquals(action.count, 1)
114
115 def test_beep(self):
116 """ Are beep characters processed correctly?
117 """
118 string = 'foo\bbar' # form feed
119 self.assertEquals(list(self.processor.split_string(string)), ['foo', '', 'bar'])
120 self.assertEquals(len(self.processor.actions), 1)
121 action = self.processor.actions[0]
122 self.assertEquals(action.action, 'beep')
123 self.assertEquals(action.count, 1)
124
105
125
106 if __name__ == '__main__':
126 if __name__ == '__main__':
107 unittest.main()
127 unittest.main()
General Comments 0
You need to be logged in to leave comments. Login now