diff --git a/kitty/charsets.c b/kitty/charsets.c index 3be565d54..9223ac3b6 100644 --- a/kitty/charsets.c +++ b/kitty/charsets.c @@ -9,6 +9,165 @@ #include "data-types.h" +static uint32_t charset_translations[4][256] = { + /* VT100 graphics mapped to Unicode */ + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002a, 0x2192, 0x2190, 0x2191, 0x2193, 0x002f, + 0x2588, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x00a0, + 0x25c6, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, 0x00b1, + 0x2591, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0x23ba, + 0x23bb, 0x2500, 0x23bc, 0x23bd, 0x251c, 0x2524, 0x2534, 0x252c, + 0x2502, 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3, 0x00b7, 0x007f, + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, + 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, + 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af, + 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7, + 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf, + 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7, + 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf, + 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7, + 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df, + 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, + 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, + 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, + 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff + }, + /* IBM Codepage 437 mapped to Unicode */ + { + 0x0000, 0x263a, 0x263b, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, + 0x25d8, 0x25cb, 0x25d9, 0x2642, 0x2640, 0x266a, 0x266b, 0x263c, + 0x25b6, 0x25c0, 0x2195, 0x203c, 0x00b6, 0x00a7, 0x25ac, 0x21a8, + 0x2191, 0x2193, 0x2192, 0x2190, 0x221f, 0x2194, 0x25b2, 0x25bc, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x2302, + 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, + 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5, + 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, + 0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192, + 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba, + 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, + 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510, + 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f, + 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, + 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, + 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4, + 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229, + 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, + 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0 + }, + // VAX 42 map + { + 0x0000, 0x263a, 0x263b, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, + 0x25d8, 0x25cb, 0x25d9, 0x2642, 0x2640, 0x266a, 0x266b, 0x263c, + 0x25b6, 0x25c0, 0x2195, 0x203c, 0x00b6, 0x00a7, 0x25ac, 0x21a8, + 0x2191, 0x2193, 0x2192, 0x2190, 0x221f, 0x2194, 0x25b2, 0x25bc, + 0x0020, 0x043b, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x0435, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, + 0x0060, 0x0441, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0435, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x043a, + 0x0070, 0x0071, 0x0442, 0x0073, 0x043b, 0x0435, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x2302, + 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, + 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5, + 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, + 0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192, + 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba, + 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, + 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510, + 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f, + 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, + 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, + 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4, + 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229, + 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, + 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0 + }, + /* UK mapping, same as 8-bit Latin1 except the pound sign replaces # */ + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, + 0x0020, 0x0021, 0x0022, 0x00a3, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, + 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, + 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af, + 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7, + 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf, + 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7, + 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf, + 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7, + 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df, + 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, + 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, + 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, + 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff + }, +}; + +uint32_t* +translation_table(uint32_t which) { + switch(which){ + default: + return NULL; + case '0': + return charset_translations[0]; + case 'U': + return charset_translations[1]; + case 'V': + return charset_translations[2]; + case 'A': + return charset_translations[3]; + } +} + // UTF-8 decode taken from: https://bjoern.hoehrmann.de/utf-8/decoder/dfa/ diff --git a/kitty/charsets.h b/kitty/charsets.h index cb27e51f5..2f9549799 100644 --- a/kitty/charsets.h +++ b/kitty/charsets.h @@ -12,3 +12,4 @@ uint32_t decode_utf8(uint32_t*, uint32_t*, uint8_t byte); size_t decode_utf8_string(const char *src, size_t sz, uint32_t *dest); unsigned int encode_utf8(uint32_t ch, char* dest); +uint32_t* translation_table(uint32_t which); diff --git a/kitty/screen.c b/kitty/screen.c index 03ddef5bd..c26eddf76 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -14,6 +14,7 @@ #include "state.h" #include "iqsort.h" #include "fonts.h" +#include "charsets.h" #include "lineops.h" #include "hyperlink.h" #include @@ -187,6 +188,7 @@ screen_reset(Screen *self) { R(default_fg); R(default_bg); R(cursor_color); R(highlight_fg); R(highlight_bg); #undef R reset_vt_parser(self->vt_parser); + zero_at_ptr(&self->charset); self->margin_top = 0; self->margin_bottom = self->lines - 1; screen_normal_keypad_mode(self); init_tabstops(self->main_tabstops, self->columns); @@ -680,12 +682,47 @@ move_cursor_off_wide_char_trailer(Screen *self, text_loop_state *s) { zero_cells(s, s->cp + self->cursor->x, s->gp + self->cursor->x); } +static void +screen_change_charset(Screen *self, uint32_t which) { + switch(which) { + case 0: + self->charset.current_num = 0; + self->charset.current = self->charset.zero; + break; + case 1: + self->charset.current_num = 1; + self->charset.current = self->charset.one; + break; + } +} + +void +screen_designate_charset(Screen *self, uint32_t which, uint32_t as) { + switch(which) { + case 0: + self->charset.zero = translation_table(as); + if (self->charset.current_num == 0) self->charset.current = self->charset.zero; + break; + case 1: + self->charset.one = translation_table(as); + if (self->charset.current_num == 1) self->charset.current = self->charset.one; + break; + } +} + + +static uint32_t +map_char(Screen *self, const uint32_t ch) { + return UNLIKELY(self->charset.current && ch < 256) ? self->charset.current[ch] : ch; +} + static void draw_text_loop(Screen *self, const uint32_t *chars, size_t num_chars, text_loop_state *s) { init_text_loop_line(self, s); - if (cursor_on_wide_char_trailer(self, s) && ' ' <= chars[0] && chars[0] != DEL && !is_combining_char(chars[0])) move_cursor_off_wide_char_trailer(self, s); + const uint32_t first_char = map_char(self, chars[0]); + if (cursor_on_wide_char_trailer(self, s) && ' ' <= first_char && first_char != DEL && !is_combining_char(first_char)) move_cursor_off_wide_char_trailer(self, s); for (size_t i = 0; i < num_chars; i++) { - uint32_t ch = chars[i]; + uint32_t ch = map_char(self, chars[i]); if (ch < ' ') { switch (ch) { case BEL: @@ -694,6 +731,10 @@ draw_text_loop(Screen *self, const uint32_t *chars, size_t num_chars, text_loop_ screen_backspace(self); break; case HT: screen_tab(self); break; + case SI: + screen_change_charset(self, 0); break; + case SO: + screen_change_charset(self, 1); break; case LF: case VT: case FF: @@ -1569,6 +1610,7 @@ screen_save_cursor(Screen *self) { sp->mDECOM = self->modes.mDECOM; sp->mDECAWM = self->modes.mDECAWM; sp->mDECSCNM = self->modes.mDECSCNM; + memcpy(&sp->charset, &self->charset, sizeof(self->charset)); sp->is_valid = true; } @@ -1646,11 +1688,13 @@ screen_restore_cursor(Screen *self) { screen_cursor_position(self, 1, 1); screen_reset_mode(self, DECOM); screen_reset_mode(self, DECSCNM); + zero_at_ptr(&self->charset); } else { set_mode_from_const(self, DECOM, sp->mDECOM); set_mode_from_const(self, DECAWM, sp->mDECAWM); set_mode_from_const(self, DECSCNM, sp->mDECSCNM); cursor_copy_to(&(sp->cursor), self->cursor); + memcpy(&self->charset, &sp->charset, sizeof(self->charset)); screen_ensure_bounds(self, false, false); } } diff --git a/kitty/screen.h b/kitty/screen.h index 4f6cda922..2af650c9f 100644 --- a/kitty/screen.h +++ b/kitty/screen.h @@ -56,9 +56,14 @@ typedef struct { #define SAVEPOINTS_SZ 256 +typedef struct CharsetState { + uint32_t *zero, *one, *current, current_num; +} CharsetState; + typedef struct { Cursor cursor; bool mDECOM, mDECAWM, mDECSCNM; + CharsetState charset; bool is_valid; } Savepoint; @@ -83,7 +88,7 @@ typedef struct { typedef struct { PyObject_HEAD - unsigned int columns, lines, margin_top, margin_bottom, charset, scrolled_by; + unsigned int columns, lines, margin_top, margin_bottom, scrolled_by; double pending_scroll_pixels_x, pending_scroll_pixels_y; CellPixelSize cell_size; OverlayLine overlay_line; @@ -160,6 +165,7 @@ typedef struct { GraphicsManager *grman; Selections selections, url_ranges; } paused_rendering; + CharsetState charset; } Screen; @@ -272,6 +278,7 @@ bool get_line_edge_colors(Screen *self, color_type *left, color_type *right); bool parse_sgr(Screen *screen, const uint8_t *buf, unsigned int num, const char *report_name, bool is_deccara); bool screen_pause_rendering(Screen *self, bool pause, int for_in_ms); void screen_check_pause_rendering(Screen *self, monotonic_t now); +void screen_designate_charset(Screen *self, uint32_t which, uint32_t as); #define DECLARE_CH_SCREEN_HANDLER(name) void screen_##name(Screen *screen); DECLARE_CH_SCREEN_HANDLER(bell) DECLARE_CH_SCREEN_HANDLER(backspace) diff --git a/kitty/vt-parser.c b/kitty/vt-parser.c index 3d8a37a4a..34044162f 100644 --- a/kitty/vt-parser.c +++ b/kitty/vt-parser.c @@ -96,6 +96,8 @@ _report_params(PyObject *dump_callback, id_type window_id, const char *name, int case BEL: REPORT_COMMAND(screen_bell); break; \ case BS: REPORT_COMMAND(screen_backspace); break; \ case HT: REPORT_COMMAND(screen_tab); break; \ + case SI: REPORT_COMMAND(screen_change_charset, 0); break; \ + case SO: REPORT_COMMAND(screen_change_charset, 1); break; \ case LF: case VT: case FF: REPORT_COMMAND(screen_linefeed); break; \ case CR: REPORT_COMMAND(screen_carriage_return); break; \ default: \ @@ -321,9 +323,7 @@ consume_esc(PS *self) { case '0': case 'U': case 'V': - // dont report this error as fish shell designates charsets for some unholy reason, creating lot of noise in the tests - /* REPORT_ERROR("Ignoring attempt to designate charset as we support only UTF-8"); */ - break; + CALL_ED2(screen_designate_charset, prev_ch - '(', ch); break; default: REPORT_ERROR("Unknown charset: 0x%x", ch); break; } diff --git a/kitty_tests/parser.py b/kitty_tests/parser.py index a766bbd45..6afb23a80 100644 --- a/kitty_tests/parser.py +++ b/kitty_tests/parser.py @@ -76,6 +76,20 @@ class TestParser(BaseTest): parse_bytes(s, x, cd) self.ae(cmds, cd.get_result()) + def test_charsets(self): + s = self.create_screen() + pb = partial(self.parse_bytes_dump, s) + pb(b'\xc3') + pb(b'\xa1', ('draw', b'\xc3\xa1'.decode('utf-8'))) + s = self.create_screen() + pb = partial(self.parse_bytes_dump, s) + pb('\033)0\x0e/_', ('screen_designate_charset', 1, ord('0')), ('screen_change_charset', 1), '/_') + self.ae(str(s.line(0)), '/\xa0') + s = self.create_screen() + pb = partial(self.parse_bytes_dump, s) + pb('\033(0/_', ('screen_designate_charset', 0, ord('0')), '/_') + self.ae(str(s.line(0)), '/\xa0') + def test_parser_threading(self): s = self.create_screen()