Files
vscode/src/vs/platform/terminal/common/capabilities/partialCommandDetectionCapability.ts
T
Matt BiernerandGitHub 5e92794be6 Re-enable running our eslint rules using ts-node (#159495)
Resubmission of #157532 with the following changes:

- Use `eslint-plugin-local` instead of `yarn` link to run our plugins
- Move our plugins to a top level `.eslintplugin` dir (as required by `eslint-plugin-local`)
- Update all names to `local/`
2022-08-30 08:40:04 +02:00

78 lines
2.5 KiB
TypeScript

/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Emitter } from 'vs/base/common/event';
import { IPartialCommandDetectionCapability, TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities';
// Importing types is safe in any layer
// eslint-disable-next-line local/code-import-patterns
import { IMarker, Terminal } from 'xterm-headless';
const enum Constants {
/**
* The minimum size of the prompt in which to assume the line is a command.
*/
MinimumPromptLength = 2
}
/**
* This capability guesses where commands are based on where the cursor was when enter was pressed.
* It's very hit or miss but it's often correct and better than nothing.
*/
export class PartialCommandDetectionCapability implements IPartialCommandDetectionCapability {
readonly type = TerminalCapability.PartialCommandDetection;
private readonly _commands: IMarker[] = [];
get commands(): readonly IMarker[] { return this._commands; }
private readonly _onCommandFinished = new Emitter<IMarker>();
readonly onCommandFinished = this._onCommandFinished.event;
constructor(
private readonly _terminal: Terminal,
) {
this._terminal.onData(e => this._onData(e));
this._terminal.parser.registerCsiHandler({ final: 'J' }, params => {
if (params.length >= 1 && (params[0] === 2 || params[0] === 3)) {
this._clearCommandsInViewport();
}
// We don't want to override xterm.js' default behavior, just augment it
return false;
});
}
private _onData(data: string): void {
if (data === '\x0d') {
this._onEnter();
}
}
private _onEnter(): void {
if (!this._terminal) {
return;
}
if (this._terminal.buffer.active.cursorX >= Constants.MinimumPromptLength) {
const marker = this._terminal.registerMarker(0);
if (marker) {
this._commands.push(marker);
this._onCommandFinished.fire(marker);
}
}
}
private _clearCommandsInViewport(): void {
// Find the number of commands on the tail end of the array that are within the viewport
let count = 0;
for (let i = this._commands.length - 1; i >= 0; i--) {
if (this._commands[i].line < this._terminal.buffer.active.baseY) {
break;
}
count++;
}
// Remove them
this._commands.splice(this._commands.length - count, count);
}
}