diff --git a/kitty/charsets.c b/kitty/charsets.c index c83def009..25e766661 100644 --- a/kitty/charsets.c +++ b/kitty/charsets.c @@ -6,7 +6,204 @@ */ #include "data-types.h" +// Taken from consolemap.c in the linux vt driver sourcecode +static uint32_t charset_translations[5][256] = { + /* 8-bit Latin-1 mapped to Unicode -- trivial mapping */ + { + 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, 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 + }, + /* 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){ + case 'B': + return charset_translations[0]; + case '0': + return charset_translations[1]; + case 'U': + return charset_translations[2]; + case 'V': + return charset_translations[3]; + case 'A': + return charset_translations[4]; + default: + return charset_translations[0]; + } +} // UTF-8 decode taken from: http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ static const uint8_t utf8_data[] = { @@ -26,7 +223,8 @@ static const uint8_t utf8_data[] = { 1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // s7..s8 }; -uint32_t decode_utf8(uint32_t* state, uint32_t* codep, uint8_t byte) { +uint32_t +decode_utf8(uint32_t* state, uint32_t* codep, uint8_t byte) { uint32_t type = utf8_data[byte]; *codep = (*state != UTF8_ACCEPT) ? diff --git a/kitty/data-types.h b/kitty/data-types.h index 150a14b11..0030ea67e 100644 --- a/kitty/data-types.h +++ b/kitty/data-types.h @@ -235,7 +235,8 @@ PyTypeObject ScreenModes_Type; #define SAVEPOINTS_SZ 256 typedef struct { - uint32_t utf8_state; + uint8_t charset; + uint32_t utf8_state, *g0_charset, *g1_charset; Cursor cursor; bool mDECOM; bool mDECAWM; @@ -257,7 +258,8 @@ typedef struct { PyObject_HEAD unsigned int columns, lines, margin_top, margin_bottom; - uint32_t utf8_state; + uint8_t charset; + uint32_t utf8_state, *g0_charset, *g1_charset; Cursor *cursor; SavepointBuffer main_savepoints, alt_savepoints; PyObject *callbacks; @@ -369,10 +371,13 @@ void screen_delete_lines(Screen *self, unsigned int count/*=1*/); void screen_delete_characters(Screen *self, unsigned int count); void screen_erase_characters(Screen *self, unsigned int count); void screen_set_margins(Screen *self, unsigned int top, unsigned int bottom); +void screen_change_charset(Screen *, uint32_t to); +void screen_designate_charset(Screen *, uint32_t which, uint32_t as); void set_title(Screen *self, PyObject*); void set_icon(Screen *self, PyObject*); void set_dynamic_color(Screen *self, unsigned int code, PyObject*); void set_color_table_color(Screen *self, unsigned int code, PyObject*); +uint32_t* translation_table(uint32_t which); void screen_request_capabilities(Screen *, PyObject *); void report_device_attributes(Screen *self, unsigned int UNUSED mode, bool UNUSED secondary); void select_graphic_rendition(Screen *self, unsigned int *params, unsigned int count); diff --git a/kitty/parser.c b/kitty/parser.c index e834bdb57..ae2c1bbea 100644 --- a/kitty/parser.c +++ b/kitty/parser.c @@ -135,10 +135,12 @@ handle_normal_mode_char(Screen *screen, uint32_t ch, PyObject DUMP_UNUSED *dump_ CALL_SCREEN_HANDLER(screen_linefeed); case CR: CALL_SCREEN_HANDLER(screen_carriage_return); - case SO: - REPORT_ERROR("Unhandled charset change command (SO), ignoring"); break; case SI: - REPORT_ERROR("Unhandled charset change command (SI), ignoring"); break; + REPORT_COMMAND(screen_change_charset, 0); + screen_change_charset(screen, 0); break; + case SO: + REPORT_COMMAND(screen_change_charset, 1); + screen_change_charset(screen, 1); break; case IND: CALL_SCREEN_HANDLER(screen_index); case RI: @@ -164,7 +166,9 @@ handle_normal_mode_char(Screen *screen, uint32_t ch, PyObject DUMP_UNUSED *dump_ // Esc mode {{{ static inline void handle_esc_mode_char(Screen *screen, uint32_t ch, PyObject DUMP_UNUSED *dump_callback) { -#define CALL_ED(name) REPORT_COMMAND(name, ch); name(screen); SET_STATE(0); break; +#define CALL_ED(name) REPORT_COMMAND(name); name(screen); SET_STATE(0); +#define CALL_ED1(name, ch) REPORT_COMMAND(name, ch); name(screen, ch); SET_STATE(0); +#define CALL_ED2(name, a, b) REPORT_COMMAND(name, a, b); name(screen, a, b); SET_STATE(0); switch(screen->parser_buf_pos) { case 0: switch (ch) { @@ -175,23 +179,23 @@ handle_esc_mode_char(Screen *screen, uint32_t ch, PyObject DUMP_UNUSED *dump_cal case ESC_CSI: SET_STATE(CSI); break; case ESC_RIS: - CALL_ED(screen_reset); + CALL_ED(screen_reset); break; case ESC_IND: - CALL_ED(screen_index); + CALL_ED(screen_index); break; case ESC_NEL: - CALL_ED(screen_nel); + CALL_ED(screen_nel); break; case ESC_RI: - CALL_ED(screen_reverse_index); + CALL_ED(screen_reverse_index); break; case ESC_HTS: - CALL_ED(screen_set_tab_stop); + CALL_ED(screen_set_tab_stop); break; case ESC_DECSC: - CALL_ED(screen_save_cursor); + CALL_ED(screen_save_cursor); break; case ESC_DECRC: - CALL_ED(screen_restore_cursor); + CALL_ED(screen_restore_cursor); break; case ESC_DECPNM: - CALL_ED(screen_normal_keypad_mode); + CALL_ED(screen_normal_keypad_mode); break; case ESC_DECPAM: - CALL_ED(screen_alternate_keypad_mode); + CALL_ED(screen_alternate_keypad_mode); break; case '%': case '(': case ')': @@ -210,21 +214,42 @@ handle_esc_mode_char(Screen *screen, uint32_t ch, PyObject DUMP_UNUSED *dump_cal } break; default: - if ((screen->parser_buf[0] == '%' && ch == 'G') || ((screen->parser_buf[0] == '(' || screen->parser_buf[0] == ')') && ch == 'B')) { - // switch to utf-8 or ascii, since we are always in utf-8, ignore. - } else if (screen->parser_buf[0] == '#') { - if (ch == '8') { - screen_align(screen); - } else { - REPORT_ERROR("Unhandled Esc # code: 0x%x", ch); - } - } else { - REPORT_ERROR("Unhandled charset related escape code: 0x%x 0x%x", screen->parser_buf[0], ch); + switch(screen->parser_buf[0]) { + case '%': + switch(ch) { + case '@': + CALL_ED1(screen_change_charset, 0); break; + case 'G': + CALL_ED1(screen_change_charset, 2); break; + default: + REPORT_ERROR("Unhandled Esc %% code: 0x%x", ch); break; + } + break; + case '#': + if (ch == '8') { CALL_ED(screen_align); } + else { REPORT_ERROR("Unhandled Esc # code: 0x%x", ch); } + break; + case '(': + case ')': + switch(ch) { + case 'A': + case 'B': + case '0': + case 'U': + case 'V': + CALL_ED2(screen_designate_charset, screen->parser_buf[0], ch); + default: + REPORT_ERROR("Unknown charset: 0x%x", ch); break; + } + break; + default: + REPORT_ERROR("Unhandled charset related escape code: 0x%x 0x%x", screen->parser_buf[0], ch); break; } SET_STATE(0); break; } #undef CALL_ED +#undef CALL_ED1 } // }}} // OSC mode {{{ @@ -596,8 +621,8 @@ dispatch_unicode_char(Screen *screen, uint32_t codepoint, PyObject DUMP_UNUSED * #undef HANDLE } -static inline void -_parse_bytes(Screen *screen, uint8_t *buf, Py_ssize_t len, PyObject DUMP_UNUSED *dump_callback) { +static inline void +parse_utf8(Screen *screen, uint8_t *buf, Py_ssize_t len, PyObject DUMP_UNUSED *dump_callback) { uint32_t prev = screen->utf8_state, codepoint = 0; for (unsigned int i = 0; i < len; i++, prev = screen->utf8_state) { switch (decode_utf8(&screen->utf8_state, &codepoint, buf[i])) { @@ -610,6 +635,24 @@ _parse_bytes(Screen *screen, uint8_t *buf, Py_ssize_t len, PyObject DUMP_UNUSED break; } } + +} + +static inline void +_parse_bytes(Screen *screen, uint8_t *buf, Py_ssize_t len, PyObject DUMP_UNUSED *dump_callback) { +#define DECODE(charset) for (unsigned int i = 0; i < len; i++) dispatch_unicode_char(screen, screen->charset[buf[i]], dump_callback); + switch(screen->charset) { + case 0: + DECODE(g0_charset); + break; + case 1: + DECODE(g1_charset); + break; + default: + parse_utf8(screen, buf, len, dump_callback); + break; + } +#undef DECODE FLUSH_DRAW; } // }}} diff --git a/kitty/screen.c b/kitty/screen.c index 2e257615b..3f9ecc65b 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -23,6 +23,12 @@ init_tabstops(bool *tabstops, index_type count) { } } +#define RESET_CHARSETS \ + self->g0_charset = translation_table(0); \ + self->g1_charset = self->g0_charset; \ + self->charset = 2; \ + self->utf8_state = 0; + static PyObject* new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) { Screen *self; @@ -34,8 +40,8 @@ new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) { if (self != NULL) { self->columns = columns; self->lines = lines; self->modes = empty_modes; - self->utf8_state = 0; self->margin_top = 0; self->margin_bottom = self->lines - 1; + RESET_CHARSETS; self->callbacks = callbacks; Py_INCREF(callbacks); self->cursor = alloc_cursor(); self->main_linebuf = alloc_linebuf(lines, columns); self->alt_linebuf = alloc_linebuf(lines, columns); @@ -59,7 +65,7 @@ screen_reset(Screen *self) { if (self->linebuf == self->alt_linebuf) screen_toggle_screen_buffer(self); linebuf_clear(self->linebuf, ' '); self->modes = empty_modes; - self->utf8_state = 0; + RESET_CHARSETS; self->margin_top = 0; self->margin_bottom = self->lines - 1; screen_normal_keypad_mode(self); init_tabstops(self->main_tabstops, self->columns); @@ -145,6 +151,25 @@ dealloc(Screen* self) { // Draw text {{{ +void +screen_change_charset(Screen *self, uint32_t to) { + self->charset = to; + self->utf8_state = 0; +} + +void +screen_designate_charset(Screen *self, uint32_t which, uint32_t as) { + switch(which) { + case 0: + self->g0_charset = translation_table(as); + break; + case 1: + self->g1_charset = translation_table(as); + break; + // We dont care about default as this is guaranteed to only be called with correct which by the parser + } +} + static inline unsigned int safe_wcwidth(uint32_t ch) { int ans = wcwidth(ch); @@ -538,6 +563,12 @@ savepoints_pop(SavepointBuffer *self) { return self->buf + ((self->start_of_data + self->count) % SAVEPOINTS_SZ); } +#define COPY_CHARSETS(self, sp) \ + sp->utf8_state = self->utf8_state; \ + sp->g0_charset = self->g0_charset; \ + sp->g1_charset = self->g1_charset; \ + sp->charset = self->charset; \ + void screen_save_cursor(Screen *self) { SavepointBuffer *pts = self->linebuf == self->main_linebuf ? &self->main_savepoints : &self->alt_savepoints; @@ -546,7 +577,7 @@ screen_save_cursor(Screen *self) { sp->mDECOM = self->modes.mDECOM; sp->mDECAWM = self->modes.mDECAWM; sp->mDECSCNM = self->modes.mDECSCNM; - sp->utf8_state = self->utf8_state; + COPY_CHARSETS(self, sp); } void @@ -557,9 +588,10 @@ screen_restore_cursor(Screen *self) { screen_cursor_position(self, 1, 1); tracker_cursor_changed(self->change_tracker); screen_reset_mode(self, DECOM); + RESET_CHARSETS; screen_reset_mode(self, DECSCNM); } else { - self->utf8_state = sp->utf8_state; + COPY_CHARSETS(sp, self); set_mode_from_const(self, DECOM, sp->mDECOM); set_mode_from_const(self, DECAWM, sp->mDECAWM); set_mode_from_const(self, DECSCNM, sp->mDECSCNM); diff --git a/kitty_tests/parser.py b/kitty_tests/parser.py index 907b6aa06..f854204de 100644 --- a/kitty_tests/parser.py +++ b/kitty_tests/parser.py @@ -62,11 +62,11 @@ class TestParser(BaseTest): def test_esc_codes(self): s = self.create_screen() pb = partial(self.parse_bytes_dump, s) - pb('12\033Da', '12', ('screen_index', ord('D')), 'a') + pb('12\033Da', '12', ('screen_index',), 'a') self.ae(str(s.line(0)), '12 ') self.ae(str(s.line(1)), ' a ') pb('\033x', ('Unknown char after ESC: 0x%x' % ord('x'),)) - pb('\033c123', ('screen_reset', ord('c')), '123') + pb('\033c123', ('screen_reset', ), '123') self.ae(str(s.line(0)), '123 ') def test_csi_codes(self):