Mercurial > vim
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 { |