mirror of
https://github.com/Microsoft/vscode
synced 2024-09-13 21:55:38 +00:00
fix #142537
This commit is contained in:
parent
a6dac4517b
commit
59e217e6be
|
@ -3,137 +3,68 @@
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { Terminal } from 'xterm';
|
import { notEqual, strictEqual, throws } from 'assert';
|
||||||
import { strictEqual } from 'assert';
|
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||||
import { timeout } from 'vs/base/common/async';
|
|
||||||
import * as sinon from 'sinon';
|
|
||||||
import { ShellIntegrationAddon } from 'vs/workbench/contrib/terminal/browser/xterm/shellIntegrationAddon';
|
|
||||||
import { ITerminalCapabilityStore, TerminalCapability } from 'vs/workbench/contrib/terminal/common/capabilities/capabilities';
|
|
||||||
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
||||||
import { ILogService, NullLogService } from 'vs/platform/log/common/log';
|
import { ILogService, NullLogService } from 'vs/platform/log/common/log';
|
||||||
|
import { DecorationAddon } from 'vs/workbench/contrib/terminal/browser/xterm/decorationAddon';
|
||||||
|
import { TerminalCapabilityStore } from 'vs/workbench/contrib/terminal/common/capabilities/terminalCapabilityStore';
|
||||||
|
import { ITerminalCommand } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||||
|
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
|
||||||
|
import { IDecoration, IDecorationOptions, Terminal } from 'xterm';
|
||||||
|
import { TerminalCapability } from 'vs/workbench/contrib/terminal/common/capabilities/capabilities';
|
||||||
|
import { CommandDetectionCapability } from 'vs/workbench/contrib/terminal/browser/capabilities/commandDetectionCapability';
|
||||||
|
|
||||||
async function writeP(terminal: Terminal, data: string): Promise<void> {
|
class TestTerminal extends Terminal {
|
||||||
return new Promise<void>((resolve, reject) => {
|
override registerDecoration(decorationOptions: IDecorationOptions): IDecoration | undefined {
|
||||||
const failTimeout = timeout(2000);
|
if (decorationOptions.marker.isDisposed) {
|
||||||
failTimeout.then(() => reject('Writing to xterm is taking longer than 2 seconds'));
|
return undefined;
|
||||||
terminal.write(data, () => {
|
}
|
||||||
failTimeout.cancel();
|
const element = document.createElement('div');
|
||||||
resolve();
|
return { marker: decorationOptions.marker, element, onDispose: () => { }, isDisposed: false, dispose: () => { }, onRender: (element: HTMLElement) => { return element; } } as unknown as IDecoration;
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
class TestShellIntegrationAddon extends ShellIntegrationAddon {
|
|
||||||
getCommandDetectionMock(terminal: Terminal): sinon.SinonMock {
|
|
||||||
const capability = super._createOrGetCommandDetection(terminal);
|
|
||||||
this.capabilities.add(TerminalCapability.CommandDetection, capability);
|
|
||||||
return sinon.mock(capability);
|
|
||||||
}
|
|
||||||
getCwdDectionMock(): sinon.SinonMock {
|
|
||||||
const capability = super._createOrGetCwdDetection();
|
|
||||||
this.capabilities.add(TerminalCapability.CwdDetection, capability);
|
|
||||||
return sinon.mock(capability);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suite('DecorationAddon', () => {
|
suite('DecorationAddon', () => {
|
||||||
let xterm: Terminal;
|
let decorationAddon: DecorationAddon;
|
||||||
let shellIntegrationAddon: TestShellIntegrationAddon;
|
let xterm: TestTerminal;
|
||||||
let capabilities: ITerminalCapabilityStore;
|
|
||||||
|
|
||||||
setup(() => {
|
setup(() => {
|
||||||
xterm = new Terminal({
|
const instantiationService = new TestInstantiationService();
|
||||||
|
const configurationService = new TestConfigurationService({
|
||||||
|
workbench: {
|
||||||
|
hover: { delay: 5 }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
xterm = new TestTerminal({
|
||||||
cols: 80,
|
cols: 80,
|
||||||
rows: 30
|
rows: 30
|
||||||
});
|
});
|
||||||
const instantiationService = new TestInstantiationService();
|
instantiationService.stub(IConfigurationService, configurationService);
|
||||||
|
const capabilities = new TerminalCapabilityStore();
|
||||||
|
capabilities.add(TerminalCapability.CommandDetection, new CommandDetectionCapability(xterm, new NullLogService()));
|
||||||
|
decorationAddon = instantiationService.createInstance(DecorationAddon, capabilities);
|
||||||
|
xterm.loadAddon(decorationAddon);
|
||||||
instantiationService.stub(ILogService, NullLogService);
|
instantiationService.stub(ILogService, NullLogService);
|
||||||
shellIntegrationAddon = instantiationService.createInstance(TestShellIntegrationAddon);
|
|
||||||
xterm.loadAddon(shellIntegrationAddon);
|
|
||||||
capabilities = shellIntegrationAddon.capabilities;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
suite('cwd detection', async () => {
|
suite('registerDecoration', async () => {
|
||||||
test('should activate capability on the cwd sequence (OSC 1337 ; CurrentDir=<cwd> ST)', async () => {
|
test('should throw when command has no marker', async () => {
|
||||||
strictEqual(capabilities.has(TerminalCapability.CwdDetection), false);
|
throws(() => decorationAddon.registerCommandDecoration({ command: 'cd src', timestamp: Date.now(), hasOutput: false } as ITerminalCommand));
|
||||||
await writeP(xterm, 'foo');
|
|
||||||
strictEqual(capabilities.has(TerminalCapability.CwdDetection), false);
|
|
||||||
await writeP(xterm, '\x1b]1337;CurrentDir=/foo\x07');
|
|
||||||
strictEqual(capabilities.has(TerminalCapability.CwdDetection), true);
|
|
||||||
});
|
});
|
||||||
test('should pass cwd sequence to the capability', async () => {
|
test('should return undefined when marker has been disposed of', async () => {
|
||||||
const mock = shellIntegrationAddon.getCwdDectionMock();
|
const marker = xterm.registerMarker(1);
|
||||||
mock.expects('updateCwd').once().withExactArgs('/foo');
|
marker?.dispose();
|
||||||
await writeP(xterm, '\x1b]1337;CurrentDir=/foo\x07');
|
strictEqual(decorationAddon.registerCommandDecoration({ command: 'cd src', marker, timestamp: Date.now(), hasOutput: false } as ITerminalCommand), undefined);
|
||||||
mock.verify();
|
|
||||||
});
|
});
|
||||||
});
|
test('should return undefined when command is just empty chars', async () => {
|
||||||
|
const marker = xterm.registerMarker(1);
|
||||||
suite('command tracking', async () => {
|
marker?.dispose();
|
||||||
test('should activate capability on the prompt start sequence (OSC 133 ; A ST)', async () => {
|
strictEqual(decorationAddon.registerCommandDecoration({ command: ' ', marker, timestamp: Date.now(), hasOutput: false } as ITerminalCommand), undefined);
|
||||||
strictEqual(capabilities.has(TerminalCapability.CommandDetection), false);
|
|
||||||
await writeP(xterm, 'foo');
|
|
||||||
strictEqual(capabilities.has(TerminalCapability.CommandDetection), false);
|
|
||||||
await writeP(xterm, '\x1b]133;A\x07');
|
|
||||||
strictEqual(capabilities.has(TerminalCapability.CommandDetection), true);
|
|
||||||
});
|
});
|
||||||
test('should pass prompt start sequence to the capability', async () => {
|
test('should return decoration when marker has not been disposed of', async () => {
|
||||||
const mock = shellIntegrationAddon.getCommandDetectionMock(xterm);
|
const marker = xterm.registerMarker(2);
|
||||||
mock.expects('handlePromptStart').once().withExactArgs();
|
notEqual(decorationAddon.registerCommandDecoration({ command: 'cd src', marker, timestamp: Date.now(), hasOutput: false } as ITerminalCommand), undefined);
|
||||||
await writeP(xterm, '\x1b]133;A\x07');
|
|
||||||
mock.verify();
|
|
||||||
});
|
|
||||||
test('should activate capability on the command start sequence (OSC 133 ; B ST)', async () => {
|
|
||||||
strictEqual(capabilities.has(TerminalCapability.CommandDetection), false);
|
|
||||||
await writeP(xterm, 'foo');
|
|
||||||
strictEqual(capabilities.has(TerminalCapability.CommandDetection), false);
|
|
||||||
await writeP(xterm, '\x1b]133;B\x07');
|
|
||||||
strictEqual(capabilities.has(TerminalCapability.CommandDetection), true);
|
|
||||||
});
|
|
||||||
test('should pass command start sequence to the capability', async () => {
|
|
||||||
const mock = shellIntegrationAddon.getCommandDetectionMock(xterm);
|
|
||||||
mock.expects('handleCommandStart').once().withExactArgs();
|
|
||||||
await writeP(xterm, '\x1b]133;B\x07');
|
|
||||||
mock.verify();
|
|
||||||
});
|
|
||||||
test('should activate capability on the command executed sequence (OSC 133 ; C ST)', async () => {
|
|
||||||
strictEqual(capabilities.has(TerminalCapability.CommandDetection), false);
|
|
||||||
await writeP(xterm, 'foo');
|
|
||||||
strictEqual(capabilities.has(TerminalCapability.CommandDetection), false);
|
|
||||||
await writeP(xterm, '\x1b]133;C\x07');
|
|
||||||
strictEqual(capabilities.has(TerminalCapability.CommandDetection), true);
|
|
||||||
});
|
|
||||||
test('should pass command executed sequence to the capability', async () => {
|
|
||||||
const mock = shellIntegrationAddon.getCommandDetectionMock(xterm);
|
|
||||||
mock.expects('handleCommandExecuted').once().withExactArgs();
|
|
||||||
await writeP(xterm, '\x1b]133;C\x07');
|
|
||||||
mock.verify();
|
|
||||||
});
|
|
||||||
test('should activate capability on the command finished sequence (OSC 133 ; D ; <ExitCode> ST)', async () => {
|
|
||||||
strictEqual(capabilities.has(TerminalCapability.CommandDetection), false);
|
|
||||||
await writeP(xterm, 'foo');
|
|
||||||
strictEqual(capabilities.has(TerminalCapability.CommandDetection), false);
|
|
||||||
await writeP(xterm, '\x1b]133;D;7\x07');
|
|
||||||
strictEqual(capabilities.has(TerminalCapability.CommandDetection), true);
|
|
||||||
});
|
|
||||||
test('should pass command finished sequence to the capability', async () => {
|
|
||||||
const mock = shellIntegrationAddon.getCommandDetectionMock(xterm);
|
|
||||||
mock.expects('handleCommandFinished').once().withExactArgs(7);
|
|
||||||
await writeP(xterm, '\x1b]133;D;7\x07');
|
|
||||||
mock.verify();
|
|
||||||
});
|
|
||||||
test('should not activate capability on the cwd sequence (OSC 1337 ; CurrentDir=<cwd> ST)', async () => {
|
|
||||||
strictEqual(capabilities.has(TerminalCapability.CommandDetection), false);
|
|
||||||
await writeP(xterm, 'foo');
|
|
||||||
strictEqual(capabilities.has(TerminalCapability.CommandDetection), false);
|
|
||||||
await writeP(xterm, '\x1b]1337;CurrentDir=/foo\x07');
|
|
||||||
strictEqual(capabilities.has(TerminalCapability.CommandDetection), false);
|
|
||||||
});
|
|
||||||
test('should pass cwd sequence to the capability if it\'s initialized', async () => {
|
|
||||||
const mock = shellIntegrationAddon.getCommandDetectionMock(xterm);
|
|
||||||
mock.expects('setCwd').once().withExactArgs('/foo');
|
|
||||||
await writeP(xterm, '\x1b]1337;CurrentDir=/foo\x07');
|
|
||||||
mock.verify();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue