this._logService.debug('CommandDetectionCapability#handleCommandStart', this._currentCommand.commandStartX, this._currentCommand.commandStartMarker?.line); } <del> private _handleCommandStartWindows(): void { </del> <ins> private async _handleCommandStartWindows(): Promise<void> { </ins> this._currentCommand.commandStartX = this._terminal.buffer.active.cursorX; // On Windows track all cursor movements after the command start sequence this._commandMarkers.length = 0; <del> // HACK: Fire command started on the following frame on Windows to allow the cursor // position to update as conpty often prints the sequence on a different line to the // actual line the command started on. timeout(0).then(() => { if (!this._currentCommand.commandExecutedMarker) { this._onCursorMoveListener = this._terminal.onCursorMove(() => { if (this._commandMarkers.length === 0 || this._commandMarkers[this._commandMarkers.length - 1].line !== this._terminal.buffer.active.cursorY) { const marker = this._terminal.registerMarker(0); if (marker) { this._commandMarkers.push(marker); } } }); </del> <ins> const lastCommand = this.commands.at(-1); function cursorOnCorrectLine(terminal: Terminal): boolean { if (!lastCommand) { return false; </ins> } <del> this._currentCommand.commandStartMarker = this._terminal.registerMarker(0); if (this._currentCommand.commandStartMarker) { const line = this._terminal.buffer.active.getLine(this._currentCommand.commandStartMarker.line); if (line) { this._currentCommand.commandStartLineContent = line.translateToString(true); </del> <ins> const cursorYAbsolute = terminal.buffer.active.baseY + terminal.buffer.active.cursorY; // If the cursor position is within the last command, we should poll. const lastCommandYAbsolute = (lastCommand.endMarker ? lastCommand.endMarker.line : lastCommand.marker?.line) ?? -1; return cursorYAbsolute > lastCommandYAbsolute; } function lineIsPrompt(terminal: Terminal): boolean { const line = terminal.buffer.active.getLine(terminal.buffer.active.baseY + terminal.buffer.active.cursorY); if (!line) { return false; } // TODO: fine tune prompt regex to accomodate for unique configurtions. return line.translateToString(true)?.match(/^(PS.+>)|([A-Z]:.*>)/) !== null; } // Conpty could have the wrong cursor position at this point. if (!cursorOnCorrectLine(this._terminal) || !lineIsPrompt(this._terminal)) { // Poll for 200ms until the cursor position is correct. for (let i = 0; i < 20; i++) { await timeout(10); if (cursorOnCorrectLine(this._terminal) && lineIsPrompt(this._terminal)) { this._logService.debug('CommandDetectionCapability#_handleCommandStartWindows polling attempts required: ', i + 1); break; </ins> } } <del> this._onCommandStarted.fire({ marker: this._currentCommand.commandStartMarker } as ITerminalCommand); this._logService.debug('CommandDetectionCapability#_handleCommandStartWindows', this._currentCommand.commandStartX, this._currentCommand.commandStartMarker?.line); }); </del> <ins> } else { // HACK: Fire command started on the following frame on Windows to allow the cursor // position to update as conpty often prints the sequence on a different line to the // actual line the command started on. await timeout(0); } if (!this._currentCommand.commandExecutedMarker) { this._onCursorMoveListener = this._terminal.onCursorMove(() => { if (this._commandMarkers.length === 0 || this._commandMarkers[this._commandMarkers.length - 1].line !== this._terminal.buffer.active.cursorY) { const marker = this._terminal.registerMarker(0); if (marker) { this._commandMarkers.push(marker); } } }); } this._currentCommand.commandStartMarker = this._terminal.registerMarker(0); if (this._currentCommand.commandStartMarker) { const line = this._terminal.buffer.active.getLine(this._currentCommand.commandStartMarker.line); if (line) { this._currentCommand.commandStartLineContent = line.translateToString(true); } } this._onCommandStarted.fire({ marker: this._currentCommand.commandStartMarker } as ITerminalCommand); this._logService.debug('CommandDetectionCapability#_handleCommandStartWindows', this._currentCommand.commandStartX, this._currentCommand.commandStartMarker?.line); </ins> } handleGenericCommand(options?: IHandleCommandOptions): void {