comparison src/libvterm/src/parser.c @ 20488:1d595fada804 v8.2.0798

patch 8.2.0798: libvterm code lags behind the upstream version Commit: https://github.com/vim/vim/commit/be593bf135f6967335b14ba188bd5f8f32175c75 Author: Bram Moolenaar <Bram@vim.org> Date: Tue May 19 21:20:04 2020 +0200 patch 8.2.0798: libvterm code lags behind the upstream version Problem: Libvterm code lags behind the upstream version. Solution: Include revisions 755 - 758.
author Bram Moolenaar <Bram@vim.org>
date Tue, 19 May 2020 21:30:07 +0200
parents 1c75e1974313
children 55a373a243c0
comparison
equal deleted inserted replaced
20487:f4ada29cdf4b 20488:1d595fada804
21 21
22 static void do_csi(VTerm *vt, char command) 22 static void do_csi(VTerm *vt, char command)
23 { 23 {
24 #ifdef DEBUG_PARSER 24 #ifdef DEBUG_PARSER
25 printf("Parsed CSI args as:\n", arglen, args); 25 printf("Parsed CSI args as:\n", arglen, args);
26 printf(" leader: %s\n", vt->parser.csi_leader); 26 printf(" leader: %s\n", vt->parser.v.csi.leader);
27 for(int argi = 0; argi < vt->parser.csi_argi; argi++) { 27 for(int argi = 0; argi < vt->parser.v.csi.argi; argi++) {
28 printf(" %lu", CSI_ARG(vt->parser.csi_args[argi])); 28 printf(" %lu", CSI_ARG(vt->parser.v.csi.args[argi]));
29 if(!CSI_ARG_HAS_MORE(vt->parser.csi_args[argi])) 29 if(!CSI_ARG_HAS_MORE(vt->parser.v.csi.args[argi]))
30 printf("\n"); 30 printf("\n");
31 printf(" intermed: %s\n", vt->parser.intermed); 31 printf(" intermed: %s\n", vt->parser.intermed);
32 } 32 }
33 #endif 33 #endif
34 34
35 if(vt->parser.callbacks && vt->parser.callbacks->csi) 35 if(vt->parser.callbacks && vt->parser.callbacks->csi)
36 if((*vt->parser.callbacks->csi)( 36 if((*vt->parser.callbacks->csi)(
37 vt->parser.csi_leaderlen ? vt->parser.csi_leader : NULL, 37 vt->parser.v.csi.leaderlen ? vt->parser.v.csi.leader : NULL,
38 vt->parser.csi_args, 38 vt->parser.v.csi.args,
39 vt->parser.csi_argi, 39 vt->parser.v.csi.argi,
40 vt->parser.intermedlen ? vt->parser.intermed : NULL, 40 vt->parser.intermedlen ? vt->parser.intermed : NULL,
41 command, 41 command,
42 vt->parser.cbdata)) 42 vt->parser.cbdata))
43 return; 43 return;
44 44
59 return; 59 return;
60 60
61 DEBUG_LOG1("libvterm: Unhandled escape ESC 0x%02x\n", command); 61 DEBUG_LOG1("libvterm: Unhandled escape ESC 0x%02x\n", command);
62 } 62 }
63 63
64 static void append_strbuffer(VTerm *vt, const char *str, size_t len) 64 static void string_fragment(VTerm *vt, const char *str, size_t len, int final)
65 { 65 {
66 if(len > vt->parser.strbuffer_len - vt->parser.strbuffer_cur) { 66 VTermStringFragment frag;
67 len = vt->parser.strbuffer_len - vt->parser.strbuffer_cur; 67
68 DEBUG_LOG1("Truncating strbuffer preserve to %zu bytes\n", len); 68 frag.str = str;
69 frag.len = len;
70 frag.initial = vt->parser.string_initial;
71 frag.final = final;
72
73 switch(vt->parser.state) {
74 case OSC:
75 if(vt->parser.callbacks && vt->parser.callbacks->osc)
76 (*vt->parser.callbacks->osc)(vt->parser.v.osc.command, frag, vt->parser.cbdata);
77 break;
78
79 case DCS:
80 if(len && vt->parser.callbacks && vt->parser.callbacks->dcs)
81 (*vt->parser.callbacks->dcs)(vt->parser.v.dcs.command, vt->parser.v.dcs.commandlen, frag, vt->parser.cbdata);
82 break;
83
84 case NORMAL:
85 case CSI_LEADER:
86 case CSI_ARGS:
87 case CSI_INTERMED:
88 case OSC_COMMAND:
89 case DCS_COMMAND:
90 break;
69 } 91 }
70 92
71 if(len > 0) { 93 vt->parser.string_initial = FALSE;
72 strncpy(vt->parser.strbuffer + vt->parser.strbuffer_cur, str, len);
73 vt->parser.strbuffer_cur += len;
74 }
75 }
76
77 static void start_string(VTerm *vt, VTermParserStringType type)
78 {
79 vt->parser.stringtype = type;
80
81 vt->parser.strbuffer_cur = 0;
82 }
83
84 static void more_string(VTerm *vt, const char *str, size_t len)
85 {
86 append_strbuffer(vt, str, len);
87 }
88
89 static void done_string(VTerm *vt, const char *str, size_t len)
90 {
91 if(vt->parser.strbuffer_cur) {
92 if(str)
93 append_strbuffer(vt, str, len);
94
95 str = vt->parser.strbuffer;
96 len = vt->parser.strbuffer_cur;
97 }
98 else if(!str) {
99 DEBUG_LOG("parser.c: TODO: No strbuffer _and_ no final fragment???\n");
100 len = 0;
101 }
102
103 switch(vt->parser.stringtype) {
104 case VTERM_PARSER_OSC:
105 if(vt->parser.callbacks && vt->parser.callbacks->osc)
106 if((*vt->parser.callbacks->osc)(str, len, vt->parser.cbdata))
107 return;
108
109 DEBUG_LOG2("libvterm: Unhandled OSC %.*s\n", (int)len, str);
110 return;
111
112 case VTERM_PARSER_DCS:
113 if(vt->parser.callbacks && vt->parser.callbacks->dcs)
114 if((*vt->parser.callbacks->dcs)(str, len, vt->parser.cbdata))
115 return;
116
117 DEBUG_LOG2("libvterm: Unhandled DCS %.*s\n", (int)len, str);
118 return;
119
120 case VTERM_N_PARSER_TYPES:
121 return;
122 }
123 } 94 }
124 95
125 size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len) 96 size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len)
126 { 97 {
127 size_t pos = 0; 98 size_t pos = 0;
133 switch(vt->parser.state) { 104 switch(vt->parser.state) {
134 case NORMAL: 105 case NORMAL:
135 case CSI_LEADER: 106 case CSI_LEADER:
136 case CSI_ARGS: 107 case CSI_ARGS:
137 case CSI_INTERMED: 108 case CSI_INTERMED:
138 case ESC: 109 case OSC_COMMAND:
110 case DCS_COMMAND:
139 string_start = NULL; 111 string_start = NULL;
140 break; 112 break;
141 case STRING: 113 case OSC:
142 case ESC_IN_STRING: 114 case DCS:
143 string_start = bytes; 115 string_start = bytes;
144 break; 116 break;
145 } 117 }
146 118
147 #define ENTER_STRING_STATE() do { vt->parser.state = STRING; string_start = bytes + pos + 1; } while(0)
148 #define ENTER_STATE(st) do { vt->parser.state = st; string_start = NULL; } while(0) 119 #define ENTER_STATE(st) do { vt->parser.state = st; string_start = NULL; } while(0)
149 #define ENTER_NORMAL_STATE() ENTER_STATE(NORMAL) 120 #define ENTER_NORMAL_STATE() ENTER_STATE(NORMAL)
150 121
151 for( ; pos < len; pos++) { 122 for( ; pos < len; pos++) {
152 unsigned char c = bytes[pos]; 123 unsigned char c = bytes[pos];
124 int c1_allowed = !vt->mode.utf8;
125 size_t string_len;
153 126
154 if(c == 0x00 || c == 0x7f) { // NUL, DEL 127 if(c == 0x00 || c == 0x7f) { // NUL, DEL
155 if(vt->parser.state >= STRING) { 128 if(vt->parser.state >= OSC) {
156 more_string(vt, string_start, bytes + pos - string_start); 129 string_fragment(vt, string_start, bytes + pos - string_start, FALSE);
157 string_start = bytes + pos + 1; 130 string_start = bytes + pos + 1;
158 } 131 }
159 continue; 132 continue;
160 } 133 }
161 if(c == 0x18 || c == 0x1a) { // CAN, SUB 134 if(c == 0x18 || c == 0x1a) { // CAN, SUB
135 vt->parser.in_esc = FALSE;
162 ENTER_NORMAL_STATE(); 136 ENTER_NORMAL_STATE();
163 continue; 137 continue;
164 } 138 }
165 else if(c == 0x1b) { // ESC 139 else if(c == 0x1b) { // ESC
166 vt->parser.intermedlen = 0; 140 vt->parser.intermedlen = 0;
167 if(vt->parser.state == STRING) 141 if(vt->parser.state < OSC)
168 vt->parser.state = ESC_IN_STRING; 142 vt->parser.state = NORMAL;
169 else 143 vt->parser.in_esc = TRUE;
170 ENTER_STATE(ESC);
171 continue; 144 continue;
172 } 145 }
173 else if(c == 0x07 && // BEL, can stand for ST in OSC or DCS state 146 else if(c == 0x07 && // BEL, can stand for ST in OSC or DCS state
174 vt->parser.state == STRING) { 147 vt->parser.state >= OSC) {
175 // fallthrough 148 // fallthrough
176 } 149 }
177 else if(c < 0x20) { // other C0 150 else if(c < 0x20) { // other C0
178 if(vterm_get_special_pty_type() == 2) { 151 if(vterm_get_special_pty_type() == 2) {
179 if(c == 0x08) // BS 152 if(c == 0x08) // BS
180 // Set the trick for BS output after a sequence, to delay backspace 153 // Set the trick for BS output after a sequence, to delay backspace
181 // activation 154 // activation
182 if(pos + 2 < len && bytes[pos + 1] == 0x20 && bytes[pos + 2] == 0x08) 155 if(pos + 2 < len && bytes[pos + 1] == 0x20 && bytes[pos + 2] == 0x08)
183 vt->in_backspace = 2; // Trigger when count down to 1 156 vt->in_backspace = 2; // Trigger when count down to 1
184 } 157 }
185 if(vt->parser.state >= STRING) 158 if(vt->parser.state >= OSC)
186 more_string(vt, string_start, bytes + pos - string_start); 159 string_fragment(vt, string_start, bytes + pos - string_start, FALSE);
187 do_control(vt, c); 160 do_control(vt, c);
188 if(vt->parser.state >= STRING) 161 if(vt->parser.state >= OSC)
189 string_start = bytes + pos + 1; 162 string_start = bytes + pos + 1;
190 continue; 163 continue;
191 } 164 }
192 // else fallthrough 165 // else fallthrough
193 166
167 string_len = bytes + pos - string_start;
168
169 if(vt->parser.in_esc) {
170 // Hoist an ESC letter into a C1 if we're not in a string mode
171 // Always accept ESC \ == ST even in string mode
172 if(!vt->parser.intermedlen &&
173 c >= 0x40 && c < 0x60 &&
174 ((vt->parser.state < OSC || c == 0x5c))) {
175 c += 0x40;
176 c1_allowed = TRUE;
177 string_len -= 1;
178 vt->parser.in_esc = FALSE;
179 }
180 else {
181 string_start = NULL;
182 vt->parser.state = NORMAL;
183 }
184 }
185
194 switch(vt->parser.state) { 186 switch(vt->parser.state) {
195 case ESC_IN_STRING:
196 if(c == 0x5c) { // ST
197 vt->parser.state = STRING;
198 done_string(vt, string_start, bytes + pos - string_start - 1);
199 ENTER_NORMAL_STATE();
200 break;
201 }
202 vt->parser.state = ESC;
203 // else fallthrough
204
205 case ESC:
206 switch(c) {
207 case 0x50: // DCS
208 start_string(vt, VTERM_PARSER_DCS);
209 ENTER_STRING_STATE();
210 break;
211 case 0x5b: // CSI
212 vt->parser.csi_leaderlen = 0;
213 ENTER_STATE(CSI_LEADER);
214 break;
215 case 0x5d: // OSC
216 start_string(vt, VTERM_PARSER_OSC);
217 ENTER_STRING_STATE();
218 break;
219 default:
220 if(is_intermed(c)) {
221 if(vt->parser.intermedlen < INTERMED_MAX-1)
222 vt->parser.intermed[vt->parser.intermedlen++] = c;
223 }
224 else if(!vt->parser.intermedlen && c >= 0x40 && c < 0x60) {
225 do_control(vt, c + 0x40);
226 ENTER_NORMAL_STATE();
227 }
228 else if(c >= 0x30 && c < 0x7f) {
229 do_escape(vt, c);
230 ENTER_NORMAL_STATE();
231 }
232 else {
233 DEBUG_LOG1("TODO: Unhandled byte %02x in Escape\n", c);
234 }
235 }
236 break;
237
238 case CSI_LEADER: 187 case CSI_LEADER:
239 // Extract leader bytes 0x3c to 0x3f 188 // Extract leader bytes 0x3c to 0x3f
240 if(c >= 0x3c && c <= 0x3f) { 189 if(c >= 0x3c && c <= 0x3f) {
241 if(vt->parser.csi_leaderlen < CSI_LEADER_MAX-1) 190 if(vt->parser.v.csi.leaderlen < CSI_LEADER_MAX-1)
242 vt->parser.csi_leader[vt->parser.csi_leaderlen++] = c; 191 vt->parser.v.csi.leader[vt->parser.v.csi.leaderlen++] = c;
243 break; 192 break;
244 } 193 }
245 194
246 // else fallthrough 195 // else fallthrough
247 vt->parser.csi_leader[vt->parser.csi_leaderlen] = 0; 196 vt->parser.v.csi.leader[vt->parser.v.csi.leaderlen] = 0;
248 197
249 vt->parser.csi_argi = 0; 198 vt->parser.v.csi.argi = 0;
250 vt->parser.csi_args[0] = CSI_ARG_MISSING; 199 vt->parser.v.csi.args[0] = CSI_ARG_MISSING;
251 vt->parser.state = CSI_ARGS; 200 vt->parser.state = CSI_ARGS;
252 201
253 // fallthrough 202 // fallthrough
254 case CSI_ARGS: 203 case CSI_ARGS:
255 // Numerical value of argument 204 // Numerical value of argument
256 if(c >= '0' && c <= '9') { 205 if(c >= '0' && c <= '9') {
257 if(vt->parser.csi_args[vt->parser.csi_argi] == CSI_ARG_MISSING) 206 if(vt->parser.v.csi.args[vt->parser.v.csi.argi] == CSI_ARG_MISSING)
258 vt->parser.csi_args[vt->parser.csi_argi] = 0; 207 vt->parser.v.csi.args[vt->parser.v.csi.argi] = 0;
259 vt->parser.csi_args[vt->parser.csi_argi] *= 10; 208 vt->parser.v.csi.args[vt->parser.v.csi.argi] *= 10;
260 vt->parser.csi_args[vt->parser.csi_argi] += c - '0'; 209 vt->parser.v.csi.args[vt->parser.v.csi.argi] += c - '0';
261 break; 210 break;
262 } 211 }
263 if(c == ':') { 212 if(c == ':') {
264 vt->parser.csi_args[vt->parser.csi_argi] |= CSI_ARG_FLAG_MORE; 213 vt->parser.v.csi.args[vt->parser.v.csi.argi] |= CSI_ARG_FLAG_MORE;
265 c = ';'; 214 c = ';';
266 } 215 }
267 if(c == ';') { 216 if(c == ';') {
268 vt->parser.csi_argi++; 217 vt->parser.v.csi.argi++;
269 vt->parser.csi_args[vt->parser.csi_argi] = CSI_ARG_MISSING; 218 vt->parser.v.csi.args[vt->parser.v.csi.argi] = CSI_ARG_MISSING;
270 break; 219 break;
271 } 220 }
272 221
273 // else fallthrough 222 // else fallthrough
274 vt->parser.csi_argi++; 223 vt->parser.v.csi.argi++;
275 vt->parser.intermedlen = 0; 224 vt->parser.intermedlen = 0;
276 vt->parser.state = CSI_INTERMED; 225 vt->parser.state = CSI_INTERMED;
277 // fallthrough 226 // fallthrough
278 case CSI_INTERMED: 227 case CSI_INTERMED:
279 if(is_intermed(c)) { 228 if(is_intermed(c)) {
291 // else was invalid CSI 240 // else was invalid CSI
292 241
293 ENTER_NORMAL_STATE(); 242 ENTER_NORMAL_STATE();
294 break; 243 break;
295 244
296 case STRING: 245 case OSC_COMMAND:
297 if(c == 0x07 || (c == 0x9c && !vt->mode.utf8)) { 246 /* Numerical value of command */
298 done_string(vt, string_start, bytes + pos - string_start); 247 if(c >= '0' && c <= '9') {
248 if(vt->parser.v.osc.command == -1)
249 vt->parser.v.osc.command = 0;
250 else
251 vt->parser.v.osc.command *= 10;
252 vt->parser.v.osc.command += c - '0';
253 break;
254 }
255 if(c == ';') {
256 vt->parser.state = OSC;
257 string_start = bytes + pos + 1;
258 break;
259 }
260
261 /* else fallthrough */
262 string_start = bytes + pos;
263 vt->parser.state = OSC;
264 goto string_state;
265
266 case DCS_COMMAND:
267 if(vt->parser.v.dcs.commandlen < CSI_LEADER_MAX)
268 vt->parser.v.dcs.command[vt->parser.v.dcs.commandlen++] = c;
269
270 if(c >= 0x40 && c<= 0x7e) {
271 string_start = bytes + pos + 1;
272 vt->parser.state = DCS;
273 }
274 break;
275
276 string_state:
277 case OSC:
278 case DCS:
279 if(c == 0x07 || (c1_allowed && c == 0x9c)) {
280 string_fragment(vt, string_start, string_len, TRUE);
299 ENTER_NORMAL_STATE(); 281 ENTER_NORMAL_STATE();
300 } 282 }
301 else if (pos + 1 == len) {
302 // end of input but OSC string isn't finished yet, copy it to
303 // vt->parser.strbuffer to continue it later
304 more_string(vt, string_start, bytes + pos + 1 - string_start);
305 }
306 break; 283 break;
307 284
308 case NORMAL: 285 case NORMAL:
309 if(c >= 0x80 && c < 0xa0 && !vt->mode.utf8) { 286 if(vt->parser.in_esc) {
287 if(is_intermed(c)) {
288 if(vt->parser.intermedlen < INTERMED_MAX-1)
289 vt->parser.intermed[vt->parser.intermedlen++] = c;
290 }
291 else if(c >= 0x30 && c < 0x7f) {
292 do_escape(vt, c);
293 vt->parser.in_esc = 0;
294 ENTER_NORMAL_STATE();
295 }
296 else {
297 DEBUG_LOG1("TODO: Unhandled byte %02x in Escape\n", c);
298 }
299 break;
300 }
301 if(c1_allowed && c >= 0x80 && c < 0xa0) {
310 switch(c) { 302 switch(c) {
311 case 0x90: // DCS 303 case 0x90: // DCS
312 start_string(vt, VTERM_PARSER_DCS); 304 vt->parser.string_initial = TRUE;
313 ENTER_STRING_STATE(); 305 vt->parser.v.dcs.commandlen = 0;
306 ENTER_STATE(DCS_COMMAND);
314 break; 307 break;
315 case 0x9b: // CSI 308 case 0x9b: // CSI
309 vt->parser.v.csi.leaderlen = 0;
316 ENTER_STATE(CSI_LEADER); 310 ENTER_STATE(CSI_LEADER);
317 break; 311 break;
318 case 0x9d: // OSC 312 case 0x9d: // OSC
319 start_string(vt, VTERM_PARSER_OSC); 313 vt->parser.v.osc.command = -1;
320 ENTER_STRING_STATE(); 314 vt->parser.string_initial = TRUE;
315 ENTER_STATE(OSC_COMMAND);
321 break; 316 break;
322 default: 317 default:
323 do_control(vt, c); 318 do_control(vt, c);
324 break; 319 break;
325 } 320 }
339 } 334 }
340 break; 335 break;
341 } 336 }
342 } 337 }
343 338
339 if(string_start)
340 string_fragment(vt, string_start, bytes + pos - string_start, FALSE);
341
344 return len; 342 return len;
345 } 343 }
346 344
347 void vterm_parser_set_callbacks(VTerm *vt, const VTermParserCallbacks *callbacks, void *user) 345 void vterm_parser_set_callbacks(VTerm *vt, const VTermParserCallbacks *callbacks, void *user)
348 { 346 {