Support carriage return ('\r') and beep ('\b') characters in the qtconsole #1089

Merged
merged 3 commits into from Dec 7, 2011
@@ -26,12 +26,19 @@
# An action for scroll requests (SU and ST) and form feeds.
ScrollAction = namedtuple('ScrollAction', ['action', 'dir', 'unit', 'count'])
+# An action for the carriage return character
+CarriageReturnAction = namedtuple('CarriageReturnAction', ['action'])
+
+# An action for the beep character
+BeepAction = namedtuple('BeepAction', ['action'])
+
# Regular expressions.
CSI_COMMANDS = 'ABCDEFGHJKSTfmnsu'
CSI_SUBPATTERN = '\[(.*?)([%s])' % CSI_COMMANDS
OSC_SUBPATTERN = '\](.*?)[\x07\x1b]'
-ANSI_PATTERN = re.compile('\x01?\x1b(%s|%s)\x02?' % \
- (CSI_SUBPATTERN, OSC_SUBPATTERN))
+ANSI_PATTERN = ('\x01?\x1b(%s|%s)\x02?' % \
+ (CSI_SUBPATTERN, OSC_SUBPATTERN))
+ANSI_OR_SPECIAL_PATTERN = re.compile('(\b|\r)|(?:%s)' % ANSI_PATTERN)
SPECIAL_PATTERN = re.compile('([\f])')
#-----------------------------------------------------------------------------
@@ -76,7 +83,7 @@ def split_string(self, string):
self.actions = []
start = 0
- for match in ANSI_PATTERN.finditer(string):
+ for match in ANSI_OR_SPECIAL_PATTERN.finditer(string):
raw = string[start:match.start()]
substring = SPECIAL_PATTERN.sub(self._replace_special, raw)
if substring or self.actions:
@@ -85,20 +92,27 @@ def split_string(self, string):
self.actions = []
groups = filter(lambda x: x is not None, match.groups())
- params = [ param for param in groups[1].split(';') if param ]
- if groups[0].startswith('['):
- # Case 1: CSI code.
- try:
- params = map(int, params)
- except ValueError:
- # Silently discard badly formed codes.
- pass
- else:
- self.set_csi_code(groups[2], params)
-
- elif groups[0].startswith(']'):
- # Case 2: OSC code.
- self.set_osc_code(params)
+ if groups[0] == '\r':
+ self.actions.append(CarriageReturnAction('carriage-return'))
+ yield ''
+ elif groups[0] == '\b':
+ self.actions.append(BeepAction('beep'))
+ yield ''
+ else:
+ params = [ param for param in groups[1].split(';') if param ]
+ if groups[0].startswith('['):
+ # Case 1: CSI code.
+ try:
+ params = map(int, params)
+ except ValueError:
+ # Silently discard badly formed codes.
+ pass
+ else:
+ self.set_csi_code(groups[2], params)
+
+ elif groups[0].startswith(']'):
+ # Case 2: OSC code.
+ self.set_osc_code(params)
raw = string[start:]
substring = SPECIAL_PATTERN.sub(self._replace_special, raw)
@@ -1513,6 +1513,13 @@ def _insert_plain_text(self, cursor, text):
cursor.joinPreviousEditBlock()
cursor.deletePreviousChar()
+ elif act.action == 'carriage-return':
+ cursor.movePosition(
+ cursor.StartOfLine, cursor.KeepAnchor)
+
+ elif act.action == 'beep':
+ QtGui.qApp.beep()
+
format = self._ansi_processor.get_format()
cursor.insertText(substring, format)
else:
@@ -90,8 +90,8 @@ def test_scroll(self):
self.fail('Too many substrings.')
self.assertEquals(i, 1, 'Too few substrings.')
- def test_specials(self):
- """ Are special characters processed correctly?
+ def test_formfeed(self):
+ """ Are formfeed characters processed correctly?
"""
string = '\f' # form feed
self.assertEquals(list(self.processor.split_string(string)), [''])
@@ -102,6 +102,26 @@ def test_specials(self):
self.assertEquals(action.unit, 'page')
self.assertEquals(action.count, 1)
+ def test_carriage_return(self):
+ """ Are carriage return characters processed correctly?
+ """
+ string = 'foo\rbar' # form feed
+ self.assertEquals(list(self.processor.split_string(string)), ['foo', '', 'bar'])
+ self.assertEquals(len(self.processor.actions), 1)
+ action = self.processor.actions[0]
+ self.assertEquals(action.action, 'carriage-return')
+ self.assertEquals(action.count, 1)
+
+ def test_beep(self):
+ """ Are beep characters processed correctly?
+ """
+ string = 'foo\bbar' # form feed
+ self.assertEquals(list(self.processor.split_string(string)), ['foo', '', 'bar'])
+ self.assertEquals(len(self.processor.actions), 1)
+ action = self.processor.actions[0]
+ self.assertEquals(action.action, 'beep')
+ self.assertEquals(action.count, 1)
+
if __name__ == '__main__':
unittest.main()