@codingame/monaco-vscode-extensions-service-override
Version:
VSCode public API plugged on the monaco editor - extensions service-override
412 lines (409 loc) • 21.7 kB
JavaScript
import { __decorate, __param } from 'vscode/external/tslib/tslib.es6.js';
import { DisposableStore, MutableDisposable, combinedDisposable, Disposable } from 'vscode/vscode/vs/base/common/lifecycle';
import { ExtHostContext, MainContext } from 'vscode/vscode/vs/workbench/api/common/extHost.protocol';
import { extHostNamedCustomer } from '../../services/extensions/common/extHostCustomers.js';
import { URI } from 'vscode/vscode/vs/base/common/uri';
import { IInstantiationService } from 'vscode/vscode/vs/platform/instantiation/common/instantiation';
import { ILogService } from 'vscode/vscode/vs/platform/log/common/log.service';
import { TerminalLocation, TerminalExitReason, ProcessPropertyType } from 'vscode/vscode/vs/platform/terminal/common/terminal';
import { TerminalDataBufferer } from 'vscode/vscode/vs/platform/terminal/common/terminalDataBuffering';
import { ITerminalService, ITerminalGroupService, ITerminalEditorService } from 'vscode/vscode/vs/workbench/contrib/terminal/browser/terminal.service';
import { TerminalProcessExtHostProxy } from 'vscode/vscode/vs/workbench/contrib/terminal/browser/terminalProcessExtHostProxy';
import { IEnvironmentVariableService } from 'vscode/vscode/vs/workbench/contrib/terminal/common/environmentVariable.service';
import { serializeEnvironmentVariableCollection, deserializeEnvironmentVariableCollection, deserializeEnvironmentDescriptionMap } from 'vscode/vscode/vs/platform/terminal/common/environmentVariableShared';
import { ITerminalProfileResolverService, ITerminalProfileService } from 'vscode/vscode/vs/workbench/contrib/terminal/common/terminal.service';
import { IRemoteAgentService } from 'vscode/vscode/vs/workbench/services/remote/common/remoteAgentService.service';
import { OS } from 'vscode/vscode/vs/base/common/platform';
import { Promises } from 'vscode/vscode/vs/base/common/async';
import { ITerminalLinkProviderService } from 'vscode/vscode/vs/workbench/contrib/terminalContrib/links/browser/links.service';
import { TerminalQuickFixType } from 'vscode/vscode/vs/workbench/contrib/terminalContrib/quickFix/browser/quickFix';
import { ITerminalQuickFixService } from 'vscode/vscode/vs/workbench/contrib/terminalContrib/quickFix/browser/quickFix.service';
import { TerminalCapability } from 'vscode/vscode/vs/platform/terminal/common/capabilities/capabilities';
let MainThreadTerminalService = class MainThreadTerminalService {
constructor(_extHostContext, _terminalService, _terminalLinkProviderService, _terminalQuickFixService, _instantiationService, _environmentVariableService, _logService, _terminalProfileResolverService, remoteAgentService, _terminalGroupService, _terminalEditorService, _terminalProfileService) {
this._extHostContext = _extHostContext;
this._terminalService = _terminalService;
this._terminalLinkProviderService = _terminalLinkProviderService;
this._terminalQuickFixService = _terminalQuickFixService;
this._instantiationService = _instantiationService;
this._environmentVariableService = _environmentVariableService;
this._logService = _logService;
this._terminalProfileResolverService = _terminalProfileResolverService;
this._terminalGroupService = _terminalGroupService;
this._terminalEditorService = _terminalEditorService;
this._terminalProfileService = _terminalProfileService;
this._store = ( new DisposableStore());
this._extHostTerminals = ( new Map());
this._terminalProcessProxies = ( new Map());
this._profileProviders = ( new Map());
this._quickFixProviders = ( new Map());
this._dataEventTracker = ( new MutableDisposable());
this._sendCommandEventListener = ( new MutableDisposable());
this._linkProvider = this._store.add(( new MutableDisposable()));
this._os = OS;
this._proxy = ( _extHostContext.getProxy(ExtHostContext.ExtHostTerminalService));
this._store.add(_terminalService.onDidCreateInstance((instance) => {
this._onTerminalOpened(instance);
this._onInstanceDimensionsChanged(instance);
}));
this._store.add(_terminalService.onDidDisposeInstance(instance => this._onTerminalDisposed(instance)));
this._store.add(_terminalService.onAnyInstanceProcessIdReady(instance => this._onTerminalProcessIdReady(instance)));
this._store.add(_terminalService.onDidChangeInstanceDimensions(instance => this._onInstanceDimensionsChanged(instance)));
this._store.add(_terminalService.onAnyInstanceMaximumDimensionsChange(instance => this._onInstanceMaximumDimensionsChanged(instance)));
this._store.add(_terminalService.onDidRequestStartExtensionTerminal(e => this._onRequestStartExtensionTerminal(e)));
this._store.add(_terminalService.onDidChangeActiveInstance(instance => this._onActiveTerminalChanged(instance ? instance.instanceId : null)));
this._store.add(_terminalService.onAnyInstanceTitleChange(instance => instance && this._onTitleChanged(instance.instanceId, instance.title)));
this._store.add(_terminalService.onAnyInstanceDataInput(instance => this._proxy.$acceptTerminalInteraction(instance.instanceId)));
this._store.add(_terminalService.onAnyInstanceSelectionChange(instance => this._proxy.$acceptTerminalSelection(instance.instanceId, instance.selection)));
for (const instance of this._terminalService.instances) {
this._onTerminalOpened(instance);
instance.processReady.then(() => this._onTerminalProcessIdReady(instance));
}
const activeInstance = this._terminalService.activeInstance;
if (activeInstance) {
this._proxy.$acceptActiveTerminalChanged(activeInstance.instanceId);
}
if (this._environmentVariableService.collections.size > 0) {
const collectionAsArray = [...this._environmentVariableService.collections.entries()];
const serializedCollections = ( collectionAsArray.map(e => {
return [e[0], serializeEnvironmentVariableCollection(e[1].map)];
}));
this._proxy.$initEnvironmentVariableCollections(serializedCollections);
}
remoteAgentService.getEnvironment().then(async (env) => {
this._os = env?.os || OS;
this._updateDefaultProfile();
});
this._store.add(this._terminalProfileService.onDidChangeAvailableProfiles(() => this._updateDefaultProfile()));
}
dispose() {
this._store.dispose();
for (const provider of ( this._profileProviders.values())) {
provider.dispose();
}
for (const provider of ( this._quickFixProviders.values())) {
provider.dispose();
}
}
async _updateDefaultProfile() {
const remoteAuthority = this._extHostContext.remoteAuthority ?? undefined;
const defaultProfile = this._terminalProfileResolverService.getDefaultProfile({ remoteAuthority, os: this._os });
const defaultAutomationProfile = this._terminalProfileResolverService.getDefaultProfile({ remoteAuthority, os: this._os, allowAutomationShell: true });
this._proxy.$acceptDefaultProfile(...(await Promise.all([defaultProfile, defaultAutomationProfile])));
}
async _getTerminalInstance(id) {
if (typeof id === 'string') {
return this._extHostTerminals.get(id);
}
return this._terminalService.getInstanceFromId(id);
}
async $createTerminal(extHostTerminalId, launchConfig) {
const shellLaunchConfig = {
name: launchConfig.name,
executable: launchConfig.shellPath,
args: launchConfig.shellArgs,
cwd: typeof launchConfig.cwd === 'string' ? launchConfig.cwd : URI.revive(launchConfig.cwd),
icon: launchConfig.icon,
color: launchConfig.color,
initialText: launchConfig.initialText,
waitOnExit: launchConfig.waitOnExit,
ignoreConfigurationCwd: true,
env: launchConfig.env,
strictEnv: launchConfig.strictEnv,
hideFromUser: launchConfig.hideFromUser,
customPtyImplementation: launchConfig.isExtensionCustomPtyTerminal
? (id, cols, rows) => ( new TerminalProcessExtHostProxy(id, cols, rows, this._terminalService))
: undefined,
extHostTerminalId,
forceShellIntegration: launchConfig.forceShellIntegration,
isFeatureTerminal: launchConfig.isFeatureTerminal,
isExtensionOwnedTerminal: launchConfig.isExtensionOwnedTerminal,
useShellEnvironment: launchConfig.useShellEnvironment,
isTransient: launchConfig.isTransient
};
const terminal = Promises.withAsyncBody(async (r) => {
const terminal = await this._terminalService.createTerminal({
config: shellLaunchConfig,
location: await this._deserializeParentTerminal(launchConfig.location)
});
r(terminal);
});
this._extHostTerminals.set(extHostTerminalId, terminal);
const terminalInstance = await terminal;
this._store.add(terminalInstance.onDisposed(() => {
this._extHostTerminals.delete(extHostTerminalId);
}));
}
async _deserializeParentTerminal(location) {
if (typeof location === 'object' && 'parentTerminal' in location) {
const parentTerminal = await this._extHostTerminals.get(( location.parentTerminal.toString()));
return parentTerminal ? { parentTerminal } : undefined;
}
return location;
}
async $show(id, preserveFocus) {
const terminalInstance = await this._getTerminalInstance(id);
if (terminalInstance) {
this._terminalService.setActiveInstance(terminalInstance);
if (terminalInstance.target === TerminalLocation.Editor) {
await this._terminalEditorService.revealActiveEditor(preserveFocus);
}
else {
await this._terminalGroupService.showPanel(!preserveFocus);
}
}
}
async $hide(id) {
const instanceToHide = await this._getTerminalInstance(id);
const activeInstance = this._terminalService.activeInstance;
if (activeInstance && activeInstance.instanceId === instanceToHide?.instanceId && activeInstance.target !== TerminalLocation.Editor) {
this._terminalGroupService.hidePanel();
}
}
async $dispose(id) {
(await this._getTerminalInstance(id))?.dispose(TerminalExitReason.Extension);
}
async $sendText(id, text, shouldExecute) {
const instance = await this._getTerminalInstance(id);
await instance?.sendText(text, shouldExecute);
}
$sendProcessExit(terminalId, exitCode) {
this._terminalProcessProxies.get(terminalId)?.emitExit(exitCode);
}
$startSendingDataEvents() {
if (!this._dataEventTracker.value) {
this._dataEventTracker.value = this._instantiationService.createInstance(TerminalDataEventTracker, (id, data) => {
this._onTerminalData(id, data);
});
for (const instance of this._terminalService.instances) {
for (const data of instance.initialDataEvents || []) {
this._onTerminalData(instance.instanceId, data);
}
}
}
}
$stopSendingDataEvents() {
this._dataEventTracker.clear();
}
$startSendingCommandEvents() {
if (this._sendCommandEventListener.value) {
return;
}
const multiplexer = this._terminalService.createOnInstanceCapabilityEvent(TerminalCapability.CommandDetection, capability => capability.onCommandFinished);
const sub = multiplexer.event(e => {
this._onDidExecuteCommand(e.instance.instanceId, {
commandLine: e.data.command,
cwd: e.data.cwd,
exitCode: e.data.exitCode,
output: e.data.getOutput()
});
});
this._sendCommandEventListener.value = combinedDisposable(multiplexer, sub);
}
$stopSendingCommandEvents() {
this._sendCommandEventListener.clear();
}
$startLinkProvider() {
this._linkProvider.value = this._terminalLinkProviderService.registerLinkProvider(( new ExtensionTerminalLinkProvider(this._proxy)));
}
$stopLinkProvider() {
this._linkProvider.clear();
}
$registerProcessSupport(isSupported) {
this._terminalService.registerProcessSupport(isSupported);
}
$registerProfileProvider(id, extensionIdentifier) {
this._profileProviders.set(id, this._terminalProfileService.registerTerminalProfileProvider(extensionIdentifier, id, {
createContributedTerminalProfile: async (options) => {
return this._proxy.$createContributedProfileTerminal(id, options);
}
}));
}
$unregisterProfileProvider(id) {
this._profileProviders.get(id)?.dispose();
this._profileProviders.delete(id);
}
async $registerQuickFixProvider(id, extensionId) {
this._quickFixProviders.set(id, this._terminalQuickFixService.registerQuickFixProvider(id, {
provideTerminalQuickFixes: async (terminalCommand, lines, options, token) => {
if (token.isCancellationRequested) {
return;
}
if (options.outputMatcher?.length && options.outputMatcher.length > 40) {
options.outputMatcher.length = 40;
this._logService.warn('Cannot exceed output matcher length of 40');
}
const commandLineMatch = terminalCommand.command.match(options.commandLineMatcher);
if (!commandLineMatch || !lines) {
return;
}
const outputMatcher = options.outputMatcher;
let outputMatch;
if (outputMatcher) {
outputMatch = getOutputMatchForLines(lines, outputMatcher);
}
if (!outputMatch) {
return;
}
const matchResult = { commandLineMatch, outputMatch, commandLine: terminalCommand.command };
if (matchResult) {
const result = await this._proxy.$provideTerminalQuickFixes(id, matchResult, token);
if (result && Array.isArray(result)) {
return ( result.map(r => parseQuickFix(id, extensionId, r)));
}
else if (result) {
return parseQuickFix(id, extensionId, result);
}
}
return;
}
}));
}
$unregisterQuickFixProvider(id) {
this._quickFixProviders.get(id)?.dispose();
this._quickFixProviders.delete(id);
}
_onActiveTerminalChanged(terminalId) {
this._proxy.$acceptActiveTerminalChanged(terminalId);
}
_onTerminalData(terminalId, data) {
this._proxy.$acceptTerminalProcessData(terminalId, data);
}
_onDidExecuteCommand(terminalId, command) {
this._proxy.$acceptDidExecuteCommand(terminalId, command);
}
_onTitleChanged(terminalId, name) {
this._proxy.$acceptTerminalTitleChange(terminalId, name);
}
_onTerminalDisposed(terminalInstance) {
this._proxy.$acceptTerminalClosed(terminalInstance.instanceId, terminalInstance.exitCode, terminalInstance.exitReason ?? TerminalExitReason.Unknown);
}
_onTerminalOpened(terminalInstance) {
const extHostTerminalId = terminalInstance.shellLaunchConfig.extHostTerminalId;
const shellLaunchConfigDto = {
name: terminalInstance.shellLaunchConfig.name,
executable: terminalInstance.shellLaunchConfig.executable,
args: terminalInstance.shellLaunchConfig.args,
cwd: terminalInstance.shellLaunchConfig.cwd,
env: terminalInstance.shellLaunchConfig.env,
hideFromUser: terminalInstance.shellLaunchConfig.hideFromUser
};
this._proxy.$acceptTerminalOpened(terminalInstance.instanceId, extHostTerminalId, terminalInstance.title, shellLaunchConfigDto);
}
_onTerminalProcessIdReady(terminalInstance) {
if (terminalInstance.processId === undefined) {
return;
}
this._proxy.$acceptTerminalProcessId(terminalInstance.instanceId, terminalInstance.processId);
}
_onInstanceDimensionsChanged(instance) {
this._proxy.$acceptTerminalDimensions(instance.instanceId, instance.cols, instance.rows);
}
_onInstanceMaximumDimensionsChanged(instance) {
this._proxy.$acceptTerminalMaximumDimensions(instance.instanceId, instance.maxCols, instance.maxRows);
}
_onRequestStartExtensionTerminal(request) {
const proxy = request.proxy;
this._terminalProcessProxies.set(proxy.instanceId, proxy);
const initialDimensions = request.cols && request.rows ? {
columns: request.cols,
rows: request.rows
} : undefined;
this._proxy.$startExtensionTerminal(proxy.instanceId, initialDimensions).then(request.callback);
proxy.onInput(data => this._proxy.$acceptProcessInput(proxy.instanceId, data));
proxy.onShutdown(immediate => this._proxy.$acceptProcessShutdown(proxy.instanceId, immediate));
proxy.onRequestCwd(() => this._proxy.$acceptProcessRequestCwd(proxy.instanceId));
proxy.onRequestInitialCwd(() => this._proxy.$acceptProcessRequestInitialCwd(proxy.instanceId));
}
$sendProcessData(terminalId, data) {
this._terminalProcessProxies.get(terminalId)?.emitData(data);
}
$sendProcessReady(terminalId, pid, cwd, windowsPty) {
this._terminalProcessProxies.get(terminalId)?.emitReady(pid, cwd, windowsPty);
}
$sendProcessProperty(terminalId, property) {
if (property.type === ProcessPropertyType.Title) {
const instance = this._terminalService.getInstanceFromId(terminalId);
instance?.rename(property.value);
}
this._terminalProcessProxies.get(terminalId)?.emitProcessProperty(property);
}
$setEnvironmentVariableCollection(extensionIdentifier, persistent, collection, descriptionMap) {
if (collection) {
const translatedCollection = {
persistent,
map: deserializeEnvironmentVariableCollection(collection),
descriptionMap: deserializeEnvironmentDescriptionMap(descriptionMap)
};
this._environmentVariableService.set(extensionIdentifier, translatedCollection);
}
else {
this._environmentVariableService.delete(extensionIdentifier);
}
}
};
MainThreadTerminalService = __decorate([
extHostNamedCustomer(MainContext.MainThreadTerminalService),
( __param(1, ITerminalService)),
( __param(2, ITerminalLinkProviderService)),
( __param(3, ITerminalQuickFixService)),
( __param(4, IInstantiationService)),
( __param(5, IEnvironmentVariableService)),
( __param(6, ILogService)),
( __param(7, ITerminalProfileResolverService)),
( __param(8, IRemoteAgentService)),
( __param(9, ITerminalGroupService)),
( __param(10, ITerminalEditorService)),
( __param(11, ITerminalProfileService))
], MainThreadTerminalService);
let TerminalDataEventTracker = class TerminalDataEventTracker extends Disposable {
constructor(_callback, _terminalService) {
super();
this._callback = _callback;
this._terminalService = _terminalService;
this._register(this._bufferer = ( new TerminalDataBufferer(this._callback)));
for (const instance of this._terminalService.instances) {
this._registerInstance(instance);
}
this._register(this._terminalService.onDidCreateInstance(instance => this._registerInstance(instance)));
this._register(this._terminalService.onDidDisposeInstance(instance => this._bufferer.stopBuffering(instance.instanceId)));
}
_registerInstance(instance) {
this._register(this._bufferer.startBuffering(instance.instanceId, instance.onData));
}
};
TerminalDataEventTracker = ( __decorate([
( __param(1, ITerminalService))
], TerminalDataEventTracker));
class ExtensionTerminalLinkProvider {
constructor(_proxy) {
this._proxy = _proxy;
}
async provideLinks(instance, line) {
const proxy = this._proxy;
const extHostLinks = await proxy.$provideLinks(instance.instanceId, line);
return ( extHostLinks.map(dto => ({
id: dto.id,
startIndex: dto.startIndex,
length: dto.length,
label: dto.label,
activate: () => proxy.$activateLink(instance.instanceId, dto.id)
})));
}
}
function getOutputMatchForLines(lines, outputMatcher) {
const match = lines.join('\n').match(outputMatcher.lineMatcher);
return match ? { regexMatch: match, outputLines: lines } : undefined;
}
function parseQuickFix(id, source, fix) {
let type = TerminalQuickFixType.TerminalCommand;
if ('uri' in fix) {
fix.uri = URI.revive(fix.uri);
type = TerminalQuickFixType.Opener;
}
else if ('id' in fix) {
type = TerminalQuickFixType.VscodeCommand;
}
return { id, type, source, ...fix };
}
export { MainThreadTerminalService, getOutputMatchForLines };