* Parse call with async handler support. * * Whether the stack state got preserved for the next call, is indicated by the return value: * - undefined (void): * all handlers were sync, no stack save, continue normally with next chunk * - Promise\ : * execution stopped a
(data: string | Uint8Array, promiseResult?: boolean)
| 423 | * and proper continuation of async parser handlers. |
| 424 | */ |
| 425 | public parse(data: string | Uint8Array, promiseResult?: boolean): void | Promise<boolean> { |
| 426 | let result: void | Promise<boolean>; |
| 427 | let cursorStartX = this._activeBuffer.x; |
| 428 | let cursorStartY = this._activeBuffer.y; |
| 429 | let start = 0; |
| 430 | const wasPaused = this._parseStack.paused; |
| 431 | |
| 432 | if (wasPaused) { |
| 433 | // assumption: _parseBuffer never mutates between async calls |
| 434 | if (result = this._parser.parse(this._parseBuffer, this._parseStack.decodedLength, promiseResult)) { |
| 435 | this._logSlowResolvingAsync(result); |
| 436 | return result; |
| 437 | } |
| 438 | cursorStartX = this._parseStack.cursorStartX; |
| 439 | cursorStartY = this._parseStack.cursorStartY; |
| 440 | this._parseStack.paused = false; |
| 441 | if (data.length > MAX_PARSEBUFFER_LENGTH) { |
| 442 | start = this._parseStack.position + MAX_PARSEBUFFER_LENGTH; |
| 443 | } |
| 444 | } |
| 445 | |
| 446 | // Log debug data, the log level gate is to prevent extra work in this hot path |
| 447 | if (this._logService.logLevel <= LogLevelEnum.DEBUG) { |
| 448 | this._logService.debug(`parsing data ${typeof data === 'string' ? ` "${data}"` : ` "${Array.prototype.map.call(data, e => String.fromCharCode(e)).join('')}"`}`); |
| 449 | } |
| 450 | if (this._logService.logLevel === LogLevelEnum.TRACE) { |
| 451 | this._logService.trace(`parsing data (codes)`, typeof data === 'string' |
| 452 | ? data.split('').map(e => e.charCodeAt(0)) |
| 453 | : data |
| 454 | ); |
| 455 | } |
| 456 | |
| 457 | // resize input buffer if needed |
| 458 | if (this._parseBuffer.length < data.length) { |
| 459 | if (this._parseBuffer.length < MAX_PARSEBUFFER_LENGTH) { |
| 460 | this._parseBuffer = new Uint32Array(Math.min(data.length, MAX_PARSEBUFFER_LENGTH)); |
| 461 | } |
| 462 | } |
| 463 | |
| 464 | // Clear the dirty row service so we know which lines changed as a result of parsing |
| 465 | // Important: do not clear between async calls, otherwise we lost pending update information. |
| 466 | if (!wasPaused) { |
| 467 | this._dirtyRowTracker.clearRange(); |
| 468 | } |
| 469 | |
| 470 | // process big data in smaller chunks |
| 471 | if (data.length > MAX_PARSEBUFFER_LENGTH) { |
| 472 | for (let i = start; i < data.length; i += MAX_PARSEBUFFER_LENGTH) { |
| 473 | const end = i + MAX_PARSEBUFFER_LENGTH < data.length ? i + MAX_PARSEBUFFER_LENGTH : data.length; |
| 474 | const len = (typeof data === 'string') |
| 475 | ? this._stringDecoder.decode(data.substring(i, end), this._parseBuffer) |
| 476 | : this._utf8Decoder.decode(data.subarray(i, end), this._parseBuffer); |
| 477 | if (result = this._parser.parse(this._parseBuffer, len)) { |
| 478 | this._preserveStack(cursorStartX, cursorStartY, len, i); |
| 479 | this._logSlowResolvingAsync(result); |
| 480 | return result; |
| 481 | } |
| 482 | } |
nothing calls this directly
no test coverage detected