VS Code merge to df8fe74bd55313de0dd2303bc47a4aab0ca56b0e (#17979)

* Merge from vscode 504f934659740e9d41501cad9f162b54d7745ad9

* delete unused folders

* distro

* Bump build node version

* update chokidar

* FIx hygiene errors

* distro

* Fix extension lint issues

* Remove strict-vscode

* Add copyright header exemptions

* Bump vscode-extension-telemetry to fix webpacking issue with zone.js

* distro

* Fix failing tests (revert marked.js back to current one until we decide to update)

* Skip searchmodel test

* Fix mac build

* temp debug script loading

* Try disabling coverage

* log error too

* Revert "log error too"

This reverts commit af0183e5d4ab458fdf44b88fbfab9908d090526f.

* Revert "temp debug script loading"

This reverts commit 3d687d541c76db2c5b55626c78ae448d3c25089c.

* Add comments explaining coverage disabling

* Fix ansi_up loading issue

* Merge latest from ads

* Use newer option

* Fix compile

* add debug logging warn

* Always log stack

* log more

* undo debug

* Update to use correct base path (+cleanup)

* distro

* fix compile errors

* Remove strict-vscode

* Fix sql editors not showing

* Show db dropdown input & fix styling

* Fix more info in gallery

* Fix gallery asset requests

* Delete unused workflow

* Fix tapable resolutions for smoke test compile error

* Fix smoke compile

* Disable crash reporting

* Disable interactive

Co-authored-by: ADS Merger <karlb@microsoft.com>
This commit is contained in:
Charles Gagnon
2022-01-06 09:06:56 -08:00
committed by GitHub
parent fd2736b6a6
commit 2bc6a0cd01
2099 changed files with 79520 additions and 43813 deletions

View File

@@ -1,20 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { isWeb } from 'vs/base/common/platform';
if (isWeb) {
CommandsRegistry.registerCommand('_workbench.fetchJSON', async function (accessor: ServicesAccessor, url: string, method: string) {
const result = await fetch(url, { method, headers: { Accept: 'application/json' } });
if (result.ok) {
return result.json();
} else {
throw new Error(result.statusText);
}
});
}

View File

@@ -66,6 +66,7 @@ import './mainThreadNotebook';
import './mainThreadNotebookKernels';
import './mainThreadNotebookDocumentsAndEditors';
import './mainThreadNotebookRenderers';
import './mainThreadInteractive';
import './mainThreadTask';
import './mainThreadLabelService';
import './mainThreadTunnelService';
@@ -73,8 +74,6 @@ import './mainThreadAuthentication';
import './mainThreadTimeline';
import './mainThreadTesting';
import './mainThreadSecretState';
import 'vs/workbench/api/common/apiCommands';
import 'vs/workbench/api/browser/apiCommands';
export class ExtensionPoints implements IWorkbenchContribution {

View File

@@ -16,6 +16,13 @@ import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { fromNow } from 'vs/base/common/date';
import { ActivationKind, IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
interface TrustedExtensionsQuickPickItem {
label: string;
description: string;
extension: AllowedExtension;
}
export class MainThreadAuthenticationProvider extends Disposable {
constructor(
@@ -38,7 +45,7 @@ export class MainThreadAuthenticationProvider extends Disposable {
return;
}
const quickPick = this.quickInputService.createQuickPick<{ label: string, description: string, extension: AllowedExtension }>();
const quickPick = this.quickInputService.createQuickPick<TrustedExtensionsQuickPickItem>();
quickPick.canSelectMany = true;
quickPick.customButton = true;
quickPick.customLabel = nls.localize('manageTrustedExtensions.cancel', 'Cancel');
@@ -60,12 +67,23 @@ export class MainThreadAuthenticationProvider extends Disposable {
quickPick.placeholder = nls.localize('manageExensions', "Choose which extensions can access this account");
quickPick.onDidAccept(() => {
const updatedAllowedList = quickPick.selectedItems.map(item => item.extension);
const updatedAllowedList = quickPick.items
.map(i => (i as TrustedExtensionsQuickPickItem).extension);
this.storageService.store(`${this.id}-${accountName}`, JSON.stringify(updatedAllowedList), StorageScope.GLOBAL, StorageTarget.USER);
quickPick.dispose();
});
quickPick.onDidChangeSelection((changed) => {
quickPick.items.forEach(item => {
if ((item as TrustedExtensionsQuickPickItem).extension) {
(item as TrustedExtensionsQuickPickItem).extension.allowed = false;
}
});
changed.forEach((item) => item.extension.allowed = true);
});
quickPick.onDidHide(() => {
quickPick.dispose();
});
@@ -126,7 +144,8 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
@IStorageService private readonly storageService: IStorageService,
@INotificationService private readonly notificationService: INotificationService,
@IQuickInputService private readonly quickInputService: IQuickInputService,
@IExtensionService private readonly extensionService: IExtensionService
@IExtensionService private readonly extensionService: IExtensionService,
@ITelemetryService private readonly telemetryService: ITelemetryService
) {
super();
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostAuthentication);
@@ -135,14 +154,6 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
this._proxy.$onDidChangeAuthenticationSessions(e.providerId, e.label);
}));
this._register(this.authenticationService.onDidRegisterAuthenticationProvider(info => {
this._proxy.$onDidChangeAuthenticationProviders([info], []);
}));
this._register(this.authenticationService.onDidUnregisterAuthenticationProvider(info => {
this._proxy.$onDidChangeAuthenticationProviders([], [info]);
}));
this._proxy.$setProviders(this.authenticationService.declaredProviders);
this._register(this.authenticationService.onDidChangeDeclaredProviders(e => {
@@ -170,13 +181,17 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
$removeSession(providerId: string, sessionId: string): Promise<void> {
return this.authenticationService.removeSession(providerId, sessionId);
}
private async loginPrompt(providerName: string, extensionName: string): Promise<boolean> {
private async loginPrompt(providerName: string, extensionName: string, recreatingSession: boolean, detail?: string): Promise<boolean> {
const message = recreatingSession
? nls.localize('confirmRelogin', "The extension '{0}' wants you to sign in again using {1}.", extensionName, providerName)
: nls.localize('confirmLogin', "The extension '{0}' wants to sign in using {1}.", extensionName, providerName);
const { choice } = await this.dialogService.show(
Severity.Info,
nls.localize('confirmLogin', "The extension '{0}' wants to sign in using {1}.", extensionName, providerName),
message,
[nls.localize('allow', "Allow"), nls.localize('cancel', "Cancel")],
{
cancelId: 1
cancelId: 1,
detail
}
);
@@ -227,12 +242,17 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
return this.authenticationService.selectSession(providerId, extensionId, extensionName, scopes, potentialSessions);
}
async $getSession(providerId: string, scopes: string[], extensionId: string, extensionName: string, options: { createIfNone: boolean, clearSessionPreference: boolean }): Promise<modes.AuthenticationSession | undefined> {
async $getSession(providerId: string, scopes: string[], extensionId: string, extensionName: string, options: { createIfNone: boolean, forceNewSession: boolean | { detail: string }, clearSessionPreference: boolean }): Promise<modes.AuthenticationSession | undefined> {
const sessions = await this.authenticationService.getSessions(providerId, scopes, true);
let silent = !options.createIfNone;
if (options.forceNewSession && !sessions.length) {
throw new Error('No existing sessions found.');
}
const silent = !options.createIfNone;
let session: modes.AuthenticationSession | undefined;
if (sessions.length) {
// Ignore existing sessions if we are forceRecreating
if (!options.forceNewSession && sessions.length) {
if (!this.authenticationService.supportsMultipleAccounts(providerId)) {
session = sessions[0];
const allowed = this.authenticationService.isAccessAllowed(providerId, session.account.label, extensionId);
@@ -253,9 +273,11 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
return this.selectSession(providerId, extensionId, extensionName, scopes, sessions, !!options.clearSessionPreference, silent);
}
} else {
if (!silent) {
const providerName = await this.authenticationService.getLabel(providerId);
const isAllowed = await this.loginPrompt(providerName, extensionName);
// If we are forceRecreating, we need to show the prompt.
if (options.forceNewSession || !silent) {
const providerName = this.authenticationService.getLabel(providerId);
const detail = (typeof options.forceNewSession === 'object') ? options.forceNewSession!.detail : undefined;
const isAllowed = await this.loginPrompt(providerName, extensionName, !!options.forceNewSession, detail);
if (!isAllowed) {
throw new Error('User did not consent to login.');
}
@@ -268,6 +290,12 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
}
if (session) {
type AuthProviderUsageClassification = {
extensionId: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
providerId: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
};
this.telemetryService.publicLog2<{ extensionId: string, providerId: string }, AuthProviderUsageClassification>('authentication.providerUsage', { providerId, extensionId });
addAccountUsage(this.storageService, providerId, session.account.label, extensionId, extensionName);
}

View File

@@ -12,6 +12,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
import { CLIOutput, IExtensionGalleryService, IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { ExtensionManagementCLIService } from 'vs/platform/extensionManagement/common/extensionManagementCLIService';
import { getExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { IExtensionManifest } from 'vs/platform/extensions/common/extensions';
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { ILabelService } from 'vs/platform/label/common/label';
@@ -21,7 +22,6 @@ import { IOpenWindowOptions, IWindowOpenable } from 'vs/platform/windows/common/
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { IExtensionManagementServerService } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
import { IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService';
import { IExtensionManifest } from 'vs/workbench/workbench.web.api';
// this class contains the commands that the CLI server is reying on

View File

@@ -23,6 +23,7 @@ import { ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneCont
import { Codicon } from 'vs/base/common/codicons';
import { registerIcon } from 'vs/platform/theme/common/iconRegistry';
import { localize } from 'vs/nls';
import { MarshalledId } from 'vs/base/common/marshalling';
export class MainThreadCommentThread implements modes.CommentThread {
@@ -154,7 +155,7 @@ export class MainThreadCommentThread implements modes.CommentThread {
toJSON(): any {
return {
$mid: 7,
$mid: MarshalledId.CommentThread,
commentControlHandle: this.controllerHandle,
commentThreadHandle: this.commentThreadHandle,
};
@@ -347,7 +348,7 @@ export class MainThreadCommentController {
toJSON(): any {
return {
$mid: 6,
$mid: MarshalledId.CommentController,
handle: this.handle
};
}

View File

@@ -23,7 +23,8 @@ import { IUndoRedoService, UndoRedoElementType } from 'vs/platform/undoRedo/comm
import { MainThreadWebviewPanels } from 'vs/workbench/api/browser/mainThreadWebviewPanels';
import { MainThreadWebviews, reviveWebviewExtension } from 'vs/workbench/api/browser/mainThreadWebviews';
import * as extHostProtocol from 'vs/workbench/api/common/extHost.protocol';
import { editorGroupToViewColumn, IRevertOptions, ISaveOptions } from 'vs/workbench/common/editor';
import { IRevertOptions, ISaveOptions } from 'vs/workbench/common/editor';
import { editorGroupToColumn } from 'vs/workbench/services/editor/common/editorGroupColumn';
import { CustomEditorInput } from 'vs/workbench/contrib/customEditor/browser/customEditorInput';
import { CustomDocumentBackupData } from 'vs/workbench/contrib/customEditor/browser/customEditorInputFactory';
import { ICustomEditorModel, ICustomEditorService } from 'vs/workbench/contrib/customEditor/common/customEditor';
@@ -195,7 +196,7 @@ export class MainThreadCustomEditors extends Disposable implements extHostProtoc
title: webviewInput.getTitle(),
webviewOptions: webviewInput.webview.contentOptions,
panelOptions: webviewInput.webview.options,
}, editorGroupToViewColumn(this._editorGroupService, webviewInput.group || 0), cancellation);
}, editorGroupToColumn(this._editorGroupService, webviewInput.group || 0), cancellation);
} catch (error) {
onUnexpectedError(error);
webviewInput.webview.html = this.mainThreadWebview.getWebviewResolvedFailedContent(viewType);

View File

@@ -5,7 +5,7 @@
import { DisposableStore } from 'vs/base/common/lifecycle';
import { URI as uri, UriComponents } from 'vs/base/common/uri';
import { IDebugService, IConfig, IDebugConfigurationProvider, IBreakpoint, IFunctionBreakpoint, IBreakpointData, IDebugAdapter, IDebugAdapterDescriptorFactory, IDebugSession, IDebugAdapterFactory, IDataBreakpoint, IDebugSessionOptions } from 'vs/workbench/contrib/debug/common/debug';
import { IDebugService, IConfig, IDebugConfigurationProvider, IBreakpoint, IFunctionBreakpoint, IBreakpointData, IDebugAdapter, IDebugAdapterDescriptorFactory, IDebugSession, IDebugAdapterFactory, IDataBreakpoint, IDebugSessionOptions, IInstructionBreakpoint } from 'vs/workbench/contrib/debug/common/debug';
import {
ExtHostContext, ExtHostDebugServiceShape, MainThreadDebugServiceShape, DebugSessionUUID, MainContext,
IExtHostContext, IBreakpointsDeltaDto, ISourceMultiBreakpointDto, ISourceBreakpointDto, IFunctionBreakpointDto, IDebugSessionDto, IDataBreakpointDto, IStartDebuggingOptions, IDebugConfiguration
@@ -226,8 +226,10 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
const debugOptions: IDebugSessionOptions = {
noDebug: options.noDebug,
parentSession,
lifecycleManagedByParent: options.lifecycleManagedByParent,
repl: options.repl,
compact: options.compact,
debugUI: options.debugUI,
compoundRoot: parentSession?.compoundRoot
};
return this.debugService.startDebugging(launch, nameOrConfig, debugOptions).then(success => {
@@ -337,7 +339,7 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
return undefined;
}
private convertToDto(bps: (ReadonlyArray<IBreakpoint | IFunctionBreakpoint | IDataBreakpoint>)): Array<ISourceBreakpointDto | IFunctionBreakpointDto | IDataBreakpointDto> {
private convertToDto(bps: (ReadonlyArray<IBreakpoint | IFunctionBreakpoint | IDataBreakpoint | IInstructionBreakpoint>)): Array<ISourceBreakpointDto | IFunctionBreakpointDto | IDataBreakpointDto> {
return bps.map(bp => {
if ('name' in bp) {
const fbp = <IFunctionBreakpoint>bp;

View File

@@ -20,7 +20,8 @@ import { MainThreadTextEditor } from 'vs/workbench/api/browser/mainThreadEditor'
import { MainThreadTextEditors } from 'vs/workbench/api/browser/mainThreadEditors';
import { ExtHostContext, ExtHostDocumentsAndEditorsShape, IDocumentsAndEditorsDelta, IExtHostContext, IModelAddedData, ITextEditorAddData, MainContext } from 'vs/workbench/api/common/extHost.protocol';
import { BaseTextEditor } from 'vs/workbench/browser/parts/editor/textEditor';
import { editorGroupToViewColumn, EditorGroupColumn, IEditorPane } from 'vs/workbench/common/editor';
import { IEditorPane } from 'vs/workbench/common/editor';
import { EditorGroupColumn, editorGroupToColumn } from 'vs/workbench/services/editor/common/editorGroupColumn';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
@@ -414,7 +415,7 @@ export class MainThreadDocumentsAndEditors {
private _findEditorPosition(editor: MainThreadTextEditor): EditorGroupColumn | undefined {
for (const editorPane of this._editorService.visibleEditorPanes) {
if (editor.matches(editorPane)) {
return editorGroupToViewColumn(this._editorGroupService, editorPane.group);
return editorGroupToColumn(this._editorGroupService, editorPane.group);
}
}
return undefined;

View File

@@ -14,12 +14,12 @@ import { ISelection } from 'vs/editor/common/core/selection';
import { IDecorationOptions, IDecorationRenderOptions, ILineChange } from 'vs/editor/common/editorCommon';
import { ISingleEditOperation } from 'vs/editor/common/model';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { ITextEditorOptions, IResourceEditorInput, EditorActivation, EditorOverride } from 'vs/platform/editor/common/editor';
import { ITextEditorOptions, IResourceEditorInput, EditorActivation, EditorResolution } from 'vs/platform/editor/common/editor';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { MainThreadDocumentsAndEditors } from 'vs/workbench/api/browser/mainThreadDocumentsAndEditors';
import { MainThreadTextEditor } from 'vs/workbench/api/browser/mainThreadEditor';
import { ExtHostContext, ExtHostEditorsShape, IApplyEditsOptions, IExtHostContext, ITextDocumentShowOptions, ITextEditorConfigurationUpdate, ITextEditorPositionData, IUndoStopOptions, MainThreadTextEditorsShape, TextEditorRevealType, IWorkspaceEditDto, WorkspaceEditType } from 'vs/workbench/api/common/extHost.protocol';
import { editorGroupToViewColumn, EditorGroupColumn, viewColumnToEditorGroup } from 'vs/workbench/common/editor';
import { editorGroupToColumn, columnToEditorGroup, EditorGroupColumn } from 'vs/workbench/services/editor/common/editorGroupColumn';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
@@ -27,6 +27,7 @@ import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/wo
import { revive } from 'vs/base/common/marshalling';
import { ResourceNotebookCellEdit } from 'vs/workbench/contrib/bulkEdit/browser/bulkCellEdits';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { NotebookDto } from 'vs/workbench/api/browser/mainThreadNotebookDto';
import { INotebookService } from 'sql/workbench/services/notebook/browser/notebookService'; // {{SQL CARBON EDIT}}
export function reviveWorkspaceEditDto2(data: IWorkspaceEditDto | undefined): ResourceEdit[] {
@@ -41,7 +42,7 @@ export function reviveWorkspaceEditDto2(data: IWorkspaceEditDto | undefined): Re
} else if (edit._type === WorkspaceEditType.Text) {
result.push(new ResourceTextEdit(edit.resource, edit.edit, edit.modelVersionId, edit.metadata));
} else if (edit._type === WorkspaceEditType.Cell) {
result.push(new ResourceNotebookCellEdit(edit.resource, edit.edit, edit.notebookVersionId, edit.metadata));
result.push(new ResourceNotebookCellEdit(edit.resource, NotebookDto.fromCellEditOperationDto(edit.edit), edit.notebookVersionId, edit.metadata));
}
}
return result;
@@ -127,7 +128,7 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
for (let editorPane of this._editorService.visibleEditorPanes) {
const id = this._documentsAndEditors.findTextEditorIdFor(editorPane);
if (id) {
result[id] = editorGroupToViewColumn(this._editorGroupService, editorPane.group);
result[id] = editorGroupToColumn(this._editorGroupService, editorPane.group);
}
}
return result;
@@ -147,7 +148,7 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
// preserve pre 1.38 behaviour to not make group active when preserveFocus: true
// but make sure to restore the editor to fix https://github.com/microsoft/vscode/issues/79633
activation: options.preserveFocus ? EditorActivation.RESTORE : undefined,
override: notebookFileTypes?.some(ext => uri?.fsPath?.toLowerCase().endsWith(ext)) || uri?.fsPath?.toLowerCase().endsWith('.sql') ? undefined : EditorOverride.DISABLED // {{SQL CARBON EDIT}}
override: notebookFileTypes?.some(ext => uri?.fsPath?.toLowerCase().endsWith(ext)) || uri?.fsPath?.toLowerCase().endsWith('.sql') ? undefined : EditorResolution.DISABLED // {{SQL CARBON EDIT}}
};
const input: IResourceEditorInput = {
@@ -155,7 +156,7 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
options: editorOptions
};
const editor = await this._editorService.openEditor(input, viewColumnToEditorGroup(this._editorGroupService, options.position));
const editor = await this._editorService.openEditor(input, columnToEditorGroup(this._editorGroupService, options.position));
if (!editor) {
return undefined;
}
@@ -169,7 +170,7 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
await this._editorService.openEditor({
resource: model.uri,
options: { preserveFocus: false }
}, viewColumnToEditorGroup(this._editorGroupService, position));
}, columnToEditorGroup(this._editorGroupService, position));
return;
}
}

View File

@@ -51,7 +51,7 @@ export class MainThreadFileSystemEventService {
changed: [],
deleted: []
};
this._listener.add(fileService.onDidFilesChange(event => {
this._listener.add(fileService.onDidChangeFilesRaw(event => {
for (let change of event.changes) {
switch (change.type) {
case FileChangeType.ADDED:

View File

@@ -0,0 +1,36 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { DisposableStore } from 'vs/base/common/lifecycle';
import { ExtHostContext, ExtHostInteractiveShape, IExtHostContext, MainThreadInteractiveShape } from 'vs/workbench/api/common/extHost.protocol'; // {{SQL CARBON EDIT}} Disable unused
// import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; {{SQL CARBON EDIT}} Disable unused
import { IInteractiveDocumentService } from 'vs/workbench/contrib/interactive/browser/interactiveDocumentService';
// @extHostNamedCustomer(MainContext.MainThreadInteractive)
export class MainThreadInteractive implements MainThreadInteractiveShape {
private readonly _proxy: ExtHostInteractiveShape;
private readonly _disposables = new DisposableStore();
constructor(
extHostContext: IExtHostContext,
@IInteractiveDocumentService interactiveDocumentService: IInteractiveDocumentService
) {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostInteractive);
this._disposables.add(interactiveDocumentService.onWillAddInteractiveDocument((e) => {
this._proxy.$willAddInteractiveDocument(e.inputUri, '\n', 'plaintext', e.notebookUri);
}));
this._disposables.add(interactiveDocumentService.onWillRemoveInteractiveDocument((e) => {
this._proxy.$willRemoveInteractiveDocument(e.inputUri, e.notebookUri);
}));
}
dispose(): void {
this._disposables.dispose();
}
}

View File

@@ -11,7 +11,7 @@ import * as search from 'vs/workbench/contrib/search/common/search';
import { CancellationToken } from 'vs/base/common/cancellation';
import { Position as EditorPosition } from 'vs/editor/common/core/position';
import { Range as EditorRange, IRange } from 'vs/editor/common/core/range';
import { ExtHostContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, MainContext, IExtHostContext, ILanguageConfigurationDto, IRegExpDto, IIndentationRuleDto, IOnEnterRuleDto, ILocationDto, IWorkspaceSymbolDto, reviveWorkspaceEditDto, IDocumentFilterDto, IDefinitionLinkDto, ISignatureHelpProviderMetadataDto, ILinkDto, ICallHierarchyItemDto, ISuggestDataDto, ICodeActionDto, ISuggestDataDtoField, ISuggestResultDtoField, ICodeActionProviderMetadataDto, ILanguageWordDefinitionDto, IdentifiableInlineCompletions, IdentifiableInlineCompletion } from '../common/extHost.protocol';
import { ExtHostContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, MainContext, IExtHostContext, ILanguageConfigurationDto, IRegExpDto, IIndentationRuleDto, IOnEnterRuleDto, ILocationDto, IWorkspaceSymbolDto, reviveWorkspaceEditDto, IDocumentFilterDto, IDefinitionLinkDto, ISignatureHelpProviderMetadataDto, ILinkDto, ICallHierarchyItemDto, ISuggestDataDto, ICodeActionDto, ISuggestDataDtoField, ISuggestResultDtoField, ICodeActionProviderMetadataDto, ILanguageWordDefinitionDto, IdentifiableInlineCompletions, IdentifiableInlineCompletion, ITypeHierarchyItemDto } from '../common/extHost.protocol';
import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';
import { LanguageConfiguration, IndentationRule, OnEnterRule } from 'vs/editor/common/modes/languageConfiguration';
import { IModeService } from 'vs/editor/common/services/modeService';
@@ -20,6 +20,7 @@ import { URI } from 'vs/base/common/uri';
import { Selection } from 'vs/editor/common/core/selection';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import * as callh from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
import * as typeh from 'vs/workbench/contrib/typeHierarchy/common/typeHierarchy';
import { mixin } from 'vs/base/common/objects';
import { decodeSemanticTokensDto } from 'vs/editor/common/services/semanticTokensDto';
@@ -148,6 +149,13 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
return data as callh.CallHierarchyItem;
}
private static _reviveTypeHierarchyItemDto(data: ITypeHierarchyItemDto | undefined): typeh.TypeHierarchyItem {
if (data) {
data.uri = URI.revive(data.uri);
}
return data as typeh.TypeHierarchyItem;
}
//#endregion
// --- outline
@@ -444,8 +452,10 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
private static _inflateSuggestDto(defaultRange: IRange | { insert: IRange, replace: IRange }, data: ISuggestDataDto): modes.CompletionItem {
const label = data[ISuggestDataDtoField.label];
return {
label: data[ISuggestDataDtoField.label2] ?? data[ISuggestDataDtoField.label],
label,
kind: data[ISuggestDataDtoField.kind] ?? modes.CompletionItemKind.Property,
tags: data[ISuggestDataDtoField.kindModifier],
detail: data[ISuggestDataDtoField.detail],
@@ -453,7 +463,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
sortText: data[ISuggestDataDtoField.sortText],
filterText: data[ISuggestDataDtoField.filterText],
preselect: data[ISuggestDataDtoField.preselect],
insertText: typeof data.h === 'undefined' ? data[ISuggestDataDtoField.label] : data.h,
insertText: data[ISuggestDataDtoField.insertText] ?? (typeof label === 'string' ? label : label.label),
range: data[ISuggestDataDtoField.range] ?? defaultRange,
insertTextRules: data[ISuggestDataDtoField.insertTextRules],
commitCharacters: data[ISuggestDataDtoField.commitCharacters],
@@ -772,6 +782,43 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
}
}
// --- type hierarchy
$registerTypeHierarchyProvider(handle: number, selector: IDocumentFilterDto[]): void {
this._registrations.set(handle, typeh.TypeHierarchyProviderRegistry.register(selector, {
prepareTypeHierarchy: async (document, position, token) => {
const items = await this._proxy.$prepareTypeHierarchy(handle, document.uri, position, token);
if (!items) {
return undefined;
}
return {
dispose: () => {
for (const item of items) {
this._proxy.$releaseTypeHierarchy(handle, item._sessionId);
}
},
roots: items.map(MainThreadLanguageFeatures._reviveTypeHierarchyItemDto)
};
},
provideSupertypes: async (item, token) => {
const supertypes = await this._proxy.$provideTypeHierarchySupertypes(handle, item._sessionId, item._itemId, token);
if (!supertypes) {
return supertypes;
}
return supertypes.map(item => MainThreadLanguageFeatures._reviveTypeHierarchyItemDto(item)) as any; // {{SQL CARBON EDIT}} Cast to any to get around weird compile error - trusting them to do the right thing here
},
provideSubtypes: async (item, token) => {
const subtypes = await this._proxy.$provideTypeHierarchySubtypes(handle, item._sessionId, item._itemId, token);
if (!subtypes) {
return subtypes;
}
return subtypes.map(MainThreadLanguageFeatures._reviveTypeHierarchyItemDto) as any; // {{SQL CARBON EDIT}} Cast to any to get around weird compile error - trusting them to do the right thing here
}
}));
}
}
export class MainThreadDocumentSemanticTokensProvider implements modes.DocumentSemanticTokensProvider {

View File

@@ -12,6 +12,8 @@ import { IPosition } from 'vs/editor/common/core/position';
import { IRange, Range } from 'vs/editor/common/core/range';
import { StandardTokenType } from 'vs/editor/common/modes';
import { ITextModelService } from 'vs/editor/common/services/resolverService';
import { ILanguageStatus, ILanguageStatusService } from 'vs/workbench/services/languageStatus/common/languageStatusService';
import { IDisposable } from 'vs/base/common/lifecycle';
@extHostNamedCustomer(MainContext.MainThreadLanguages)
export class MainThreadLanguages implements MainThreadLanguagesShape {
@@ -21,8 +23,8 @@ export class MainThreadLanguages implements MainThreadLanguagesShape {
@IModeService private readonly _modeService: IModeService,
@IModelService private readonly _modelService: IModelService,
@ITextModelService private _resolverService: ITextModelService,
) {
}
@ILanguageStatusService private readonly _languageStatusService: ILanguageStatusService,
) { }
dispose(): void {
// nothing
@@ -62,4 +64,17 @@ export class MainThreadLanguages implements MainThreadLanguagesShape {
range: new Range(position.lineNumber, 1 + tokens.getStartOffset(idx), position.lineNumber, 1 + tokens.getEndOffset(idx))
};
}
// --- language status
private readonly _status = new Map<number, IDisposable>();
$setLanguageStatus(handle: number, status: ILanguageStatus): void {
this._status.get(handle)?.dispose();
this._status.set(handle, this._languageStatusService.addStatus(status));
}
$removeLanguageStatus(handle: number): void {
this._status.get(handle)?.dispose();
}
}

View File

@@ -9,8 +9,10 @@ import { IDisposable } from 'vs/base/common/lifecycle';
import { IExtHostContext, ExtHostContext, MainThreadLogShape, MainContext } from 'vs/workbench/api/common/extHost.protocol';
import { UriComponents, URI } from 'vs/base/common/uri';
import { FileLogger } from 'vs/platform/log/common/fileLog';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { basename } from 'vs/base/common/path';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
@extHostNamedCustomer(MainContext.MainThreadLog)
export class MainThreadLogService implements MainThreadLogShape {
@@ -40,9 +42,26 @@ export class MainThreadLogService implements MainThreadLogShape {
const uri = URI.revive(file);
let logger = this._loggers.get(uri.toString());
if (!logger) {
logger = this._instaService.createInstance(FileLogger, basename(file.path), URI.revive(file), this._logService.getLevel());
logger = this._instaService.createInstance(FileLogger, basename(file.path), URI.revive(file), this._logService.getLevel(), false);
this._loggers.set(uri.toString(), logger);
}
logger.log(level, message);
}
}
// --- Internal commands to improve extension test runs
CommandsRegistry.registerCommand('_extensionTests.setLogLevel', function (accessor: ServicesAccessor, level: number) {
const logService = accessor.get(ILogService);
const environmentService = accessor.get(IEnvironmentService);
if (environmentService.isExtensionDevelopment && !!environmentService.extensionTestsLocationURI) {
logService.setLevel(level);
}
});
CommandsRegistry.registerCommand('_extensionTests.getLogLevel', function (accessor: ServicesAccessor) {
const logService = accessor.get(ILogService);
return logService.getLevel();
});

View File

@@ -33,7 +33,7 @@ export class MainThreadMessageService implements MainThreadMessageServiceShape {
$showMessage(severity: Severity, message: string, options: MainThreadMessageOptions, commands: { title: string; isCloseAffordance: boolean; handle: number; }[]): Promise<number | undefined> {
if (options.modal) {
return this._showModalMessage(severity, message, commands, options.useCustom);
return this._showModalMessage(severity, message, options.detail, commands, options.useCustom);
} else {
return this._showMessage(severity, message, commands, options.extension);
}
@@ -100,7 +100,7 @@ export class MainThreadMessageService implements MainThreadMessageServiceShape {
});
}
private async _showModalMessage(severity: Severity, message: string, commands: { title: string; isCloseAffordance: boolean; handle: number; }[], useCustom?: boolean): Promise<number | undefined> {
private async _showModalMessage(severity: Severity, message: string, detail: string | undefined, commands: { title: string; isCloseAffordance: boolean; handle: number; }[], useCustom?: boolean): Promise<number | undefined> {
let cancelId: number | undefined = undefined;
const buttons = commands.map((command, index) => {
@@ -121,7 +121,7 @@ export class MainThreadMessageService implements MainThreadMessageServiceShape {
cancelId = buttons.length - 1;
}
const { choice } = await this._dialogService.show(severity, message, buttons, { cancelId, custom: useCustom });
const { choice } = await this._dialogService.show(severity, message, buttons, { cancelId, custom: useCustom, detail });
return choice === commands.length ? undefined : commands[choice].handle;
}
}

View File

@@ -8,11 +8,13 @@ import { CancellationToken } from 'vs/base/common/cancellation';
import { Emitter } from 'vs/base/common/event';
import { DisposableStore, dispose, IDisposable } from 'vs/base/common/lifecycle';
import { URI } from 'vs/base/common/uri';
import { NotebookDto } from 'vs/workbench/api/browser/mainThreadNotebookDto';
// import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; {{SQL CARBON EDIT}} Disable VS Code notebooks
import { INotebookCellStatusBarService } from 'vs/workbench/contrib/notebook/common/notebookCellStatusBarService';
import { INotebookCellStatusBarItemProvider, INotebookContributionData, NotebookDataDto, TransientCellMetadata, TransientDocumentMetadata, TransientOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { INotebookCellStatusBarItemProvider, INotebookContributionData, NotebookData as NotebookData, TransientCellMetadata, TransientDocumentMetadata, TransientOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { INotebookContentProvider, INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
import { ExtHostContext, ExtHostNotebookShape, IExtHostContext, MainThreadNotebookShape, NotebookExtensionDescription } from '../common/extHost.protocol'; // {{SQL CARBON EDIT}} Remove MainContext
import { SerializableObjectWithBuffers } from 'vs/workbench/services/extensions/common/proxyIdentifier';
import { ExtHostContext, ExtHostNotebookShape, IExtHostContext, MainThreadNotebookShape, NotebookExtensionDescription } from '../common/extHost.protocol'; // {{SQL CARBON EDIT}} Disable VS Code notebooks
// @extHostNamedCustomer(MainContext.MainThreadNotebook) {{SQL CARBON EDIT}} Disable VS Code notebooks
export class MainThreadNotebooks implements MainThreadNotebookShape {
@@ -56,7 +58,7 @@ export class MainThreadNotebooks implements MainThreadNotebookShape {
open: async (uri: URI, backupId: string | undefined, untitledDocumentData: VSBuffer | undefined, token: CancellationToken) => {
const data = await this._proxy.$openNotebook(viewType, uri, backupId, untitledDocumentData, token);
return {
data,
data: NotebookDto.fromNotebookDataDto(data.value),
transientOptions: contentOptions
};
},
@@ -100,14 +102,16 @@ export class MainThreadNotebooks implements MainThreadNotebookShape {
}
}
$registerNotebookSerializer(handle: number, extension: NotebookExtensionDescription, viewType: string, options: TransientOptions, data: INotebookContributionData | undefined): void {
const registration = this._notebookService.registerNotebookSerializer(viewType, extension, {
options,
dataToNotebook: (data: VSBuffer): Promise<NotebookDataDto> => {
return this._proxy.$dataToNotebook(handle, data, CancellationToken.None);
dataToNotebook: async (data: VSBuffer): Promise<NotebookData> => {
const dto = await this._proxy.$dataToNotebook(handle, data, CancellationToken.None);
return NotebookDto.fromNotebookDataDto(dto.value);
},
notebookToData: (data: NotebookDataDto): Promise<VSBuffer> => {
return this._proxy.$notebookToData(handle, data, CancellationToken.None);
notebookToData: (data: NotebookData): Promise<VSBuffer> => {
return this._proxy.$notebookToData(handle, new SerializableObjectWithBuffers(NotebookDto.toNotebookDataDto(data)), CancellationToken.None);
}
});
const disposables = new DisposableStore();

View File

@@ -9,15 +9,13 @@ import { URI, UriComponents } from 'vs/base/common/uri';
import { BoundModelReferenceCollection } from 'vs/workbench/api/browser/mainThreadDocuments';
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
import { IImmediateCellEditOperation, IMainCellDto, NotebookCellsChangeType, NotebookDataDto } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { NotebookCellsChangeType } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { INotebookEditorModelResolverService } from 'vs/workbench/contrib/notebook/common/notebookEditorModelResolverService';
import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity';
import { ExtHostContext, ExtHostNotebookDocumentsShape, IExtHostContext, MainThreadNotebookDocumentsShape } from '../common/extHost.protocol';
import { ExtHostContext, ExtHostNotebookDocumentsShape, IExtHostContext, MainThreadNotebookDocumentsShape, NotebookCellDto, NotebookCellsChangedEventDto, NotebookDataDto } from '../common/extHost.protocol';
import { MainThreadNotebooksAndEditors } from 'vs/workbench/api/browser/mainThreadNotebookDocumentsAndEditors';
import { onUnexpectedError } from 'vs/base/common/errors';
import { Schemas } from 'vs/base/common/network';
import { NotebookProviderInfo } from 'vs/workbench/contrib/notebook/common/notebookProvider';
import { NotebookDto } from 'vs/workbench/api/browser/mainThreadNotebookDto';
import { SerializableObjectWithBuffers } from 'vs/workbench/services/extensions/common/proxyIdentifier';
export class MainThreadNotebookDocuments implements MainThreadNotebookDocumentsShape {
@@ -30,7 +28,6 @@ export class MainThreadNotebookDocuments implements MainThreadNotebookDocumentsS
constructor(
extHostContext: IExtHostContext,
notebooksAndEditors: MainThreadNotebooksAndEditors,
@INotebookService private readonly _notebookService: INotebookService,
@INotebookEditorModelResolverService private readonly _notebookEditorModelResolverService: INotebookEditorModelResolverService,
@IUriIdentityService private readonly _uriIdentityService: IUriIdentityService
) {
@@ -56,36 +53,59 @@ export class MainThreadNotebookDocuments implements MainThreadNotebookDocumentsS
for (const textModel of notebooks) {
const disposableStore = new DisposableStore();
disposableStore.add(textModel.onDidChangeContent(event => {
const dto = event.rawEvents.map(e => {
const data =
e.kind === NotebookCellsChangeType.ModelChange || e.kind === NotebookCellsChangeType.Initialize
? {
kind: e.kind,
versionId: event.versionId,
changes: e.changes.map(diff => [diff[0], diff[1], diff[2].map(cell => MainThreadNotebookDocuments._cellToDto(cell as NotebookCellTextModel))] as [number, number, IMainCellDto[]])
}
: (
e.kind === NotebookCellsChangeType.Move
? {
kind: e.kind,
index: e.index,
length: e.length,
newIdx: e.newIdx,
versionId: event.versionId,
cells: e.cells.map(cell => MainThreadNotebookDocuments._cellToDto(cell as NotebookCellTextModel))
}
: e
);
return data;
});
const eventDto: NotebookCellsChangedEventDto = {
versionId: event.versionId,
rawEvents: []
};
for (const e of event.rawEvents) {
switch (e.kind) {
case NotebookCellsChangeType.ModelChange:
eventDto.rawEvents.push({
kind: e.kind,
changes: e.changes.map(diff => [diff[0], diff[1], diff[2].map(cell => NotebookDto.toNotebookCellDto(cell as NotebookCellTextModel))] as [number, number, NotebookCellDto[]])
});
break;
case NotebookCellsChangeType.Move:
eventDto.rawEvents.push({
kind: e.kind,
index: e.index,
length: e.length,
newIdx: e.newIdx,
});
break;
case NotebookCellsChangeType.Output:
eventDto.rawEvents.push({
kind: e.kind,
index: e.index,
outputs: e.outputs.map(NotebookDto.toNotebookOutputDto)
});
break;
case NotebookCellsChangeType.OutputItem:
eventDto.rawEvents.push({
kind: e.kind,
index: e.index,
outputId: e.outputId,
outputItems: e.outputItems.map(NotebookDto.toNotebookOutputItemDto),
append: e.append
});
break;
case NotebookCellsChangeType.ChangeLanguage:
case NotebookCellsChangeType.ChangeCellMetadata:
case NotebookCellsChangeType.ChangeCellInternalMetadata:
eventDto.rawEvents.push(e);
break;
}
}
// using the model resolver service to know if the model is dirty or not.
// assuming this is the first listener it can mean that at first the model
// is marked as dirty and that another event is fired
this._proxy.$acceptModelChanged(
textModel.uri,
{ rawEvents: dto, versionId: event.versionId },
new SerializableObjectWithBuffers(eventDto),
this._notebookEditorModelResolverService.isDirty(textModel.uri)
);
@@ -106,39 +126,9 @@ export class MainThreadNotebookDocuments implements MainThreadNotebookDocumentsS
}
}
private static _cellToDto(cell: NotebookCellTextModel): IMainCellDto {
return {
handle: cell.handle,
uri: cell.uri,
source: cell.textBuffer.getLinesContent(),
eol: cell.textBuffer.getEOL(),
language: cell.language,
cellKind: cell.cellKind,
outputs: cell.outputs,
metadata: cell.metadata,
internalMetadata: cell.internalMetadata,
};
}
async $tryCreateNotebook(options: { viewType: string, content?: NotebookDataDto }): Promise<UriComponents> {
const info = this._notebookService.getContributedNotebookType(options.viewType);
if (!info) {
throw new Error('UNKNOWN view type: ' + options.viewType);
}
// find a free URI for the untitled case
const suffix = NotebookProviderInfo.possibleFileEnding(info.selectors) ?? '';
let uri: URI;
for (let counter = 1; ; counter++) {
let candidate = URI.from({ scheme: Schemas.untitled, path: `Untitled-${counter}${suffix}`, query: options.viewType });
if (!this._notebookService.getNotebookTextModel(candidate)) {
uri = candidate;
break;
}
}
const ref = await this._notebookEditorModelResolverService.resolve(uri, options.viewType);
const ref = await this._notebookEditorModelResolverService.resolve({ untitledResource: undefined }, options.viewType);
// untitled notebooks are disposed when they get saved. we should not hold a reference
// to such a disposed notebook and therefore dispose the reference as well
@@ -147,17 +137,14 @@ export class MainThreadNotebookDocuments implements MainThreadNotebookDocumentsS
});
// untitled notebooks are dirty by default
this._proxy.$acceptDirtyStateChanged(uri, true);
this._proxy.$acceptDirtyStateChanged(ref.object.resource, true);
// apply content changes... slightly HACKY -> this triggers a change event
if (options.content) {
ref.object.notebook.reset(
options.content.cells,
options.content.metadata,
ref.object.notebook.transientOptions
);
const data = NotebookDto.fromNotebookDataDto(options.content);
ref.object.notebook.reset(data.cells, data.metadata, ref.object.notebook.transientOptions);
}
return uri;
return ref.object.resource;
}
async $tryOpenNotebook(uriComponents: UriComponents): Promise<URI> {
@@ -175,19 +162,4 @@ export class MainThreadNotebookDocuments implements MainThreadNotebookDocumentsS
ref.dispose();
return saveResult;
}
async $applyEdits(resource: UriComponents, cellEdits: IImmediateCellEditOperation[], computeUndoRedo = true): Promise<void> {
const textModel = this._notebookService.getNotebookTextModel(URI.from(resource));
if (!textModel) {
throw new Error(`Can't apply edits to unknown notebook model: ${URI.revive(resource).toString()}`);
}
try {
textModel.applyEdits(cellEdits, true, undefined, () => undefined, undefined, computeUndoRedo);
} catch (e) {
// Clearing outputs at the same time as the EH calling append/replaceOutputItems is an expected race, and it should be a no-op.
// And any other failure should not throw back to the extension.
onUnexpectedError(e);
}
}
}

View File

@@ -9,9 +9,10 @@ import { combinedDisposable, DisposableStore, IDisposable } from 'vs/base/common
import { URI } from 'vs/base/common/uri';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { MainThreadNotebookDocuments } from 'vs/workbench/api/browser/mainThreadNotebookDocuments';
import { NotebookDto } from 'vs/workbench/api/browser/mainThreadNotebookDto';
import { MainThreadNotebookEditors } from 'vs/workbench/api/browser/mainThreadNotebookEditors';
// import { extHostCustomer } from 'vs/workbench/api/common/extHostCustomers'; {{SQL CARBON EDIT}} Disable VS Code notebooks
import { editorGroupToViewColumn } from 'vs/workbench/common/editor';
import { editorGroupToColumn } from 'vs/workbench/services/editor/common/editorGroupColumn';
import { getNotebookEditorFromEditorPane, IActiveNotebookEditor, INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { INotebookEditorService } from 'vs/workbench/contrib/notebook/browser/notebookEditorService';
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
@@ -19,6 +20,7 @@ import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookS
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { ExtHostContext, ExtHostNotebookShape, IExtHostContext, INotebookDocumentsAndEditorsDelta, INotebookEditorAddData, INotebookModelAddedData, MainContext } from '../common/extHost.protocol';
import { SerializableObjectWithBuffers } from 'vs/workbench/services/extensions/common/proxyIdentifier';
interface INotebookAndEditorDelta {
removedDocuments: URI[];
@@ -189,7 +191,7 @@ export class MainThreadNotebooksAndEditors {
};
// send to extension FIRST
this._proxy.$acceptDocumentAndEditorsDelta(dto);
this._proxy.$acceptDocumentAndEditorsDelta(new SerializableObjectWithBuffers(dto));
// handle internally
this._onDidRemoveEditors.fire(delta.removedEditors);
@@ -226,17 +228,7 @@ export class MainThreadNotebooksAndEditors {
uri: e.uri,
metadata: e.metadata,
versionId: e.versionId,
cells: e.cells.map(cell => ({
handle: cell.handle,
uri: cell.uri,
source: cell.textBuffer.getLinesContent(),
eol: cell.textBuffer.getEOL(),
language: cell.language,
cellKind: cell.cellKind,
outputs: cell.outputs,
metadata: cell.metadata,
internalMetadata: cell.internalMetadata,
}))
cells: e.cells.map(NotebookDto.toNotebookCellDto)
};
}
@@ -246,10 +238,10 @@ export class MainThreadNotebooksAndEditors {
return {
id: add.getId(),
documentUri: add.viewModel.uri,
documentUri: add.textModel.uri,
selections: add.getSelections(),
visibleRanges: add.visibleRanges,
viewColumn: pane && editorGroupToViewColumn(this._editorGroupService, pane.group)
viewColumn: pane && editorGroupToColumn(this._editorGroupService, pane.group)
};
}
}

View File

@@ -0,0 +1,127 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as extHostProtocol from 'vs/workbench/api/common/extHost.protocol';
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
import * as notebookCommon from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { CellExecutionUpdateType, ICellExecuteUpdate } from 'vs/workbench/contrib/notebook/common/notebookExecutionService';
export namespace NotebookDto {
export function toNotebookOutputItemDto(item: notebookCommon.IOutputItemDto): extHostProtocol.NotebookOutputItemDto {
return {
mime: item.mime,
valueBytes: item.data
};
}
export function toNotebookOutputDto(output: notebookCommon.IOutputDto): extHostProtocol.NotebookOutputDto {
return {
outputId: output.outputId,
metadata: output.metadata,
items: output.outputs.map(toNotebookOutputItemDto)
};
}
export function toNotebookCellDataDto(cell: notebookCommon.ICellDto2): extHostProtocol.NotebookCellDataDto {
return {
cellKind: cell.cellKind,
language: cell.language,
mime: cell.mime,
source: cell.source,
internalMetadata: cell.internalMetadata,
metadata: cell.metadata,
outputs: cell.outputs.map(toNotebookOutputDto)
};
}
export function toNotebookDataDto(data: notebookCommon.NotebookData): extHostProtocol.NotebookDataDto {
return {
metadata: data.metadata,
cells: data.cells.map(toNotebookCellDataDto)
};
}
export function fromNotebookOutputItemDto(item: extHostProtocol.NotebookOutputItemDto): notebookCommon.IOutputItemDto {
return {
mime: item.mime,
data: item.valueBytes
};
}
export function fromNotebookOutputDto(output: extHostProtocol.NotebookOutputDto): notebookCommon.IOutputDto {
return {
outputId: output.outputId,
metadata: output.metadata,
outputs: output.items.map(fromNotebookOutputItemDto)
};
}
export function fromNotebookCellDataDto(cell: extHostProtocol.NotebookCellDataDto): notebookCommon.ICellDto2 {
return {
cellKind: cell.cellKind,
language: cell.language,
mime: cell.mime,
source: cell.source,
outputs: cell.outputs.map(fromNotebookOutputDto),
metadata: cell.metadata,
internalMetadata: cell.internalMetadata
};
}
export function fromNotebookDataDto(data: extHostProtocol.NotebookDataDto): notebookCommon.NotebookData {
return {
metadata: data.metadata,
cells: data.cells.map(fromNotebookCellDataDto)
};
}
export function toNotebookCellDto(cell: NotebookCellTextModel): extHostProtocol.NotebookCellDto {
return {
handle: cell.handle,
uri: cell.uri,
source: cell.textBuffer.getLinesContent(),
eol: cell.textBuffer.getEOL(),
language: cell.language,
cellKind: cell.cellKind,
outputs: cell.outputs.map(toNotebookOutputDto),
metadata: cell.metadata,
internalMetadata: cell.internalMetadata,
};
}
export function fromCellExecuteUpdateDto(data: extHostProtocol.ICellExecuteUpdateDto): ICellExecuteUpdate {
if (data.editType === CellExecutionUpdateType.Output) {
return {
editType: data.editType,
cellHandle: data.cellHandle,
append: data.append,
outputs: data.outputs.map(fromNotebookOutputDto)
};
} else if (data.editType === CellExecutionUpdateType.OutputItems) {
return {
editType: data.editType,
append: data.append,
outputId: data.outputId,
items: data.items.map(fromNotebookOutputItemDto)
};
} else {
return data;
}
}
export function fromCellEditOperationDto(edit: extHostProtocol.ICellEditOperationDto): notebookCommon.ICellEditOperation {
if (edit.editType === notebookCommon.CellEditType.Replace) {
return {
editType: edit.editType,
index: edit.index,
count: edit.count,
cells: edit.cells.map(fromNotebookCellDataDto)
};
} else {
return edit;
}
}
}

View File

@@ -6,19 +6,20 @@
import { DisposableStore, dispose } from 'vs/base/common/lifecycle';
import { getNotebookEditorFromEditorPane, INotebookEditor, INotebookEditorOptions } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { INotebookEditorService } from 'vs/workbench/contrib/notebook/browser/notebookEditorService';
import { ExtHostContext, ExtHostNotebookEditorsShape, IExtHostContext, INotebookDocumentShowOptions, INotebookEditorViewColumnInfo, MainThreadNotebookEditorsShape, NotebookEditorRevealType } from '../common/extHost.protocol';
import { ExtHostContext, ExtHostNotebookEditorsShape, ICellEditOperationDto, IExtHostContext, INotebookDocumentShowOptions, INotebookEditorViewColumnInfo, MainThreadNotebookEditorsShape, NotebookEditorRevealType } from '../common/extHost.protocol';
import { MainThreadNotebooksAndEditors } from 'vs/workbench/api/browser/mainThreadNotebookDocumentsAndEditors';
import { ICellEditOperation, INotebookDecorationRenderOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { INotebookDecorationRenderOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { ICellRange } from 'vs/workbench/contrib/notebook/common/notebookRange';
import { ILogService } from 'vs/platform/log/common/log';
import { URI, UriComponents } from 'vs/base/common/uri';
import { EditorActivation, EditorOverride } from 'vs/platform/editor/common/editor';
import { EditorActivation, EditorResolution } from 'vs/platform/editor/common/editor';
import { NotebookEditorInput } from 'vs/workbench/contrib/notebook/common/notebookEditorInput';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { editorGroupToViewColumn } from 'vs/workbench/common/editor';
import { editorGroupToColumn } from 'vs/workbench/services/editor/common/editorGroupColumn';
import { equals } from 'vs/base/common/objects';
import { NotebookDto } from 'vs/workbench/api/browser/mainThreadNotebookDto';
class MainThreadNotebook {
@@ -95,7 +96,7 @@ export class MainThreadNotebookEditors implements MainThreadNotebookEditorsShape
for (let editorPane of this._editorService.visibleEditorPanes) {
const candidate = getNotebookEditorFromEditorPane(editorPane);
if (candidate && this._mainThreadEditors.has(candidate.getId())) {
result[candidate.getId()] = editorGroupToViewColumn(this._editorGroupService, editorPane.group);
result[candidate.getId()] = editorGroupToColumn(this._editorGroupService, editorPane.group);
}
}
if (!equals(result, this._currentViewColumnInfo)) {
@@ -104,7 +105,7 @@ export class MainThreadNotebookEditors implements MainThreadNotebookEditorsShape
}
}
async $tryApplyEdits(editorId: string, modelVersionId: number, cellEdits: ICellEditOperation[]): Promise<boolean> {
async $tryApplyEdits(editorId: string, modelVersionId: number, cellEdits: ICellEditOperationDto[]): Promise<boolean> {
const wrapper = this._mainThreadEditors.get(editorId);
if (!wrapper) {
return false;
@@ -118,7 +119,7 @@ export class MainThreadNotebookEditors implements MainThreadNotebookEditorsShape
return false;
}
//todo@jrieken use proper selection logic!
return editor.textModel.applyEdits(cellEdits, true, undefined, () => undefined, undefined);
return editor.textModel.applyEdits(cellEdits.map(NotebookDto.fromCellEditOperationDto), true, undefined, () => undefined, undefined);
}
async $tryShowNotebookDocument(resource: UriComponents, viewType: string, options: INotebookDocumentShowOptions): Promise<string> {
@@ -130,7 +131,7 @@ export class MainThreadNotebookEditors implements MainThreadNotebookEditorsShape
// preserve pre 1.38 behaviour to not make group active when preserveFocus: true
// but make sure to restore the editor to fix https://github.com/microsoft/vscode/issues/79633
activation: options.preserveFocus ? EditorActivation.RESTORE : undefined,
override: EditorOverride.DISABLED
override: EditorResolution.DISABLED
};
const input = NotebookEditorInput.create(this._instantiationService, URI.revive(resource), viewType);
@@ -189,9 +190,14 @@ export class MainThreadNotebookEditors implements MainThreadNotebookEditorsShape
$trySetSelections(id: string, ranges: ICellRange[]): void {
const editor = this._notebookEditorService.getNotebookEditor(id);
if (editor) {
// @rebornix how to set an editor selection?
// editor.setSelections(ranges)
if (!editor) {
return;
}
editor.setSelections(ranges);
if (ranges.length) {
editor.setFocus({ start: ranges[0].start, end: ranges[0].start + 1 });
}
}
}

View File

@@ -3,23 +3,26 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { flatten, isNonEmptyArray } from 'vs/base/common/arrays';
import { flatten, groupBy, isNonEmptyArray } from 'vs/base/common/arrays';
import { onUnexpectedError } from 'vs/base/common/errors';
import { Emitter, Event } from 'vs/base/common/event';
import { combinedDisposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
import { URI, UriComponents } from 'vs/base/common/uri';
import { IModeService } from 'vs/editor/common/services/modeService';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { NotebookDto } from 'vs/workbench/api/browser/mainThreadNotebookDto';
// import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; {{SQL CARBON EDIT}} Disable VS Code notebooks
import { INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { INotebookEditorService } from 'vs/workbench/contrib/notebook/browser/notebookEditorService';
import { INotebookKernel, INotebookKernelChangeEvent } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { INotebookKernelService } from 'vs/workbench/contrib/notebook/common/notebookKernelService';
import { ExtHostContext, ExtHostNotebookKernelsShape, IExtHostContext, INotebookKernelDto2, MainThreadNotebookKernelsShape } from '../common/extHost.protocol';// {{SQL CARBON EDIT}} Remove MainContext
import { INotebookCellExecution, INotebookExecutionService } from 'vs/workbench/contrib/notebook/common/notebookExecutionService';
import { INotebookKernel, INotebookKernelChangeEvent, INotebookKernelService } from 'vs/workbench/contrib/notebook/common/notebookKernelService';
import { SerializableObjectWithBuffers } from 'vs/workbench/services/extensions/common/proxyIdentifier';
import { ExtHostContext, ExtHostNotebookKernelsShape, ICellExecuteUpdateDto, IExtHostContext, INotebookKernelDto2, MainThreadNotebookKernelsShape } from '../common/extHost.protocol'; // {{SQL CARBON EDIT}} Disable VS Code notebooks
abstract class MainThreadKernel implements INotebookKernel {
private readonly _onDidChange = new Emitter<INotebookKernelChangeEvent>();
private readonly preloads: { uri: URI, provides: string[] }[];
private readonly preloads: { uri: URI, provides: string[]; }[];
readonly onDidChange: Event<INotebookKernelChangeEvent> = this._onDidChange.event;
readonly id: string;
@@ -97,10 +100,14 @@ export class MainThreadNotebookKernels implements MainThreadNotebookKernelsShape
private readonly _kernels = new Map<number, [kernel: MainThreadKernel, registraion: IDisposable]>();
private readonly _proxy: ExtHostNotebookKernelsShape;
private readonly _executions = new Map<number, INotebookCellExecution>();
constructor(
extHostContext: IExtHostContext,
@IModeService private readonly _modeService: IModeService,
@INotebookKernelService private readonly _notebookKernelService: INotebookKernelService,
@INotebookExecutionService private readonly _notebookExecutionService: INotebookExecutionService,
// @INotebookService private readonly _notebookService: INotebookService,
@INotebookEditorService notebookEditorService: INotebookEditorService
) {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostNotebookKernels);
@@ -125,7 +132,7 @@ export class MainThreadNotebookKernels implements MainThreadNotebookKernelsShape
if (!editor.hasModel()) {
return;
}
const { selected } = this._notebookKernelService.getMatchingKernel(editor.viewModel.notebookDocument);
const { selected } = this._notebookKernelService.getMatchingKernel(editor.textModel);
if (!selected) {
return;
}
@@ -155,7 +162,7 @@ export class MainThreadNotebookKernels implements MainThreadNotebookKernelsShape
if (!editor.hasModel()) {
continue;
}
if (this._notebookKernelService.getMatchingKernel(editor.viewModel.notebookDocument).selected !== kernel) {
if (this._notebookKernelService.getMatchingKernel(editor.textModel).selected !== kernel) {
// different kernel
continue;
}
@@ -186,7 +193,7 @@ export class MainThreadNotebookKernels implements MainThreadNotebookKernelsShape
}
}(data, this._modeService);
const listener = this._notebookKernelService.onDidChangeNotebookKernelBinding(e => {
const listener = this._notebookKernelService.onDidChangeSelectedNotebooks(e => {
if (e.oldKernel === kernel.id) {
this._proxy.$acceptNotebookAssociation(handle, e.notebook, false);
} else if (e.newKernel === kernel.id) {
@@ -219,4 +226,33 @@ export class MainThreadNotebookKernels implements MainThreadNotebookKernelsShape
this._notebookKernelService.updateKernelNotebookAffinity(tuple[0], URI.revive(notebook), value);
}
}
// --- execution
$addExecution(handle: number, uri: UriComponents, cellHandle: number): void {
const execution = this._notebookExecutionService.createNotebookCellExecution(URI.revive(uri), cellHandle);
this._executions.set(handle, execution);
}
$updateExecutions(data: SerializableObjectWithBuffers<ICellExecuteUpdateDto[]>): void {
const updates = data.value;
const groupedUpdates = groupBy(updates, (a, b) => a.executionHandle - b.executionHandle);
groupedUpdates.forEach(datas => {
const first = datas[0];
const execution = this._executions.get(first.executionHandle);
if (!execution) {
return;
}
try {
execution.update(datas.map(NotebookDto.fromCellExecuteUpdateDto));
} catch (e) {
onUnexpectedError(e);
}
});
}
$removeExecution(handle: number): void {
this._executions.delete(handle);
}
}

View File

@@ -23,7 +23,7 @@ export class MainThreadNotebookRenderers extends Disposable implements MainThrea
}));
}
$postMessage(editorId: string, rendererId: string, message: unknown): void {
this.messaging.fireDidReceiveMessage(editorId, rendererId, message);
$postMessage(editorId: string | undefined, rendererId: string, message: unknown): Promise<boolean> {
return this.messaging.receiveMessage(editorId, rendererId, message);
}
}

View File

@@ -17,6 +17,7 @@ import { IViewsService } from 'vs/workbench/common/views';
export class MainThreadOutputService extends Disposable implements MainThreadOutputServiceShape {
private static _idPool = 1;
private static _extensionIdPool = new Map<string, number>();
private readonly _proxy: ExtHostOutputServiceShape;
private readonly _outputService: IOutputService;
@@ -41,8 +42,16 @@ export class MainThreadOutputService extends Disposable implements MainThreadOut
setVisibleChannel();
}
public $register(label: string, log: boolean, file?: UriComponents): Promise<string> {
const id = 'extension-output-#' + (MainThreadOutputService._idPool++);
public $register(label: string, log: boolean, file?: UriComponents, extensionId?: string): Promise<string> {
let id: string;
if (extensionId) {
const idCounter = (MainThreadOutputService._extensionIdPool.get(extensionId) || 0) + 1;
MainThreadOutputService._extensionIdPool.set(extensionId, idCounter);
id = `extension-output-${extensionId}-#${idCounter}`;
} else {
id = `extension-output-#${(MainThreadOutputService._idPool++)}`;
}
Registry.as<IOutputChannelRegistry>(Extensions.OutputChannels).registerChannel({ id, label, file: file ? URI.revive(file) : undefined, log });
this._register(toDisposable(() => this.$dispose(id)));
return Promise.resolve(id);

View File

@@ -3,18 +3,24 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IPickOptions, IInputOptions, IQuickInputService, IQuickInput } from 'vs/platform/quickinput/common/quickInput';
import { IPickOptions, IInputOptions, IQuickInputService, IQuickInput, IQuickPick, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';
import { ExtHostContext, MainThreadQuickOpenShape, ExtHostQuickOpenShape, TransferQuickPickItems, MainContext, IExtHostContext, TransferQuickInput, TransferQuickInputButton, IInputBoxOptions } from 'vs/workbench/api/common/extHost.protocol';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { URI } from 'vs/base/common/uri';
import { CancellationToken } from 'vs/base/common/cancellation';
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
interface QuickInputSession {
input: IQuickInput;
handlesToItems: Map<number, TransferQuickPickItems>;
}
function reviveIconPathUris(iconPath: { dark: URI; light?: URI | undefined; }) {
iconPath.dark = URI.revive(iconPath.dark);
if (iconPath.light) {
iconPath.light = URI.revive(iconPath.light);
}
}
@extHostNamedCustomer(MainContext.MainThreadQuickOpen)
export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
@@ -126,49 +132,39 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
const sessionId = params.id;
let session = this.sessions.get(sessionId);
if (!session) {
const input = params.type === 'quickPick' ? this._quickInputService.createQuickPick() : this._quickInputService.createInputBox();
input.onDidAccept(() => {
this._proxy.$onDidAccept(sessionId);
});
input.onDidTriggerButton(button => {
this._proxy.$onDidTriggerButton(sessionId, (button as TransferQuickInputButton).handle);
});
input.onDidChangeValue(value => {
this._proxy.$onDidChangeValue(sessionId, value);
});
input.onDidHide(() => {
this._proxy.$onDidHide(sessionId);
});
if (params.type === 'quickPick') {
const input = this._quickInputService.createQuickPick();
input.onDidAccept(() => {
this._proxy.$onDidAccept(sessionId);
});
input.onDidChangeActive(items => {
// Add extra events specific for quickpick
const quickpick = input as IQuickPick<IQuickPickItem>;
quickpick.onDidChangeActive(items => {
this._proxy.$onDidChangeActive(sessionId, items.map(item => (item as TransferQuickPickItems).handle));
});
input.onDidChangeSelection(items => {
quickpick.onDidChangeSelection(items => {
this._proxy.$onDidChangeSelection(sessionId, items.map(item => (item as TransferQuickPickItems).handle));
});
input.onDidTriggerButton(button => {
this._proxy.$onDidTriggerButton(sessionId, (button as TransferQuickInputButton).handle);
quickpick.onDidTriggerItemButton((e) => {
this._proxy.$onDidTriggerItemButton(sessionId, (e.item as TransferQuickPickItems).handle, (e.button as TransferQuickInputButton).handle);
});
input.onDidChangeValue(value => {
this._proxy.$onDidChangeValue(sessionId, value);
});
input.onDidHide(() => {
this._proxy.$onDidHide(sessionId);
});
session = {
input,
handlesToItems: new Map()
};
} else {
const input = this._quickInputService.createInputBox();
input.onDidAccept(() => {
this._proxy.$onDidAccept(sessionId);
});
input.onDidTriggerButton(button => {
this._proxy.$onDidTriggerButton(sessionId, (button as TransferQuickInputButton).handle);
});
input.onDidChangeValue(value => {
this._proxy.$onDidChangeValue(sessionId, value);
});
input.onDidHide(() => {
this._proxy.$onDidHide(sessionId);
});
session = {
input,
handlesToItems: new Map()
};
}
session = {
input,
handlesToItems: new Map()
};
this.sessions.set(sessionId, session);
}
const { input, handlesToItems } = session;
@@ -185,6 +181,15 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
} else if (param === 'items') {
handlesToItems.clear();
params[param].forEach((item: TransferQuickPickItems) => {
if (item.buttons) {
item.buttons = item.buttons.map((button: TransferQuickInputButton) => {
if (button.iconPath) {
reviveIconPathUris(button.iconPath);
}
return button;
});
}
handlesToItems.set(item.handle, item);
});
(input as any)[param] = params[param];
@@ -197,23 +202,12 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
if (button.handle === -1) {
return this._quickInputService.backButton;
}
const { iconPath, tooltip, handle } = button;
if ('id' in iconPath) {
return {
iconClass: ThemeIcon.asClassName(iconPath),
tooltip,
handle
};
} else {
return {
iconPath: {
dark: URI.revive(iconPath.dark),
light: iconPath.light && URI.revive(iconPath.light)
},
tooltip,
handle
};
if (button.iconPath) {
reviveIconPathUris(button.iconPath);
}
return button;
});
} else {
(input as any)[param] = params[param];

View File

@@ -12,6 +12,9 @@ import { Command } from 'vs/editor/common/modes';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { ISplice, Sequence } from 'vs/base/common/sequence';
import { CancellationToken } from 'vs/base/common/cancellation';
import { MarshalledId } from 'vs/base/common/marshalling';
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
import { IMarkdownString } from 'vs/base/common/htmlContent';
class MainThreadSCMResourceGroup implements ISCMResourceGroup {
@@ -36,7 +39,7 @@ class MainThreadSCMResourceGroup implements ISCMResourceGroup {
toJSON(): any {
return {
$mid: 4,
$mid: MarshalledId.ScmResourceGroup,
sourceControlHandle: this.sourceControlHandle,
groupHandle: this.handle
};
@@ -78,7 +81,7 @@ class MainThreadSCMResource implements ISCMResource {
toJSON(): any {
return {
$mid: 3,
$mid: MarshalledId.ScmResource,
sourceControlHandle: this.sourceControlHandle,
groupHandle: this.groupHandle,
handle: this.handle
@@ -203,11 +206,14 @@ class MainThreadSCMProvider implements ISCMProvider {
for (const [start, deleteCount, rawResources] of groupSlices) {
const resources = rawResources.map(rawResource => {
const [handle, sourceUri, icons, tooltip, strikeThrough, faded, contextValue, command] = rawResource;
const icon = icons[0];
const iconDark = icons[1] || icon;
const [light, dark] = icons;
const icon = ThemeIcon.isThemeIcon(light) ? light : URI.revive(light);
const iconDark = (ThemeIcon.isThemeIcon(dark) ? dark : URI.revive(dark)) || icon;
const decorations = {
icon: icon ? URI.revive(icon) : undefined,
iconDark: iconDark ? URI.revive(iconDark) : undefined,
icon: icon,
iconDark: iconDark,
tooltip,
strikeThrough,
faded
@@ -256,7 +262,7 @@ class MainThreadSCMProvider implements ISCMProvider {
toJSON(): any {
return {
$mid: 5,
$mid: MarshalledId.ScmProvider,
handle: this.handle
};
}
@@ -433,7 +439,7 @@ export class MainThreadSCM implements MainThreadSCMShape {
repository.input.setFocus();
}
$showValidationMessage(sourceControlHandle: number, message: string, type: InputValidationType) {
$showValidationMessage(sourceControlHandle: number, message: string | IMarkdownString, type: InputValidationType) {
const repository = this._repositories.get(sourceControlHandle);
if (!repository) {
return;

View File

@@ -6,6 +6,7 @@
import { CancellationToken } from 'vs/base/common/cancellation';
import { dispose, IDisposable, DisposableStore } from 'vs/base/common/lifecycle';
import { URI, UriComponents } from 'vs/base/common/uri';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { IFileMatch, IFileQuery, IRawFileMatch2, ISearchComplete, ISearchCompleteStats, ISearchProgressItem, ISearchResultProvider, ISearchService, ITextQuery, QueryType, SearchProviderType } from 'vs/workbench/services/search/common/search';
@@ -20,9 +21,15 @@ export class MainThreadSearch implements MainThreadSearchShape {
constructor(
extHostContext: IExtHostContext,
@ISearchService private readonly _searchService: ISearchService,
@ITelemetryService private readonly _telemetryService: ITelemetryService
@ITelemetryService private readonly _telemetryService: ITelemetryService,
@IConfigurationService _configurationService: IConfigurationService,
) {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostSearch);
const forceEHSearch = _configurationService.getValue('search.experimental.forceExtensionHostSearch');
if (forceEHSearch) {
this._proxy.$enableExtensionHostSearch();
}
}
dispose(): void {

View File

@@ -11,6 +11,7 @@ import { dispose } from 'vs/base/common/lifecycle';
import { Command } from 'vs/editor/common/modes';
import { IAccessibilityInformation } from 'vs/platform/accessibility/common/accessibility';
import { getCodiconAriaLabel } from 'vs/base/common/codicons';
import { IMarkdownString } from 'vs/base/common/htmlContent';
@extHostNamedCustomer(MainContext.MainThreadStatusBar)
export class MainThreadStatusBar implements MainThreadStatusBarShape {
@@ -27,7 +28,7 @@ export class MainThreadStatusBar implements MainThreadStatusBarShape {
this.entries.clear();
}
$setEntry(entryId: number, id: string, name: string, text: string, tooltip: string | undefined, command: Command | undefined, color: string | ThemeColor | undefined, backgroundColor: string | ThemeColor | undefined, alignment: MainThreadStatusBarAlignment, priority: number | undefined, accessibilityInformation: IAccessibilityInformation): void {
$setEntry(entryId: number, id: string, name: string, text: string, tooltip: IMarkdownString | string | undefined, command: Command | undefined, color: string | ThemeColor | undefined, backgroundColor: string | ThemeColor | undefined, alignment: MainThreadStatusBarAlignment, priority: number | undefined, accessibilityInformation: IAccessibilityInformation): void {
// if there are icons in the text use the tooltip for the aria label
let ariaLabel: string;
let role: string | undefined = undefined;
@@ -36,6 +37,10 @@ export class MainThreadStatusBar implements MainThreadStatusBarShape {
role = accessibilityInformation.role;
} else {
ariaLabel = getCodiconAriaLabel(text);
if (tooltip) {
const tooltipString = typeof tooltip === 'string' ? tooltip : tooltip.value;
ariaLabel += `, ${tooltipString}`;
}
}
const entry: IStatusbarEntry = { name, text, tooltip, command, color, backgroundColor, ariaLabel, role };

View File

@@ -17,7 +17,7 @@ import { IWorkspace, IWorkspaceContextService, IWorkspaceFolder } from 'vs/platf
import {
ContributedTask, ConfiguringTask, KeyedTaskIdentifier, TaskExecution, Task, TaskEvent, TaskEventKind,
PresentationOptions, CommandOptions, CommandConfiguration, RuntimeType, CustomTask, TaskScope, TaskSource,
TaskSourceKind, ExtensionTaskSource, RunOptions, TaskSet, TaskDefinition
TaskSourceKind, ExtensionTaskSource, RunOptions, TaskSet, TaskDefinition, TaskGroup
} from 'vs/workbench/contrib/tasks/common/tasks';
@@ -320,9 +320,8 @@ namespace TaskDTO {
hasDefinedMatchers: ContributedTask.is(task) ? task.hasDefinedMatchers : false,
runOptions: RunOptionsDTO.from(task.runOptions),
};
if (task.configurationProperties.group) {
result.group = task.configurationProperties.group;
}
result.group = TaskGroup.from(task.configurationProperties.group);
if (task.configurationProperties.detail) {
result.detail = task.configurationProperties.detail;
}

View File

@@ -4,15 +4,15 @@
*--------------------------------------------------------------------------------------------*/
import { DisposableStore, Disposable, IDisposable } from 'vs/base/common/lifecycle';
import { ExtHostContext, ExtHostTerminalServiceShape, MainThreadTerminalServiceShape, MainContext, IExtHostContext, TerminalLaunchConfig, ITerminalDimensionsDto, TerminalIdentifier } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostContext, ExtHostTerminalServiceShape, MainThreadTerminalServiceShape, MainContext, IExtHostContext, TerminalLaunchConfig, ITerminalDimensionsDto, ExtHostTerminalIdentifier } from 'vs/workbench/api/common/extHost.protocol';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { URI } from 'vs/base/common/uri';
import { StopWatch } from 'vs/base/common/stopwatch';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ILogService } from 'vs/platform/log/common/log';
import { IShellLaunchConfig, IShellLaunchConfigDto, ITerminalDimensions, TitleEventSource } from 'vs/platform/terminal/common/terminal';
import { IShellLaunchConfig, IShellLaunchConfigDto, ITerminalDimensions, TerminalLocation, TitleEventSource } from 'vs/platform/terminal/common/terminal';
import { TerminalDataBufferer } from 'vs/platform/terminal/common/terminalDataBuffering';
import { ITerminalExternalLinkProvider, ITerminalInstance, ITerminalInstanceService, ITerminalLink, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal';
import { ITerminalEditorService, ITerminalExternalLinkProvider, ITerminalGroupService, ITerminalInstance, ITerminalInstanceService, ITerminalLink, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal';
import { TerminalProcessExtHostProxy } from 'vs/workbench/contrib/terminal/browser/terminalProcessExtHostProxy';
import { IEnvironmentVariableService, ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { deserializeEnvironmentVariableCollection, serializeEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariableShared';
@@ -20,6 +20,7 @@ import { IStartExtensionTerminalRequest, ITerminalProcessExtHostProxy, ITerminal
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
import { withNullAsUndefined } from 'vs/base/common/types';
import { OperatingSystem, OS } from 'vs/base/common/platform';
import { TerminalEditorLocationOptions } from 'vscode';
@extHostNamedCustomer(MainContext.MainThreadTerminalService)
export class MainThreadTerminalService implements MainThreadTerminalServiceShape {
@@ -30,7 +31,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
* to a numeric terminal id (an id generated on the renderer side)
* This comes in play only when dealing with terminals created on the extension host side
*/
private _extHostTerminalIds = new Map<string, number>();
private _extHostTerminals = new Map<string, Promise<ITerminalInstance>>();
private readonly _toDispose = new DisposableStore();
private readonly _terminalProcessProxies = new Map<number, ITerminalProcessExtHostProxy>();
private readonly _profileProviders = new Map<string, IDisposable>();
@@ -53,30 +54,33 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
@IEnvironmentVariableService private readonly _environmentVariableService: IEnvironmentVariableService,
@ILogService private readonly _logService: ILogService,
@ITerminalProfileResolverService private readonly _terminalProfileResolverService: ITerminalProfileResolverService,
@IRemoteAgentService remoteAgentService: IRemoteAgentService
@IRemoteAgentService remoteAgentService: IRemoteAgentService,
@ITerminalGroupService private readonly _terminalGroupService: ITerminalGroupService,
@ITerminalEditorService private readonly _terminalEditorService: ITerminalEditorService
) {
this._proxy = _extHostContext.getProxy(ExtHostContext.ExtHostTerminalService);
// ITerminalService listeners
this._toDispose.add(_terminalService.onInstanceCreated((instance) => {
this._toDispose.add(_terminalService.onDidCreateInstance((instance) => {
this._onTerminalOpened(instance);
this._onInstanceDimensionsChanged(instance);
}));
this._toDispose.add(_terminalService.onInstanceDisposed(instance => this._onTerminalDisposed(instance)));
this._toDispose.add(_terminalService.onInstanceProcessIdReady(instance => this._onTerminalProcessIdReady(instance)));
this._toDispose.add(_terminalService.onInstanceDimensionsChanged(instance => this._onInstanceDimensionsChanged(instance)));
this._toDispose.add(_terminalService.onInstanceMaximumDimensionsChanged(instance => this._onInstanceMaximumDimensionsChanged(instance)));
this._toDispose.add(_terminalService.onInstanceRequestStartExtensionTerminal(e => this._onRequestStartExtensionTerminal(e)));
this._toDispose.add(_terminalService.onActiveInstanceChanged(instance => this._onActiveTerminalChanged(instance ? instance.instanceId : null)));
this._toDispose.add(_terminalService.onInstanceTitleChanged(instance => instance && this._onTitleChanged(instance.instanceId, instance.title)));
this._toDispose.add(_terminalService.onDidDisposeInstance(instance => this._onTerminalDisposed(instance)));
this._toDispose.add(_terminalService.onDidReceiveProcessId(instance => this._onTerminalProcessIdReady(instance)));
this._toDispose.add(_terminalService.onDidChangeInstanceDimensions(instance => this._onInstanceDimensionsChanged(instance)));
this._toDispose.add(_terminalService.onDidMaximumDimensionsChange(instance => this._onInstanceMaximumDimensionsChanged(instance)));
this._toDispose.add(_terminalService.onDidRequestStartExtensionTerminal(e => this._onRequestStartExtensionTerminal(e)));
this._toDispose.add(_terminalService.onDidChangeActiveInstance(instance => this._onActiveTerminalChanged(instance ? instance.instanceId : null)));
this._toDispose.add(_terminalService.onDidChangeInstanceTitle(instance => instance && this._onTitleChanged(instance.instanceId, instance.title)));
this._toDispose.add(_terminalService.onDidInputInstanceData(instance => this._proxy.$acceptTerminalInteraction(instance.instanceId)));
// Set initial ext host state
this._terminalService.terminalInstances.forEach(t => {
this._terminalService.instances.forEach(t => {
this._onTerminalOpened(t);
t.processReady.then(() => this._onTerminalProcessIdReady(t));
});
const activeInstance = this._terminalService.getActiveInstance();
const activeInstance = this._terminalService.activeInstance;
if (activeInstance) {
this._proxy.$acceptActiveTerminalChanged(activeInstance.instanceId);
}
@@ -107,19 +111,11 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
this._proxy.$acceptDefaultProfile(...await Promise.all([defaultProfile, defaultAutomationProfile]));
}
private _getTerminalId(id: TerminalIdentifier): number | undefined {
if (typeof id === 'number') {
return id;
private async _getTerminalInstance(id: ExtHostTerminalIdentifier): Promise<ITerminalInstance | undefined> {
if (typeof id === 'string') {
return this._extHostTerminals.get(id);
}
return this._extHostTerminalIds.get(id);
}
private _getTerminalInstance(id: TerminalIdentifier): ITerminalInstance | undefined {
const rendererId = this._getTerminalId(id);
if (typeof rendererId === 'number') {
return this._terminalService.getInstanceFromId(rendererId);
}
return undefined;
return this._terminalService.getInstanceFromId(id);
}
public async $createTerminal(extHostTerminalId: string, launchConfig: TerminalLaunchConfig): Promise<void> {
@@ -129,6 +125,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
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,
@@ -138,46 +135,55 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
customPtyImplementation: launchConfig.isExtensionCustomPtyTerminal
? (id, cols, rows) => new TerminalProcessExtHostProxy(id, cols, rows, this._terminalService)
: undefined,
extHostTerminalId: extHostTerminalId,
extHostTerminalId,
isFeatureTerminal: launchConfig.isFeatureTerminal,
isExtensionOwnedTerminal: launchConfig.isExtensionOwnedTerminal,
useShellEnvironment: launchConfig.useShellEnvironment
useShellEnvironment: launchConfig.useShellEnvironment,
};
let terminal: ITerminalInstance | undefined;
if (launchConfig.isSplitTerminal) {
const activeInstance = this._terminalService.getActiveInstance();
if (activeInstance) {
terminal = withNullAsUndefined(this._terminalService.splitInstance(activeInstance, shellLaunchConfig));
}
}
if (!terminal) {
terminal = this._terminalService.createTerminal(shellLaunchConfig);
}
this._extHostTerminalIds.set(extHostTerminalId, terminal.instanceId);
this._extHostTerminals.set(extHostTerminalId, new Promise(async r => {
const terminal = await this._terminalService.createTerminal({
config: shellLaunchConfig,
location: await this._deserializeParentTerminal(launchConfig.location)
});
r(terminal);
}));
}
public $show(id: TerminalIdentifier, preserveFocus: boolean): void {
const terminalInstance = this._getTerminalInstance(id);
private async _deserializeParentTerminal(location?: TerminalLocation | TerminalEditorLocationOptions | { parentTerminal: ExtHostTerminalIdentifier } | { splitActiveTerminal: boolean }): Promise<TerminalLocation | TerminalEditorLocationOptions | { parentTerminal: ITerminalInstance } | { splitActiveTerminal: boolean } | undefined> {
if (typeof location === 'object' && 'parentTerminal' in location) {
const parentTerminal = await this._extHostTerminals.get(location.parentTerminal.toString());
return parentTerminal ? { parentTerminal } : undefined;
}
return location;
}
public async $show(id: ExtHostTerminalIdentifier, preserveFocus: boolean): Promise<void> {
const terminalInstance = await this._getTerminalInstance(id);
if (terminalInstance) {
this._terminalService.setActiveInstance(terminalInstance);
this._terminalService.showPanel(!preserveFocus);
if (terminalInstance.target === TerminalLocation.Editor) {
this._terminalEditorService.revealActiveEditor(preserveFocus);
} else {
this._terminalGroupService.showPanel(!preserveFocus);
}
}
}
public $hide(id: TerminalIdentifier): void {
const rendererId = this._getTerminalId(id);
const instance = this._terminalService.getActiveInstance();
if (instance && instance.instanceId === rendererId) {
this._terminalService.hidePanel();
public async $hide(id: ExtHostTerminalIdentifier): Promise<void> {
const instanceToHide = await this._getTerminalInstance(id);
const activeInstance = this._terminalService.activeInstance;
if (activeInstance && activeInstance.instanceId === instanceToHide?.instanceId && activeInstance.target !== TerminalLocation.Editor) {
this._terminalGroupService.hidePanel();
}
}
public $dispose(id: TerminalIdentifier): void {
this._getTerminalInstance(id)?.dispose();
public async $dispose(id: ExtHostTerminalIdentifier): Promise<void> {
(await this._getTerminalInstance(id))?.dispose();
}
public $sendText(id: TerminalIdentifier, text: string, addNewLine: boolean): void {
this._getTerminalInstance(id)?.sendText(text, addNewLine);
public async $sendText(id: ExtHostTerminalIdentifier, text: string, addNewLine: boolean): Promise<void> {
const instance = await this._getTerminalInstance(id);
await instance?.sendText(text, addNewLine);
}
public $startSendingDataEvents(): void {
@@ -186,7 +192,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
this._onTerminalData(id, data);
});
// Send initial events if they exist
this._terminalService.terminalInstances.forEach(t => {
this._terminalService.instances.forEach(t => {
t.initialDataEvents?.forEach(d => this._onTerminalData(t.instanceId, d));
});
}
@@ -211,10 +217,12 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
this._terminalService.registerProcessSupport(isSupported);
}
public $registerProfileProvider(id: string): void {
public $registerProfileProvider(id: string, extensionIdentifier: string): void {
// Proxy profile provider requests through the extension host
this._profileProviders.set(id, this._terminalService.registerTerminalProfileProvider(id, {
createContributedTerminalProfile: async (isSplitTerminal) => this._proxy.$createContributedProfileTerminal(id, isSplitTerminal)
this._profileProviders.set(id, this._terminalService.registerTerminalProfileProvider(extensionIdentifier, id, {
createContributedTerminalProfile: async (options) => {
return this._proxy.$createContributedProfileTerminal(id, options);
}
}));
}
@@ -267,7 +275,6 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
this._proxy.$acceptTerminalMaximumDimensions(instance.instanceId, instance.maxCols, instance.maxRows);
}
private _onRequestStartExtensionTerminal(request: IStartExtensionTerminalRequest): void {
const proxy = request.proxy;
this._terminalProcessProxies.set(proxy.instanceId, proxy);
@@ -380,9 +387,9 @@ class TerminalDataEventTracker extends Disposable {
this._register(this._bufferer = new TerminalDataBufferer(this._callback));
this._terminalService.terminalInstances.forEach(instance => this._registerInstance(instance));
this._register(this._terminalService.onInstanceCreated(instance => this._registerInstance(instance)));
this._register(this._terminalService.onInstanceDisposed(instance => this._bufferer.stopBuffering(instance.instanceId)));
this._terminalService.instances.forEach(instance => this._registerInstance(instance));
this._register(this._terminalService.onDidCreateInstance(instance => this._registerInstance(instance)));
this._register(this._terminalService.onDidDisposeInstance(instance => this._bufferer.stopBuffering(instance.instanceId)));
}
private _registerInstance(instance: ITerminalInstance): void {

View File

@@ -5,17 +5,19 @@
import { VSBuffer } from 'vs/base/common/buffer';
import { CancellationToken } from 'vs/base/common/cancellation';
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
import { Disposable, DisposableStore, IDisposable, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { isDefined } from 'vs/base/common/types';
import { URI, UriComponents } from 'vs/base/common/uri';
import { URI } from 'vs/base/common/uri';
import { Range } from 'vs/editor/common/core/range';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { TestResultState } from 'vs/workbench/api/common/extHostTypes';
import { ExtensionRunTestsRequest, getTestSubscriptionKey, ITestItem, ITestMessage, ITestRunTask, RunTestsRequest, TestDiffOpType, TestsDiff } from 'vs/workbench/contrib/testing/common/testCollection';
import { MutableObservableValue } from 'vs/workbench/contrib/testing/common/observableValue';
import { ExtensionRunTestsRequest, ITestItem, ITestMessage, ITestRunProfile, ITestRunTask, ResolvedTestRunRequest, TestDiffOpType, TestResultState, TestsDiff } from 'vs/workbench/contrib/testing/common/testCollection';
import { ITestProfileService } from 'vs/workbench/contrib/testing/common/testProfileService';
import { TestCoverage } from 'vs/workbench/contrib/testing/common/testCoverage';
import { LiveTestResult } from 'vs/workbench/contrib/testing/common/testResult';
import { ITestResultService } from 'vs/workbench/contrib/testing/common/testResultService';
import { ITestRootProvider, ITestService } from 'vs/workbench/contrib/testing/common/testService';
import { ExtHostContext, ExtHostTestingResource, ExtHostTestingShape, IExtHostContext, MainContext, MainThreadTestingShape } from '../common/extHost.protocol';
import { IMainThreadTestController, ITestRootProvider, ITestService } from 'vs/workbench/contrib/testing/common/testService';
import { ExtHostContext, ExtHostTestingShape, IExtHostContext, ILocationDto, MainContext, MainThreadTestingShape } from '../common/extHost.protocol';
const reviveDiff = (diff: TestsDiff) => {
for (const entry of diff) {
@@ -34,24 +36,31 @@ const reviveDiff = (diff: TestsDiff) => {
@extHostNamedCustomer(MainContext.MainThreadTesting)
export class MainThreadTesting extends Disposable implements MainThreadTestingShape, ITestRootProvider {
private readonly proxy: ExtHostTestingShape;
private readonly testSubscriptions = new Map<string, IDisposable>();
private readonly testProviderRegistrations = new Map<string, IDisposable>();
private readonly diffListener = this._register(new MutableDisposable());
private readonly testProviderRegistrations = new Map<string, {
instance: IMainThreadTestController;
label: MutableObservableValue<string>;
disposable: IDisposable
}>();
constructor(
extHostContext: IExtHostContext,
@ITestService private readonly testService: ITestService,
@ITestProfileService private readonly testProfiles: ITestProfileService,
@ITestResultService private readonly resultService: ITestResultService,
) {
super();
this.proxy = extHostContext.getProxy(ExtHostContext.ExtHostTesting);
this._register(this.testService.onShouldSubscribe(args => this.proxy.$subscribeToTests(args.resource, args.uri)));
this._register(this.testService.onShouldUnsubscribe(args => this.proxy.$unsubscribeFromTests(args.resource, args.uri)));
const prevResults = resultService.results.map(r => r.toJSON()).filter(isDefined);
if (prevResults.length) {
this.proxy.$publishTestResults(prevResults);
}
this._register(this.testService.onDidCancelTestRun(({ runId }) => {
this.proxy.$cancelExtensionTestRun(runId);
}));
this._register(resultService.onResultsChanged(evt => {
const results = 'completed' in evt ? evt.completed : ('inserted' in evt ? evt.inserted : undefined);
const serialized = results?.toJSON();
@@ -59,18 +68,36 @@ export class MainThreadTesting extends Disposable implements MainThreadTestingSh
this.proxy.$publishTestResults([serialized]);
}
}));
}
this._register(testService.registerRootProvider(this));
for (const { resource, uri } of this.testService.subscriptions) {
this.proxy.$subscribeToTests(resource, uri);
/**
* @inheritdoc
*/
$publishTestRunProfile(profile: ITestRunProfile): void {
const controller = this.testProviderRegistrations.get(profile.controllerId);
if (controller) {
this.testProfiles.addProfile(controller.instance, profile);
}
}
/**
* @inheritdoc
*/
$addTestsToRun(runId: string, tests: ITestItem[]): void {
$updateTestRunConfig(controllerId: string, profileId: number, update: Partial<ITestRunProfile>): void {
this.testProfiles.updateProfile(controllerId, profileId, update);
}
/**
* @inheritdoc
*/
$removeTestProfile(controllerId: string, profileId: number): void {
this.testProfiles.removeProfile(controllerId, profileId);
}
/**
* @inheritdoc
*/
$addTestsToRun(controllerId: string, runId: string, tests: ITestItem[]): void {
for (const test of tests) {
test.uri = URI.revive(test.uri);
if (test.range) {
@@ -78,7 +105,24 @@ export class MainThreadTesting extends Disposable implements MainThreadTestingSh
}
}
this.withLiveRun(runId, r => r.addTestChainToRun(tests));
this.withLiveRun(runId, r => r.addTestChainToRun(controllerId, tests));
}
/**
* @inheritdoc
*/
$signalCoverageAvailable(runId: string, taskId: string): void {
this.withLiveRun(runId, run => {
const task = run.tasks.find(t => t.id === taskId);
if (!task) {
return;
}
(task.coverage as MutableObservableValue<TestCoverage>).value = new TestCoverage({
provideFileCoverage: token => this.proxy.$provideFileCoverage(runId, taskId, token),
resolveFileCoverage: (i, token) => this.proxy.$resolveFileCoverage(runId, taskId, i, token),
});
});
}
/**
@@ -119,85 +163,110 @@ export class MainThreadTesting extends Disposable implements MainThreadTestingSh
/**
* @inheritdoc
*/
public $appendOutputToRun(runId: string, _taskId: string, output: VSBuffer): void {
this.withLiveRun(runId, r => r.output.append(output));
public $appendOutputToRun(runId: string, taskId: string, output: VSBuffer, locationDto?: ILocationDto, testId?: string): void {
const location = locationDto && {
uri: URI.revive(locationDto.uri),
range: Range.lift(locationDto.range)
};
this.withLiveRun(runId, r => r.appendOutput(output, taskId, location, testId));
}
/**
* @inheritdoc
*/
public $appendTestMessageInRun(runId: string, taskId: string, testId: string, message: ITestMessage): void {
public $appendTestMessagesInRun(runId: string, taskId: string, testId: string, messages: ITestMessage[]): void {
const r = this.resultService.getResult(runId);
if (r && r instanceof LiveTestResult) {
if (message.location) {
message.location.uri = URI.revive(message.location.uri);
message.location.range = Range.lift(message.location.range);
}
for (const message of messages) {
if (message.location) {
message.location.uri = URI.revive(message.location.uri);
message.location.range = Range.lift(message.location.range);
}
r.appendMessage(testId, taskId, message);
r.appendMessage(testId, taskId, message);
}
}
}
/**
* @inheritdoc
*/
public $registerTestController(id: string) {
const disposable = this.testService.registerTestController(id, {
runTests: (req, token) => this.proxy.$runTestsForProvider(req, token),
lookupTest: test => this.proxy.$lookupTest(test),
expandTest: (src, levels) => this.proxy.$expandTest(src, isFinite(levels) ? levels : -1),
public $registerTestController(controllerId: string, labelStr: string) {
const disposable = new DisposableStore();
const label = new MutableObservableValue(labelStr);
const controller: IMainThreadTestController = {
id: controllerId,
label,
configureRunProfile: id => this.proxy.$configureRunProfile(controllerId, id),
runTests: (req, token) => this.proxy.$runControllerTests(req, token),
expandTest: (testId, levels) => this.proxy.$expandTest(testId, isFinite(levels) ? levels : -1),
};
disposable.add(toDisposable(() => this.testProfiles.removeProfile(controllerId)));
disposable.add(this.testService.registerTestController(controllerId, controller));
this.testProviderRegistrations.set(controllerId, {
instance: controller,
label,
disposable
});
this.testProviderRegistrations.set(id, disposable);
}
/**
* @inheritdoc
*/
public $unregisterTestController(id: string) {
this.testProviderRegistrations.get(id)?.dispose();
this.testProviderRegistrations.delete(id);
public $updateControllerLabel(controllerId: string, label: string) {
const controller = this.testProviderRegistrations.get(controllerId);
if (controller) {
controller.label.value = label;
}
}
/**
* @inheritdoc
*/
public $subscribeToDiffs(resource: ExtHostTestingResource, uriComponents: UriComponents): void {
const uri = URI.revive(uriComponents);
const disposable = this.testService.subscribeToDiffs(resource, uri,
diff => this.proxy.$acceptDiff(resource, uriComponents, diff));
this.testSubscriptions.set(getTestSubscriptionKey(resource, uri), disposable);
public $unregisterTestController(controllerId: string) {
this.testProviderRegistrations.get(controllerId)?.disposable.dispose();
this.testProviderRegistrations.delete(controllerId);
}
/**
* @inheritdoc
*/
public $unsubscribeFromDiffs(resource: ExtHostTestingResource, uriComponents: UriComponents): void {
const key = getTestSubscriptionKey(resource, URI.revive(uriComponents));
this.testSubscriptions.get(key)?.dispose();
this.testSubscriptions.delete(key);
public $subscribeToDiffs(): void {
this.proxy.$acceptDiff(this.testService.collection.getReviverDiff());
this.diffListener.value = this.testService.onDidProcessDiff(this.proxy.$acceptDiff, this.proxy);
}
/**
* @inheritdoc
*/
public $publishDiff(resource: ExtHostTestingResource, uri: UriComponents, diff: TestsDiff): void {
public $unsubscribeFromDiffs(): void {
this.diffListener.clear();
}
/**
* @inheritdoc
*/
public $publishDiff(controllerId: string, diff: TestsDiff): void {
reviveDiff(diff);
this.testService.publishDiff(resource, URI.revive(uri), diff);
this.testService.publishDiff(controllerId, diff);
}
public async $runTests(req: RunTestsRequest, token: CancellationToken): Promise<string> {
const result = await this.testService.runTests(req, token);
public async $runTests(req: ResolvedTestRunRequest, token: CancellationToken): Promise<string> {
const result = await this.testService.runResolvedTests(req, token);
return result.id;
}
public override dispose() {
super.dispose();
for (const subscription of this.testSubscriptions.values()) {
subscription.dispose();
for (const subscription of this.testProviderRegistrations.values()) {
subscription.disposable.dispose();
}
this.testSubscriptions.clear();
this.testProviderRegistrations.clear();
}
private withLiveRun<T>(runId: string, fn: (run: LiveTestResult) => T): T | undefined {

View File

@@ -13,7 +13,7 @@ import { isUndefinedOrNull, isNumber } from 'vs/base/common/types';
import { Registry } from 'vs/platform/registry/common/platform';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { ILogService } from 'vs/platform/log/common/log';
import { IConnectionTreeService } from 'sql/workbench/services/connection/common/connectionTreeService';
import { IConnectionTreeService } from 'sql/workbench/services/connection/common/connectionTreeService'; // {{SQL CARBON EDIT}} Add our tree service
import { TreeDataTransferConverter } from 'vs/workbench/api/common/shared/treeDataTransfer';
@extHostNamedCustomer(MainContext.MainThreadTreeViews)
@@ -198,14 +198,14 @@ export class TreeViewDataProvider implements ITreeViewDataProvider {
this.hasResolve = this._proxy.$hasResolve(this.treeViewId);
}
getChildren(treeItem?: ITreeItem): Promise<ITreeItem[]> {
return Promise.resolve(this._proxy.$getChildren(this.treeViewId, treeItem ? treeItem.handle : undefined)
getChildren(treeItem?: ITreeItem): Promise<ITreeItem[] | undefined> {
return this._proxy.$getChildren(this.treeViewId, treeItem ? treeItem.handle : undefined)
.then(
children => this.postGetChildren(children),
err => {
this.notificationService.error(err);
return [];
}));
});
}
getItemsToRefresh(itemsToRefreshByHandle: { [treeItemHandle: string]: ITreeItem }): ITreeItem[] {
@@ -242,8 +242,11 @@ export class TreeViewDataProvider implements ITreeViewDataProvider {
return this.itemsMap.size === 0;
}
protected async postGetChildren(elements: ITreeItem[]): Promise<ITreeItem[]> { // {{SQL CARBON EDIT}} For use by Component Tree View
const result: ITreeItem[] = []; // {{SQL CARBON EDIT}}
protected async postGetChildren(elements: ITreeItem[] | undefined): Promise<ITreeItem[] | undefined> { // {{SQL CARBON EDIT}} For use by Component Tree View
if (elements === undefined) {
return undefined;
}
const result: ITreeItem[] = []; // {{SQL CARBON EDIT}} We don't always return ResolvableTreeItems
const hasResolve = await this.hasResolve;
if (elements) {
for (const element of elements) {

View File

@@ -7,8 +7,8 @@ import * as nls from 'vs/nls';
import { MainThreadTunnelServiceShape, IExtHostContext, MainContext, ExtHostContext, ExtHostTunnelServiceShape, CandidatePortSource, PortAttributesProviderSelector } from 'vs/workbench/api/common/extHost.protocol';
import { TunnelDto } from 'vs/workbench/api/common/extHostTunnelService';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { CandidatePort, IRemoteExplorerService, makeAddress, PORT_AUTO_FORWARD_SETTING, PORT_AUTO_SOURCE_SETTING, PORT_AUTO_SOURCE_SETTING_OUTPUT, PORT_AUTO_SOURCE_SETTING_PROCESS } from 'vs/workbench/services/remote/common/remoteExplorerService';
import { ITunnelProvider, ITunnelService, TunnelCreationOptions, TunnelProviderFeatures, TunnelOptions, RemoteTunnel, isPortPrivileged, ProvidedPortAttributes, PortAttributesProvider } from 'vs/platform/remote/common/tunnel';
import { CandidatePort, IRemoteExplorerService, makeAddress, PORT_AUTO_FORWARD_SETTING, PORT_AUTO_SOURCE_SETTING, PORT_AUTO_SOURCE_SETTING_OUTPUT, PORT_AUTO_SOURCE_SETTING_PROCESS, TunnelSource } from 'vs/workbench/services/remote/common/remoteExplorerService';
import { ITunnelProvider, ITunnelService, TunnelCreationOptions, TunnelProviderFeatures, TunnelOptions, RemoteTunnel, isPortPrivileged, ProvidedPortAttributes, PortAttributesProvider, TunnelProtocol } from 'vs/platform/remote/common/tunnel';
import { Disposable } from 'vs/base/common/lifecycle';
import type { TunnelDescription } from 'vs/platform/remote/common/remoteAuthorityResolver';
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
@@ -57,6 +57,9 @@ export class MainThreadTunnelService extends Disposable implements MainThreadTun
return this._proxy.$registerCandidateFinder(this.processFindingEnabled());
}
}));
this._register(this.tunnelService.onAddedTunnelProvider(() => {
return this._proxy.$registerCandidateFinder(this.processFindingEnabled());
}));
}
private _alreadyRegistered: boolean = false;
@@ -94,7 +97,16 @@ export class MainThreadTunnelService extends Disposable implements MainThreadTun
}
async $openTunnel(tunnelOptions: TunnelOptions, source: string): Promise<TunnelDto | undefined> {
const tunnel = await this.remoteExplorerService.forward(tunnelOptions.remoteAddress, tunnelOptions.localAddressPort, tunnelOptions.label, source, false);
const tunnel = await this.remoteExplorerService.forward({
remote: tunnelOptions.remoteAddress,
local: tunnelOptions.localAddressPort,
name: tunnelOptions.label,
source: {
source: TunnelSource.Extension,
description: source
},
elevateIfNeeded: false
});
if (tunnel) {
if (!this.elevateionRetry
&& (tunnelOptions.localAddressPort !== undefined)
@@ -118,7 +130,16 @@ export class MainThreadTunnelService extends Disposable implements MainThreadTun
run: async () => {
this.elevateionRetry = true;
await this.remoteExplorerService.close({ host: tunnel.tunnelRemoteHost, port: tunnel.tunnelRemotePort });
await this.remoteExplorerService.forward(tunnelOptions.remoteAddress, tunnelOptions.localAddressPort, tunnelOptions.label, source, true);
await this.remoteExplorerService.forward({
remote: tunnelOptions.remoteAddress,
local: tunnelOptions.localAddressPort,
name: tunnelOptions.label,
source: {
source: TunnelSource.Extension,
description: source
},
elevateIfNeeded: true
});
this.elevateionRetry = false;
}
}]);
@@ -156,6 +177,7 @@ export class MainThreadTunnelService extends Disposable implements MainThreadTun
localAddress: typeof tunnel.localAddress === 'string' ? tunnel.localAddress : makeAddress(tunnel.localAddress.host, tunnel.localAddress.port),
tunnelLocalPort: typeof tunnel.localAddress !== 'string' ? tunnel.localAddress.port : undefined,
public: tunnel.public,
protocol: tunnel.protocol ?? TunnelProtocol.Http,
dispose: async (silent?: boolean) => {
this.logService.trace(`ForwardedPorts: (MainThreadTunnelService) Closing tunnel from tunnel provider: ${tunnel?.remoteAddress.host}:${tunnel?.remoteAddress.port}`);
return this._proxy.$closeTunnel({ host: tunnel.remoteAddress.host, port: tunnel.remoteAddress.port }, silent);

View File

@@ -9,7 +9,8 @@ import { URI, UriComponents } from 'vs/base/common/uri';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { MainThreadWebviews, reviveWebviewContentOptions, reviveWebviewExtension } from 'vs/workbench/api/browser/mainThreadWebviews';
import * as extHostProtocol from 'vs/workbench/api/common/extHost.protocol';
import { EditorGroupColumn, editorGroupToViewColumn, IEditorInput, viewColumnToEditorGroup } from 'vs/workbench/common/editor';
import { IEditorInput } from 'vs/workbench/common/editor';
import { EditorGroupColumn, columnToEditorGroup, editorGroupToColumn } from 'vs/workbench/services/editor/common/editorGroupColumn';
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
import { WebviewOptions } from 'vs/workbench/contrib/webview/browser/webview';
import { WebviewInput } from 'vs/workbench/contrib/webviewPanel/browser/webviewEditorInput';
@@ -161,7 +162,7 @@ export class MainThreadWebviewPanels extends Disposable implements extHostProtoc
const mainThreadShowOptions: ICreateWebViewShowOptions = Object.create(null);
if (showOptions) {
mainThreadShowOptions.preserveFocus = !!showOptions.preserveFocus;
mainThreadShowOptions.group = viewColumnToEditorGroup(this._editorGroupService, showOptions.viewColumn);
mainThreadShowOptions.group = columnToEditorGroup(this._editorGroupService, showOptions.viewColumn);
}
const extension = reviveWebviewExtension(extensionData);
@@ -171,10 +172,14 @@ export class MainThreadWebviewPanels extends Disposable implements extHostProtoc
/* __GDPR__
"webviews:createWebviewPanel" : {
"extensionId" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
"extensionId" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"viewType" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
}
*/
this._telemetryService.publicLog('webviews:createWebviewPanel', { extensionId: extension.id.value });
this._telemetryService.publicLog('webviews:createWebviewPanel', {
extensionId: extension.id.value,
viewType
});
}
public $disposeWebview(handle: extHostProtocol.WebviewHandle): void {
@@ -198,7 +203,7 @@ export class MainThreadWebviewPanels extends Disposable implements extHostProtoc
return;
}
const targetGroup = this._editorGroupService.getGroup(viewColumnToEditorGroup(this._editorGroupService, showOptions.viewColumn)) || this._editorGroupService.getGroup(webview.group || 0);
const targetGroup = this._editorGroupService.getGroup(columnToEditorGroup(this._editorGroupService, showOptions.viewColumn)) || this._editorGroupService.getGroup(webview.group || 0);
if (targetGroup) {
this._webviewWorkbenchService.revealWebview(webview, targetGroup, !!showOptions.preserveFocus);
}
@@ -239,7 +244,7 @@ export class MainThreadWebviewPanels extends Disposable implements extHostProtoc
state,
panelOptions: webviewInput.webview.options,
webviewOptions: webviewInput.webview.contentOptions,
}, editorGroupToViewColumn(this._editorGroupService, webviewInput.group || 0));
}, editorGroupToColumn(this._editorGroupService, webviewInput.group || 0));
} catch (error) {
onUnexpectedError(error);
webviewInput.webview.html = this._mainThreadWebviews.getWebviewResolvedFailedContent(viewType);
@@ -277,7 +282,7 @@ export class MainThreadWebviewPanels extends Disposable implements extHostProtoc
viewStates[handle] = {
visible: topLevelInput === group.activeEditor,
active: editorInput === activeEditorInput,
position: editorGroupToViewColumn(this._editorGroupService, group.id),
position: editorGroupToColumn(this._editorGroupService, group.id),
};
}
};

View File

@@ -214,7 +214,7 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {
}
private isWorkspaceTrusted(): boolean {
return this._workspaceTrustManagementService.isWorkpaceTrusted();
return this._workspaceTrustManagementService.isWorkspaceTrusted();
}
private _onDidGrantWorkspaceTrust(): void {

View File

@@ -1,112 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { URI } from 'vs/base/common/uri';
import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters';
import { CommandsRegistry, ICommandService, ICommandHandler } from 'vs/platform/commands/common/commands';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { ILogService } from 'vs/platform/log/common/log';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IViewDescriptorService, IViewsService, ViewVisibilityState } from 'vs/workbench/common/views';
// -----------------------------------------------------------------
// The following commands are registered on both sides separately.
//
// We are trying to maintain backwards compatibility for cases where
// API commands are encoded as markdown links, for example.
// -----------------------------------------------------------------
export interface ICommandsExecutor {
executeCommand<T>(id: string, ...args: any[]): Promise<T | undefined>;
}
function adjustHandler(handler: (executor: ICommandsExecutor, ...args: any[]) => any): ICommandHandler {
return (accessor, ...args: any[]) => {
return handler(accessor.get(ICommandService), ...args);
};
}
CommandsRegistry.registerCommand('_extensionTests.setLogLevel', function (accessor: ServicesAccessor, level: number) {
const logService = accessor.get(ILogService);
const environmentService = accessor.get(IEnvironmentService);
if (environmentService.isExtensionDevelopment && !!environmentService.extensionTestsLocationURI) {
logService.setLevel(level);
}
});
CommandsRegistry.registerCommand('_extensionTests.getLogLevel', function (accessor: ServicesAccessor) {
const logService = accessor.get(ILogService);
return logService.getLevel();
});
CommandsRegistry.registerCommand('_workbench.action.moveViews', async function (accessor: ServicesAccessor, options: { viewIds: string[], destinationId: string }) {
const viewDescriptorService = accessor.get(IViewDescriptorService);
const destination = viewDescriptorService.getViewContainerById(options.destinationId);
if (!destination) {
return;
}
// FYI, don't use `moveViewsToContainer` in 1 shot, because it expects all views to have the same current location
for (const viewId of options.viewIds) {
const viewDescriptor = viewDescriptorService.getViewDescriptorById(viewId);
if (viewDescriptor?.canMoveView) {
viewDescriptorService.moveViewsToContainer([viewDescriptor], destination, ViewVisibilityState.Default);
}
}
await accessor.get(IViewsService).openViewContainer(destination.id, true);
});
export class MoveViewsAPICommand {
public static readonly ID = 'vscode.moveViews';
public static execute(executor: ICommandsExecutor, options: { viewIds: string[], destinationId: string }): Promise<any> {
if (!Array.isArray(options?.viewIds) || typeof options?.destinationId !== 'string') {
return Promise.reject('Invalid arguments');
}
return executor.executeCommand('_workbench.action.moveViews', options);
}
}
CommandsRegistry.registerCommand({
id: MoveViewsAPICommand.ID,
handler: adjustHandler(MoveViewsAPICommand.execute),
description: {
description: 'Move Views',
args: []
}
});
// -----------------------------------------------------------------
// The following commands are registered on the renderer but as API
// command. DO NOT USE this unless you have understood what this
// means
// -----------------------------------------------------------------
class OpenAPICommand {
public static readonly ID = 'vscode.open';
public static execute(executor: ICommandsExecutor, resource: URI): Promise<any> {
return executor.executeCommand('_workbench.open', resource);
}
}
CommandsRegistry.registerCommand(OpenAPICommand.ID, adjustHandler(OpenAPICommand.execute));
class DiffAPICommand {
public static readonly ID = 'vscode.diff';
public static execute(executor: ICommandsExecutor, left: URI, right: URI, label: string, options?: typeConverters.TextEditorOpenOptions): Promise<any> {
return executor.executeCommand('_workbench.diff', [
left, right,
label,
]);
}
}
CommandsRegistry.registerCommand(DiffAPICommand.ID, adjustHandler(DiffAPICommand.execute));

View File

@@ -34,7 +34,10 @@ const configurationEntrySchema: IJSONSchema = {
},
additionalProperties: {
anyOf: [
{ $ref: 'http://json-schema.org/draft-07/schema#' },
{
title: nls.localize('vscode.extension.contributes.configuration.properties.schema', 'Schema of the configuration property.'),
$ref: 'http://json-schema.org/draft-07/schema#'
},
{
type: 'object',
properties: {
@@ -81,6 +84,16 @@ const configurationEntrySchema: IJSONSchema = {
markdownDeprecationMessage: {
type: 'string',
description: nls.localize('scope.markdownDeprecationMessage', 'If set, the property is marked as deprecated and the given message is shown as an explanation in the markdown format.')
},
editPresentation: {
type: 'string',
enum: ['singlelineText', 'multilineText'],
enumDescriptions: [
nls.localize('scope.singlelineText.description', 'The value will be shown in an inputbox.'),
nls.localize('scope.multilineText.description', 'The value will be shown in a textarea.')
],
default: 'singlelineText',
description: nls.localize('scope.editPresentation', 'When specified, controls the presentation format of the string setting.')
}
}
}
@@ -159,6 +172,8 @@ configurationExtPoint.setHandler((extensions, { added, removed }) => {
configurationRegistry.deregisterConfigurations(removedConfigurations);
}
const seenProperties = new Set<string>();
function handleConfiguration(node: IConfigurationNode, extension: IExtensionPointUser<any>): IConfigurationNode[] {
const configurations: IConfigurationNode[] = [];
let configuration = objects.deepClone(node);
@@ -176,6 +191,60 @@ configurationExtPoint.setHandler((extensions, { added, removed }) => {
return configurations;
}
function validateProperties(configuration: IConfigurationNode, extension: IExtensionPointUser<any>): void {
let properties = configuration.properties;
if (properties) {
if (typeof properties !== 'object') {
extension.collector.error(nls.localize('invalid.properties', "'configuration.properties' must be an object"));
configuration.properties = {};
}
for (let key in properties) {
const message = validateProperty(key);
if (message) {
delete properties[key];
extension.collector.warn(message);
continue;
}
if (seenProperties.has(key)) {
delete properties[key];
extension.collector.warn(nls.localize('config.property.duplicate', "Cannot register '{0}'. This property is already registered.", key));
continue;
}
const propertyConfiguration = properties[key];
if (!isObject(propertyConfiguration)) {
delete properties[key];
extension.collector.error(nls.localize('invalid.property', "configuration.properties property '{0}' must be an object", key));
continue;
}
seenProperties.add(key);
if (propertyConfiguration.scope) {
if (propertyConfiguration.scope.toString() === 'application') {
propertyConfiguration.scope = ConfigurationScope.APPLICATION;
} else if (propertyConfiguration.scope.toString() === 'machine') {
propertyConfiguration.scope = ConfigurationScope.MACHINE;
} else if (propertyConfiguration.scope.toString() === 'resource') {
propertyConfiguration.scope = ConfigurationScope.RESOURCE;
} else if (propertyConfiguration.scope.toString() === 'machine-overridable') {
propertyConfiguration.scope = ConfigurationScope.MACHINE_OVERRIDABLE;
} else if (propertyConfiguration.scope.toString() === 'language-overridable') {
propertyConfiguration.scope = ConfigurationScope.LANGUAGE_OVERRIDABLE;
} else {
propertyConfiguration.scope = ConfigurationScope.WINDOW;
}
} else {
propertyConfiguration.scope = ConfigurationScope.WINDOW;
}
}
}
let subNodes = configuration.allOf;
if (subNodes) {
extension.collector.error(nls.localize('invalid.allOf', "'configuration.allOf' is deprecated and should no longer be used. Instead, pass multiple configuration sections as an array to the 'configuration' contribution point."));
for (let node of subNodes) {
validateProperties(node, extension);
}
}
}
if (added.length) {
const addedConfigurations: IConfigurationNode[] = [];
for (let extension of added) {
@@ -196,54 +265,6 @@ configurationExtPoint.setHandler((extensions, { added, removed }) => {
});
// END VSCode extension point `configuration`
function validateProperties(configuration: IConfigurationNode, extension: IExtensionPointUser<any>): void {
let properties = configuration.properties;
if (properties) {
if (typeof properties !== 'object') {
extension.collector.error(nls.localize('invalid.properties', "'configuration.properties' must be an object"));
configuration.properties = {};
}
for (let key in properties) {
const message = validateProperty(key);
if (message) {
delete properties[key];
extension.collector.warn(message);
continue;
}
const propertyConfiguration = properties[key];
if (!isObject(propertyConfiguration)) {
delete properties[key];
extension.collector.error(nls.localize('invalid.property', "configuration.properties property '{0}' must be an object", key));
continue;
}
if (propertyConfiguration.scope) {
if (propertyConfiguration.scope.toString() === 'application') {
propertyConfiguration.scope = ConfigurationScope.APPLICATION;
} else if (propertyConfiguration.scope.toString() === 'machine') {
propertyConfiguration.scope = ConfigurationScope.MACHINE;
} else if (propertyConfiguration.scope.toString() === 'resource') {
propertyConfiguration.scope = ConfigurationScope.RESOURCE;
} else if (propertyConfiguration.scope.toString() === 'machine-overridable') {
propertyConfiguration.scope = ConfigurationScope.MACHINE_OVERRIDABLE;
} else if (propertyConfiguration.scope.toString() === 'language-overridable') {
propertyConfiguration.scope = ConfigurationScope.LANGUAGE_OVERRIDABLE;
} else {
propertyConfiguration.scope = ConfigurationScope.WINDOW;
}
} else {
propertyConfiguration.scope = ConfigurationScope.WINDOW;
}
}
}
let subNodes = configuration.allOf;
if (subNodes) {
extension.collector.error(nls.localize('invalid.allOf', "'configuration.allOf' is deprecated and should no longer be used. Instead, pass multiple configuration sections as an array to the 'configuration' contribution point."));
for (let node of subNodes) {
validateProperties(node, extension);
}
}
}
const jsonRegistry = Registry.as<IJSONContributionRegistry>(JSONExtensions.JSONContribution);
jsonRegistry.registerSchema('vscode://schemas/workspaceConfig', {
allowComments: true,
@@ -321,6 +342,11 @@ jsonRegistry.registerSchema('vscode://schemas/workspaceConfig', {
type: 'string',
doNotSuggest: true,
description: nls.localize('workspaceConfig.remoteAuthority', "The remote server where the workspace is located."),
},
'transient': {
type: 'boolean',
doNotSuggest: true,
description: nls.localize('workspaceConfig.transient', "A transient workspace will disappear when restarting or reloading."),
}
},
errorMessage: nls.localize('unknownWorkspaceProperty', "Unknown workspace configuration property")

View File

@@ -17,7 +17,7 @@ import { ExtHostContext, MainContext, ExtHostLogServiceShape, UIKind, CandidateP
import { ExtHostApiCommands } from 'vs/workbench/api/common/extHostApiCommands';
import { ExtHostClipboard } from 'vs/workbench/api/common/extHostClipboard';
import { IExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
import { ExtHostComments } from 'vs/workbench/api/common/extHostComments';
import { createExtHostComments } from 'vs/workbench/api/common/extHostComments';
import { ExtHostConfigProvider, IExtHostConfiguration } from 'vs/workbench/api/common/extHostConfiguration';
import { ExtHostDiagnostics } from 'vs/workbench/api/common/extHostDiagnostics';
import { ExtHostDialogs } from 'vs/workbench/api/common/extHostDialogs';
@@ -90,6 +90,7 @@ import { Schemas } from 'vs/base/common/network';
import { matchesScheme } from 'vs/platform/opener/common/opener';
// import { ExtHostNotebookEditors } from 'vs/workbench/api/common/extHostNotebookEditors'; {{SQL CARBON EDIT}} Disable VS Code notebooks
// import { ExtHostNotebookDocuments } from 'vs/workbench/api/common/extHostNotebookDocuments'; {{SQL CARBON EDIT}} Disable VS Code notebooks
// import { ExtHostInteractive } from 'vs/workbench/api/common/extHostInteractive'; {{SQL CARBON EDIT}} Remove until we need it
import { ExtHostNotebook } from 'sql/workbench/api/common/extHostNotebook';
import { functionalityNotSupportedError } from 'sql/base/common/locConstants';
@@ -165,7 +166,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor, ex
const extHostFileSystemEvent = rpcProtocol.set(ExtHostContext.ExtHostFileSystemEventService, new ExtHostFileSystemEventService(rpcProtocol, extHostLogService, extHostDocumentsAndEditors));
const extHostQuickOpen = rpcProtocol.set(ExtHostContext.ExtHostQuickOpen, createExtHostQuickOpen(rpcProtocol, extHostWorkspace, extHostCommands));
const extHostSCM = rpcProtocol.set(ExtHostContext.ExtHostSCM, new ExtHostSCM(rpcProtocol, extHostCommands, extHostLogService));
const extHostComment = rpcProtocol.set(ExtHostContext.ExtHostComments, new ExtHostComments(rpcProtocol, extHostCommands, extHostDocuments));
const extHostComment = rpcProtocol.set(ExtHostContext.ExtHostComments, createExtHostComments(rpcProtocol, extHostCommands, extHostDocuments));
const extHostProgress = rpcProtocol.set(ExtHostContext.ExtHostProgress, new ExtHostProgress(rpcProtocol.getProxy(MainContext.MainThreadProgress)));
const extHostLabelService = rpcProtocol.set(ExtHostContext.ExtHosLabelService, new ExtHostLabelService(rpcProtocol));
const extHostTheming = rpcProtocol.set(ExtHostContext.ExtHostTheming, new ExtHostTheming(rpcProtocol));
@@ -175,8 +176,9 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor, ex
const extHostWebviewPanels = rpcProtocol.set(ExtHostContext.ExtHostWebviewPanels, new ExtHostWebviewPanels(rpcProtocol, extHostWebviews, extHostWorkspace));
const extHostCustomEditors = rpcProtocol.set(ExtHostContext.ExtHostCustomEditors, new ExtHostCustomEditors(rpcProtocol, extHostDocuments, extensionStoragePaths, extHostWebviews, extHostWebviewPanels));
const extHostWebviewViews = rpcProtocol.set(ExtHostContext.ExtHostWebviewViews, new ExtHostWebviewViews(rpcProtocol, extHostWebviews));
const extHostTesting = rpcProtocol.set(ExtHostContext.ExtHostTesting, new ExtHostTesting(rpcProtocol, extHostDocumentsAndEditors, extHostWorkspace));
const extHostTesting = rpcProtocol.set(ExtHostContext.ExtHostTesting, new ExtHostTesting(rpcProtocol, extHostCommands));
const extHostUriOpeners = rpcProtocol.set(ExtHostContext.ExtHostUriOpeners, new ExtHostUriOpeners(rpcProtocol));
// rpcProtocol.set(ExtHostContext.ExtHostInteractive, new ExtHostInteractive(rpcProtocol, extHostNotebook, extHostDocumentsAndEditors, extHostCommands)); {{SQL CARBON EDIT}} Disable interactive stuff until we need it
// Check that no named customers are missing
// {{SQL CARBON EDIT}} filter out the services we don't expose
@@ -186,7 +188,8 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor, ex
ExtHostContext.ExtHostNotebookDocuments,
ExtHostContext.ExtHostNotebookEditors,
ExtHostContext.ExtHostNotebookKernels,
ExtHostContext.ExtHostNotebookRenderers
ExtHostContext.ExtHostNotebookRenderers,
ExtHostContext.ExtHostInteractive
]);
const expected: ProxyIdentifier<any>[] = values(ExtHostContext).filter(v => !filteredProxies.has(v));
@@ -238,6 +241,9 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor, ex
const authentication: typeof vscode.authentication = {
getSession(providerId: string, scopes: readonly string[], options?: vscode.AuthenticationGetSessionOptions) {
if (options?.forceNewSession) {
checkProposedApiEnabled(extension);
}
return extHostAuthentication.getSession(extension, providerId, scopes, options as any);
},
get onDidChangeSessions(): Event<vscode.AuthenticationSessionsChangeEvent> {
@@ -245,18 +251,6 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor, ex
},
registerAuthenticationProvider(id: string, label: string, provider: vscode.AuthenticationProvider, options?: vscode.AuthenticationProviderOptions): vscode.Disposable {
return extHostAuthentication.registerAuthenticationProvider(id, label, provider, options);
},
get onDidChangeAuthenticationProviders(): Event<vscode.AuthenticationProvidersChangeEvent> {
checkProposedApiEnabled(extension);
return extHostAuthentication.onDidChangeAuthenticationProviders;
},
get providers(): ReadonlyArray<vscode.AuthenticationProviderInformation> {
checkProposedApiEnabled(extension);
return extHostAuthentication.providers;
},
logout(providerId: string, sessionId: string): Thenable<void> {
checkProposedApiEnabled(extension);
return extHostAuthentication.removeSession(providerId, sessionId);
}
};
@@ -313,6 +307,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor, ex
get language() { return initData.environment.appLanguage; },
get appName() { return initData.environment.appName; },
get appRoot() { return initData.environment.appRoot?.fsPath ?? ''; },
get embedderIdentifier() { return initData.environment.embedderIdentifier; },
get uriScheme() { return initData.environment.appUriScheme; },
get clipboard(): vscode.Clipboard { return extHostClipboard.value; },
get shell() {
@@ -339,16 +334,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor, ex
return extHostUrls.createAppUri(uri);
}
const isHttp = matchesScheme(uri, Schemas.http) || matchesScheme(uri, Schemas.https);
if (!isHttp) {
checkProposedApiEnabled(extension); // https://github.com/microsoft/vscode/issues/124263
}
try {
return await extHostWindow.asExternalUri(uri, { allowTunneling: !!initData.remote.authority });
} catch (err) {
if (isHttp) {
if (matchesScheme(uri, Schemas.http) || matchesScheme(uri, Schemas.https)) {
return uri;
}
@@ -371,30 +360,18 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor, ex
? extHostTypes.ExtensionKind.Workspace
: extHostTypes.ExtensionKind.UI;
const test: typeof vscode.test = {
registerTestController(provider) {
checkProposedApiEnabled(extension);
return extHostTesting.registerTestController(extension.identifier.value, provider);
const tests: typeof vscode.tests = {
createTestController(provider, label) {
return extHostTesting.createTestController(provider, label);
},
createDocumentTestObserver(document) {
createTestObserver() {
checkProposedApiEnabled(extension);
return extHostTesting.createTextDocumentTestObserver(document);
},
createWorkspaceTestObserver(workspaceFolder) {
checkProposedApiEnabled(extension);
return extHostTesting.createWorkspaceTestObserver(workspaceFolder);
return extHostTesting.createTestObserver();
},
runTests(provider) {
checkProposedApiEnabled(extension);
return extHostTesting.runTests(provider);
},
createTestItem<T>(options: vscode.TestItemOptions, data?: T) {
return new extHostTypes.TestItemImpl(options.id, options.label, options.uri, data);
},
createTestRun(request, name, persist) {
checkProposedApiEnabled(extension);
return extHostTesting.createTestRun(extension.identifier.value, request, name, persist);
},
get onDidChangeTestResults() {
checkProposedApiEnabled(extension);
return extHostTesting.onResultsChanged;
@@ -405,9 +382,6 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor, ex
},
};
// todo@connor4312: backwards compatibility for a short period
(test as any).createTestRunTask = test.createTestRun;
// namespace: extensions
const extensions: typeof vscode.extensions = {
getExtension(extensionId: string): vscode.Extension<any> | undefined {
@@ -543,6 +517,14 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor, ex
registerInlayHintsProvider(selector: vscode.DocumentSelector, provider: vscode.InlayHintsProvider): vscode.Disposable {
checkProposedApiEnabled(extension);
return extHostLanguageFeatures.registerInlayHintsProvider(extension, selector, provider);
},
registerTypeHierarchyProvider(selector: vscode.DocumentSelector, provider: vscode.TypeHierarchyProvider): vscode.Disposable {
checkProposedApiEnabled(extension);
return extHostLanguageFeatures.registerTypeHierarchyProvider(extension, selector, provider);
},
createLanguageStatusItem(selector: vscode.DocumentSelector): vscode.LanguageStatusItem {
checkProposedApiEnabled(extension);
return extHostLanguages.createLanguageStatusItem(selector);
}
};
@@ -601,6 +583,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor, ex
checkProposedApiEnabled(extension);
return extHostTerminalService.onDidChangeTerminalDimensions(listener, thisArg, disposables);
},
onDidChangeTerminalState(listener, thisArg?, disposables?) {
checkProposedApiEnabled(extension);
return extHostTerminalService.onDidChangeTerminalState(listener, thisArg, disposables);
},
onDidWriteTerminalData(listener, thisArg?, disposables?) {
checkProposedApiEnabled(extension);
return extHostTerminalService.onDidWriteTerminalData(listener, thisArg, disposables);
@@ -645,7 +631,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor, ex
alignment = priorityOrAlignment;
priority = priorityArg;
} else {
alignment = alignmentOrId as number; // {{SQL CARBON EDIT}} strict-null-check
alignment = alignmentOrId;
priority = priorityOrAlignment;
}
@@ -664,7 +650,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor, ex
return extHostProgress.withProgress(extension, options, task);
},
createOutputChannel(name: string): vscode.OutputChannel {
return extHostOutputService.createOutputChannel(name);
return extHostOutputService.createOutputChannel(name, extension);
},
createWebviewPanel(viewType: string, title: string, showOptions: vscode.ViewColumn | { viewColumn: vscode.ViewColumn, preserveFocus?: boolean }, options?: vscode.WebviewPanelOptions & vscode.WebviewOptions): vscode.WebviewPanel {
return extHostWebviewPanels.createWebviewPanel(extension, viewType, title, showOptions, options);
@@ -675,12 +661,12 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor, ex
},
createTerminal(nameOrOptions?: vscode.TerminalOptions | vscode.ExtensionTerminalOptions | string, shellPath?: string, shellArgs?: string[] | string): vscode.Terminal {
if (typeof nameOrOptions === 'object') {
if ('location' in nameOrOptions) {
checkProposedApiEnabled(extension);
}
if ('pty' in nameOrOptions) {
return extHostTerminalService.createExtensionTerminal(nameOrOptions);
}
if (nameOrOptions.iconPath) {
checkProposedApiEnabled(extension);
}
return extHostTerminalService.createTerminalFromOptions(nameOrOptions);
}
return extHostTerminalService.createTerminal(nameOrOptions, shellPath, shellArgs);
@@ -689,7 +675,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor, ex
return extHostTerminalService.registerLinkProvider(provider);
},
registerTerminalProfileProvider(id: string, provider: vscode.TerminalProfileProvider): vscode.Disposable {
return extHostTerminalService.registerProfileProvider(id, provider);
return extHostTerminalService.registerProfileProvider(extension, id, provider);
},
registerTreeDataProvider(viewId: string, treeDataProvider: vscode.TreeDataProvider<any>): vscode.Disposable {
return extHostTreeViews.registerTreeDataProvider(viewId, treeDataProvider, extension);
@@ -1052,66 +1038,87 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor, ex
get activeDebugSession() {
extHostLogService.warn('Debug API is disabled in Azure Data Studio');
return undefined!;
// return extHostDebugService.activeDebugSession; {{SQL CARBON EDIT}} Removed
},
get activeDebugConsole() {
extHostLogService.warn('Debug API is disabled in Azure Data Studio');
return undefined!;
// return extHostDebugService.activeDebugConsole; {{SQL CARBON EDIT}} Removed
},
get breakpoints() {
extHostLogService.warn('Debug API is disabled in Azure Data Studio');
return [];
return undefined!;
// return extHostDebugService.breakpoints; {{SQL CARBON EDIT}} Removed
},
onDidStartDebugSession(listener, thisArg?, disposables?) {
extHostLogService.warn('Debug API is disabled in Azure Data Studio');
return undefined!;
// return extHostDebugService.onDidStartDebugSession(listener, thisArg, disposables); {{SQL CARBON EDIT}} Removed
},
onDidTerminateDebugSession(listener, thisArg?, disposables?) {
extHostLogService.warn('Debug API is disabled in Azure Data Studio');
return undefined!;
// return extHostDebugService.onDidTerminateDebugSession(listener, thisArg, disposables); {{SQL CARBON EDIT}} Removed
},
onDidChangeActiveDebugSession(listener, thisArg?, disposables?) {
extHostLogService.warn('Debug API is disabled in Azure Data Studio');
return undefined!;
// return extHostDebugService.onDidChangeActiveDebugSession(listener, thisArg, disposables); {{SQL CARBON EDIT}} Removed
},
onDidReceiveDebugSessionCustomEvent(listener, thisArg?, disposables?) {
extHostLogService.warn('Debug API is disabled in Azure Data Studio');
return undefined!;
// return extHostDebugService.onDidReceiveDebugSessionCustomEvent(listener, thisArg, disposables); {{SQL CARBON EDIT}} Removed
},
onDidChangeBreakpoints(listener, thisArgs?, disposables?) {
extHostLogService.warn('Debug API is disabled in Azure Data Studio');
return undefined!;
// return extHostDebugService.onDidChangeBreakpoints(listener, thisArgs, disposables); {{SQL CARBON EDIT}} Removed
},
registerDebugConfigurationProvider(debugType: string, provider: vscode.DebugConfigurationProvider, triggerKind?: vscode.DebugConfigurationProviderTriggerKind) {
extHostLogService.warn('Debug API is disabled in Azure Data Studio');
return undefined!;
// return extHostDebugService.registerDebugConfigurationProvider(debugType, provider, triggerKind || extHostTypes.DebugConfigurationProviderTriggerKind.Initial); {{SQL CARBON EDIT}} Removed
},
registerDebugAdapterDescriptorFactory(debugType: string, factory: vscode.DebugAdapterDescriptorFactory) {
extHostLogService.warn('Debug API is disabled in Azure Data Studio');
return undefined!;
// return extHostDebugService.registerDebugAdapterDescriptorFactory(extension, debugType, factory); {{SQL CARBON EDIT}} Removed
},
registerDebugAdapterTrackerFactory(debugType: string, factory: vscode.DebugAdapterTrackerFactory) {
extHostLogService.warn('Debug API is disabled in Azure Data Studio');
return undefined!;
// return extHostDebugService.registerDebugAdapterTrackerFactory(debugType, factory); {{SQL CARBON EDIT}} Removed
},
startDebugging(folder: vscode.WorkspaceFolder | undefined, nameOrConfig: string | vscode.DebugConfiguration, parentSessionOrOptions?: vscode.DebugSession | vscode.DebugSessionOptions) {
extHostLogService.warn('Debug API is disabled in Azure Data Studio');
return undefined!;
/* {{SQL CARBON EDIT}} Removed
if (!parentSessionOrOptions || (typeof parentSessionOrOptions === 'object' && 'configuration' in parentSessionOrOptions)) {
return extHostDebugService.startDebugging(folder, nameOrConfig, { parentSession: parentSessionOrOptions });
}
return extHostDebugService.startDebugging(folder, nameOrConfig, parentSessionOrOptions || {});
*/
},
stopDebugging(session?: vscode.DebugSession) {
extHostLogService.warn('Debug API is disabled in Azure Data Studio');
return undefined!;
// return extHostDebugService.stopDebugging(session); {{SQL CARBON EDIT}} Removed
},
addBreakpoints(breakpoints: readonly vscode.Breakpoint[]) {
extHostLogService.warn('Debug API is disabled in Azure Data Studio'); // {{SQL CARBON EDIT}}
extHostLogService.warn('Debug API is disabled in Azure Data Studio');
return undefined!;
// return extHostDebugService.addBreakpoints(breakpoints); {{SQL CARBON EDIT}} Removed
},
removeBreakpoints(breakpoints: readonly vscode.Breakpoint[]) {
extHostLogService.warn('Debug API is disabled in Azure Data Studio'); // {{SQL CARBON EDIT}}
extHostLogService.warn('Debug API is disabled in Azure Data Studio');
return undefined!;
// return extHostDebugService.removeBreakpoints(breakpoints); {{SQL CARBON EDIT}} Removed
},
asDebugSourceUri(source: vscode.DebugProtocolSource, session?: vscode.DebugSession): vscode.Uri {
extHostLogService.warn('Debug API is disabled in Azure Data Studio');
return undefined!;
// return extHostDebugService.asDebugSourceUri(source, session); {{SQL CARBON EDIT}} Removed
}
};
@@ -1168,7 +1175,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor, ex
// {{SQL CARBON EDIT}} Disable VS Code notebooks
throw new Error(functionalityNotSupportedError);
// checkProposedApiEnabled(extension);
// return extHostNotebookRenderers.createRendererMessaging(rendererId);
// return extHostNotebookRenderers.createRendererMessaging(extension, rendererId);
},
onDidChangeNotebookDocumentMetadata(listener, thisArgs?, disposables?) {
// {{SQL CARBON EDIT}} Disable VS Code notebooks
@@ -1222,7 +1229,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor, ex
notebooks,
scm,
tasks,
test,
tests,
window,
workspace,
// types
@@ -1324,6 +1331,9 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor, ex
TaskPanelKind: extHostTypes.TaskPanelKind,
TaskRevealKind: extHostTypes.TaskRevealKind,
TaskScope: extHostTypes.TaskScope,
TerminalLink: extHostTypes.TerminalLink,
TerminalLocation: extHostTypes.TerminalLocation,
TerminalProfile: extHostTypes.TerminalProfile,
TextDocumentSaveReason: extHostTypes.TextDocumentSaveReason,
TextEdit: extHostTypes.TextEdit,
TextEditorCursorStyle: TextEditorCursorStyle,
@@ -1334,6 +1344,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor, ex
ThemeIcon: extHostTypes.ThemeIcon,
TreeItem: extHostTypes.TreeItem,
TreeItemCollapsibleState: extHostTypes.TreeItemCollapsibleState,
TypeHierarchyItem: extHostTypes.TypeHierarchyItem,
UIKind: UIKind,
Uri: URI,
ViewColumn: extHostTypes.ViewColumn,
@@ -1360,12 +1371,19 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor, ex
NotebookControllerAffinity: extHostTypes.NotebookControllerAffinity,
PortAttributes: extHostTypes.PortAttributes,
LinkedEditingRanges: extHostTypes.LinkedEditingRanges,
TestItemStatus: extHostTypes.TestItemStatus,
TestResultState: extHostTypes.TestResultState,
TestRunRequest: extHostTypes.TestRunRequest,
TestMessage: extHostTypes.TestMessage,
TestTag: extHostTypes.TestTag,
TestRunProfileKind: extHostTypes.TestRunProfileKind,
TextSearchCompleteMessageType: TextSearchCompleteMessageType,
TestMessageSeverity: extHostTypes.TestMessageSeverity,
WorkspaceTrustState: extHostTypes.WorkspaceTrustState
CoveredCount: extHostTypes.CoveredCount,
FileCoverage: extHostTypes.FileCoverage,
StatementCoverage: extHostTypes.StatementCoverage,
BranchCoverage: extHostTypes.BranchCoverage,
FunctionCoverage: extHostTypes.FunctionCoverage,
WorkspaceTrustState: extHostTypes.WorkspaceTrustState,
LanguageStatusSeverity: extHostTypes.LanguageStatusSeverity,
};
};
}

View File

@@ -14,7 +14,6 @@ import { IExtHostTerminalService, WorkerExtHostTerminalService } from 'vs/workbe
import { IExtHostTask, WorkerExtHostTask } from 'vs/workbench/api/common/extHostTask';
// import { IExtHostDebugService, WorkerExtHostDebugService } from 'vs/workbench/api/common/extHostDebugService'; {{SQL CARBON EDIT}}
import { IExtHostSearch, ExtHostSearch } from 'vs/workbench/api/common/extHostSearch';
import { IExtensionStoragePaths, ExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths';
import { IExtHostStorage, ExtHostStorage } from 'vs/workbench/api/common/extHostStorage';
import { IExtHostTunnelService, ExtHostTunnelService } from 'vs/workbench/api/common/extHostTunnelService';
import { IExtHostApiDeprecationService, ExtHostApiDeprecationService, } from 'vs/workbench/api/common/extHostApiDeprecationService';
@@ -25,7 +24,6 @@ import { IExtHostSecretState, ExtHostSecretState } from 'vs/workbench/api/common
import { ExtHostTelemetry, IExtHostTelemetry } from 'vs/workbench/api/common/extHostTelemetry';
import { ExtHostEditorTabs, IExtHostEditorTabs } from 'vs/workbench/api/common/extHostEditorTabs';
registerSingleton(IExtensionStoragePaths, ExtensionStoragePaths);
registerSingleton(IExtHostApiDeprecationService, ExtHostApiDeprecationService);
registerSingleton(IExtHostCommands, ExtHostCommands);
registerSingleton(IExtHostConfiguration, ExtHostConfiguration);

View File

@@ -24,6 +24,7 @@ import { EndOfLineSequence, ISingleEditOperation } from 'vs/editor/common/model'
import { IModelChangedEvent } from 'vs/editor/common/model/mirrorTextModel';
import * as modes from 'vs/editor/common/modes';
import { CharacterPair, CommentRule, EnterAction } from 'vs/editor/common/modes/languageConfiguration';
import { ILanguageStatus } from 'vs/workbench/services/languageStatus/common/languageStatusService';
import { IAccessibilityInformation } from 'vs/platform/accessibility/common/accessibility';
import { ICommandHandlerDescription } from 'vs/platform/commands/common/commands';
import { ConfigurationTarget, IConfigurationChange, IConfigurationData, IConfigurationOverrides } from 'vs/platform/configuration/common/configuration';
@@ -39,28 +40,32 @@ import { IRemoteConnectionData, RemoteAuthorityResolverErrorCode, ResolverResult
import { ProvidedPortAttributes, TunnelCreationOptions, TunnelOptions, TunnelProviderFeatures } from 'vs/platform/remote/common/tunnel';
import { ClassifiedEvent, GDPRClassification, StrictPropertyCheck } from 'vs/platform/telemetry/common/gdprTypings';
import { ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry';
import { TreeDataTransferDTO } from 'vs/workbench/api/common/shared/treeDataTransfer';
import { IShellLaunchConfig, IShellLaunchConfigDto, ITerminalDimensions, ITerminalEnvironment, ITerminalLaunchError, ITerminalProfile } from 'vs/platform/terminal/common/terminal';
import { ICreateContributedTerminalProfileOptions, IShellLaunchConfig, IShellLaunchConfigDto, ITerminalDimensions, ITerminalEnvironment, ITerminalLaunchError, ITerminalProfile, TerminalLocation } from 'vs/platform/terminal/common/terminal';
import { ThemeColor, ThemeIcon } from 'vs/platform/theme/common/themeService';
import { IExtensionIdWithVersion } from 'vs/platform/userDataSync/common/extensionsStorageSync';
import { WorkspaceTrustRequestOptions } from 'vs/platform/workspace/common/workspaceTrust';
import { ExtensionActivationReason } from 'vs/workbench/api/common/extHostExtensionActivator';
import { ExtHostInteractive } from 'vs/workbench/api/common/extHostInteractive';
import { TunnelDto } from 'vs/workbench/api/common/extHostTunnelService';
import { DebugConfigurationProviderTriggerKind, TestResultState } from 'vs/workbench/api/common/extHostTypes';
import { DebugConfigurationProviderTriggerKind } from 'vs/workbench/api/common/extHostTypes';
import * as tasks from 'vs/workbench/api/common/shared/tasks';
import { EditorGroupColumn, SaveReason } from 'vs/workbench/common/editor';
import { TreeDataTransferDTO } from 'vs/workbench/api/common/shared/treeDataTransfer';
import { SaveReason } from 'vs/workbench/common/editor';
import { IRevealOptions, ITreeItem } from 'vs/workbench/common/views';
import { CallHierarchyItem } from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
import { IAdapterDescriptor, IConfig, IDebugSessionReplMode } from 'vs/workbench/contrib/debug/common/debug';
import { CellKind, ICellEditOperation, IImmediateCellEditOperation, IMainCellDto, INotebookCellStatusBarItem, INotebookContributionData, INotebookDecorationRenderOptions, IOutputDto, NotebookCellMetadata, NotebookCellsChangedEventDto, NotebookDataDto, NotebookDocumentMetadata, TransientCellMetadata, TransientDocumentMetadata, TransientOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import * as notebookCommon from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { CellExecutionUpdateType, ICellExecutionComplete, ICellExecutionStateUpdate } from 'vs/workbench/contrib/notebook/common/notebookExecutionService';
import { ICellRange } from 'vs/workbench/contrib/notebook/common/notebookRange';
import { InputValidationType } from 'vs/workbench/contrib/scm/common/scm';
import { ITextQueryBuilderOptions } from 'vs/workbench/contrib/search/common/queryBuilder';
import { ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { ExtensionRunTestsRequest, InternalTestItem, ISerializedTestResults, ITestItem, ITestMessage, ITestRunTask, RunTestForProviderRequest, RunTestsRequest, TestIdWithSrc, TestsDiff } from 'vs/workbench/contrib/testing/common/testCollection';
import { CoverageDetails, ExtensionRunTestsRequest, IFileCoverage, ISerializedTestResults, ITestItem, ITestMessage, ITestRunProfile, ITestRunTask, ResolvedTestRunRequest, RunTestForControllerRequest, TestResultState, TestsDiff } from 'vs/workbench/contrib/testing/common/testCollection';
import { InternalTimelineOptions, Timeline, TimelineChangeEvent, TimelineOptions, TimelineProviderDescriptor } from 'vs/workbench/contrib/timeline/common/timeline';
import { TypeHierarchyItem } from 'vs/workbench/contrib/typeHierarchy/common/typeHierarchy';
import { EditorGroupColumn } from 'vs/workbench/services/editor/common/editorGroupColumn';
import { ActivationKind, ExtensionHostKind, MissingExtensionDependency } from 'vs/workbench/services/extensions/common/extensions';
import { createExtHostContextProxyIdentifier as createExtId, createMainContextProxyIdentifier as createMainId, IRPCProtocol } from 'vs/workbench/services/extensions/common/proxyIdentifier';
import { createExtHostContextProxyIdentifier as createExtId, createMainContextProxyIdentifier as createMainId, IRPCProtocol, SerializableObjectWithBuffers } from 'vs/workbench/services/extensions/common/proxyIdentifier';
import { CandidatePort } from 'vs/workbench/services/remote/common/remoteExplorerService';
import * as search from 'vs/workbench/services/search/common/search';
import * as statusbar from 'vs/workbench/services/statusbar/common/statusbar';
@@ -71,6 +76,7 @@ import { ITreeItem as sqlITreeItem } from 'sql/workbench/common/views';
export interface IEnvironment {
isExtensionDevelopmentDebug: boolean;
appName: string;
embedderIdentifier: string;
appRoot?: URI;
appLanguage: string;
appUriScheme: string;
@@ -79,6 +85,7 @@ export interface IEnvironment {
globalStorageHome: URI;
workspaceStorageHome: URI;
useHostProxy?: boolean;
skipWorkspaceStorageLock?: boolean;
}
export interface IStaticWorkspaceData {
@@ -172,7 +179,7 @@ export interface MainThreadAuthenticationShape extends IDisposable {
$unregisterAuthenticationProvider(id: string): void;
$ensureProvider(id: string): Promise<void>;
$sendDidChangeSessions(providerId: string, event: modes.AuthenticationSessionsChangeEvent): void;
$getSession(providerId: string, scopes: readonly string[], extensionId: string, extensionName: string, options: { createIfNone?: boolean, clearSessionPreference?: boolean }): Promise<modes.AuthenticationSession | undefined>;
$getSession(providerId: string, scopes: readonly string[], extensionId: string, extensionName: string, options: { createIfNone?: boolean, forceNewSession?: boolean | { detail: string }, clearSessionPreference?: boolean }): Promise<modes.AuthenticationSession | undefined>;
$removeSession(providerId: string, sessionId: string): Promise<void>;
}
@@ -416,6 +423,7 @@ export interface MainThreadLanguageFeaturesShape extends IDisposable {
$emitFoldingRangeEvent(eventHandle: number, event?: any): void;
$registerSelectionRangeProvider(handle: number, selector: IDocumentFilterDto[]): void;
$registerCallHierarchyProvider(handle: number, selector: IDocumentFilterDto[]): void;
$registerTypeHierarchyProvider(handle: number, selector: IDocumentFilterDto[]): void;
$setLanguageConfiguration(handle: number, languageId: string, configuration: ILanguageConfigurationDto): void;
}
@@ -423,11 +431,14 @@ export interface MainThreadLanguagesShape extends IDisposable {
$getLanguages(): Promise<string[]>;
$changeLanguage(resource: UriComponents, languageId: string): Promise<void>;
$tokensAtPosition(resource: UriComponents, position: IPosition): Promise<undefined | { type: modes.StandardTokenType, range: IRange }>;
$setLanguageStatus(handle: number, status: ILanguageStatus): void;
$removeLanguageStatus(handle: number): void;
}
export interface MainThreadMessageOptions {
extension?: IExtensionDescription;
modal?: boolean;
detail?: string;
useCustom?: boolean;
}
@@ -436,7 +447,7 @@ export interface MainThreadMessageServiceShape extends IDisposable {
}
export interface MainThreadOutputServiceShape extends IDisposable {
$register(label: string, log: boolean, file?: UriComponents): Promise<string>;
$register(label: string, log: boolean, file?: UriComponents, extensionId?: string): Promise<string>;
$append(channelId: string, value: string): Promise<void> | undefined;
$update(channelId: string): Promise<void> | undefined;
$clear(channelId: string, till: number): Promise<void> | undefined;
@@ -460,7 +471,7 @@ export interface MainThreadProgressShape extends IDisposable {
* All other terminals (that are not created on the extension host side) always
* use the numeric id.
*/
export type TerminalIdentifier = number | string;
export type ExtHostTerminalIdentifier = number | string;
export interface TerminalLaunchConfig {
name?: string;
@@ -469,6 +480,7 @@ export interface TerminalLaunchConfig {
cwd?: string | UriComponents;
env?: ITerminalEnvironment;
icon?: URI | { light: URI; dark: URI } | ThemeIcon;
color?: string;
initialText?: string;
waitOnExit?: boolean;
strictEnv?: boolean;
@@ -477,21 +489,21 @@ export interface TerminalLaunchConfig {
isFeatureTerminal?: boolean;
isExtensionOwnedTerminal?: boolean;
useShellEnvironment?: boolean;
isSplitTerminal?: boolean;
location?: TerminalLocation | { viewColumn: number, preserveFocus?: boolean } | { parentTerminal: ExtHostTerminalIdentifier } | { splitActiveTerminal: boolean };
}
export interface MainThreadTerminalServiceShape extends IDisposable {
$createTerminal(extHostTerminalId: string, config: TerminalLaunchConfig): Promise<void>;
$dispose(id: TerminalIdentifier): void;
$hide(id: TerminalIdentifier): void;
$sendText(id: TerminalIdentifier, text: string, addNewLine: boolean): void;
$show(id: TerminalIdentifier, preserveFocus: boolean): void;
$dispose(id: ExtHostTerminalIdentifier): void;
$hide(id: ExtHostTerminalIdentifier): void;
$sendText(id: ExtHostTerminalIdentifier, text: string, addNewLine: boolean): void;
$show(id: ExtHostTerminalIdentifier, preserveFocus: boolean): void;
$startSendingDataEvents(): void;
$stopSendingDataEvents(): void;
$startLinkProvider(): void;
$stopLinkProvider(): void;
$registerProcessSupport(isSupported: boolean): void;
$registerProfileProvider(id: string): void;
$registerProfileProvider(id: string, extensionIdentifier: string): void;
$unregisterProfileProvider(id: string): void;
$setEnvironmentVariableCollection(extensionIdentifier: string, persistent: boolean, collection: ISerializableEnvironmentVariableCollection | undefined): void;
@@ -508,12 +520,11 @@ export interface MainThreadTerminalServiceShape extends IDisposable {
export interface TransferQuickPickItems extends quickInput.IQuickPickItem {
handle: number;
buttons?: TransferQuickInputButton[];
}
export interface TransferQuickInputButton {
export interface TransferQuickInputButton extends quickInput.IQuickInputButton {
handle: number;
iconPath: { dark: URI; light?: URI; } | { id: string; };
tooltip?: string;
}
export type TransferQuickInput = TransferQuickPick | TransferInputBox;
@@ -599,7 +610,7 @@ export interface MainThreadQuickOpenShape extends IDisposable {
}
export interface MainThreadStatusBarShape extends IDisposable {
$setEntry(id: number, statusId: string, statusName: string, text: string, tooltip: string | undefined, command: ICommandDto | undefined, color: string | ThemeColor | undefined, backgroundColor: string | ThemeColor | undefined, alignment: statusbar.StatusbarAlignment, priority: number | undefined, accessibilityInformation: IAccessibilityInformation | undefined): void;
$setEntry(id: number, statusId: string, statusName: string, text: string, tooltip: IMarkdownString | string | undefined, command: ICommandDto | undefined, color: string | ThemeColor | undefined, backgroundColor: string | ThemeColor | undefined, alignment: statusbar.StatusbarAlignment, priority: number | undefined, accessibilityInformation: IAccessibilityInformation | undefined): void;
$dispose(id: number): void;
}
@@ -661,7 +672,7 @@ export interface WebviewExtensionDescription {
export interface NotebookExtensionDescription {
readonly id: ExtensionIdentifier;
readonly location: UriComponents;
readonly location: UriComponents | undefined;
}
export enum WebviewEditorCapabilities {
@@ -838,28 +849,6 @@ export enum CellOutputKind {
Rich = 3
}
export interface ICellDto {
handle: number;
uri: UriComponents,
source: string[];
language: string;
cellKind: CellKind;
outputs: IOutputDto[];
metadata?: NotebookCellMetadata;
}
export type NotebookCellsSplice = [
number /* start */,
number /* delete count */,
ICellDto[]
];
export type NotebookCellOutputsSplice = [
number /* start */,
number /* delete count */,
IOutputDto[]
];
export enum NotebookEditorRevealType {
Default = 0,
InCenter = 1,
@@ -874,7 +863,7 @@ export interface INotebookDocumentShowOptions {
selections?: ICellRange[];
}
export type INotebookCellStatusBarEntryDto = Dto<INotebookCellStatusBarItem>;
export type INotebookCellStatusBarEntryDto = Dto<notebookCommon.INotebookCellStatusBarItem>;
export interface INotebookCellStatusBarListDto {
items: INotebookCellStatusBarEntryDto[];
@@ -882,11 +871,11 @@ export interface INotebookCellStatusBarListDto {
}
export interface MainThreadNotebookShape extends IDisposable {
$registerNotebookProvider(extension: NotebookExtensionDescription, viewType: string, options: TransientOptions, registration: INotebookContributionData | undefined): Promise<void>;
$updateNotebookProviderOptions(viewType: string, options?: { transientOutputs: boolean; transientCellMetadata: TransientCellMetadata; transientDocumentMetadata: TransientDocumentMetadata; }): Promise<void>;
$registerNotebookProvider(extension: NotebookExtensionDescription, viewType: string, options: notebookCommon.TransientOptions, registration: notebookCommon.INotebookContributionData | undefined): Promise<void>;
$updateNotebookProviderOptions(viewType: string, options?: { transientOutputs: boolean; transientCellMetadata: notebookCommon.TransientCellMetadata; transientDocumentMetadata: notebookCommon.TransientDocumentMetadata; }): Promise<void>;
$unregisterNotebookProvider(viewType: string): Promise<void>;
$registerNotebookSerializer(handle: number, extension: NotebookExtensionDescription, viewType: string, options: TransientOptions, registration: INotebookContributionData | undefined): void;
$registerNotebookSerializer(handle: number, extension: NotebookExtensionDescription, viewType: string, options: notebookCommon.TransientOptions, registration: notebookCommon.INotebookContributionData | undefined): void;
$unregisterNotebookSerializer(handle: number): void;
$registerNotebookCellStatusBarItemProvider(handle: number, eventHandle: number | undefined, viewType: string): Promise<void>;
@@ -897,18 +886,17 @@ export interface MainThreadNotebookShape extends IDisposable {
export interface MainThreadNotebookEditorsShape extends IDisposable {
$tryShowNotebookDocument(uriComponents: UriComponents, viewType: string, options: INotebookDocumentShowOptions): Promise<string>;
$tryRevealRange(id: string, range: ICellRange, revealType: NotebookEditorRevealType): Promise<void>;
$registerNotebookEditorDecorationType(key: string, options: INotebookDecorationRenderOptions): void;
$registerNotebookEditorDecorationType(key: string, options: notebookCommon.INotebookDecorationRenderOptions): void;
$removeNotebookEditorDecorationType(key: string): void;
$trySetSelections(id: string, range: ICellRange[]): void;
$trySetDecorations(id: string, range: ICellRange, decorationKey: string): void;
$tryApplyEdits(editorId: string, modelVersionId: number, cellEdits: ICellEditOperation[]): Promise<boolean>
$tryApplyEdits(editorId: string, modelVersionId: number, cellEdits: ICellEditOperationDto[]): Promise<boolean>
}
export interface MainThreadNotebookDocumentsShape extends IDisposable {
$tryCreateNotebook(options: { viewType: string, content?: NotebookDataDto }): Promise<UriComponents>;
$tryOpenNotebook(uriComponents: UriComponents): Promise<UriComponents>;
$trySaveNotebook(uri: UriComponents): Promise<boolean>;
$applyEdits(resource: UriComponents, edits: IImmediateCellEditOperation[], computeUndoRedo?: boolean): Promise<void>;
}
export interface INotebookKernelDto2 {
@@ -925,16 +913,49 @@ export interface INotebookKernelDto2 {
preloads?: { uri: UriComponents; provides: string[] }[];
}
export interface ICellExecuteOutputEditDto {
editType: CellExecutionUpdateType.Output;
executionHandle: number;
cellHandle: number;
append?: boolean;
outputs: NotebookOutputDto[]
}
export interface ICellExecuteOutputItemEditDto {
editType: CellExecutionUpdateType.OutputItems;
executionHandle: number;
append?: boolean;
outputId: string;
items: NotebookOutputItemDto[]
}
export interface ICellExecutionStateUpdateDto extends ICellExecutionStateUpdate {
executionHandle: number;
}
export interface ICellExecutionCompleteDto extends ICellExecutionComplete {
executionHandle: number;
}
export type ICellExecuteUpdateDto = ICellExecuteOutputEditDto | ICellExecuteOutputItemEditDto | ICellExecutionStateUpdateDto | ICellExecutionCompleteDto;
export interface MainThreadNotebookKernelsShape extends IDisposable {
$postMessage(handle: number, editorId: string | undefined, message: any): Promise<boolean>;
$addKernel(handle: number, data: INotebookKernelDto2): Promise<void>;
$updateKernel(handle: number, data: Partial<INotebookKernelDto2>): void;
$removeKernel(handle: number): void;
$updateNotebookPriority(handle: number, uri: UriComponents, value: number | undefined): void;
$addExecution(handle: number, uri: UriComponents, cellHandle: number): void;
$updateExecutions(data: SerializableObjectWithBuffers<ICellExecuteUpdateDto[]>): void;
$removeExecution(handle: number): void;
}
export interface MainThreadNotebookRenderersShape extends IDisposable {
$postMessage(editorId: string, rendererId: string, message: unknown): void;
$postMessage(editorId: string | undefined, rendererId: string, message: unknown): Promise<boolean>;
}
export interface MainThreadInteractiveShape extends IDisposable {
}
export interface MainThreadUrlsShape extends IDisposable {
@@ -1042,7 +1063,7 @@ export interface SCMGroupFeatures {
export type SCMRawResource = [
number /*handle*/,
UriComponents /*resourceUri*/,
UriComponents[] /*icons: light, dark*/,
[UriComponents | ThemeIcon | undefined, UriComponents | ThemeIcon | undefined] /*icons: light, dark*/,
string /*tooltip*/,
boolean /*strike through*/,
boolean /*faded*/,
@@ -1077,7 +1098,7 @@ export interface MainThreadSCMShape extends IDisposable {
$setInputBoxPlaceholder(sourceControlHandle: number, placeholder: string): void;
$setInputBoxVisibility(sourceControlHandle: number, visible: boolean): void;
$setInputBoxFocus(sourceControlHandle: number): void;
$showValidationMessage(sourceControlHandle: number, message: string, type: InputValidationType): void;
$showValidationMessage(sourceControlHandle: number, message: string | IMarkdownString, type: InputValidationType): void;
$setValidationProviderIsEnabled(sourceControlHandle: number, enabled: boolean): void;
}
@@ -1092,9 +1113,13 @@ export interface IDebugConfiguration {
export interface IStartDebuggingOptions {
parentSessionID?: DebugSessionUUID;
lifecycleManagedByParent?: boolean;
repl?: IDebugSessionReplMode;
noDebug?: boolean;
compact?: boolean;
debugUI?: {
simple?: boolean;
};
}
export interface MainThreadDebugServiceShape extends IDisposable {
@@ -1238,8 +1263,7 @@ export interface ExtHostDocumentsAndEditorsShape {
}
export interface ExtHostTreeViewsShape {
// {{SQL CARBON EDIT}}
$getChildren(treeViewId: string, treeItemHandle?: string): Promise<sqlITreeItem[]>;
$getChildren(treeViewId: string, treeItemHandle?: string): Promise<sqlITreeItem[] | undefined>; // {{SQL CARBON EDIT}}
$onDrop(treeViewId: string, treeDataTransfer: TreeDataTransferDTO, newParentTreeItemHandle: string): Promise<void>;
$setExpanded(treeViewId: string, treeItemHandle: string, expanded: boolean): void;
$setSelection(treeViewId: string, treeItemHandles: string[]): void;
@@ -1285,7 +1309,6 @@ export interface ExtHostAuthenticationShape {
$createSession(id: string, scopes: string[]): Promise<modes.AuthenticationSession>;
$removeSession(id: string, sessionId: string): Promise<void>;
$onDidChangeAuthenticationSessions(id: string, label: string): Promise<void>;
$onDidChangeAuthenticationProviders(added: modes.AuthenticationProviderInformation[], removed: modes.AuthenticationProviderInformation[]): Promise<void>;
$setProviders(providers: modes.AuthenticationProviderInformation[]): Promise<void>;
}
@@ -1294,6 +1317,7 @@ export interface ExtHostSecretStateShape {
}
export interface ExtHostSearchShape {
$enableExtensionHostSearch(): void;
$provideFileSearchResults(handle: number, session: number, query: search.IRawQuery, token: CancellationToken): Promise<search.ISearchCompleteStats>;
$provideTextSearchResults(handle: number, session: number, query: search.IRawTextQuery, token: CancellationToken): Promise<search.ISearchCompleteStats>;
$clearCache(cacheKey: string): Promise<void>;
@@ -1402,14 +1426,10 @@ export const enum ISuggestDataDtoField {
additionalTextEdits = 'l',
command = 'm',
kindModifier = 'n',
// to merge into label
label2 = 'o',
}
export interface ISuggestDataDto {
[ISuggestDataDtoField.label]: string;
[ISuggestDataDtoField.label2]?: string | modes.CompletionItemLabel;
[ISuggestDataDtoField.label]: string | modes.CompletionItemLabel;
[ISuggestDataDtoField.kind]?: modes.CompletionItemKind;
[ISuggestDataDtoField.detail]?: string;
[ISuggestDataDtoField.documentation]?: string | IMarkdownString;
@@ -1520,12 +1540,22 @@ export interface IWorkspaceTextEditDto {
metadata?: IWorkspaceEditEntryMetadataDto;
}
export type ICellEditOperationDto =
notebookCommon.ICellPartialMetadataEdit
| notebookCommon.IDocumentMetadataEdit
| {
editType: notebookCommon.CellEditType.Replace,
index: number,
count: number,
cells: NotebookCellDataDto[]
};
export interface IWorkspaceCellEditDto {
_type: WorkspaceEditType.Cell;
resource: UriComponents;
edit: ICellEditOperation;
notebookVersionId?: number;
metadata?: IWorkspaceEditEntryMetadataDto;
edit: ICellEditOperationDto;
}
export interface IWorkspaceEditDto {
@@ -1626,6 +1656,8 @@ export interface IInlineValueContextDto {
stoppedLocation: IRange;
}
export type ITypeHierarchyItemDto = Dto<TypeHierarchyItem>;
export interface ExtHostLanguageFeaturesShape {
$provideDocumentSymbols(handle: number, resource: UriComponents, token: CancellationToken): Promise<modes.DocumentSymbol[] | undefined>;
$provideCodeLenses(handle: number, resource: UriComponents, token: CancellationToken): Promise<ICodeLensListDto | undefined>;
@@ -1676,6 +1708,10 @@ export interface ExtHostLanguageFeaturesShape {
$provideCallHierarchyOutgoingCalls(handle: number, sessionId: string, itemId: string, token: CancellationToken): Promise<IOutgoingCallDto[] | undefined>;
$releaseCallHierarchy(handle: number, sessionId: string): void;
$setWordDefinitions(wordDefinitions: ILanguageWordDefinitionDto[]): void;
$prepareTypeHierarchy(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<ITypeHierarchyItemDto[] | undefined>;
$provideTypeHierarchySupertypes(handle: number, sessionId: string, itemId: string, token: CancellationToken): Promise<ITypeHierarchyItemDto[] | undefined>;
$provideTypeHierarchySubtypes(handle: number, sessionId: string, itemId: string, token: CancellationToken): Promise<ITypeHierarchyItemDto[] | undefined>;
$releaseTypeHierarchy(handle: number, sessionId: string): void;
}
export interface ExtHostQuickOpenShape {
@@ -1686,6 +1722,7 @@ export interface ExtHostQuickOpenShape {
$onDidAccept(sessionId: number): void;
$onDidChangeValue(sessionId: number, value: string): void;
$onDidTriggerButton(sessionId: number, handle: number): void;
$onDidTriggerItemButton(sessionId: number, itemHandle: number, buttonHandle: number): void;
$onDidHide(sessionId: number): void;
}
@@ -1719,6 +1756,7 @@ export interface ExtHostTerminalServiceShape {
$acceptTerminalTitleChange(id: number, name: string): void;
$acceptTerminalDimensions(id: number, cols: number, rows: number): void;
$acceptTerminalMaximumDimensions(id: number, cols: number, rows: number): void;
$acceptTerminalInteraction(id: number): void;
$startExtensionTerminal(id: number, initialDimensions: ITerminalDimensionsDto | undefined): Promise<ITerminalLaunchError | undefined>;
$acceptProcessAckDataEvent(id: number, charCount: number): void;
$acceptProcessInput(id: number, data: string): void;
@@ -1731,14 +1769,14 @@ export interface ExtHostTerminalServiceShape {
$activateLink(id: number, linkId: number): void;
$initEnvironmentVariableCollections(collections: [string, ISerializableEnvironmentVariableCollection][]): void;
$acceptDefaultProfile(profile: ITerminalProfile, automationProfile: ITerminalProfile): void;
$createContributedProfileTerminal(id: string, isSplitTerminal: boolean): Promise<void>;
$createContributedProfileTerminal(id: string, options: ICreateContributedTerminalProfileOptions): Promise<void>;
}
export interface ExtHostSCMShape {
$provideOriginalResource(sourceControlHandle: number, uri: UriComponents, token: CancellationToken): Promise<UriComponents | null>;
$onInputBoxValueChange(sourceControlHandle: number, value: string): void;
$executeResourceCommand(sourceControlHandle: number, groupHandle: number, handle: number, preserveFocus: boolean): Promise<void>;
$validateInput(sourceControlHandle: number, value: string, cursorPosition: number): Promise<[string, number] | undefined>;
$validateInput(sourceControlHandle: number, value: string, cursorPosition: number): Promise<[string | IMarkdownString, number] | undefined>;
$setSelectedSourceControl(selectedSourceControlHandle: number | undefined): Promise<void>;
}
@@ -1888,15 +1926,15 @@ export interface INotebookEditorPropertiesChangeData {
}
export interface INotebookDocumentPropertiesChangeData {
metadata?: NotebookDocumentMetadata;
metadata?: notebookCommon.NotebookDocumentMetadata;
}
export interface INotebookModelAddedData {
uri: UriComponents;
versionId: number;
cells: IMainCellDto[],
cells: NotebookCellDto[],
viewType: string;
metadata?: NotebookDocumentMetadata;
metadata?: notebookCommon.NotebookDocumentMetadata;
}
export interface INotebookEditorAddData {
@@ -1916,17 +1954,56 @@ export interface INotebookDocumentsAndEditorsDelta {
visibleEditors?: string[];
}
export interface NotebookOutputItemDto {
readonly mime: string;
readonly valueBytes: VSBuffer;
}
export interface NotebookOutputDto {
items: NotebookOutputItemDto[];
outputId: string;
metadata?: Record<string, any>;
}
export interface NotebookCellDataDto {
source: string;
language: string;
mime: string | undefined;
cellKind: notebookCommon.CellKind;
outputs: NotebookOutputDto[];
metadata?: notebookCommon.NotebookCellMetadata;
internalMetadata?: notebookCommon.NotebookCellInternalMetadata;
}
export interface NotebookDataDto {
readonly cells: NotebookCellDataDto[];
readonly metadata: notebookCommon.NotebookDocumentMetadata;
}
export interface NotebookCellDto {
handle: number;
uri: UriComponents;
eol: string;
source: string[];
language: string;
mime?: string;
cellKind: notebookCommon.CellKind;
outputs: NotebookOutputDto[];
metadata?: notebookCommon.NotebookCellMetadata;
internalMetadata?: notebookCommon.NotebookCellInternalMetadata;
}
export interface ExtHostNotebookShape extends ExtHostNotebookDocumentsAndEditorsShape {
$provideNotebookCellStatusBarItems(handle: number, uri: UriComponents, index: number, token: CancellationToken): Promise<INotebookCellStatusBarListDto | undefined>;
$releaseNotebookCellStatusBarItems(id: number): void;
$openNotebook(viewType: string, uri: UriComponents, backupId: string | undefined, untitledDocumentData: VSBuffer | undefined, token: CancellationToken): Promise<NotebookDataDto>;
$openNotebook(viewType: string, uri: UriComponents, backupId: string | undefined, untitledDocumentData: VSBuffer | undefined, token: CancellationToken): Promise<SerializableObjectWithBuffers<NotebookDataDto>>;
$saveNotebook(viewType: string, uri: UriComponents, token: CancellationToken): Promise<boolean>;
$saveNotebookAs(viewType: string, uri: UriComponents, target: UriComponents, token: CancellationToken): Promise<boolean>;
$backupNotebook(viewType: string, uri: UriComponents, cancellation: CancellationToken): Promise<string>;
$dataToNotebook(handle: number, data: VSBuffer, token: CancellationToken): Promise<NotebookDataDto>;
$notebookToData(handle: number, data: NotebookDataDto, token: CancellationToken): Promise<VSBuffer>;
$dataToNotebook(handle: number, data: VSBuffer, token: CancellationToken): Promise<SerializableObjectWithBuffers<NotebookDataDto>>;
$notebookToData(handle: number, data: SerializableObjectWithBuffers<NotebookDataDto>, token: CancellationToken): Promise<VSBuffer>;
}
export interface ExtHostNotebookRenderersShape {
@@ -1934,11 +2011,50 @@ export interface ExtHostNotebookRenderersShape {
}
export interface ExtHostNotebookDocumentsAndEditorsShape {
$acceptDocumentAndEditorsDelta(delta: INotebookDocumentsAndEditorsDelta): void;
$acceptDocumentAndEditorsDelta(delta: SerializableObjectWithBuffers<INotebookDocumentsAndEditorsDelta>): void;
}
export type NotebookRawContentEventDto =
// notebookCommon.NotebookCellsInitializeEvent<NotebookCellDto>
| {
readonly kind: notebookCommon.NotebookCellsChangeType.ModelChange;
readonly changes: notebookCommon.NotebookCellTextModelSplice<NotebookCellDto>[];
}
| {
readonly kind: notebookCommon.NotebookCellsChangeType.Move;
readonly index: number;
readonly length: number;
readonly newIdx: number;
}
| {
readonly kind: notebookCommon.NotebookCellsChangeType.Output;
readonly index: number;
readonly outputs: NotebookOutputDto[];
}
| {
readonly kind: notebookCommon.NotebookCellsChangeType.OutputItem;
readonly index: number;
readonly outputId: string;
readonly outputItems: NotebookOutputItemDto[];
readonly append: boolean;
}
| notebookCommon.NotebookCellsChangeLanguageEvent
| notebookCommon.NotebookCellsChangeMimeEvent
| notebookCommon.NotebookCellsChangeMetadataEvent
| notebookCommon.NotebookCellsChangeInternalMetadataEvent
// | notebookCommon.NotebookDocumentChangeMetadataEvent
// | notebookCommon.NotebookCellContentChangeEvent
// | notebookCommon.NotebookDocumentUnknownChangeEvent
;
export type NotebookCellsChangedEventDto = {
readonly rawEvents: NotebookRawContentEventDto[];
readonly versionId: number;
};
export interface ExtHostNotebookDocumentsShape {
$acceptModelChanged(uriComponents: UriComponents, event: NotebookCellsChangedEventDto, isDirty: boolean): void;
$acceptModelChanged(uriComponents: UriComponents, event: SerializableObjectWithBuffers<NotebookCellsChangedEventDto>, isDirty: boolean): void;
$acceptDirtyStateChanged(uriComponents: UriComponents, isDirty: boolean): void;
$acceptModelSaved(uriComponents: UriComponents): void;
$acceptDocumentPropertiesChanged(uriComponents: UriComponents, data: INotebookDocumentPropertiesChangeData): void;
@@ -1958,6 +2074,11 @@ export interface ExtHostNotebookKernelsShape {
$acceptKernelMessageFromRenderer(handle: number, editorId: string, message: any): void;
}
export interface ExtHostInteractiveShape {
$willAddInteractiveDocument(uri: UriComponents, eol: string, modeId: string, notebookUri: UriComponents): void;
$willRemoveInteractiveDocument(uri: UriComponents, notebookUri: UriComponents): void;
}
export interface ExtHostStorageShape {
$acceptValue(shared: boolean, key: string, value: object | undefined): void;
}
@@ -1988,41 +2109,68 @@ export const enum ExtHostTestingResource {
}
export interface ExtHostTestingShape {
$runTestsForProvider(req: RunTestForProviderRequest, token: CancellationToken): Promise<void>;
$subscribeToTests(resource: ExtHostTestingResource, uri: UriComponents): void;
$unsubscribeFromTests(resource: ExtHostTestingResource, uri: UriComponents): void;
$lookupTest(test: TestIdWithSrc): Promise<InternalTestItem | undefined>;
$acceptDiff(resource: ExtHostTestingResource, uri: UriComponents, diff: TestsDiff): void;
$runControllerTests(req: RunTestForControllerRequest, token: CancellationToken): Promise<void>;
$cancelExtensionTestRun(runId: string | undefined): void;
/** Handles a diff of tests, as a result of a subscribeToDiffs() call */
$acceptDiff(diff: TestsDiff): void;
/** Publishes that a test run finished. */
$publishTestResults(results: ISerializedTestResults[]): void;
$expandTest(src: TestIdWithSrc, levels: number): Promise<void>;
/** Expands a test item's children, by the given number of levels. */
$expandTest(testId: string, levels: number): Promise<void>;
/** Requests file coverage for a test run. Errors if not available. */
$provideFileCoverage(runId: string, taskId: string, token: CancellationToken): Promise<IFileCoverage[]>;
/**
* Requests coverage details for the file index in coverage data for the run.
* Requires file coverage to have been previously requested via $provideFileCoverage.
*/
$resolveFileCoverage(runId: string, taskId: string, fileIndex: number, token: CancellationToken): Promise<CoverageDetails[]>;
/** Configures a test run config. */
$configureRunProfile(controllerId: string, configId: number): void;
}
export interface MainThreadTestingShape {
/** Registeres that there's a test controller with the given ID */
$registerTestController(id: string): void;
// --- test lifecycle:
/** Registers that there's a test controller with the given ID */
$registerTestController(controllerId: string, label: string): void;
/** Updates the label of an existing test controller. */
$updateControllerLabel(controllerId: string, label: string): void;
/** Diposes of the test controller with the given ID */
$unregisterTestController(id: string): void;
/** Requests tests from the given resource/uri, from the observer API. */
$subscribeToDiffs(resource: ExtHostTestingResource, uri: UriComponents): void;
/** Stops requesting tests from the given resource/uri, from the observer API. */
$unsubscribeFromDiffs(resource: ExtHostTestingResource, uri: UriComponents): void;
$unregisterTestController(controllerId: string): void;
/** Requests tests published to VS Code. */
$subscribeToDiffs(): void;
/** Stops requesting tests published to VS Code. */
$unsubscribeFromDiffs(): void;
/** Publishes that new tests were available on the given source. */
$publishDiff(resource: ExtHostTestingResource, uri: UriComponents, diff: TestsDiff): void;
/** Request by an extension to run tests. */
$runTests(req: RunTestsRequest, token: CancellationToken): Promise<string>;
$publishDiff(controllerId: string, diff: TestsDiff): void;
// --- test run configurations:
/** Called when a new test run configuration is available */
$publishTestRunProfile(config: ITestRunProfile): void;
/** Updates an existing test run configuration */
$updateTestRunConfig(controllerId: string, configId: number, update: Partial<ITestRunProfile>): void;
/** Removes a previously-published test run config */
$removeTestProfile(controllerId: string, configId: number): void;
// --- test run handling:
/** Request by an extension to run tests. */
$runTests(req: ResolvedTestRunRequest, token: CancellationToken): Promise<string>;
/**
* Adds tests to the run. The tests are given in descending depth. The first
* item will be a previously-known test, or a test root.
*/
$addTestsToRun(runId: string, tests: ITestItem[]): void;
$addTestsToRun(controllerId: string, runId: string, tests: ITestItem[]): void;
/** Updates the state of a test run in the given run. */
$updateTestStateInRun(runId: string, taskId: string, testId: string, state: TestResultState, duration?: number): void;
/** Appends a message to a test in the run. */
$appendTestMessageInRun(runId: string, taskId: string, testId: string, message: ITestMessage): void;
$appendTestMessagesInRun(runId: string, taskId: string, testId: string, messages: ITestMessage[]): void;
/** Appends raw output to the test run.. */
$appendOutputToRun(runId: string, taskId: string, output: VSBuffer): void;
$appendOutputToRun(runId: string, taskId: string, output: VSBuffer, location?: ILocationDto, testId?: string): void;
/** Triggered when coverage is added to test results. */
$signalCoverageAvailable(runId: string, taskId: string): void;
/** Signals a task in a test run started. */
$startedTestRunTask(runId: string, task: ITestRunTask): void;
/** Signals a task in a test run ended. */
@@ -2087,6 +2235,7 @@ export const MainContext = {
MainThreadNotebookEditors: createMainId<MainThreadNotebookEditorsShape>('MainThreadNotebookEditorsShape'),
MainThreadNotebookKernels: createMainId<MainThreadNotebookKernelsShape>('MainThreadNotebookKernels'),
MainThreadNotebookRenderers: createMainId<MainThreadNotebookRenderersShape>('MainThreadNotebookRenderers'),
MainThreadInteractive: createMainId<MainThreadInteractiveShape>('MainThreadInteractive'),
MainThreadTheming: createMainId<MainThreadThemingShape>('MainThreadTheming'),
MainThreadTunnelService: createMainId<MainThreadTunnelServiceShape>('MainThreadTunnelService'),
MainThreadTimeline: createMainId<MainThreadTimelineShape>('MainThreadTimeline'),
@@ -2137,6 +2286,7 @@ export const ExtHostContext = {
ExtHostNotebookEditors: createMainId<ExtHostNotebookEditorsShape>('ExtHostNotebookEditors'),
ExtHostNotebookKernels: createMainId<ExtHostNotebookKernelsShape>('ExtHostNotebookKernels'),
ExtHostNotebookRenderers: createMainId<ExtHostNotebookRenderersShape>('ExtHostNotebookRenderers'),
ExtHostInteractive: createMainId<ExtHostInteractive>('ExtHostInteractive'),
ExtHostTheming: createMainId<ExtHostThemingShape>('ExtHostTheming'),
ExtHostTunnelService: createMainId<ExtHostTunnelServiceShape>('ExtHostTunnelService'),
ExtHostAuthentication: createMainId<ExtHostAuthenticationShape>('ExtHostAuthentication'),

View File

@@ -7,7 +7,7 @@ import { URI } from 'vs/base/common/uri';
import type * as vscode from 'vscode';
import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters';
import * as types from 'vs/workbench/api/common/extHostTypes';
import { IRawColorInfo, IWorkspaceEditDto, ICallHierarchyItemDto, IIncomingCallDto, IOutgoingCallDto } from 'vs/workbench/api/common/extHost.protocol';
import { IRawColorInfo, IWorkspaceEditDto, ICallHierarchyItemDto, IIncomingCallDto, IOutgoingCallDto, ITypeHierarchyItemDto } from 'vs/workbench/api/common/extHost.protocol';
import * as modes from 'vs/editor/common/modes';
import * as search from 'vs/workbench/contrib/search/common/search';
import { ApiCommand, ApiCommandArgument, ApiCommandResult, ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
@@ -406,6 +406,22 @@ const newCommands: ApiCommand[] = [
],
ApiCommandResult.Void
),
// --- type hierarchy
new ApiCommand(
'vscode.prepareTypeHierarchy', '_executePrepareTypeHierarchy', 'Prepare type hierarchy at a position inside a document',
[ApiCommandArgument.Uri, ApiCommandArgument.Position],
new ApiCommandResult<ITypeHierarchyItemDto[], types.TypeHierarchyItem[]>('A TypeHierarchyItem or undefined', v => v.map(typeConverters.TypeHierarchyItem.to))
),
new ApiCommand(
'vscode.provideSupertypes', '_executeProvideSupertypes', 'Compute supertypes for an item',
[ApiCommandArgument.TypeHierarchyItem],
new ApiCommandResult<ITypeHierarchyItemDto[], types.TypeHierarchyItem[]>('A TypeHierarchyItem or undefined', v => v.map(typeConverters.TypeHierarchyItem.to))
),
new ApiCommand(
'vscode.provideSubtypes', '_executeProvideSubtypes', 'Compute subtypes for an item',
[ApiCommandArgument.TypeHierarchyItem],
new ApiCommandResult<ITypeHierarchyItemDto[], types.TypeHierarchyItem[]>('A TypeHierarchyItem or undefined', v => v.map(typeConverters.TypeHierarchyItem.to))
),
];
//#endregion

View File

@@ -27,9 +27,6 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape {
private _providers: vscode.AuthenticationProviderInformation[] = [];
private _onDidChangeAuthenticationProviders = new Emitter<vscode.AuthenticationProvidersChangeEvent>();
readonly onDidChangeAuthenticationProviders: Event<vscode.AuthenticationProvidersChangeEvent> = this._onDidChangeAuthenticationProviders.event;
private _onDidChangeSessions = new Emitter<vscode.AuthenticationSessionsChangeEvent>();
readonly onDidChangeSessions: Event<vscode.AuthenticationSessionsChangeEvent> = this._onDidChangeSessions.event;
@@ -44,11 +41,9 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape {
return Promise.resolve();
}
get providers(): ReadonlyArray<vscode.AuthenticationProviderInformation> {
return Object.freeze(this._providers.slice());
}
async getSession(requestingExtension: IExtensionDescription, providerId: string, scopes: readonly string[], options: vscode.AuthenticationGetSessionOptions & { createIfNone: true }): Promise<vscode.AuthenticationSession>;
async getSession(requestingExtension: IExtensionDescription, providerId: string, scopes: readonly string[], options: vscode.AuthenticationGetSessionOptions & ({ createIfNone: true } | { forceNewSession: true } | { forceNewSession: { detail: string } })): Promise<vscode.AuthenticationSession>;
async getSession(requestingExtension: IExtensionDescription, providerId: string, scopes: readonly string[], options: vscode.AuthenticationGetSessionOptions & { forceNewSession: true }): Promise<vscode.AuthenticationSession>;
async getSession(requestingExtension: IExtensionDescription, providerId: string, scopes: readonly string[], options: vscode.AuthenticationGetSessionOptions & { forceNewSession: { detail: string } }): Promise<vscode.AuthenticationSession>;
async getSession(requestingExtension: IExtensionDescription, providerId: string, scopes: readonly string[], options: vscode.AuthenticationGetSessionOptions = {}): Promise<vscode.AuthenticationSession | undefined> {
const extensionId = ExtensionIdentifier.toKey(requestingExtension.identifier);
const inFlightRequests = this._inFlightRequests.get(extensionId) || [];
@@ -164,22 +159,4 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape {
this._onDidChangeSessions.fire({ provider: { id, label } });
return Promise.resolve();
}
$onDidChangeAuthenticationProviders(added: modes.AuthenticationProviderInformation[], removed: modes.AuthenticationProviderInformation[]) {
added.forEach(provider => {
if (!this._providers.some(p => p.id === provider.id)) {
this._providers.push(provider);
}
});
removed.forEach(p => {
const index = this._providers.findIndex(provider => provider.id === p.id);
if (index > -1) {
this._providers.splice(index);
}
});
this._onDidChangeAuthenticationProviders.fire({ added, removed });
return Promise.resolve();
}
}

View File

@@ -378,7 +378,8 @@ export class ApiCommandArgument<V, O = V> {
static readonly Number = new ApiCommandArgument<number>('number', '', v => typeof v === 'number', v => v);
static readonly String = new ApiCommandArgument<string>('string', '', v => typeof v === 'string', v => v);
static readonly CallHierarchyItem = new ApiCommandArgument('item', 'A call hierarchy item', v => v instanceof extHostTypes.CallHierarchyItem, extHostTypeConverter.CallHierarchyItem.to);
static readonly CallHierarchyItem = new ApiCommandArgument('item', 'A call hierarchy item', v => v instanceof extHostTypes.CallHierarchyItem, extHostTypeConverter.CallHierarchyItem.from);
static readonly TypeHierarchyItem = new ApiCommandArgument('item', 'A type hierarchy item', v => v instanceof extHostTypes.TypeHierarchyItem, extHostTypeConverter.TypeHierarchyItem.from);
constructor(
readonly name: string,

File diff suppressed because it is too large Load Diff

View File

@@ -16,7 +16,7 @@ import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePa
import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters';
import { ExtHostWebviews, shouldSerializeBuffersForPostMessage, toExtensionData } from 'vs/workbench/api/common/extHostWebview';
import { ExtHostWebviewPanels } from 'vs/workbench/api/common/extHostWebviewPanels';
import { EditorGroupColumn } from 'vs/workbench/common/editor';
import { EditorGroupColumn } from 'vs/workbench/services/editor/common/editorGroupColumn';
import type * as vscode from 'vscode';
import { Cache } from './cache';
import * as extHostProtocol from './extHost.protocol';

View File

@@ -289,9 +289,11 @@ export abstract class ExtHostDebugServiceBase implements IExtHostDebugService, E
public startDebugging(folder: vscode.WorkspaceFolder | undefined, nameOrConfig: string | vscode.DebugConfiguration, options: vscode.DebugSessionOptions): Promise<boolean> {
return this._debugServiceProxy.$startDebugging(folder ? folder.uri : undefined, nameOrConfig, {
parentSessionID: options.parentSession ? options.parentSession.id : undefined,
lifecycleManagedByParent: options.lifecycleManagedByParent,
repl: options.consoleMode === DebugConsoleMode.MergeWithParent ? 'mergeWithParent' : 'separate',
noDebug: options.noDebug,
compact: options.compact
compact: options.compact,
debugUI: options.debugUI
});
}

View File

@@ -10,7 +10,7 @@ import type * as vscode from 'vscode';
import { MainContext, MainThreadDiagnosticsShape, ExtHostDiagnosticsShape, IMainContext } from './extHost.protocol';
import { DiagnosticSeverity } from './extHostTypes';
import * as converter from './extHostTypeConverters';
import { Event, Emitter } from 'vs/base/common/event';
import { Event, Emitter, DebounceEmitter } from 'vs/base/common/event';
import { ILogService } from 'vs/platform/log/common/log';
import { ResourceMap } from 'vs/base/common/map';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
@@ -215,15 +215,7 @@ export class ExtHostDiagnostics implements ExtHostDiagnosticsShape {
private readonly _proxy: MainThreadDiagnosticsShape;
private readonly _collections = new Map<string, DiagnosticCollection>();
private readonly _onDidChangeDiagnostics = new Emitter<vscode.Uri[]>();
static _debouncer(last: vscode.Uri[] | undefined, current: vscode.Uri[]): vscode.Uri[] {
if (!last) {
return current;
} else {
return last.concat(current);
}
}
private readonly _onDidChangeDiagnostics = new DebounceEmitter<vscode.Uri[]>({ merge: all => all.flat(), delay: 50 });
static _mapper(last: vscode.Uri[]): { uris: readonly vscode.Uri[] } {
const map = new ResourceMap<vscode.Uri>();
@@ -233,7 +225,7 @@ export class ExtHostDiagnostics implements ExtHostDiagnosticsShape {
return { uris: Object.freeze(Array.from(map.values())) };
}
readonly onDidChangeDiagnostics: Event<vscode.DiagnosticChangeEvent> = Event.map(Event.debounce(this._onDidChangeDiagnostics.event, ExtHostDiagnostics._debouncer, 50), ExtHostDiagnostics._mapper);
readonly onDidChangeDiagnostics: Event<vscode.DiagnosticChangeEvent> = Event.map(this._onDidChangeDiagnostics.event, ExtHostDiagnostics._mapper);
constructor(mainContext: IMainContext, @ILogService private readonly _logService: ILogService) {
this._proxy = mainContext.getProxy(MainContext.MainThreadDiagnostics);

View File

@@ -143,7 +143,7 @@ export class ExtHostDocumentData extends MirrorTextModel {
private _offsetAt(position: vscode.Position): number {
position = this._validatePosition(position);
this._ensureLineStarts();
return this._lineStarts!.getAccumulatedValue(position.line - 1) + position.character;
return this._lineStarts!.getPrefixSum(position.line - 1) + position.character;
}
private _positionAt(offset: number): vscode.Position {

View File

@@ -92,7 +92,7 @@ export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsSha
// double check -> only notebook cell documents should be
// referenced/opened more than once...
if (ref) {
if (resource.scheme !== Schemas.vscodeNotebookCell) {
if (resource.scheme !== Schemas.vscodeNotebookCell && resource.scheme !== Schemas.vscodeInteractiveInput) {
throw new Error(`document '${resource} already exists!'`);
}
}

View File

@@ -204,6 +204,8 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme
}
public async deactivateAll(): Promise<void> {
this._storagePath.onWillDeactivateAll();
let allPromises: Promise<void>[] = [];
try {
const allExtensions = this._registry.getAllExtensionDescriptions();
@@ -551,7 +553,7 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme
public async $extensionTestsExecute(): Promise<number> {
await this._eagerExtensionsActivated.wait();
try {
return this._doHandleExtensionTests();
return await this._doHandleExtensionTests();
} catch (error) {
console.error(error); // ensure any error message makes it onto the console
throw error;

View File

@@ -3,8 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Emitter, Event } from 'vs/base/common/event';
import { AsyncEmitter, IWaitUntil } from 'vs/base/common/async';
import { Emitter, Event, AsyncEmitter, IWaitUntil } from 'vs/base/common/event';
import { IRelativePattern, parse } from 'vs/base/common/glob';
import { URI } from 'vs/base/common/uri';
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';

View File

@@ -0,0 +1,60 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { URI, UriComponents } from 'vs/base/common/uri';
import { ExtHostInteractiveShape, IMainContext } from 'vs/workbench/api/common/extHost.protocol';
import { ApiCommand, ApiCommandArgument, ApiCommandResult, ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook';
import { NotebookEditor } from 'vscode';
export class ExtHostInteractive implements ExtHostInteractiveShape {
constructor(
mainContext: IMainContext,
private _extHostNotebooks: ExtHostNotebookController,
private _textDocumentsAndEditors: ExtHostDocumentsAndEditors,
private _commands: ExtHostCommands
) {
const apiCommand = new ApiCommand(
'interactive.open',
'_interactive.open',
'Open interactive window and return notebook editor and input URI',
[
new ApiCommandArgument('showOptions', 'Show Options', v => true, v => v),
new ApiCommandArgument('resource', 'Interactive resource Uri', v => true, v => v),
new ApiCommandArgument('controllerId', 'Notebook controller Id', v => true, v => v),
new ApiCommandArgument('title', 'Interactive editor title', v => true, v => v)
],
new ApiCommandResult<{ notebookUri: UriComponents, inputUri: UriComponents, notebookEditorId?: string }, { notebookUri: URI, inputUri: URI, notebookEditor?: NotebookEditor }>('Notebook and input URI', (v: { notebookUri: UriComponents, inputUri: UriComponents, notebookEditorId?: string }) => {
if (v.notebookEditorId !== undefined) {
const editor = this._extHostNotebooks.getEditorById(v.notebookEditorId);
return { notebookUri: URI.revive(v.notebookUri), inputUri: URI.revive(v.inputUri), notebookEditor: editor.apiEditor };
}
return { notebookUri: URI.revive(v.notebookUri), inputUri: URI.revive(v.inputUri) };
})
);
this._commands.registerApiCommand(apiCommand);
}
$willAddInteractiveDocument(uri: UriComponents, eol: string, modeId: string, notebookUri: UriComponents) {
this._textDocumentsAndEditors.acceptDocumentsAndEditorsDelta({
addedDocuments: [{
EOL: eol,
lines: [''],
modeId: modeId,
uri: uri,
isDirty: false,
versionId: 1,
notebook: this._extHostNotebooks.getNotebookDocument(URI.revive(notebookUri))?.apiNotebook
}]
});
}
$willRemoveInteractiveDocument(uri: UriComponents, notebookUri: UriComponents) {
this._textDocumentsAndEditors.acceptDocumentsAndEditorsDelta({
removedDocuments: [uri]
});
}
}

View File

@@ -987,8 +987,7 @@ class SuggestAdapter {
//
x: id,
//
[extHostProtocol.ISuggestDataDtoField.label]: item.label ?? '',
[extHostProtocol.ISuggestDataDtoField.label2]: item.label2,
[extHostProtocol.ISuggestDataDtoField.label]: item.label,
[extHostProtocol.ISuggestDataDtoField.kind]: item.kind !== undefined ? typeConvert.CompletionItemKind.from(item.kind) : undefined,
[extHostProtocol.ISuggestDataDtoField.kindModifier]: item.tags && item.tags.map(typeConvert.CompletionItemTag.from),
[extHostProtocol.ISuggestDataDtoField.detail]: item.detail,
@@ -1433,17 +1432,7 @@ class CallHierarchyAdapter {
private _cacheAndConvertItem(sessionId: string, item: vscode.CallHierarchyItem): extHostProtocol.ICallHierarchyItemDto {
const map = this._cache.get(sessionId)!;
const dto: extHostProtocol.ICallHierarchyItemDto = {
_sessionId: sessionId,
_itemId: map.size.toString(36),
name: item.name,
detail: item.detail,
kind: typeConvert.SymbolKind.from(item.kind),
uri: item.uri,
range: typeConvert.Range.from(item.range),
selectionRange: typeConvert.Range.from(item.selectionRange),
tags: item.tags?.map(typeConvert.SymbolTag.from)
};
const dto = typeConvert.CallHierarchyItem.from(item, sessionId, map.size.toString(36));
map.set(dto._itemId, item);
return dto;
}
@@ -1454,12 +1443,86 @@ class CallHierarchyAdapter {
}
}
class TypeHierarchyAdapter {
private readonly _idPool = new IdGenerator('');
private readonly _cache = new Map<string, Map<string, vscode.TypeHierarchyItem>>();
constructor(
private readonly _documents: ExtHostDocuments,
private readonly _provider: vscode.TypeHierarchyProvider
) { }
async prepareSession(uri: URI, position: IPosition, token: CancellationToken): Promise<extHostProtocol.ITypeHierarchyItemDto[] | undefined> {
const doc = this._documents.getDocument(uri);
const pos = typeConvert.Position.to(position);
const items = await this._provider.prepareTypeHierarchy(doc, pos, token);
if (!items) {
return undefined;
}
const sessionId = this._idPool.nextId();
this._cache.set(sessionId, new Map());
if (Array.isArray(items)) {
return items.map(item => this._cacheAndConvertItem(sessionId, item));
} else {
return [this._cacheAndConvertItem(sessionId, items)];
}
}
async provideSupertypes(sessionId: string, itemId: string, token: CancellationToken): Promise<extHostProtocol.ITypeHierarchyItemDto[] | undefined> {
const item = this._itemFromCache(sessionId, itemId);
if (!item) {
throw new Error('missing type hierarchy item');
}
const supertypes = await this._provider.provideTypeHierarchySupertypes(item, token);
if (!supertypes) {
return undefined;
}
return supertypes.map(supertype => {
return this._cacheAndConvertItem(sessionId, supertype);
});
}
async provideSubtypes(sessionId: string, itemId: string, token: CancellationToken): Promise<extHostProtocol.ITypeHierarchyItemDto[] | undefined> {
const item = this._itemFromCache(sessionId, itemId);
if (!item) {
throw new Error('missing type hierarchy item');
}
const subtypes = await this._provider.provideTypeHierarchySubtypes(item, token);
if (!subtypes) {
return undefined;
}
return subtypes.map(subtype => {
return this._cacheAndConvertItem(sessionId, subtype);
});
}
releaseSession(sessionId: string): void {
this._cache.delete(sessionId);
}
private _cacheAndConvertItem(sessionId: string, item: vscode.TypeHierarchyItem): extHostProtocol.ITypeHierarchyItemDto {
const map = this._cache.get(sessionId)!;
const dto = typeConvert.TypeHierarchyItem.from(item, sessionId, map.size.toString(36));
map.set(dto._itemId, item);
return dto;
}
private _itemFromCache(sessionId: string, itemId: string): vscode.TypeHierarchyItem | undefined {
const map = this._cache.get(sessionId);
return map?.get(itemId);
}
}
type Adapter = DocumentSymbolAdapter | CodeLensAdapter | DefinitionAdapter | HoverAdapter
| DocumentHighlightAdapter | ReferenceAdapter | CodeActionAdapter | DocumentFormattingAdapter
| RangeFormattingAdapter | OnTypeFormattingAdapter | NavigateTypeAdapter | RenameAdapter
| SuggestAdapter | SignatureHelpAdapter | LinkProviderAdapter | ImplementationAdapter
| TypeDefinitionAdapter | ColorProviderAdapter | FoldingProviderAdapter | DeclarationAdapter
| SelectionRangeAdapter | CallHierarchyAdapter | DocumentSemanticTokensAdapter | DocumentRangeSemanticTokensAdapter
| SelectionRangeAdapter | CallHierarchyAdapter | TypeHierarchyAdapter
| DocumentSemanticTokensAdapter | DocumentRangeSemanticTokensAdapter
| EvaluatableExpressionAdapter | InlineValuesAdapter
| LinkedEditingRangeAdapter | InlayHintsAdapter | InlineCompletionAdapter;
@@ -2068,6 +2131,29 @@ export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageF
this._withAdapter(handle, CallHierarchyAdapter, adapter => Promise.resolve(adapter.releaseSession(sessionId)), undefined);
}
// --- type hierarchy
registerTypeHierarchyProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.TypeHierarchyProvider): vscode.Disposable {
const handle = this._addNewAdapter(new TypeHierarchyAdapter(this._documents, provider), extension);
this._proxy.$registerTypeHierarchyProvider(handle, this._transformDocumentSelector(selector));
return this._createDisposable(handle);
}
$prepareTypeHierarchy(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<extHostProtocol.ITypeHierarchyItemDto[] | undefined> {
return this._withAdapter(handle, TypeHierarchyAdapter, adapter => Promise.resolve(adapter.prepareSession(URI.revive(resource), position, token)), undefined);
}
$provideTypeHierarchySupertypes(handle: number, sessionId: string, itemId: string, token: CancellationToken): Promise<extHostProtocol.ITypeHierarchyItemDto[] | undefined> {
return this._withAdapter(handle, TypeHierarchyAdapter, adapter => adapter.provideSupertypes(sessionId, itemId, token), undefined);
}
$provideTypeHierarchySubtypes(handle: number, sessionId: string, itemId: string, token: CancellationToken): Promise<extHostProtocol.ITypeHierarchyItemDto[] | undefined> {
return this._withAdapter(handle, TypeHierarchyAdapter, adapter => adapter.provideSubtypes(sessionId, itemId, token), undefined);
}
$releaseTypeHierarchy(handle: number, sessionId: string): void {
this._withAdapter(handle, TypeHierarchyAdapter, adapter => Promise.resolve(adapter.releaseSession(sessionId)), undefined);
}
// --- configuration
private static _serializeRegExp(regExp: RegExp): extHostProtocol.IRegExpDto {

View File

@@ -7,7 +7,10 @@ import { MainContext, MainThreadLanguagesShape, IMainContext } from './extHost.p
import type * as vscode from 'vscode';
import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
import * as typeConvert from 'vs/workbench/api/common/extHostTypeConverters';
import { StandardTokenType, Range, Position } from 'vs/workbench/api/common/extHostTypes';
import { StandardTokenType, Range, Position, LanguageStatusSeverity } from 'vs/workbench/api/common/extHostTypes';
import Severity from 'vs/base/common/severity';
import { disposableTimeout } from 'vs/base/common/async';
import { IDisposable } from 'vs/base/common/lifecycle';
export class ExtHostLanguages {
@@ -61,4 +64,69 @@ export class ExtHostLanguages {
}
return result;
}
private _handlePool: number = 0;
createLanguageStatusItem(selector: vscode.DocumentSelector): vscode.LanguageStatusItem {
const handle = this._handlePool++;
const proxy = this._proxy;
const data: { selector: any, text: string, detail: string | vscode.MarkdownString, severity: vscode.LanguageStatusSeverity } = {
selector,
text: '',
detail: '',
severity: LanguageStatusSeverity.Information,
};
let soonHandle: IDisposable | undefined;
const updateAsync = () => {
soonHandle?.dispose();
soonHandle = disposableTimeout(() => {
this._proxy.$setLanguageStatus(handle, {
selector: data.selector,
text: data.text,
message: typeof data.detail === 'string' ? data.detail : typeConvert.MarkdownString.from(data.detail),
severity: data.severity === LanguageStatusSeverity.Error ? Severity.Error : data.severity === LanguageStatusSeverity.Warning ? Severity.Warning : Severity.Info
});
}, 0);
};
const result: vscode.LanguageStatusItem = {
get selector() {
return data.selector;
},
set selector(value) {
data.selector = value;
updateAsync();
},
get text() {
return data.text;
},
set text(value) {
data.text = value;
updateAsync();
},
get detail() {
return data.detail;
},
set detail(value) {
data.detail = value;
updateAsync();
},
get severity() {
return data.severity;
},
set severity(value) {
data.severity = value;
updateAsync();
},
dispose() {
soonHandle?.dispose();
proxy.$removeLanguageStatus(handle);
}
};
updateAsync();
return result;
}
}

View File

@@ -56,7 +56,7 @@ export class ExtensionMemento implements vscode.Memento {
}, 0);
}
get keys(): readonly string[] {
keys(): readonly string[] {
// Filter out `undefined` values, as they can stick around in the `_value` until the `onDidChangeStorage` event runs
return Object.entries(this._value ?? {}).filter(([, value]) => value !== undefined).map(([key]) => key);
}

View File

@@ -37,8 +37,9 @@ export class ExtHostMessageService {
if (typeof optionsOrFirstItem === 'string' || isMessageItem(optionsOrFirstItem)) {
items = [optionsOrFirstItem, ...rest];
} else {
options.modal = optionsOrFirstItem && optionsOrFirstItem.modal;
options.useCustom = optionsOrFirstItem && optionsOrFirstItem.useCustom;
options.modal = optionsOrFirstItem?.modal;
options.useCustom = optionsOrFirstItem?.useCustom;
options.detail = optionsOrFirstItem?.detail;
items = rest;
}

View File

@@ -10,19 +10,21 @@ import { IRelativePattern } from 'vs/base/common/glob';
import { hash } from 'vs/base/common/hash';
import { DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { ResourceMap } from 'vs/base/common/map';
import { MarshalledId } from 'vs/base/common/marshalling';
import { isFalsyOrWhitespace } from 'vs/base/common/strings';
import { assertIsDefined } from 'vs/base/common/types';
import { URI, UriComponents } from 'vs/base/common/uri';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { Cache } from 'vs/workbench/api/common/cache';
import { ExtHostNotebookShape, IMainContext, IModelAddedData, INotebookCellStatusBarListDto, INotebookDocumentsAndEditorsDelta, INotebookDocumentShowOptions, INotebookEditorAddData, MainContext, MainThreadNotebookDocumentsShape, MainThreadNotebookEditorsShape, MainThreadNotebookShape } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostNotebookShape, IMainContext, IModelAddedData, INotebookCellStatusBarListDto, INotebookDocumentsAndEditorsDelta, INotebookDocumentShowOptions, INotebookEditorAddData, MainContext, MainThreadNotebookDocumentsShape, MainThreadNotebookEditorsShape, MainThreadNotebookShape, NotebookDataDto } from 'vs/workbench/api/common/extHost.protocol';
import { CommandsConverter, ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths';
import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters';
import * as extHostTypes from 'vs/workbench/api/common/extHostTypes';
import { INotebookExclusiveDocumentFilter, INotebookContributionData, NotebookCellsChangeType, NotebookDataDto } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { INotebookExclusiveDocumentFilter, INotebookContributionData } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { SerializableObjectWithBuffers } from 'vs/workbench/services/extensions/common/proxyIdentifier';
import type * as vscode from 'vscode';
import { ExtHostCell, ExtHostNotebookDocument } from './extHostNotebookDocument';
import { ExtHostNotebookEditor } from './extHostNotebookEditor';
@@ -91,7 +93,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
commands.registerArgumentProcessor({
// Serialized INotebookCellActionContext
processArgument: (arg) => {
if (arg && arg.$mid === 12) {
if (arg && arg.$mid === MarshalledId.NotebookCellActionContext) {
const notebookUri = arg.notebookEditor?.notebookUri;
const cellHandle = arg.cell.handle;
@@ -185,7 +187,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
private static _convertNotebookRegistrationData(extension: IExtensionDescription, registration: vscode.NotebookRegistrationData | undefined): INotebookContributionData | undefined {
if (!registration) {
return undefined; // {{SQL CARBON EDIT}} Strict nulls
return undefined; // {{SQL CARBON EDIT}} strict-nulls
}
const viewOptionsFilenamePattern = registration.filenamePattern
.map(pattern => typeConverters.NotebookExclusiveDocumentPattern.from(pattern))
@@ -333,33 +335,33 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
});
}
async $dataToNotebook(handle: number, bytes: VSBuffer, token: CancellationToken): Promise<NotebookDataDto> {
async $dataToNotebook(handle: number, bytes: VSBuffer, token: CancellationToken): Promise<SerializableObjectWithBuffers<NotebookDataDto>> {
const serializer = this._notebookSerializer.get(handle);
if (!serializer) {
throw new Error('NO serializer found');
}
const data = await serializer.deserializeNotebook(bytes.buffer, token);
return typeConverters.NotebookData.from(data);
return new SerializableObjectWithBuffers(typeConverters.NotebookData.from(data));
}
async $notebookToData(handle: number, data: NotebookDataDto, token: CancellationToken): Promise<VSBuffer> {
async $notebookToData(handle: number, data: SerializableObjectWithBuffers<NotebookDataDto>, token: CancellationToken): Promise<VSBuffer> {
const serializer = this._notebookSerializer.get(handle);
if (!serializer) {
throw new Error('NO serializer found');
}
const bytes = await serializer.serializeNotebook(typeConverters.NotebookData.to(data), token);
const bytes = await serializer.serializeNotebook(typeConverters.NotebookData.to(data.value), token);
return VSBuffer.wrap(bytes);
}
// --- open, save, saveAs, backup
async $openNotebook(viewType: string, uri: UriComponents, backupId: string | undefined, untitledDocumentData: VSBuffer | undefined, token: CancellationToken): Promise<NotebookDataDto> {
async $openNotebook(viewType: string, uri: UriComponents, backupId: string | undefined, untitledDocumentData: VSBuffer | undefined, token: CancellationToken): Promise<SerializableObjectWithBuffers<NotebookDataDto>> {
const { provider } = this._getProviderData(viewType);
const data = await provider.openNotebook(URI.revive(uri), { backupId, untitledDocumentData: untitledDocumentData?.buffer }, token);
return {
return new SerializableObjectWithBuffers({
metadata: data.metadata ?? Object.create(null),
cells: data.cells.map(typeConverters.NotebookCellData.from),
};
});
}
async $saveNotebook(viewType: string, uri: UriComponents, token: CancellationToken): Promise<boolean> {
@@ -410,10 +412,10 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
this._editors.set(editorId, editor);
}
$acceptDocumentAndEditorsDelta(delta: INotebookDocumentsAndEditorsDelta): void {
$acceptDocumentAndEditorsDelta(delta: SerializableObjectWithBuffers<INotebookDocumentsAndEditorsDelta>): void {
if (delta.removedDocuments) {
for (const uri of delta.removedDocuments) {
if (delta.value.removedDocuments) {
for (const uri of delta.value.removedDocuments) {
const revivedUri = URI.revive(uri);
const document = this._documents.get(revivedUri);
@@ -432,13 +434,12 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
}
}
if (delta.addedDocuments) {
if (delta.value.addedDocuments) {
const addedCellDocuments: IModelAddedData[] = [];
for (const modelData of delta.addedDocuments) {
for (const modelData of delta.value.addedDocuments) {
const uri = URI.revive(modelData.uri);
const viewType = modelData.viewType;
if (this._documents.has(uri)) {
throw new Error(`adding EXISTING notebook ${uri} `);
@@ -463,19 +464,10 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
that._onDidChangeCellExecutionState.fire(event);
}
},
viewType,
modelData.metadata ?? Object.create({}),
uri,
modelData
);
document.acceptModelChanged({
versionId: modelData.versionId,
rawEvents: [{
kind: NotebookCellsChangeType.Initialize,
changes: [[0, 0, modelData.cells]]
}]
}, false);
// add cell document as vscode.TextDocument
addedCellDocuments.push(...modelData.cells.map(cell => ExtHostCell.asModelAddData(document.apiNotebook, cell)));
@@ -487,8 +479,8 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
}
}
if (delta.addedEditors) {
for (const editorModelData of delta.addedEditors) {
if (delta.value.addedEditors) {
for (const editorModelData of delta.value.addedEditors) {
if (this._editors.has(editorModelData.id)) {
return;
}
@@ -504,8 +496,8 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
const removedEditors: ExtHostNotebookEditor[] = [];
if (delta.removedEditors) {
for (const editorid of delta.removedEditors) {
if (delta.value.removedEditors) {
for (const editorid of delta.value.removedEditors) {
const editor = this._editors.get(editorid);
if (editor) {
@@ -520,8 +512,8 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
}
}
if (delta.visibleEditors) {
this._visibleNotebookEditors = delta.visibleEditors.map(id => this._editors.get(id)!).filter(editor => !!editor) as ExtHostNotebookEditor[];
if (delta.value.visibleEditors) {
this._visibleNotebookEditors = delta.value.visibleEditors.map(id => this._editors.get(id)!).filter(editor => !!editor) as ExtHostNotebookEditor[];
const visibleEditorsSet = new Set<string>();
this._visibleNotebookEditors.forEach(editor => visibleEditorsSet.add(editor.id));
@@ -534,13 +526,13 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
this._onDidChangeVisibleNotebookEditors.fire(this.visibleNotebookEditors);
}
if (delta.newActiveEditor === null) {
if (delta.value.newActiveEditor === null) {
// clear active notebook as current active editor is non-notebook editor
this._activeNotebookEditor = undefined;
} else if (delta.newActiveEditor) {
this._activeNotebookEditor = this._editors.get(delta.newActiveEditor);
} else if (delta.value.newActiveEditor) {
this._activeNotebookEditor = this._editors.get(delta.value.newActiveEditor);
}
if (delta.newActiveEditor !== undefined) {
if (delta.value.newActiveEditor !== undefined) {
this._onDidChangeActiveNotebookEditor.fire(this._activeNotebookEditor?.apiEditor);
}
}

View File

@@ -107,23 +107,29 @@ export class ExtHostNotebookConcatDocument implements vscode.NotebookConcatTextD
// get start and end locations and create substrings
const start = this.locationAt(range.start);
const end = this.locationAt(range.end);
const startCell = this._cells[this._cellUris.get(start.uri) ?? -1];
const endCell = this._cells[this._cellUris.get(end.uri) ?? -1];
if (!startCell || !endCell) {
const startIdx = this._cellUris.get(start.uri);
const endIdx = this._cellUris.get(end.uri);
if (startIdx === undefined || endIdx === undefined) {
return '';
} else if (startCell === endCell) {
return startCell.document.getText(new types.Range(start.range.start, end.range.end));
} else {
const a = startCell.document.getText(new types.Range(start.range.start, new types.Position(startCell.document.lineCount, 0)));
const b = endCell.document.getText(new types.Range(new types.Position(0, 0), end.range.end));
return a + '\n' + b;
}
if (startIdx === endIdx) {
return this._cells[startIdx].document.getText(new types.Range(start.range.start, end.range.end));
}
const parts = [this._cells[startIdx].document.getText(new types.Range(start.range.start, new types.Position(this._cells[startIdx].document.lineCount, 0)))];
for (let i = startIdx + 1; i < endIdx; i++) {
parts.push(this._cells[i].document.getText());
}
parts.push(this._cells[endIdx].document.getText(new types.Range(new types.Position(0, 0), end.range.end)));
return parts.join('\n');
}
offsetAt(position: vscode.Position): number {
const idx = this._cellLines.getIndexOf(position.line);
const offset1 = this._cellLengths.getAccumulatedValue(idx.index - 1);
const offset1 = this._cellLengths.getPrefixSum(idx.index - 1);
const offset2 = this._cells[idx.index].document.offsetAt(position.with(idx.remainder));
return offset1 + offset2;
}
@@ -131,13 +137,13 @@ export class ExtHostNotebookConcatDocument implements vscode.NotebookConcatTextD
positionAt(locationOrOffset: vscode.Location | number): vscode.Position {
if (typeof locationOrOffset === 'number') {
const idx = this._cellLengths.getIndexOf(locationOrOffset);
const lineCount = this._cellLines.getAccumulatedValue(idx.index - 1);
const lineCount = this._cellLines.getPrefixSum(idx.index - 1);
return this._cells[idx.index].document.positionAt(idx.remainder).translate(lineCount);
}
const idx = this._cellUris.get(locationOrOffset.uri);
if (idx !== undefined) {
const line = this._cellLines.getAccumulatedValue(idx - 1);
const line = this._cellLines.getPrefixSum(idx - 1);
return new types.Position(line + locationOrOffset.range.start.line, locationOrOffset.range.start.character);
}
// do better?
@@ -180,7 +186,7 @@ export class ExtHostNotebookConcatDocument implements vscode.NotebookConcatTextD
const cellPosition = new types.Position(startIdx.remainder, position.character);
const validCellPosition = this._cells[startIdx.index].document.validatePosition(cellPosition);
const line = this._cellLines.getAccumulatedValue(startIdx.index - 1);
const line = this._cellLines.getPrefixSum(startIdx.index - 1);
return new types.Position(line + validCellPosition.line, validCellPosition.character);
}
}

View File

@@ -6,12 +6,12 @@
import { Schemas } from 'vs/base/common/network';
import { deepFreeze, equals } from 'vs/base/common/objects';
import { URI } from 'vs/base/common/uri';
import { INotebookDocumentPropertiesChangeData, MainThreadNotebookDocumentsShape } from 'vs/workbench/api/common/extHost.protocol';
import * as extHostProtocol from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
import { ExtHostDocumentsAndEditors, IExtHostModelAddedData } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
import * as extHostTypeConverters from 'vs/workbench/api/common/extHostTypeConverters';
import * as extHostTypes from 'vs/workbench/api/common/extHostTypes';
import { CellKind, IMainCellDto, IOutputDto, IOutputItemDto, NotebookCellInternalMetadata, NotebookCellMetadata, NotebookCellsChangedEventDto, NotebookCellsChangeType, NotebookCellsSplice2 } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import * as notebookCommon from 'vs/workbench/contrib/notebook/common/notebookCommon';
import * as vscode from 'vscode';
class RawContentChangeEvent {
@@ -32,7 +32,7 @@ class RawContentChangeEvent {
export class ExtHostCell {
static asModelAddData(notebook: vscode.NotebookDocument, cell: IMainCellDto): IExtHostModelAddedData {
static asModelAddData(notebook: vscode.NotebookDocument, cell: extHostProtocol.NotebookCellDto): IExtHostModelAddedData {
return {
EOL: cell.eol,
lines: cell.source,
@@ -45,31 +45,32 @@ export class ExtHostCell {
}
private _outputs: vscode.NotebookCellOutput[];
private _metadata: NotebookCellMetadata;
private _previousResult: vscode.NotebookCellExecutionSummary | undefined;
private _metadata: Readonly<notebookCommon.NotebookCellMetadata>;
private _previousResult: Readonly<vscode.NotebookCellExecutionSummary | undefined>;
private _internalMetadata: NotebookCellInternalMetadata;
private _internalMetadata: notebookCommon.NotebookCellInternalMetadata;
readonly handle: number;
readonly uri: URI;
readonly cellKind: CellKind;
readonly cellKind: notebookCommon.CellKind;
private _apiCell: vscode.NotebookCell | undefined;
private _mime: string | undefined;
constructor(
readonly notebook: ExtHostNotebookDocument,
private readonly _extHostDocument: ExtHostDocumentsAndEditors,
private readonly _cellData: IMainCellDto,
private readonly _cellData: extHostProtocol.NotebookCellDto,
) {
this.handle = _cellData.handle;
this.uri = URI.revive(_cellData.uri);
this.cellKind = _cellData.cellKind;
this._outputs = _cellData.outputs.map(extHostTypeConverters.NotebookCellOutput.to);
this._internalMetadata = _cellData.internalMetadata ?? {};
this._metadata = _cellData.metadata ?? {};
this._previousResult = extHostTypeConverters.NotebookCellExecutionSummary.to(_cellData.internalMetadata ?? {});
this._metadata = Object.freeze(_cellData.metadata ?? {});
this._previousResult = Object.freeze(extHostTypeConverters.NotebookCellExecutionSummary.to(_cellData.internalMetadata ?? {}));
}
get internalMetadata(): NotebookCellInternalMetadata {
get internalMetadata(): notebookCommon.NotebookCellInternalMetadata {
return this._internalMetadata;
}
@@ -85,6 +86,8 @@ export class ExtHostCell {
notebook: that.notebook.apiNotebook,
kind: extHostTypeConverters.NotebookCellKind.to(this._cellData.cellKind),
document: data.document,
get mime() { return that._mime; },
set mime(value: string | undefined) { that._mime = value; },
get outputs() { return that._outputs.slice(0); },
get metadata() { return that._metadata; },
get executionSummary() { return that._previousResult; }
@@ -93,11 +96,11 @@ export class ExtHostCell {
return this._apiCell;
}
setOutputs(newOutputs: IOutputDto[]): void {
setOutputs(newOutputs: extHostProtocol.NotebookOutputDto[]): void {
this._outputs = newOutputs.map(extHostTypeConverters.NotebookCellOutput.to);
}
setOutputItems(outputId: string, append: boolean, newOutputItems: IOutputItemDto[]) {
setOutputItems(outputId: string, append: boolean, newOutputItems: extHostProtocol.NotebookOutputItemDto[]) {
const newItems = newOutputItems.map(extHostTypeConverters.NotebookCellOutputItem.to);
const output = this._outputs.find(op => op.id === outputId);
if (output) {
@@ -108,13 +111,17 @@ export class ExtHostCell {
}
}
setMetadata(newMetadata: NotebookCellMetadata): void {
this._metadata = newMetadata;
setMetadata(newMetadata: notebookCommon.NotebookCellMetadata): void {
this._metadata = Object.freeze(newMetadata);
}
setInternalMetadata(newInternalMetadata: NotebookCellInternalMetadata): void {
setInternalMetadata(newInternalMetadata: notebookCommon.NotebookCellInternalMetadata): void {
this._internalMetadata = newInternalMetadata;
this._previousResult = extHostTypeConverters.NotebookCellExecutionSummary.to(newInternalMetadata);
this._previousResult = Object.freeze(extHostTypeConverters.NotebookCellExecutionSummary.to(newInternalMetadata));
}
setMime(newMime: string | undefined) {
}
}
@@ -131,23 +138,30 @@ export class ExtHostNotebookDocument {
private static _handlePool: number = 0;
readonly handle = ExtHostNotebookDocument._handlePool++;
private _cells: ExtHostCell[] = [];
private readonly _cells: ExtHostCell[] = [];
private readonly _notebookType: string;
private _notebook: vscode.NotebookDocument | undefined;
private _metadata: Record<string, any>;
private _versionId: number = 0;
private _isDirty: boolean = false;
private _backup?: vscode.NotebookDocumentBackup;
private _disposed: boolean = false;
constructor(
private readonly _proxy: MainThreadNotebookDocumentsShape,
private readonly _proxy: extHostProtocol.MainThreadNotebookDocumentsShape,
private readonly _textDocumentsAndEditors: ExtHostDocumentsAndEditors,
private readonly _textDocuments: ExtHostDocuments,
private readonly _emitter: INotebookEventEmitter,
private readonly _notebookType: string,
private _metadata: Record<string, any>,
readonly uri: URI,
) { }
data: extHostProtocol.INotebookModelAddedData
) {
this._notebookType = data.viewType;
this._metadata = Object.freeze(data.metadata ?? Object.create(null));
this._spliceNotebookCells([[0, 0, data.cells]], true /* init -> no event*/);
this._versionId = data.versionId;
}
dispose() {
this._disposed = true;
@@ -191,32 +205,36 @@ export class ExtHostNotebookDocument {
this._backup = undefined;
}
acceptDocumentPropertiesChanged(data: INotebookDocumentPropertiesChangeData) {
acceptDocumentPropertiesChanged(data: extHostProtocol.INotebookDocumentPropertiesChangeData) {
if (data.metadata) {
this._metadata = { ...this._metadata, ...data.metadata };
this._metadata = Object.freeze({ ...this._metadata, ...data.metadata });
}
}
acceptModelChanged(event: NotebookCellsChangedEventDto, isDirty: boolean): void {
acceptDirty(isDirty: boolean): void {
this._isDirty = isDirty;
}
acceptModelChanged(event: extHostProtocol.NotebookCellsChangedEventDto, isDirty: boolean): void {
this._versionId = event.versionId;
this._isDirty = isDirty;
for (const rawEvent of event.rawEvents) {
if (rawEvent.kind === NotebookCellsChangeType.Initialize) {
this._spliceNotebookCells(rawEvent.changes, true);
} if (rawEvent.kind === NotebookCellsChangeType.ModelChange) {
if (rawEvent.kind === notebookCommon.NotebookCellsChangeType.ModelChange) {
this._spliceNotebookCells(rawEvent.changes, false);
} else if (rawEvent.kind === NotebookCellsChangeType.Move) {
} else if (rawEvent.kind === notebookCommon.NotebookCellsChangeType.Move) {
this._moveCell(rawEvent.index, rawEvent.newIdx);
} else if (rawEvent.kind === NotebookCellsChangeType.Output) {
} else if (rawEvent.kind === notebookCommon.NotebookCellsChangeType.Output) {
this._setCellOutputs(rawEvent.index, rawEvent.outputs);
} else if (rawEvent.kind === NotebookCellsChangeType.OutputItem) {
} else if (rawEvent.kind === notebookCommon.NotebookCellsChangeType.OutputItem) {
this._setCellOutputItems(rawEvent.index, rawEvent.outputId, rawEvent.append, rawEvent.outputItems);
} else if (rawEvent.kind === NotebookCellsChangeType.ChangeLanguage) {
} else if (rawEvent.kind === notebookCommon.NotebookCellsChangeType.ChangeLanguage) {
this._changeCellLanguage(rawEvent.index, rawEvent.language);
} else if (rawEvent.kind === NotebookCellsChangeType.ChangeCellMetadata) {
} else if (rawEvent.kind === notebookCommon.NotebookCellsChangeType.ChangeCellMime) {
this._changeCellMime(rawEvent.index, rawEvent.mime);
} else if (rawEvent.kind === notebookCommon.NotebookCellsChangeType.ChangeCellMetadata) {
this._changeCellMetadata(rawEvent.index, rawEvent.metadata);
} else if (rawEvent.kind === NotebookCellsChangeType.ChangeCellInternalMetadata) {
} else if (rawEvent.kind === notebookCommon.NotebookCellsChangeType.ChangeCellInternalMetadata) {
this._changeCellInternalMetadata(rawEvent.index, rawEvent.internalMetadata);
}
}
@@ -261,7 +279,7 @@ export class ExtHostNotebookDocument {
return this._proxy.$trySaveNotebook(this.uri);
}
private _spliceNotebookCells(splices: NotebookCellsSplice2[], initialization: boolean): void {
private _spliceNotebookCells(splices: notebookCommon.NotebookCellTextModelSplice<extHostProtocol.NotebookCellDto>[], initialization: boolean): void {
if (this._disposed) {
return;
}
@@ -317,13 +335,13 @@ export class ExtHostNotebookDocument {
}));
}
private _setCellOutputs(index: number, outputs: IOutputDto[]): void {
private _setCellOutputs(index: number, outputs: extHostProtocol.NotebookOutputDto[]): void {
const cell = this._cells[index];
cell.setOutputs(outputs);
this._emitter.emitCellOutputsChange(deepFreeze({ document: this.apiNotebook, cells: [cell.apiCell] }));
}
private _setCellOutputItems(index: number, outputId: string, append: boolean, outputItems: IOutputItemDto[]): void {
private _setCellOutputItems(index: number, outputId: string, append: boolean, outputItems: extHostProtocol.NotebookOutputItemDto[]): void {
const cell = this._cells[index];
cell.setOutputItems(outputId, append, outputItems);
this._emitter.emitCellOutputsChange(deepFreeze({ document: this.apiNotebook, cells: [cell.apiCell] }));
@@ -336,7 +354,12 @@ export class ExtHostNotebookDocument {
}
}
private _changeCellMetadata(index: number, newMetadata: NotebookCellMetadata): void {
private _changeCellMime(index: number, newMime: string | undefined): void {
const cell = this._cells[index];
cell.apiCell.mime = newMime;
}
private _changeCellMetadata(index: number, newMetadata: notebookCommon.NotebookCellMetadata): void {
const cell = this._cells[index];
const originalExtMetadata = cell.apiCell.metadata;
@@ -348,7 +371,7 @@ export class ExtHostNotebookDocument {
}
}
private _changeCellInternalMetadata(index: number, newInternalMetadata: NotebookCellInternalMetadata): void {
private _changeCellInternalMetadata(index: number, newInternalMetadata: notebookCommon.NotebookCellInternalMetadata): void {
const cell = this._cells[index];
const originalInternalMetadata = cell.internalMetadata;

View File

@@ -6,12 +6,12 @@
import { Emitter } from 'vs/base/common/event';
import { URI, UriComponents } from 'vs/base/common/uri';
import { ILogService } from 'vs/platform/log/common/log';
import { ExtHostNotebookDocumentsShape, INotebookDocumentPropertiesChangeData } from 'vs/workbench/api/common/extHost.protocol';
import * as extHostProtocol from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook';
import { NotebookCellsChangedEventDto } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { SerializableObjectWithBuffers } from 'vs/workbench/services/extensions/common/proxyIdentifier';
import type * as vscode from 'vscode';
export class ExtHostNotebookDocuments implements ExtHostNotebookDocumentsShape {
export class ExtHostNotebookDocuments implements extHostProtocol.ExtHostNotebookDocumentsShape {
private readonly _onDidChangeNotebookDocumentMetadata = new Emitter<vscode.NotebookDocumentMetadataChangeEvent>();
readonly onDidChangeNotebookDocumentMetadata = this._onDidChangeNotebookDocumentMetadata.event;
@@ -24,14 +24,14 @@ export class ExtHostNotebookDocuments implements ExtHostNotebookDocumentsShape {
private readonly _notebooksAndEditors: ExtHostNotebookController,
) { }
$acceptModelChanged(uri: UriComponents, event: NotebookCellsChangedEventDto, isDirty: boolean): void {
$acceptModelChanged(uri: UriComponents, event: SerializableObjectWithBuffers<extHostProtocol.NotebookCellsChangedEventDto>, isDirty: boolean): void {
const document = this._notebooksAndEditors.getNotebookDocument(URI.revive(uri));
document.acceptModelChanged(event, isDirty);
document.acceptModelChanged(event.value, isDirty);
}
$acceptDirtyStateChanged(uri: UriComponents, isDirty: boolean): void {
const document = this._notebooksAndEditors.getNotebookDocument(URI.revive(uri));
document.acceptModelChanged({ rawEvents: [], versionId: document.apiNotebook.version }, isDirty);
document.acceptDirty(isDirty);
}
$acceptModelSaved(uri: UriComponents): void {
@@ -39,7 +39,7 @@ export class ExtHostNotebookDocuments implements ExtHostNotebookDocumentsShape {
this._onDidSaveNotebookDocument.fire(document.apiNotebook);
}
$acceptDocumentPropertiesChanged(uri: UriComponents, data: INotebookDocumentPropertiesChangeData): void {
$acceptDocumentPropertiesChanged(uri: UriComponents, data: extHostProtocol.INotebookDocumentPropertiesChangeData): void {
this._logService.debug('ExtHostNotebook#$acceptDocumentPropertiesChanged', uri.path, data);
const document = this._notebooksAndEditors.getNotebookDocument(URI.revive(uri));
document.acceptDocumentPropertiesChanged(data);

View File

@@ -3,17 +3,17 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { MainThreadNotebookEditorsShape } from 'vs/workbench/api/common/extHost.protocol';
import { ICellEditOperationDto, MainThreadNotebookEditorsShape } from 'vs/workbench/api/common/extHost.protocol';
import * as extHostTypes from 'vs/workbench/api/common/extHostTypes';
import * as extHostConverter from 'vs/workbench/api/common/extHostTypeConverters';
import { CellEditType, ICellEditOperation, ICellReplaceEdit } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { CellEditType } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import * as vscode from 'vscode';
import { ExtHostNotebookDocument } from './extHostNotebookDocument';
import { illegalArgument } from 'vs/base/common/errors';
interface INotebookEditData {
documentVersionId: number;
cellEdits: ICellEditOperation[];
cellEdits: ICellEditOperationDto[];
}
class NotebookEditorCellEditBuilder implements vscode.NotebookEditorEdit {
@@ -21,7 +21,7 @@ class NotebookEditorCellEditBuilder implements vscode.NotebookEditorEdit {
private readonly _documentVersionId: number;
private _finalized: boolean = false;
private _collectedEdits: ICellEditOperation[] = [];
private _collectedEdits: ICellEditOperationDto[] = [];
constructor(documentVersionId: number) {
this._documentVersionId = documentVersionId;
@@ -52,7 +52,7 @@ class NotebookEditorCellEditBuilder implements vscode.NotebookEditorEdit {
replaceCellMetadata(index: number, metadata: Record<string, any>): void {
this._throwIfFinalized();
this._collectedEdits.push({
editType: CellEditType.Metadata,
editType: CellEditType.PartialMetadata,
index,
metadata
});
@@ -174,7 +174,7 @@ export class ExtHostNotebookEditor {
return Promise.resolve(true);
}
const compressedEdits: ICellEditOperation[] = [];
const compressedEdits: ICellEditOperationDto[] = [];
let compressedEditsIndex = -1;
for (let i = 0; i < editData.cellEdits.length; i++) {
@@ -190,8 +190,8 @@ export class ExtHostNotebookEditor {
const edit = editData.cellEdits[i];
if (prev.editType === CellEditType.Replace && edit.editType === CellEditType.Replace) {
if (prev.index === edit.index) {
prev.cells.push(...(editData.cellEdits[i] as ICellReplaceEdit).cells);
prev.count += (editData.cellEdits[i] as ICellReplaceEdit).count;
prev.cells.push(...(editData.cellEdits[i] as any).cells);
prev.count += (editData.cellEdits[i] as any).count;
continue;
}
}

View File

@@ -3,25 +3,26 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { asArray } from 'vs/base/common/arrays';
import { timeout } from 'vs/base/common/async';
import { CancellationTokenSource } from 'vs/base/common/cancellation';
import { Emitter } from 'vs/base/common/event';
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import { ExtHostNotebookKernelsShape, IMainContext, INotebookKernelDto2, MainContext, MainThreadNotebookDocumentsShape, MainThreadNotebookKernelsShape } from 'vs/workbench/api/common/extHost.protocol';
import * as vscode from 'vscode';
import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook';
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { URI, UriComponents } from 'vs/base/common/uri';
import * as extHostTypeConverters from 'vs/workbench/api/common/extHostTypeConverters';
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
import { asWebviewUri } from 'vs/workbench/api/common/shared/webview';
import { ResourceMap } from 'vs/base/common/map';
import { timeout } from 'vs/base/common/async';
import { ExtHostCell, ExtHostNotebookDocument } from 'vs/workbench/api/common/extHostNotebookDocument';
import { CellEditType, IImmediateCellEditOperation, IOutputDto, NotebookCellExecutionState, NullablePartialNotebookCellInternalMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { CancellationTokenSource } from 'vs/base/common/cancellation';
import { asArray } from 'vs/base/common/arrays';
import { URI, UriComponents } from 'vs/base/common/uri';
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { ILogService } from 'vs/platform/log/common/log';
import { ExtHostNotebookKernelsShape, ICellExecuteUpdateDto, IMainContext, INotebookKernelDto2, MainContext, MainThreadNotebookKernelsShape, NotebookOutputDto } from 'vs/workbench/api/common/extHost.protocol';
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook';
import { ExtHostCell, ExtHostNotebookDocument } from 'vs/workbench/api/common/extHostNotebookDocument';
import * as extHostTypeConverters from 'vs/workbench/api/common/extHostTypeConverters';
import { NotebookCellOutput } from 'vs/workbench/api/common/extHostTypes';
import { asWebviewUri } from 'vs/workbench/api/common/shared/webview';
import { CellExecutionUpdateType } from 'vs/workbench/contrib/notebook/common/notebookExecutionService';
import { checkProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions';
import { SerializableObjectWithBuffers } from 'vs/workbench/services/extensions/common/proxyIdentifier';
import * as vscode from 'vscode';
interface IKernelData {
extensionId: ExtensionIdentifier,
@@ -40,12 +41,12 @@ export class ExtHostNotebookKernels implements ExtHostNotebookKernelsShape {
private _handlePool: number = 0;
constructor(
private readonly _mainContext: IMainContext,
mainContext: IMainContext,
private readonly _initData: IExtHostInitDataService,
private readonly _extHostNotebook: ExtHostNotebookController,
@ILogService private readonly _logService: ILogService,
) {
this._proxy = _mainContext.getProxy(MainContext.MainThreadNotebookKernels);
this._proxy = mainContext.getProxy(MainContext.MainThreadNotebookKernels);
}
createNotebookController(extension: IExtensionDescription, id: string, viewType: string, label: string, handler?: (cells: vscode.NotebookCell[], notebook: vscode.NotebookDocument, controller: vscode.NotebookController) => void | Thenable<void>, preloads?: vscode.NotebookRendererScript[]): vscode.NotebookController {
@@ -303,7 +304,7 @@ export class ExtHostNotebookKernels implements ExtHostNotebookKernelsShape {
if (this._activeExecutions.has(cellObj.uri)) {
throw new Error(`duplicate execution for ${cellObj.uri}`);
}
const execution = new NotebookCellExecutionTask(cellObj.notebook, cellObj, this._mainContext.getProxy(MainContext.MainThreadNotebookDocuments));
const execution = new NotebookCellExecutionTask(cellObj.notebook, cellObj, this._proxy);
this._activeExecutions.set(cellObj.uri, execution);
const listener = execution.onDidChangeState(() => {
if (execution.state === NotebookCellExecutionTaskState.Resolved) {
@@ -324,6 +325,9 @@ export enum NotebookCellExecutionTaskState { // {{SQL CARBON EDIT}} Use for our
}
class NotebookCellExecutionTask extends Disposable {
private static HANDLE = 0;
private _handle = NotebookCellExecutionTask.HANDLE++;
private _onDidChangeState = new Emitter<void>();
readonly onDidChangeState = this._onDidChangeState.event;
@@ -332,36 +336,34 @@ class NotebookCellExecutionTask extends Disposable {
private readonly _tokenSource = this._register(new CancellationTokenSource());
private readonly _collector: TimeoutBasedCollector<IImmediateCellEditOperation>;
private readonly _collector: TimeoutBasedCollector<ICellExecuteUpdateDto>;
private _executionOrder: number | undefined;
constructor(
private readonly _document: ExtHostNotebookDocument,
private readonly _cell: ExtHostCell,
private readonly _proxy: MainThreadNotebookDocumentsShape
private readonly _proxy: MainThreadNotebookKernelsShape
) {
super();
this._collector = new TimeoutBasedCollector(10, edits => this.applyEdits(edits));
this._collector = new TimeoutBasedCollector(10, updates => this.update(updates));
this._executionOrder = _cell.internalMetadata.executionOrder;
this.mixinMetadata({
runState: NotebookCellExecutionState.Pending,
executionOrder: null
});
this._proxy.$addExecution(this._handle, this._cell.notebook.uri, this._cell.handle);
}
cancel(): void {
this._tokenSource.cancel();
}
private async applyEditSoon(edit: IImmediateCellEditOperation): Promise<void> {
await this._collector.addItem(edit);
private async updateSoon(update: ICellExecuteUpdateDto): Promise<void> {
await this._collector.addItem(update);
}
private async applyEdits(edits: IImmediateCellEditOperation[]): Promise<void> {
return this._proxy.$applyEdits(this._document.uri, edits, false);
private async update(update: ICellExecuteUpdateDto | ICellExecuteUpdateDto[]): Promise<void> {
const updates = Array.isArray(update) ? update : [update];
return this._proxy.$updateExecutions(new SerializableObjectWithBuffers(updates));
}
private verifyStateForOutput() {
@@ -374,17 +376,9 @@ class NotebookCellExecutionTask extends Disposable {
}
}
private mixinMetadata(mixinMetadata: NullablePartialNotebookCellInternalMetadata) {
const edit: IImmediateCellEditOperation = { editType: CellEditType.PartialInternalMetadata, handle: this._cell.handle, internalMetadata: mixinMetadata };
this.applyEdits([edit]);
}
private cellIndexToHandle(cellOrCellIndex: vscode.NotebookCell | number | undefined): number {
private cellIndexToHandle(cellOrCellIndex: vscode.NotebookCell | undefined): number {
let cell: ExtHostCell | undefined = this._cell;
if (typeof cellOrCellIndex === 'number') {
// todo@jrieken remove support for number shortly
cell = this._document.getCellFromIndex(cellOrCellIndex);
} else if (cellOrCellIndex) {
if (cellOrCellIndex) {
cell = this._document.getCellFromApiCell(cellOrCellIndex);
}
if (!cell) {
@@ -393,7 +387,7 @@ class NotebookCellExecutionTask extends Disposable {
return cell.handle;
}
private validateAndConvertOutputs(items: vscode.NotebookCellOutput[]): IOutputDto[] {
private validateAndConvertOutputs(items: vscode.NotebookCellOutput[]): NotebookOutputDto[] {
return items.map(output => {
const newOutput = NotebookCellOutput.ensureUniqueMimeTypes(output.items, true);
if (newOutput === output.items) {
@@ -407,18 +401,28 @@ class NotebookCellExecutionTask extends Disposable {
});
}
private async updateOutputs(outputs: vscode.NotebookCellOutput | vscode.NotebookCellOutput[], cell: vscode.NotebookCell | number | undefined, append: boolean): Promise<void> {
private async updateOutputs(outputs: vscode.NotebookCellOutput | vscode.NotebookCellOutput[], cell: vscode.NotebookCell | undefined, append: boolean): Promise<void> {
const handle = this.cellIndexToHandle(cell);
const outputDtos = this.validateAndConvertOutputs(asArray(outputs));
return this.applyEditSoon({ editType: CellEditType.Output, handle, append, outputs: outputDtos });
return this.updateSoon(
{
editType: CellExecutionUpdateType.Output,
executionHandle: this._handle,
cellHandle: handle,
append,
outputs: outputDtos
});
}
private async updateOutputItems(items: vscode.NotebookCellOutputItem | vscode.NotebookCellOutputItem[], outputOrOutputId: vscode.NotebookCellOutput | string, append: boolean): Promise<void> {
if (NotebookCellOutput.isNotebookCellOutput(outputOrOutputId)) {
outputOrOutputId = outputOrOutputId.id;
}
private async updateOutputItems(items: vscode.NotebookCellOutputItem | vscode.NotebookCellOutputItem[], output: vscode.NotebookCellOutput, append: boolean): Promise<void> {
items = NotebookCellOutput.ensureUniqueMimeTypes(asArray(items), true);
return this.applyEditSoon({ editType: CellEditType.OutputItems, items: items.map(extHostTypeConverters.NotebookCellOutputItem.from), outputId: outputOrOutputId, append });
return this.updateSoon({
editType: CellExecutionUpdateType.OutputItems,
executionHandle: this._handle,
items: items.map(extHostTypeConverters.NotebookCellOutputItem.from),
outputId: output.id,
append
});
}
asApiObject(): vscode.NotebookCellExecution {
@@ -429,9 +433,11 @@ class NotebookCellExecutionTask extends Disposable {
get executionOrder() { return that._executionOrder; },
set executionOrder(v: number | undefined) {
that._executionOrder = v;
that.mixinMetadata({
executionOrder: v
});
that.update([{
editType: CellExecutionUpdateType.ExecutionState,
executionHandle: that._handle,
executionOrder: that._executionOrder
}]);
},
start(startTime?: number): void {
@@ -442,9 +448,10 @@ class NotebookCellExecutionTask extends Disposable {
that._state = NotebookCellExecutionTaskState.Started;
that._onDidChangeState.fire();
that.mixinMetadata({
runState: NotebookCellExecutionState.Executing,
runStartTime: startTime ?? null
that.update({
editType: CellExecutionUpdateType.ExecutionState,
executionHandle: that._handle,
runStartTime: startTime
});
},
@@ -456,34 +463,41 @@ class NotebookCellExecutionTask extends Disposable {
that._state = NotebookCellExecutionTaskState.Resolved;
that._onDidChangeState.fire();
that.mixinMetadata({
runState: null,
lastRunSuccess: success ?? null,
runEndTime: endTime ?? null,
that.updateSoon({
editType: CellExecutionUpdateType.Complete,
executionHandle: that._handle,
runEndTime: endTime,
lastRunSuccess: success
});
// The last update needs to be ordered correctly and applied immediately,
// so we use updateSoon and immediately flush.
that._collector.flush();
that._proxy.$removeExecution(that._handle);
},
clearOutput(cell?: vscode.NotebookCell | number): Thenable<void> {
clearOutput(cell?: vscode.NotebookCell): Thenable<void> {
that.verifyStateForOutput();
return that.updateOutputs([], cell, false);
},
appendOutput(outputs: vscode.NotebookCellOutput | vscode.NotebookCellOutput[], cell?: vscode.NotebookCell | number): Promise<void> {
appendOutput(outputs: vscode.NotebookCellOutput | vscode.NotebookCellOutput[], cell?: vscode.NotebookCell): Promise<void> {
that.verifyStateForOutput();
return that.updateOutputs(outputs, cell, true);
},
replaceOutput(outputs: vscode.NotebookCellOutput | vscode.NotebookCellOutput[], cell?: vscode.NotebookCell | number): Promise<void> {
replaceOutput(outputs: vscode.NotebookCellOutput | vscode.NotebookCellOutput[], cell?: vscode.NotebookCell): Promise<void> {
that.verifyStateForOutput();
return that.updateOutputs(outputs, cell, false);
},
appendOutputItems(items: vscode.NotebookCellOutputItem | vscode.NotebookCellOutputItem[], output: vscode.NotebookCellOutput | string): Promise<void> {
appendOutputItems(items: vscode.NotebookCellOutputItem | vscode.NotebookCellOutputItem[], output: vscode.NotebookCellOutput): Promise<void> {
that.verifyStateForOutput();
return that.updateOutputItems(items, output, true);
},
replaceOutputItems(items: vscode.NotebookCellOutputItem | vscode.NotebookCellOutputItem[], output: vscode.NotebookCellOutput | string): Promise<void> {
replaceOutputItems(items: vscode.NotebookCellOutputItem | vscode.NotebookCellOutputItem[], output: vscode.NotebookCellOutput): Promise<void> {
that.verifyStateForOutput();
return that.updateOutputItems(items, output, false);
}
@@ -495,22 +509,38 @@ class NotebookCellExecutionTask extends Disposable {
class TimeoutBasedCollector<T> {
private batch: T[] = [];
private waitPromise: Promise<void> | undefined;
private lastFlush = Date.now();
constructor(
private readonly delay: number,
private readonly callback: (items: T[]) => Promise<void>) { }
private readonly callback: (items: T[]) => Promise<void> | void) { }
addItem(item: T): Promise<void> {
this.batch.push(item);
if (!this.waitPromise) {
this.waitPromise = timeout(this.delay).then(() => {
this.waitPromise = undefined;
const batch = this.batch;
this.batch = [];
return this.callback(batch);
return this.flush();
});
}
// This can be called by the extension repeatedly for a long time before the timeout is able to run.
// Force a flush after the delay.
if (Date.now() - this.lastFlush > this.delay) {
this.flush();
}
return this.waitPromise;
}
flush(): void | Promise<void> {
if (this.batch.length === 0) {
return;
}
this.lastFlush = Date.now();
this.waitPromise = undefined;
const batch = this.batch;
this.batch = [];
return this.callback(batch);
}
}

View File

@@ -4,13 +4,15 @@
*--------------------------------------------------------------------------------------------*/
import { Emitter } from 'vs/base/common/event';
import { IExtensionManifest } from 'vs/platform/extensions/common/extensions';
import { ExtHostNotebookRenderersShape, IMainContext, MainContext, MainThreadNotebookRenderersShape } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook';
import { ExtHostNotebookEditor } from 'vs/workbench/api/common/extHostNotebookEditor';
import * as vscode from 'vscode';
export class ExtHostNotebookRenderers implements ExtHostNotebookRenderersShape {
private readonly _rendererMessageEmitters = new Map<string /* rendererId */, Emitter<vscode.NotebookRendererMessage<any>>>();
private readonly _rendererMessageEmitters = new Map<string /* rendererId */, Emitter<{ editor: vscode.NotebookEditor, message: any }>>();
private readonly proxy: MainThreadNotebookRenderersShape;
constructor(mainContext: IMainContext, private readonly _extHostNotebook: ExtHostNotebookController) {
@@ -22,17 +24,35 @@ export class ExtHostNotebookRenderers implements ExtHostNotebookRenderersShape {
this._rendererMessageEmitters.get(rendererId)?.fire({ editor: editor.apiEditor, message });
}
public createRendererMessaging<TSend, TRecv>(rendererId: string): vscode.NotebookRendererMessaging<TSend, TRecv> {
const messaging: vscode.NotebookRendererMessaging<TSend, TRecv> = {
onDidReceiveMessage: (...args) =>
this.getOrCreateEmitterFor(rendererId).event(...args),
postMessage: (editor, message) => {
const extHostEditor = ExtHostNotebookEditor.apiEditorsToExtHost.get(editor);
if (!extHostEditor) {
throw new Error(`The first argument to postMessage() must be a NotebookEditor`);
public createRendererMessaging(manifest: IExtensionManifest, rendererId: string): vscode.NotebookRendererMessaging {
if (!manifest.contributes?.notebookRenderer?.some(r => r.id === rendererId)) {
throw new Error(`Extensions may only call createRendererMessaging() for renderers they contribute (got ${rendererId})`);
}
// In the stable API, the editor is given as an empty object, and this map
// is used to maintain references. This can be removed after editor finalization.
const notebookEditorVisible = !!manifest.enableProposedApi;
const notebookEditorAliases = new WeakMap<{}, vscode.NotebookEditor>();
const messaging: vscode.NotebookRendererMessaging = {
onDidReceiveMessage: (listener, thisArg, disposables) => {
const wrappedListener = notebookEditorVisible ? listener : (evt: { editor: vscode.NotebookEditor, message: any }) => {
const obj = {};
notebookEditorAliases.set(obj, evt.editor);
listener({ editor: obj as vscode.NotebookEditor, message: evt.message });
};
return this.getOrCreateEmitterFor(rendererId).event(wrappedListener, thisArg, disposables);
},
postMessage: (message, editorOrAlias) => {
if (ExtHostNotebookEditor.apiEditorsToExtHost.has(message)) { // back compat for swapped args
[message, editorOrAlias] = [editorOrAlias, message];
}
this.proxy.$postMessage(extHostEditor.id, rendererId, message);
const editor = notebookEditorVisible ? editorOrAlias : notebookEditorAliases.get(editorOrAlias!);
const extHostEditor = editor && ExtHostNotebookEditor.apiEditorsToExtHost.get(editor);
return this.proxy.$postMessage(extHostEditor?.id, rendererId, message);
},
};

View File

@@ -11,6 +11,7 @@ import { Disposable } from 'vs/base/common/lifecycle';
import { VSBuffer } from 'vs/base/common/buffer';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
export abstract class AbstractExtHostOutputChannel extends Disposable implements vscode.OutputChannel {
@@ -23,12 +24,12 @@ export abstract class AbstractExtHostOutputChannel extends Disposable implements
protected readonly _onDidAppend: Emitter<void> = this._register(new Emitter<void>());
readonly onDidAppend: Event<void> = this._onDidAppend.event;
constructor(name: string, log: boolean, file: URI | undefined, proxy: MainThreadOutputServiceShape) {
constructor(name: string, log: boolean, file: URI | undefined, extensionId: string | undefined, proxy: MainThreadOutputServiceShape) {
super();
this._name = name;
this._proxy = proxy;
this._id = proxy.$register(this.name, log, file);
this._id = proxy.$register(this.name, log, file, extensionId);
this._disposed = false;
this._offset = 0;
}
@@ -86,8 +87,8 @@ export abstract class AbstractExtHostOutputChannel extends Disposable implements
export class ExtHostPushOutputChannel extends AbstractExtHostOutputChannel {
constructor(name: string, proxy: MainThreadOutputServiceShape) {
super(name, false, undefined, proxy);
constructor(name: string, extensionId: string, proxy: MainThreadOutputServiceShape) {
super(name, false, undefined, extensionId, proxy);
}
override append(value: string): void {
@@ -100,7 +101,7 @@ export class ExtHostPushOutputChannel extends AbstractExtHostOutputChannel {
class ExtHostLogFileOutputChannel extends AbstractExtHostOutputChannel {
constructor(name: string, file: URI, proxy: MainThreadOutputServiceShape) {
super(name, true, file, proxy);
super(name, true, file, undefined, proxy);
}
override append(value: string): void {
@@ -148,12 +149,12 @@ export class ExtHostOutputService implements ExtHostOutputServiceShape {
$setVisibleChannel(channelId: string): void {
}
createOutputChannel(name: string): vscode.OutputChannel {
createOutputChannel(name: string, extension: IExtensionDescription): vscode.OutputChannel {
name = name.trim();
if (!name) {
throw new Error('illegal argument `name`. must not be falsy');
}
return new ExtHostPushOutputChannel(name, this._proxy);
return new ExtHostPushOutputChannel(name, extension.identifier.value, this._proxy);
}
createOutputChannelFromLogFile(name: string, file: URI): vscode.OutputChannel {

View File

@@ -9,7 +9,7 @@ import { Emitter } from 'vs/base/common/event';
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
import { IExtHostWorkspaceProvider } from 'vs/workbench/api/common/extHostWorkspace';
import { InputBox, InputBoxOptions, QuickInput, QuickInputButton, QuickPick, QuickPickItem, QuickPickOptions, WorkspaceFolder, WorkspaceFolderPickOptions } from 'vscode';
import { InputBox, InputBoxOptions, QuickInput, QuickInputButton, QuickPick, QuickPickItem, QuickPickItemButtonEvent, QuickPickOptions, WorkspaceFolder, WorkspaceFolderPickOptions } from 'vscode';
import { ExtHostQuickOpenShape, IMainContext, MainContext, TransferQuickPickItems, TransferQuickInput, TransferQuickInputButton } from './extHost.protocol';
import { URI } from 'vs/base/common/uri';
import { ThemeIcon, QuickInputButtons } from 'vs/workbench/api/common/extHostTypes';
@@ -17,6 +17,7 @@ import { isPromiseCanceledError } from 'vs/base/common/errors';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { coalesce } from 'vs/base/common/arrays';
import Severity from 'vs/base/common/severity';
import { ThemeIcon as ThemeIconUtils } from 'vs/platform/theme/common/themeService';
export type Item = string | QuickPickItem;
@@ -238,6 +239,13 @@ export function createExtHostQuickOpen(mainContext: IMainContext, workspace: IEx
}
}
$onDidTriggerItemButton(sessionId: number, itemHandle: number, buttonHandle: number): void {
const session = this._sessions.get(sessionId);
if (session instanceof ExtHostQuickPick) {
session._fireDidTriggerItemButton(itemHandle, buttonHandle);
}
}
$onDidHide(sessionId: number): void {
const session = this._sessions.get(sessionId);
if (session) {
@@ -369,11 +377,13 @@ export function createExtHostQuickOpen(mainContext: IMainContext, workspace: IEx
this._handlesToButtons.set(handle, button);
});
this.update({
buttons: buttons.map<TransferQuickInputButton>((button, i) => ({
iconPath: getIconUris(button.iconPath),
tooltip: button.tooltip,
handle: button === QuickInputButtons.Back ? -1 : i,
}))
buttons: buttons.map<TransferQuickInputButton>((button, i) => {
return {
...getIconPathOrClass(button),
tooltip: button.tooltip,
handle: button === QuickInputButtons.Back ? -1 : i,
};
})
});
}
@@ -481,6 +491,22 @@ export function createExtHostQuickOpen(mainContext: IMainContext, workspace: IEx
return typeof iconPath === 'object' && 'dark' in iconPath ? iconPath.dark : iconPath;
}
function getIconPathOrClass(button: QuickInputButton) {
const iconPathOrIconClass = getIconUris(button.iconPath);
let iconPath: { dark: URI; light?: URI | undefined; } | undefined;
let iconClass: string | undefined;
if ('id' in iconPathOrIconClass) {
iconClass = ThemeIconUtils.asClassName(iconPathOrIconClass);
} else {
iconPath = iconPathOrIconClass;
}
return {
iconPath,
iconClass
};
}
class ExtHostQuickPick<T extends QuickPickItem> extends ExtHostQuickInput implements QuickPick<T> {
private _items: T[] = [];
@@ -494,12 +520,14 @@ export function createExtHostQuickOpen(mainContext: IMainContext, workspace: IEx
private readonly _onDidChangeActiveEmitter = new Emitter<T[]>();
private _selectedItems: T[] = [];
private readonly _onDidChangeSelectionEmitter = new Emitter<T[]>();
private readonly _onDidTriggerItemButtonEmitter = new Emitter<QuickPickItemButtonEvent<T>>();
constructor(extensionId: ExtensionIdentifier, enableProposedApi: boolean, onDispose: () => void) {
constructor(extensionId: ExtensionIdentifier, private readonly enableProposedApi: boolean, onDispose: () => void) {
super(extensionId, onDispose);
this._disposables.push(
this._onDidChangeActiveEmitter,
this._onDidChangeSelectionEmitter,
this._onDidTriggerItemButtonEmitter
);
this.update({ type: 'quickPick' });
}
@@ -523,7 +551,17 @@ export function createExtHostQuickOpen(mainContext: IMainContext, workspace: IEx
handle: i,
detail: item.detail,
picked: item.picked,
alwaysShow: item.alwaysShow
alwaysShow: item.alwaysShow,
// Proposed API only at the moment
buttons: item.buttons && this.enableProposedApi
? item.buttons.map<TransferQuickInputButton>((button, i) => {
return {
...getIconPathOrClass(button),
tooltip: button.tooltip,
handle: i
};
})
: undefined,
}))
});
}
@@ -597,6 +635,22 @@ export function createExtHostQuickOpen(mainContext: IMainContext, workspace: IEx
this._selectedItems = items;
this._onDidChangeSelectionEmitter.fire(items);
}
onDidTriggerItemButton = this._onDidTriggerItemButtonEmitter.event;
_fireDidTriggerItemButton(itemHandle: number, buttonHandle: number) {
const item = this._handlesToItems.get(itemHandle)!;
if (!item || !item.buttons || !item.buttons.length) {
return;
}
const button = item.buttons[buttonHandle];
if (button) {
this._onDidTriggerItemButtonEmitter.fire({
button,
item
});
}
}
}
class ExtHostInputBox extends ExtHostQuickInput implements InputBox {

View File

@@ -18,18 +18,26 @@ import { ILogService } from 'vs/platform/log/common/log';
import { CancellationToken } from 'vs/base/common/cancellation';
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { checkProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions';
import { MarshalledId } from 'vs/base/common/marshalling';
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
import { IMarkdownString } from 'vs/base/common/htmlContent';
import { MarkdownString } from 'vs/workbench/api/common/extHostTypeConverters';
type ProviderHandle = number;
type GroupHandle = number;
type ResourceStateHandle = number;
function getIconResource(decorations?: vscode.SourceControlResourceThemableDecorations): vscode.Uri | undefined {
function getIconResource(decorations?: vscode.SourceControlResourceThemableDecorations): UriComponents | ThemeIcon | undefined {
if (!decorations) {
return undefined;
} else if (typeof decorations.iconPath === 'string') {
return URI.file(decorations.iconPath);
} else {
} else if (URI.isUri(decorations.iconPath)) {
return decorations.iconPath;
} else if (ThemeIcon.isThemeIcon(decorations.iconPath)) {
return decorations.iconPath;
} else {
return undefined;
}
}
@@ -42,8 +50,8 @@ function compareResourceThemableDecorations(a: vscode.SourceControlResourceThema
return 1;
}
const aPath = typeof a.iconPath === 'string' ? a.iconPath : a.iconPath.fsPath;
const bPath = typeof b.iconPath === 'string' ? b.iconPath : b.iconPath.fsPath;
const aPath = typeof a.iconPath === 'string' ? a.iconPath : URI.isUri(a.iconPath) ? a.iconPath.fsPath : (a.iconPath as vscode.ThemeIcon).id;
const bPath = typeof b.iconPath === 'string' ? b.iconPath : URI.isUri(b.iconPath) ? b.iconPath.fsPath : (b.iconPath as vscode.ThemeIcon).id;
return comparePaths(aPath, bPath);
}
@@ -269,7 +277,7 @@ export class ExtHostSCMInputBox implements vscode.SourceControlInputBox {
this._proxy.$setInputBoxFocus(this._sourceControlHandle);
}
showValidationMessage(message: string, type: vscode.SourceControlInputBoxValidationType) {
showValidationMessage(message: string | vscode.MarkdownString, type: vscode.SourceControlInputBoxValidationType) {
checkProposedApiEnabled(this._extension);
this._proxy.$showValidationMessage(this._sourceControlHandle, message, type as any);
@@ -367,12 +375,8 @@ class ExtHostSourceControlResourceGroup implements vscode.SourceControlResourceG
this._resourceStatesMap.set(handle, r);
const sourceUri = r.resourceUri;
const iconUri = getIconResource(r.decorations);
const lightIconUri = r.decorations && getIconResource(r.decorations.light) || iconUri;
const darkIconUri = r.decorations && getIconResource(r.decorations.dark) || iconUri;
const icons: UriComponents[] = [];
let command: ICommandDto | undefined;
let command: ICommandDto | undefined;
if (r.command) {
if (r.command.command === 'vscode.open' || r.command.command === 'vscode.diff') {
const disposables = new DisposableStore();
@@ -383,13 +387,10 @@ class ExtHostSourceControlResourceGroup implements vscode.SourceControlResourceG
}
}
if (lightIconUri) {
icons.push(lightIconUri);
}
if (darkIconUri && (darkIconUri.toString() !== lightIconUri?.toString())) {
icons.push(darkIconUri);
}
const icon = getIconResource(r.decorations);
const lightIcon = r.decorations && getIconResource(r.decorations.light) || icon;
const darkIcon = r.decorations && getIconResource(r.decorations.dark) || icon;
const icons: SCMRawResource[2] = [lightIcon, darkIcon];
const tooltip = (r.decorations && r.decorations.tooltip) || '';
const strikeThrough = r.decorations && !!r.decorations.strikeThrough;
@@ -660,7 +661,7 @@ export class ExtHostSCM implements ExtHostSCMShape {
_commands.registerArgumentProcessor({
processArgument: arg => {
if (arg && arg.$mid === 3) {
if (arg && arg.$mid === MarshalledId.ScmResource) {
const sourceControl = this._sourceControls.get(arg.sourceControlHandle);
if (!sourceControl) {
@@ -674,7 +675,7 @@ export class ExtHostSCM implements ExtHostSCMShape {
}
return group.getResourceState(arg.handle);
} else if (arg && arg.$mid === 4) {
} else if (arg && arg.$mid === MarshalledId.ScmResourceGroup) {
const sourceControl = this._sourceControls.get(arg.sourceControlHandle);
if (!sourceControl) {
@@ -682,7 +683,7 @@ export class ExtHostSCM implements ExtHostSCMShape {
}
return sourceControl.getResourceGroup(arg.groupHandle);
} else if (arg && arg.$mid === 5) {
} else if (arg && arg.$mid === MarshalledId.ScmProvider) {
const sourceControl = this._sourceControls.get(arg.handle);
if (!sourceControl) {
@@ -771,7 +772,7 @@ export class ExtHostSCM implements ExtHostSCMShape {
return group.$executeResourceCommand(handle, preserveFocus);
}
$validateInput(sourceControlHandle: number, value: string, cursorPosition: number): Promise<[string, number] | undefined> {
$validateInput(sourceControlHandle: number, value: string, cursorPosition: number): Promise<[string | IMarkdownString, number] | undefined> {
this.logService.trace('ExtHostSCM#$validateInput', sourceControlHandle);
const sourceControl = this._sourceControls.get(sourceControlHandle);
@@ -789,7 +790,12 @@ export class ExtHostSCM implements ExtHostSCMShape {
return Promise.resolve(undefined);
}
return Promise.resolve<[string, number]>([result.message, result.type]);
const message = MarkdownString.fromStrict(result.message);
if (!message) {
return Promise.resolve(undefined);
}
return Promise.resolve<[string | IMarkdownString, number]>([message, result.type]);
});
}

View File

@@ -105,11 +105,13 @@ export class ExtHostSearch implements ExtHostSearchShape {
return engine.search(progress => this._proxy.$handleTextMatch(handle, session, progress), token);
}
$enableExtensionHostSearch(): void { }
protected createTextSearchManager(query: ITextQuery, provider: vscode.TextSearchProvider): TextSearchManager {
return new TextSearchManager(query, provider, {
readdir: resource => Promise.resolve([]), // TODO@rob implement
toCanonicalName: encoding => encoding
});
}, 'textSearchProvider');
}
}

View File

@@ -11,13 +11,17 @@ import { localize } from 'vs/nls';
import { CommandsConverter } from 'vs/workbench/api/common/extHostCommands';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { MarkdownString } from 'vs/workbench/api/common/extHostTypeConverters';
export class ExtHostStatusBarEntry implements vscode.StatusBarItem {
private static ID_GEN = 0;
private static ALLOWED_BACKGROUND_COLORS = new Map<string, ThemeColor>(
[['statusBarItem.errorBackground', new ThemeColor('statusBarItem.errorForeground')]]
[
['statusBarItem.errorBackground', new ThemeColor('statusBarItem.errorForeground')],
['statusBarItem.warningBackground', new ThemeColor('statusBarItem.warningForeground')]
]
);
#proxy: MainThreadStatusBarShape;
@@ -35,7 +39,7 @@ export class ExtHostStatusBarEntry implements vscode.StatusBarItem {
private _visible: boolean = false;
private _text: string = '';
private _tooltip?: string;
private _tooltip?: string | vscode.MarkdownString;
private _name?: string;
private _color?: string | ThemeColor;
private _backgroundColor?: ThemeColor;
@@ -83,10 +87,6 @@ export class ExtHostStatusBarEntry implements vscode.StatusBarItem {
return this._name;
}
public get tooltip(): string | undefined {
return this._tooltip;
}
public get color(): string | ThemeColor | undefined {
return this._color;
}
@@ -209,8 +209,10 @@ export class ExtHostStatusBarEntry implements vscode.StatusBarItem {
color = ExtHostStatusBarEntry.ALLOWED_BACKGROUND_COLORS.get(this._backgroundColor.id);
}
const tooltip = this._tooltip ? MarkdownString.fromStrict(this._tooltip) : undefined;
// Set to status bar
this.#proxy.$setEntry(this._entryId, id, name, this._text, this._tooltip, this._command?.internal, color,
this.#proxy.$setEntry(this._entryId, id, name, this._text, tooltip, this._command?.internal, color,
this._backgroundColor, this._alignment === ExtHostStatusBarAlignment.Left ? MainThreadStatusBarAlignment.LEFT : MainThreadStatusBarAlignment.RIGHT,
this._priority, this._accessibilityInformation);
}, 0);

View File

@@ -18,6 +18,7 @@ export interface IExtensionStoragePaths {
whenReady: Promise<any>;
workspaceValue(extension: IExtensionDescription): URI | undefined;
globalValue(extension: IExtensionDescription): URI;
onWillDeactivateAll(): void;
}
export class ExtensionStoragePaths implements IExtensionStoragePaths {
@@ -25,14 +26,14 @@ export class ExtensionStoragePaths implements IExtensionStoragePaths {
readonly _serviceBrand: undefined;
private readonly _workspace?: IStaticWorkspaceData;
private readonly _environment: IEnvironment;
protected readonly _environment: IEnvironment;
readonly whenReady: Promise<URI | undefined>;
private _value?: URI;
constructor(
@IExtHostInitDataService initData: IExtHostInitDataService,
@ILogService private readonly _logService: ILogService,
@ILogService protected readonly _logService: ILogService,
@IExtHostConsumerFileSystem private readonly _extHostFileSystem: IExtHostConsumerFileSystem
) {
this._workspace = initData.workspace ?? undefined;
@@ -40,12 +41,16 @@ export class ExtensionStoragePaths implements IExtensionStoragePaths {
this.whenReady = this._getOrCreateWorkspaceStoragePath().then(value => this._value = value);
}
protected async _getWorkspaceStorageURI(storageName: string): Promise<URI> {
return URI.joinPath(this._environment.workspaceStorageHome, storageName);
}
private async _getOrCreateWorkspaceStoragePath(): Promise<URI | undefined> {
if (!this._workspace) {
return Promise.resolve(undefined);
}
const storageName = this._workspace.id;
const storageUri = URI.joinPath(this._environment.workspaceStorageHome, storageName);
const storageUri = await this._getWorkspaceStorageURI(storageName);
try {
await this._extHostFileSystem.value.stat(storageUri);
@@ -84,4 +89,7 @@ export class ExtensionStoragePaths implements IExtensionStoragePaths {
globalValue(extension: IExtensionDescription): URI {
return URI.joinPath(this._environment.globalStorageHome, extension.identifier.value.toLowerCase());
}
onWillDeactivateAll(): void {
}
}

View File

@@ -8,7 +8,7 @@ import { asPromise } from 'vs/base/common/async';
import { Event, Emitter } from 'vs/base/common/event';
import { MainContext, MainThreadTaskShape, ExtHostTaskShape } from 'vs/workbench/api/common/extHost.protocol';
import * as Objects from 'vs/base/common/objects';
import * as types from 'vs/workbench/api/common/extHostTypes';
import { IExtHostWorkspaceProvider, IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
import type * as vscode from 'vscode';
@@ -213,6 +213,14 @@ export namespace TaskHandleDTO {
};
}
}
export namespace TaskGroupDTO {
export function from(value: vscode.TaskGroup): tasks.TaskGroupDTO | undefined {
if (value === undefined || value === null) {
return undefined;
}
return { _id: value.id, isDefault: value.isDefault };
}
}
export namespace TaskDTO {
export function fromMany(tasks: vscode.Task[], extension: IExtensionDescription): tasks.TaskDTO[] {
@@ -257,7 +265,6 @@ export namespace TaskDTO {
if (!definition || !scope) {
return undefined;
}
const group = (value.group as types.TaskGroup) ? (value.group as types.TaskGroup).id : undefined;
const result: tasks.TaskDTO = {
_id: (value as types.Task)._id!,
definition,
@@ -269,7 +276,7 @@ export namespace TaskDTO {
},
execution: execution!,
isBackground: value.isBackground,
group: group,
group: TaskGroupDTO.from(value.group as vscode.TaskGroup),
presentationOptions: TaskPresentationOptionsDTO.from(value.presentationOptions),
problemMatchers: value.problemMatchers,
hasDefinedMatchers: (value as types.Task).hasDefinedMatchers,
@@ -311,7 +318,13 @@ export namespace TaskDTO {
result.isBackground = value.isBackground;
}
if (value.group !== undefined) {
result.group = types.TaskGroup.from(value.group);
result.group = types.TaskGroup.from(value.group._id);
if (result.group) {
result.group = Objects.deepClone(result.group);
if (value.group.isDefault) {
result.group.isDefault = value.group.isDefault;
}
}
}
if (value.presentationOptions) {
result.presentationOptions = TaskPresentationOptionsDTO.to(value.presentationOptions)!;

View File

@@ -5,12 +5,12 @@
import type * as vscode from 'vscode';
import { Event, Emitter } from 'vs/base/common/event';
import { ExtHostTerminalServiceShape, MainContext, MainThreadTerminalServiceShape, ITerminalDimensionsDto, ITerminalLinkDto, TerminalIdentifier } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostTerminalServiceShape, MainContext, MainThreadTerminalServiceShape, ITerminalDimensionsDto, ITerminalLinkDto, ExtHostTerminalIdentifier } from 'vs/workbench/api/common/extHost.protocol';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { URI } from 'vs/base/common/uri';
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
import { IDisposable, DisposableStore, Disposable } from 'vs/base/common/lifecycle';
import { Disposable as VSCodeDisposable, EnvironmentVariableMutatorType, ThemeColor } from './extHostTypes';
import { Disposable as VSCodeDisposable, EnvironmentVariableMutatorType } from './extHostTypes';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { localize } from 'vs/nls';
import { NotSupportedError } from 'vs/base/common/errors';
@@ -18,9 +18,9 @@ import { serializeEnvironmentVariableCollection } from 'vs/workbench/contrib/ter
import { CancellationTokenSource } from 'vs/base/common/cancellation';
import { generateUuid } from 'vs/base/common/uuid';
import { ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { IProcessReadyEvent, IShellLaunchConfigDto, ITerminalChildProcess, ITerminalDimensionsOverride, ITerminalLaunchError, ITerminalProfile, TerminalIcon, TerminalShellType } from 'vs/platform/terminal/common/terminal';
import { ICreateContributedTerminalProfileOptions, IProcessReadyEvent, IShellLaunchConfigDto, ITerminalChildProcess, ITerminalDimensionsOverride, ITerminalLaunchError, ITerminalProfile, TerminalIcon, TerminalLocation, TerminalShellType } from 'vs/platform/terminal/common/terminal';
import { TerminalDataBufferer } from 'vs/platform/terminal/common/terminalDataBuffering';
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
import { ThemeColor } from 'vs/platform/theme/common/themeService';
import { withNullAsUndefined } from 'vs/base/common/types';
export interface IExtHostTerminalService extends ExtHostTerminalServiceShape, IDisposable {
@@ -34,6 +34,7 @@ export interface IExtHostTerminalService extends ExtHostTerminalServiceShape, ID
onDidOpenTerminal: Event<vscode.Terminal>;
onDidChangeActiveTerminal: Event<vscode.Terminal | undefined>;
onDidChangeTerminalDimensions: Event<vscode.TerminalDimensionsChangeEvent>;
onDidChangeTerminalState: Event<vscode.Terminal>;
onDidWriteTerminalData: Event<vscode.TerminalDataWriteEvent>;
createTerminal(name?: string, shellPath?: string, shellArgs?: string[] | string): vscode.Terminal;
@@ -43,14 +44,15 @@ export interface IExtHostTerminalService extends ExtHostTerminalServiceShape, ID
getDefaultShell(useAutomationShell: boolean): string;
getDefaultShellArgs(useAutomationShell: boolean): string[] | string;
registerLinkProvider(provider: vscode.TerminalLinkProvider): vscode.Disposable;
registerProfileProvider(id: string, provider: vscode.TerminalProfileProvider): vscode.Disposable;
registerProfileProvider(extension: IExtensionDescription, id: string, provider: vscode.TerminalProfileProvider): vscode.Disposable;
getEnvironmentVariableCollection(extension: IExtensionDescription, persistent?: boolean): vscode.EnvironmentVariableCollection;
}
export interface ITerminalInternalOptions {
isFeatureTerminal?: boolean;
useShellEnvironment?: boolean;
isSplitTerminal?: boolean;
resolvedExtHostIdentifier?: ExtHostTerminalIdentifier;
splitActiveTerminal?: boolean;
}
export const IExtHostTerminalService = createDecorator<IExtHostTerminalService>('IExtHostTerminalService');
@@ -62,6 +64,7 @@ export class ExtHostTerminal {
private _pidPromiseComplete: ((value: number | undefined) => any) | undefined;
private _rows: number | undefined;
private _exitStatus: vscode.TerminalExitStatus | undefined;
private _state: vscode.TerminalState = { interactedWith: false };
public isOpen: boolean = false;
@@ -69,7 +72,7 @@ export class ExtHostTerminal {
constructor(
private _proxy: MainThreadTerminalServiceShape,
public _id: TerminalIdentifier,
public _id: ExtHostTerminalIdentifier,
private readonly _creationOptions: vscode.TerminalOptions | vscode.ExtensionTerminalOptions,
private _name?: string,
) {
@@ -90,6 +93,9 @@ export class ExtHostTerminal {
get exitStatus(): vscode.TerminalExitStatus | undefined {
return that._exitStatus;
},
get state(): vscode.TerminalState {
return that._state;
},
sendText(text: string, addNewLine: boolean = true): void {
that._checkDisposed();
that._proxy.$sendText(that._id, text, addNewLine);
@@ -134,17 +140,19 @@ export class ExtHostTerminal {
cwd: withNullAsUndefined(options.cwd),
env: withNullAsUndefined(options.env),
icon: withNullAsUndefined(asTerminalIcon(options.iconPath)),
color: ThemeColor.isThemeColor(options.color) ? options.color.id : undefined,
initialText: withNullAsUndefined(options.message),
strictEnv: withNullAsUndefined(options.strictEnv),
hideFromUser: withNullAsUndefined(options.hideFromUser),
isFeatureTerminal: withNullAsUndefined(internalOptions?.isFeatureTerminal),
isExtensionOwnedTerminal: true,
useShellEnvironment: withNullAsUndefined(internalOptions?.useShellEnvironment),
isSplitTerminal: withNullAsUndefined(internalOptions?.isSplitTerminal)
location: this._serializeParentTerminal(options.location, internalOptions?.resolvedExtHostIdentifier, internalOptions?.splitActiveTerminal)
});
}
public async createExtensionTerminal(isSplitTerminal?: boolean, iconPath?: URI | { light: URI; dark: URI } | ThemeIcon): Promise<number> {
public async createExtensionTerminal(location?: TerminalLocation | vscode.TerminalEditorLocationOptions | vscode.TerminalSplitLocationOptions, parentTerminal?: ExtHostTerminalIdentifier, iconPath?: TerminalIcon, color?: ThemeColor): Promise<number> {
if (typeof this._id !== 'string') {
throw new Error('Terminal has already been created');
}
@@ -152,7 +160,8 @@ export class ExtHostTerminal {
name: this._name,
isExtensionCustomPtyTerminal: true,
icon: iconPath,
isSplitTerminal
color: ThemeColor.isThemeColor(color) ? color.id : undefined,
location: this._serializeParentTerminal(location, parentTerminal)
});
// At this point, the id has been set via `$acceptTerminalOpened`
if (typeof this._id === 'string') {
@@ -161,6 +170,15 @@ export class ExtHostTerminal {
return this._id;
}
private _serializeParentTerminal(location?: TerminalLocation | vscode.TerminalEditorLocationOptions | vscode.TerminalSplitLocationOptions, parentTerminal?: ExtHostTerminalIdentifier, splitActiveTerminal?: boolean): TerminalLocation | vscode.TerminalEditorLocationOptions | { parentTerminal: ExtHostTerminalIdentifier } | { splitActiveTerminal: boolean } | undefined {
if (typeof location === 'object' && 'parentTerminal' in location) {
return parentTerminal ? { parentTerminal } : undefined;
} else if (splitActiveTerminal) {
return { splitActiveTerminal: true };
}
return location;
}
private _checkDisposed() {
if (this._disposed) {
throw new Error('Terminal has already been disposed');
@@ -188,6 +206,14 @@ export class ExtHostTerminal {
return true;
}
public setInteractedWith(): boolean {
if (!this._state.interactedWith) {
this._state = { interactedWith: true };
return true;
}
return false;
}
public _setProcessId(processId: number | undefined): void {
// The event may fire 2 times when the panel is restored
if (this._pidPromiseComplete) {
@@ -245,7 +271,7 @@ export class ExtHostPseudoterminal implements ITerminalChildProcess {
}
async processBinary(data: string): Promise<void> {
// No-op, processBinary is not supported in extextion owned terminals.
// No-op, processBinary is not supported in extension owned terminals.
}
acknowledgeDataEvent(charCount: number): void {
@@ -253,6 +279,10 @@ export class ExtHostPseudoterminal implements ITerminalChildProcess {
// implemented it will need new pause and resume VS Code APIs.
}
async setUnicodeVersion(version: '6' | '11'): Promise<void> {
// No-op, xterm-headless isn't used for extension owned terminals.
}
getInitialCwd(): Promise<string> {
return Promise.resolve('');
}
@@ -321,16 +351,18 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I
public get activeTerminal(): vscode.Terminal | undefined { return this._activeTerminal?.value; }
public get terminals(): vscode.Terminal[] { return this._terminals.map(term => term.value); }
protected readonly _onDidCloseTerminal: Emitter<vscode.Terminal> = new Emitter<vscode.Terminal>();
public get onDidCloseTerminal(): Event<vscode.Terminal> { return this._onDidCloseTerminal && this._onDidCloseTerminal.event; }
protected readonly _onDidOpenTerminal: Emitter<vscode.Terminal> = new Emitter<vscode.Terminal>();
public get onDidOpenTerminal(): Event<vscode.Terminal> { return this._onDidOpenTerminal && this._onDidOpenTerminal.event; }
protected readonly _onDidChangeActiveTerminal: Emitter<vscode.Terminal | undefined> = new Emitter<vscode.Terminal | undefined>();
public get onDidChangeActiveTerminal(): Event<vscode.Terminal | undefined> { return this._onDidChangeActiveTerminal && this._onDidChangeActiveTerminal.event; }
protected readonly _onDidChangeTerminalDimensions: Emitter<vscode.TerminalDimensionsChangeEvent> = new Emitter<vscode.TerminalDimensionsChangeEvent>();
public get onDidChangeTerminalDimensions(): Event<vscode.TerminalDimensionsChangeEvent> { return this._onDidChangeTerminalDimensions && this._onDidChangeTerminalDimensions.event; }
protected readonly _onDidCloseTerminal = new Emitter<vscode.Terminal>();
readonly onDidCloseTerminal = this._onDidCloseTerminal.event;
protected readonly _onDidOpenTerminal = new Emitter<vscode.Terminal>();
readonly onDidOpenTerminal = this._onDidOpenTerminal.event;
protected readonly _onDidChangeActiveTerminal = new Emitter<vscode.Terminal | undefined>();
readonly onDidChangeActiveTerminal = this._onDidChangeActiveTerminal.event;
protected readonly _onDidChangeTerminalDimensions = new Emitter<vscode.TerminalDimensionsChangeEvent>();
readonly onDidChangeTerminalDimensions = this._onDidChangeTerminalDimensions.event;
protected readonly _onDidChangeTerminalState = new Emitter<vscode.Terminal>();
readonly onDidChangeTerminalState = this._onDidChangeTerminalState.event;
protected readonly _onDidWriteTerminalData: Emitter<vscode.TerminalDataWriteEvent>;
public get onDidWriteTerminalData(): Event<vscode.TerminalDataWriteEvent> { return this._onDidWriteTerminalData && this._onDidWriteTerminalData.event; }
get onDidWriteTerminalData(): Event<vscode.TerminalDataWriteEvent> { return this._onDidWriteTerminalData.event; }
constructor(
supportsProcesses: boolean,
@@ -369,7 +401,7 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I
public createExtensionTerminal(options: vscode.ExtensionTerminalOptions, internalOptions?: ITerminalInternalOptions): vscode.Terminal {
const terminal = new ExtHostTerminal(this._proxy, generateUuid(), options, options.name);
const p = new ExtHostPseudoterminal(options.pty);
terminal.createExtensionTerminal(internalOptions?.isSplitTerminal, asTerminalIcon(options.iconPath)).then(id => {
terminal.createExtensionTerminal(this._resolveLocation(options.location), internalOptions?.resolvedExtHostIdentifier, asTerminalIcon(options.iconPath), asTerminalColor(options.color)).then(id => {
const disposable = this._setupExtHostProcessListeners(id, p);
this._terminalProcessDisposables[id] = disposable;
});
@@ -377,6 +409,13 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I
return terminal.value;
}
private _resolveLocation(location?: TerminalLocation | vscode.TerminalEditorLocationOptions | vscode.TerminalSplitLocationOptions): undefined | TerminalLocation | vscode.TerminalEditorLocationOptions {
if (typeof location === 'object' && 'parentTerminal' in location) {
return undefined;
}
return location;
}
public attachPtyToTerminal(id: number, pty: vscode.Pseudoterminal): void {
const terminal = this._getTerminalById(id);
if (!terminal) {
@@ -392,7 +431,7 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I
if (id === null) {
this._activeTerminal = undefined;
if (original !== this._activeTerminal) {
this._onDidChangeActiveTerminal.fire(this._activeTerminal?.value); // {{SQL CARBON EDIT}}
this._onDidChangeActiveTerminal.fire(this._activeTerminal.value);
}
return;
}
@@ -544,6 +583,13 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I
this._terminalProcesses.get(id)?.input(data);
}
public $acceptTerminalInteraction(id: number): void {
const terminal = this._getTerminalById(id);
if (terminal?.setInteractedWith()) {
this._onDidChangeTerminalState.fire(terminal.value);
}
}
public $acceptProcessResize(id: number, cols: number, rows: number): void {
try {
this._terminalProcesses.get(id)?.resize(cols, rows);
@@ -584,32 +630,33 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I
});
}
public registerProfileProvider(id: string, provider: vscode.TerminalProfileProvider): vscode.Disposable {
public registerProfileProvider(extension: IExtensionDescription, id: string, provider: vscode.TerminalProfileProvider): vscode.Disposable {
if (this._profileProviders.has(id)) {
throw new Error(`Terminal profile provider "${id}" already registered`);
}
this._profileProviders.set(id, provider);
this._proxy.$registerProfileProvider(id);
this._proxy.$registerProfileProvider(id, extension.identifier.value);
return new VSCodeDisposable(() => {
this._profileProviders.delete(id);
this._proxy.$unregisterProfileProvider(id);
});
}
public async $createContributedProfileTerminal(id: string, isSplitTerminal: boolean): Promise<void> {
public async $createContributedProfileTerminal(id: string, options: ICreateContributedTerminalProfileOptions): Promise<void> {
const token = new CancellationTokenSource().token;
const options = await this._profileProviders.get(id)?.provideProfileOptions(token);
const profile = await this._profileProviders.get(id)?.provideTerminalProfile(token);
if (token.isCancellationRequested) {
return;
}
if (!options) {
if (!profile || !('options' in profile)) {
throw new Error(`No terminal profile options provided for id "${id}"`);
}
if ('pty' in options) {
this.createExtensionTerminal(options, { isSplitTerminal });
if ('pty' in profile.options) {
this.createExtensionTerminal(profile.options, options);
return;
}
this.createTerminalFromOptions(options, { isSplitTerminal });
this.createTerminalFromOptions(profile.options, options);
}
public async $provideLinks(terminalId: number, line: string): Promise<ITerminalLinkDto[]> {
@@ -708,7 +755,7 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I
return index !== null ? array[index] : null;
}
private _getTerminalObjectIndexById<T extends ExtHostTerminal>(array: T[], id: TerminalIdentifier): number | null {
private _getTerminalObjectIndexById<T extends ExtHostTerminal>(array: T[], id: ExtHostTerminalIdentifier): number | null {
let index: number | null = null;
array.some((item, i) => {
const thisId = item._id;
@@ -839,14 +886,20 @@ export class WorkerExtHostTerminalService extends BaseExtHostTerminalService {
}
function asTerminalIcon(iconPath?: vscode.Uri | { light: vscode.Uri; dark: vscode.Uri } | vscode.ThemeIcon): TerminalIcon | undefined {
if (!iconPath) {
if (!iconPath || typeof iconPath === 'string') {
return undefined;
}
if (!('id' in iconPath)) {
return iconPath;
}
return {
id: iconPath.id,
color: iconPath.color as ThemeColor
};
}
function asTerminalColor(color?: vscode.ThemeColor): ThemeColor | undefined {
return ThemeColor.isThemeColor(color) ? color as ThemeColor : undefined;
}

File diff suppressed because it is too large Load Diff

View File

@@ -3,42 +3,320 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Emitter } from 'vs/base/common/event';
import { TestItemImpl } from 'vs/workbench/api/common/extHostTypes';
import { TestIdPathParts } from 'vs/workbench/contrib/testing/common/testId';
import * as vscode from 'vscode';
export const enum ExtHostTestItemEventType {
NewChild,
Disposed,
export const enum ExtHostTestItemEventOp {
Upsert,
RemoveChild,
Invalidated,
SetProp,
Bulk,
}
export interface ITestItemUpsertChild {
op: ExtHostTestItemEventOp.Upsert;
item: TestItemImpl;
}
export interface ITestItemRemoveChild {
op: ExtHostTestItemEventOp.RemoveChild;
id: string;
}
export interface ITestItemInvalidated {
op: ExtHostTestItemEventOp.Invalidated;
}
export interface ITestItemSetProp {
op: ExtHostTestItemEventOp.SetProp;
key: keyof vscode.TestItem;
value: any;
previous: any;
}
export interface ITestItemBulkReplace {
op: ExtHostTestItemEventOp.Bulk;
ops: (ITestItemUpsertChild | ITestItemRemoveChild)[];
}
export type ExtHostTestItemEvent =
| [evt: ExtHostTestItemEventType.NewChild, item: TestItemImpl]
| [evt: ExtHostTestItemEventType.Disposed]
| [evt: ExtHostTestItemEventType.Invalidated]
| [evt: ExtHostTestItemEventType.SetProp, key: keyof vscode.TestItem<never>, value: any];
| ITestItemUpsertChild
| ITestItemRemoveChild
| ITestItemInvalidated
| ITestItemSetProp
| ITestItemBulkReplace;
export interface IExtHostTestItemApi {
children: Map<string, TestItemImpl>;
controllerId: string;
parent?: TestItemImpl;
bus: Emitter<ExtHostTestItemEvent>;
listener?: (evt: ExtHostTestItemEvent) => void;
}
const eventPrivateApis = new WeakMap<TestItemImpl, IExtHostTestItemApi>();
export const createPrivateApiFor = (impl: TestItemImpl, controllerId: string) => {
const api: IExtHostTestItemApi = { controllerId };
eventPrivateApis.set(impl, api);
return api;
};
/**
* Gets the private API for a test item implementation. This implementation
* is a managed object, but we keep a weakmap to avoid exposing any of the
* internals to extensions.
*/
export const getPrivateApiFor = (impl: TestItemImpl) => {
let api = eventPrivateApis.get(impl);
if (!api) {
api = { children: new Map(), bus: new Emitter() };
eventPrivateApis.set(impl, api);
export const getPrivateApiFor = (impl: TestItemImpl) => eventPrivateApis.get(impl)!;
const testItemPropAccessor = <K extends keyof vscode.TestItem>(
api: IExtHostTestItemApi,
key: K,
defaultValue: vscode.TestItem[K],
equals: (a: vscode.TestItem[K], b: vscode.TestItem[K]) => boolean
) => {
let value = defaultValue;
return {
enumerable: true,
configurable: false,
get() {
return value;
},
set(newValue: vscode.TestItem[K]) {
if (!equals(value, newValue)) {
const oldValue = value;
value = newValue;
api.listener?.({
op: ExtHostTestItemEventOp.SetProp,
key,
value: newValue,
previous: oldValue,
});
}
},
};
};
type WritableProps = Pick<vscode.TestItem, 'range' | 'label' | 'description' | 'canResolveChildren' | 'busy' | 'error' | 'tags'>;
const strictEqualComparator = <T>(a: T, b: T) => a === b;
const propComparators: { [K in keyof Required<WritableProps>]: (a: vscode.TestItem[K], b: vscode.TestItem[K]) => boolean } = {
range: (a, b) => {
if (a === b) { return true; }
if (!a || !b) { return false; }
return a.isEqual(b);
},
label: strictEqualComparator,
description: strictEqualComparator,
busy: strictEqualComparator,
error: strictEqualComparator,
canResolveChildren: strictEqualComparator,
tags: (a, b) => {
if (a.length !== b.length) {
return false;
}
if (a.some(t1 => !b.find(t2 => t1.id === t2.id))) {
return false;
}
return true;
},
};
const writablePropKeys = Object.keys(propComparators) as (keyof Required<WritableProps>)[];
const makePropDescriptors = (api: IExtHostTestItemApi, label: string): { [K in keyof Required<WritableProps>]: PropertyDescriptor } => ({
range: testItemPropAccessor(api, 'range', undefined, propComparators.range),
label: testItemPropAccessor(api, 'label', label, propComparators.label),
description: testItemPropAccessor(api, 'description', undefined, propComparators.description),
canResolveChildren: testItemPropAccessor(api, 'canResolveChildren', false, propComparators.canResolveChildren),
busy: testItemPropAccessor(api, 'busy', false, propComparators.busy),
error: testItemPropAccessor(api, 'error', undefined, propComparators.error),
tags: testItemPropAccessor(api, 'tags', [], propComparators.tags),
});
/**
* Returns a partial test item containing the writable properties in B that
* are different from A.
*/
export const diffTestItems = (a: vscode.TestItem, b: vscode.TestItem) => {
const output = new Map<keyof WritableProps, unknown>();
for (const key of writablePropKeys) {
const cmp = propComparators[key] as (a: unknown, b: unknown) => boolean;
if (!cmp(a[key], b[key])) {
output.set(key, b[key]);
}
}
return api;
return output;
};
export class DuplicateTestItemError extends Error {
constructor(id: string) {
super(`Attempted to insert a duplicate test item ID ${id}`);
}
}
export class InvalidTestItemError extends Error {
constructor(id: string) {
super(`TestItem with ID "${id}" is invalid. Make sure to create it from the createTestItem method.`);
}
}
export class MixedTestItemController extends Error {
constructor(id: string, ctrlA: string, ctrlB: string) {
super(`TestItem with ID "${id}" is from controller "${ctrlA}" and cannot be added as a child of an item from controller "${ctrlB}".`);
}
}
export type TestItemCollectionImpl = vscode.TestItemCollection & { toJSON(): readonly TestItemImpl[] } & Iterable<TestItemImpl>;
const createTestItemCollection = (owningItem: TestItemImpl): TestItemCollectionImpl => {
const api = getPrivateApiFor(owningItem);
let mapped = new Map<string, TestItemImpl>();
return {
/** @inheritdoc */
get size() {
return mapped.size;
},
/** @inheritdoc */
forEach(callback: (item: vscode.TestItem, collection: vscode.TestItemCollection) => unknown, thisArg?: unknown) {
for (const item of mapped.values()) {
callback.call(thisArg, item, this);
}
},
/** @inheritdoc */
replace(items: Iterable<vscode.TestItem>) {
const newMapped = new Map<string, TestItemImpl>();
const toDelete = new Set(mapped.keys());
const bulk: ITestItemBulkReplace = { op: ExtHostTestItemEventOp.Bulk, ops: [] };
for (const item of items) {
if (!(item instanceof TestItemImpl)) {
throw new InvalidTestItemError(item.id);
}
const itemController = getPrivateApiFor(item).controllerId;
if (itemController !== api.controllerId) {
throw new MixedTestItemController(item.id, itemController, api.controllerId);
}
if (newMapped.has(item.id)) {
throw new DuplicateTestItemError(item.id);
}
newMapped.set(item.id, item);
toDelete.delete(item.id);
bulk.ops.push({ op: ExtHostTestItemEventOp.Upsert, item });
}
for (const id of toDelete.keys()) {
bulk.ops.push({ op: ExtHostTestItemEventOp.RemoveChild, id });
}
api.listener?.(bulk);
// important mutations come after firing, so if an error happens no
// changes will be "saved":
mapped = newMapped;
},
/** @inheritdoc */
add(item: vscode.TestItem) {
if (!(item instanceof TestItemImpl)) {
throw new InvalidTestItemError(item.id);
}
mapped.set(item.id, item);
api.listener?.({ op: ExtHostTestItemEventOp.Upsert, item });
},
/** @inheritdoc */
delete(id: string) {
if (mapped.delete(id)) {
api.listener?.({ op: ExtHostTestItemEventOp.RemoveChild, id });
}
},
/** @inheritdoc */
get(itemId: string) {
return mapped.get(itemId);
},
/** JSON serialization function. */
toJSON() {
return Array.from(mapped.values());
},
/** @inheritdoc */
[Symbol.iterator]() {
return mapped.values();
},
};
};
export class TestItemImpl implements vscode.TestItem {
public readonly id!: string;
public readonly uri!: vscode.Uri | undefined;
public readonly children!: TestItemCollectionImpl;
public readonly parent!: TestItemImpl | undefined;
public range!: vscode.Range | undefined;
public description!: string | undefined;
public label!: string;
public error!: string | vscode.MarkdownString;
public busy!: boolean;
public canResolveChildren!: boolean;
public tags!: readonly vscode.TestTag[];
/**
* Note that data is deprecated and here for back-compat only
*/
constructor(controllerId: string, id: string, label: string, uri: vscode.Uri | undefined) {
if (id.includes(TestIdPathParts.Delimiter)) {
throw new Error(`Test IDs may not include the ${JSON.stringify(id)} symbol`);
}
const api = createPrivateApiFor(this, controllerId);
Object.defineProperties(this, {
id: {
value: id,
enumerable: true,
writable: false,
},
uri: {
value: uri,
enumerable: true,
writable: false,
},
parent: {
enumerable: false,
get() {
return api.parent instanceof TestItemRootImpl ? undefined : api.parent;
},
},
children: {
value: createTestItemCollection(this),
enumerable: true,
writable: false,
},
...makePropDescriptors(api, label),
});
}
/** @deprecated back compat */
public invalidateResults() {
getPrivateApiFor(this).listener?.({ op: ExtHostTestItemEventOp.Invalidated });
}
}
export class TestItemRootImpl extends TestItemImpl {
constructor(controllerId: string, label: string) {
super(controllerId, controllerId, label, undefined);
}
}

View File

@@ -13,6 +13,7 @@ import { CancellationToken } from 'vs/base/common/cancellation';
import { CommandsConverter, ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
import { ThemeIcon } from 'vs/workbench/api/common/extHostTypes';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { MarshalledId } from 'vs/base/common/marshalling';
export interface IExtHostTimeline extends ExtHostTimelineShape {
readonly _serviceBrand: undefined;
@@ -38,7 +39,7 @@ export class ExtHostTimeline implements IExtHostTimeline {
commands.registerArgumentProcessor({
processArgument: arg => {
if (arg && arg.$mid === 11) {
if (arg && arg.$mid === MarshalledId.TimelineActionContext) {
const uri = arg.uri === undefined ? undefined : URI.revive(arg.uri);
return this._itemsBySourceAndUriMap.get(arg.source)?.get(getUriKey(uri))?.get(arg.handle);
}
@@ -131,7 +132,7 @@ export class ExtHostTimeline implements IExtHostTimeline {
let themeIcon;
if (item.iconPath) {
if (iconPath instanceof ThemeIcon) {
themeIcon = { id: iconPath.id };
themeIcon = { id: iconPath.id, color: iconPath.color };
}
else if (URI.isUri(iconPath)) {
icon = iconPath;

View File

@@ -123,7 +123,7 @@ export class ExtHostTreeViews implements ExtHostTreeViewsShape {
};
}
$getChildren(treeViewId: string, treeItemHandle?: string): Promise<ITreeItem[]> {
$getChildren(treeViewId: string, treeItemHandle?: string): Promise<ITreeItem[] | undefined> {
const treeView = this.treeViews.get(treeViewId);
if (!treeView) {
return Promise.reject(new Error(localize('treeView.notRegistered', 'No tree view with id \'{0}\' registered.', treeViewId)));
@@ -224,7 +224,7 @@ export class ExtHostTreeView<T> extends Disposable {
private readonly dataProvider: vscode.TreeDataProvider<T>;
private readonly dndController: vscode.DragAndDropController<T> | undefined;
private roots: TreeNode[] | null = null;
private roots: TreeNode[] | undefined = undefined;
private elements: Map<TreeItemHandle, T> = new Map<TreeItemHandle, T>();
// {{SQL CARBON EDIT}}
protected nodes: Map<T, TreeNode> = new Map<T, TreeNode>();
@@ -276,7 +276,10 @@ export class ExtHostTreeView<T> extends Disposable {
if (this.proxy) {
this.proxy.$registerTreeViewDataProvider(viewId, { showCollapseAll: !!options.showCollapseAll, canSelectMany: !!options.canSelectMany, canDragAndDrop: options.dragAndDropController !== undefined });
}
if (this.dataProvider.onDidChangeTreeData) {
this.dndController = options.dragAndDropController;
if (this.dataProvider.onDidChangeTreeData2) {
this._register(this.dataProvider.onDidChangeTreeData2(elementOrElements => this._onDidChangeData.fire({ message: false, element: elementOrElements })));
} else if (this.dataProvider.onDidChangeTreeData) {
this._register(this.dataProvider.onDidChangeTreeData(element => this._onDidChangeData.fire({ message: false, element })));
}
@@ -316,16 +319,20 @@ export class ExtHostTreeView<T> extends Disposable {
}));
}
getChildren(parentHandle: TreeItemHandle | Root): Promise<ITreeItem[]> {
async getChildren(parentHandle: TreeItemHandle | Root): Promise<ITreeItem[] | undefined> {
const parentElement = parentHandle ? this.getExtensionElement(parentHandle) : undefined;
if (parentHandle && !parentElement) {
this.logService.error(`No tree item with id \'${parentHandle}\' found.`);
return Promise.resolve([]);
}
const childrenNodes = this.getChildrenNodes(parentHandle); // Get it from cache
return (childrenNodes ? Promise.resolve(childrenNodes) : this.fetchChildrenNodes(parentElement))
.then(nodes => nodes.map(n => n.item));
let childrenNodes: TreeNode[] | undefined = this.getChildrenNodes(parentHandle); // Get it from cache
if (!childrenNodes) {
childrenNodes = await this.fetchChildrenNodes(parentElement);
}
return childrenNodes ? childrenNodes.map(n => n.item) : undefined;
}
getExtensionElement(treeItemHandle: TreeItemHandle): T | undefined {
@@ -481,7 +488,7 @@ export class ExtHostTreeView<T> extends Disposable {
}));
}
private getChildrenNodes(parentNodeOrHandle: TreeNode | TreeItemHandle | Root): TreeNode[] | null {
private getChildrenNodes(parentNodeOrHandle: TreeNode | TreeItemHandle | Root): TreeNode[] | undefined {
if (parentNodeOrHandle) {
let parentNode: TreeNode | undefined;
if (typeof parentNodeOrHandle === 'string') {
@@ -490,12 +497,12 @@ export class ExtHostTreeView<T> extends Disposable {
} else {
parentNode = parentNodeOrHandle;
}
return parentNode ? parentNode.children || null : null;
return parentNode ? parentNode.children || undefined : undefined;
}
return this.roots;
}
private async fetchChildrenNodes(parentElement?: T): Promise<TreeNode[]> {
private async fetchChildrenNodes(parentElement?: T): Promise<TreeNode[] | undefined> {
// clear children cache
this.clearChildren(parentElement);
@@ -505,7 +512,7 @@ export class ExtHostTreeView<T> extends Disposable {
const parentNode = parentElement ? this.nodes.get(parentElement) : undefined;
const elements = await this.dataProvider.getChildren(parentElement);
if (cts.token.isCancellationRequested) {
return [];
return undefined;
}
const items = await Promise.all(coalesce(elements || []).map(async element => {
@@ -513,7 +520,7 @@ export class ExtHostTreeView<T> extends Disposable {
return item && !cts.token.isCancellationRequested ? this.createAndRegisterTreeNode(element, item, parentNode) : null;
}));
if (cts.token.isCancellationRequested) {
return [];
return undefined;
}
return coalesce(items);
@@ -797,9 +804,8 @@ export class ExtHostTreeView<T> extends Disposable {
}
}
// {{SQL CARBON EDIT}}
protected clearAll(): void {
this.roots = null;
protected clearAll(): void { // {{SQL CARBON EDIT}}
this.roots = undefined;
this.elements.clear();
this.nodes.forEach(node => node.dispose());
this.nodes.clear();

View File

@@ -17,11 +17,12 @@ export interface TunnelDto {
remoteAddress: { port: number, host: string };
localAddress: { port: number, host: string } | string;
public: boolean;
protocol: string | undefined;
}
export namespace TunnelDto {
export function fromApiTunnel(tunnel: vscode.Tunnel): TunnelDto {
return { remoteAddress: tunnel.remoteAddress, localAddress: tunnel.localAddress, public: !!tunnel.public };
return { remoteAddress: tunnel.remoteAddress, localAddress: tunnel.localAddress, public: !!tunnel.public, protocol: tunnel.protocol };
}
export function fromServiceTunnel(tunnel: RemoteTunnel): TunnelDto {
return {
@@ -30,7 +31,8 @@ export namespace TunnelDto {
port: tunnel.tunnelRemotePort
},
localAddress: tunnel.localAddress,
public: tunnel.public
public: tunnel.public,
protocol: tunnel.protocol
};
}
}

View File

@@ -4,6 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { coalesce, isNonEmptyArray } from 'vs/base/common/arrays';
import { VSBuffer } from 'vs/base/common/buffer';
import * as htmlContent from 'vs/base/common/htmlContent';
import { DisposableStore } from 'vs/base/common/lifecycle';
import * as marked from 'vs/base/common/marked/marked';
@@ -19,18 +20,21 @@ import { IContentDecorationRenderOptions, IDecorationOptions, IDecorationRenderO
import { EndOfLineSequence, TrackedRangeStickiness } from 'vs/editor/common/model';
import * as modes from 'vs/editor/common/modes';
import * as languageSelector from 'vs/editor/common/modes/languageSelector';
import { EditorOverride, ITextEditorOptions } from 'vs/platform/editor/common/editor';
import { EditorResolution, ITextEditorOptions } from 'vs/platform/editor/common/editor';
import { IMarkerData, IRelatedInformation, MarkerSeverity, MarkerTag } from 'vs/platform/markers/common/markers';
import { ProgressLocation as MainProgressLocation } from 'vs/platform/progress/common/progress';
import * as extHostProtocol from 'vs/workbench/api/common/extHost.protocol';
import { CommandsConverter } from 'vs/workbench/api/common/extHostCommands';
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook';
import { EditorGroupColumn, SaveReason } from 'vs/workbench/common/editor';
import { getPrivateApiFor, TestItemImpl } from 'vs/workbench/api/common/extHostTestingPrivateApi';
import { SaveReason } from 'vs/workbench/common/editor';
import * as notebooks from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { ICellRange } from 'vs/workbench/contrib/notebook/common/notebookRange';
import * as search from 'vs/workbench/contrib/search/common/search';
import { ISerializedTestResults, ITestItem, ITestMessage, SerializedTestResultItem } from 'vs/workbench/contrib/testing/common/testCollection';
import { CoverageDetails, DetailType, ICoveredCount, IFileCoverage, ISerializedTestResults, ITestErrorMessage, ITestItem, ITestItemContext, ITestTag, SerializedTestResultItem, TestMessageType } from 'vs/workbench/contrib/testing/common/testCollection';
import { TestId } from 'vs/workbench/contrib/testing/common/testId';
import { EditorGroupColumn } from 'vs/workbench/services/editor/common/editorGroupColumn';
import { ACTIVE_GROUP, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService';
import type * as vscode from 'vscode';
import * as types from './extHostTypes';
@@ -548,33 +552,6 @@ export namespace WorkspaceEdit {
notebookVersionId: extHostNotebooks?.getNotebookDocument(entry.uri, true)?.apiNotebook.version
});
} else if (entry._type === types.FileEditType.CellOutput) {
if (entry.newOutputs) {
result.edits.push({
_type: extHostProtocol.WorkspaceEditType.Cell,
metadata: entry.metadata,
resource: entry.uri,
edit: {
editType: notebooks.CellEditType.Output,
index: entry.index,
append: entry.append,
outputs: entry.newOutputs.map(NotebookCellOutput.from)
}
});
}
// todo@joh merge metadata and output edit?
if (entry.newMetadata) {
result.edits.push({
_type: extHostProtocol.WorkspaceEditType.Cell,
metadata: entry.metadata,
resource: entry.uri,
edit: {
editType: notebooks.CellEditType.PartialMetadata,
index: entry.index,
metadata: entry.newMetadata
}
});
}
} else if (entry._type === types.FileEditType.CellReplace) {
result.edits.push({
_type: extHostProtocol.WorkspaceEditType.Cell,
@@ -588,18 +565,6 @@ export namespace WorkspaceEdit {
cells: entry.cells.map(NotebookCellData.from)
}
});
} else if (entry._type === types.FileEditType.CellOutputItem) {
result.edits.push({
_type: extHostProtocol.WorkspaceEditType.Cell,
metadata: entry.metadata,
resource: entry.uri,
edit: {
editType: notebooks.CellEditType.OutputItems,
outputId: entry.outputId,
items: entry.newOutputItems?.map(NotebookCellOutputItem.from) || [],
append: entry.append
}
});
}
}
}
@@ -759,6 +724,28 @@ export namespace CallHierarchyItem {
return result;
}
export function from(item: vscode.CallHierarchyItem, sessionId?: string, itemId?: string): extHostProtocol.ICallHierarchyItemDto {
sessionId = sessionId ?? (<types.CallHierarchyItem>item)._sessionId;
itemId = itemId ?? (<types.CallHierarchyItem>item)._itemId;
if (sessionId === undefined || itemId === undefined) {
throw new Error('invalid item');
}
return {
_sessionId: sessionId,
_itemId: itemId,
name: item.name,
detail: item.detail,
kind: SymbolKind.from(item.kind),
uri: item.uri,
range: Range.from(item.range),
selectionRange: Range.from(item.selectionRange),
tags: item.tags?.map(SymbolTag.from)
};
}
}
export namespace CallHierarchyIncomingCall {
@@ -1036,11 +1023,7 @@ export namespace CompletionItem {
export function to(suggestion: modes.CompletionItem, converter?: CommandsConverter): types.CompletionItem {
const result = new types.CompletionItem(typeof suggestion.label === 'string' ? suggestion.label : suggestion.label.name);
if (typeof suggestion.label !== 'string') {
result.label2 = suggestion.label;
}
const result = new types.CompletionItem(suggestion.label);
result.insertText = suggestion.insertText;
result.kind = CompletionItemKind.to(suggestion.kind);
result.tags = suggestion.tags?.map(CompletionItemTag.to);
@@ -1343,7 +1326,7 @@ export namespace TextEditorOpenOptions {
inactive: options.background,
preserveFocus: options.preserveFocus,
selection: typeof options.selection === 'object' ? Range.from(options.selection) : undefined,
override: typeof options.override === 'boolean' ? EditorOverride.DISABLED : undefined
override: typeof options.override === 'boolean' ? EditorResolution.DISABLED : undefined
};
}
@@ -1458,8 +1441,8 @@ export namespace NotebookCellKind {
export namespace NotebookData {
export function from(data: vscode.NotebookData): notebooks.NotebookDataDto {
const res: notebooks.NotebookDataDto = {
export function from(data: vscode.NotebookData): extHostProtocol.NotebookDataDto {
const res: extHostProtocol.NotebookDataDto = {
metadata: data.metadata ?? Object.create(null),
cells: [],
};
@@ -1470,7 +1453,7 @@ export namespace NotebookData {
return res;
}
export function to(data: notebooks.NotebookDataDto): vscode.NotebookData {
export function to(data: extHostProtocol.NotebookDataDto): vscode.NotebookData {
const res = new types.NotebookData(
data.cells.map(NotebookCellData.to),
);
@@ -1483,10 +1466,11 @@ export namespace NotebookData {
export namespace NotebookCellData {
export function from(data: vscode.NotebookCellData): notebooks.ICellDto2 {
export function from(data: vscode.NotebookCellData): extHostProtocol.NotebookCellDataDto {
return {
cellKind: NotebookCellKind.from(data.kind),
language: data.languageId,
mime: data.mime,
source: data.value,
metadata: data.metadata,
internalMetadata: NotebookCellExecutionSummary.from(data.executionSummary ?? {}),
@@ -1494,11 +1478,12 @@ export namespace NotebookCellData {
};
}
export function to(data: notebooks.ICellDto2): vscode.NotebookCellData {
export function to(data: extHostProtocol.NotebookCellDataDto): vscode.NotebookCellData {
return new types.NotebookCellData(
NotebookCellKind.to(data.cellKind),
data.source,
data.language,
data.mime,
data.outputs ? data.outputs.map(NotebookCellOutput.to) : undefined,
data.metadata,
data.internalMetadata ? NotebookCellExecutionSummary.to(data.internalMetadata) : undefined
@@ -1507,29 +1492,29 @@ export namespace NotebookCellData {
}
export namespace NotebookCellOutputItem {
export function from(item: types.NotebookCellOutputItem): notebooks.IOutputItemDto {
export function from(item: types.NotebookCellOutputItem): extHostProtocol.NotebookOutputItemDto {
return {
mime: item.mime,
valueBytes: Array.from(item.data), //todo@jrieken this HACKY and SLOW... hoist VSBuffer instead
valueBytes: VSBuffer.wrap(item.data),
};
}
export function to(item: notebooks.IOutputItemDto): types.NotebookCellOutputItem {
return new types.NotebookCellOutputItem(new Uint8Array(item.valueBytes), item.mime);
export function to(item: extHostProtocol.NotebookOutputItemDto): types.NotebookCellOutputItem {
return new types.NotebookCellOutputItem(item.valueBytes.buffer, item.mime);
}
}
export namespace NotebookCellOutput {
export function from(output: vscode.NotebookCellOutput): notebooks.IOutputDto {
export function from(output: vscode.NotebookCellOutput): extHostProtocol.NotebookOutputDto {
return {
outputId: output.id,
outputs: output.items.map(NotebookCellOutputItem.from),
items: output.items.map(NotebookCellOutputItem.from),
metadata: output.metadata
};
}
export function to(output: notebooks.IOutputDto): vscode.NotebookCellOutput {
const items = output.outputs.map(NotebookCellOutputItem.to);
export function to(output: extHostProtocol.NotebookOutputDto): vscode.NotebookCellOutput {
const items = output.items.map(NotebookCellOutputItem.to);
return new types.NotebookCellOutput(items, output.outputId, output.metadata);
}
}
@@ -1655,100 +1640,132 @@ export namespace NotebookRendererScript {
}
export namespace TestMessage {
export function from(message: vscode.TestMessage): ITestMessage {
export function from(message: vscode.TestMessage): ITestErrorMessage {
return {
message: MarkdownString.fromStrict(message.message) || '',
severity: message.severity,
expectedOutput: message.expectedOutput,
actualOutput: message.actualOutput,
type: TestMessageType.Error,
expected: message.expectedOutput,
actual: message.actualOutput,
location: message.location ? location.from(message.location) as any : undefined,
};
}
export function to(item: ITestMessage): vscode.TestMessage {
export function to(item: ITestErrorMessage): vscode.TestMessage {
const message = new types.TestMessage(typeof item.message === 'string' ? item.message : MarkdownString.to(item.message));
message.severity = item.severity;
message.actualOutput = item.actualOutput;
message.expectedOutput = item.expectedOutput;
message.actualOutput = item.actual;
message.expectedOutput = item.expected;
return message;
}
}
export namespace TestItem {
export type Raw<T = unknown> = vscode.TestItem<T>;
export namespace TestTag {
const enum Constants {
Delimiter = '\0',
}
export function from(item: vscode.TestItem<unknown>): ITestItem {
export const namespace = (ctrlId: string, tagId: string) =>
ctrlId + Constants.Delimiter + tagId;
export const denamespace = (namespaced: string) => {
const index = namespaced.indexOf(Constants.Delimiter);
return { ctrlId: namespaced.slice(0, index), tagId: namespaced.slice(index + 1) };
};
}
export namespace TestItem {
export type Raw = vscode.TestItem;
export function from(item: TestItemImpl): ITestItem {
const ctrlId = getPrivateApiFor(item).controllerId;
return {
extId: item.id,
extId: TestId.fromExtHostTestItem(item, ctrlId).toString(),
label: item.label,
uri: item.uri,
tags: item.tags.map(t => TestTag.namespace(ctrlId, t.id)),
range: Range.from(item.range) || null,
debuggable: item.debuggable ?? false,
description: item.description || null,
runnable: item.runnable ?? true,
error: item.error ? (MarkdownString.fromStrict(item.error) || null) : null,
};
}
export function fromResultSnapshot(item: vscode.TestResultSnapshot): ITestItem {
export function toPlain(item: ITestItem): Omit<vscode.TestItem, 'children' | 'invalidate' | 'discoverChildren'> {
return {
extId: item.id,
label: item.label,
uri: item.uri,
range: Range.from(item.range) || null,
debuggable: false,
description: item.description || null,
error: null,
runnable: true,
};
}
export function toPlain(item: ITestItem): Omit<vscode.TestItem<never>, 'children' | 'invalidate' | 'discoverChildren'> {
return {
id: item.extId,
id: TestId.fromString(item.extId).localId,
label: item.label,
uri: URI.revive(item.uri),
tags: (item.tags || []).map(t => {
const { tagId } = TestTag.denamespace(t);
return new types.TestTag(tagId, tagId);
}),
range: Range.to(item.range || undefined),
addChild: () => undefined,
dispose: () => undefined,
status: types.TestItemStatus.Pending,
data: undefined as never,
debuggable: item.debuggable,
invalidateResults: () => undefined,
canResolveChildren: false,
busy: false,
description: item.description || undefined,
runnable: item.runnable,
};
}
export function to(item: ITestItem): types.TestItemImpl {
const testItem = new types.TestItemImpl(item.extId, item.label, URI.revive(item.uri), undefined);
function to(item: ITestItem): TestItemImpl {
const testId = TestId.fromString(item.extId);
const testItem = new TestItemImpl(testId.controllerId, testId.localId, item.label, URI.revive(item.uri));
testItem.range = Range.to(item.range || undefined);
testItem.debuggable = item.debuggable;
testItem.description = item.description || undefined;
testItem.runnable = item.runnable;
return testItem;
}
export function toItemFromContext(context: ITestItemContext): TestItemImpl {
let node: TestItemImpl | undefined;
for (const test of context.tests) {
const next = to(test.item);
getPrivateApiFor(next).parent = node;
node = next;
}
return node!;
}
}
export namespace TestTag {
export function from(tag: vscode.TestTag): ITestTag {
return { id: tag.id, label: tag.label };
}
export function to(tag: ITestTag): vscode.TestTag {
return new types.TestTag(tag.id, tag.label);
}
}
export namespace TestResults {
const convertTestResultItem = (item: SerializedTestResultItem, byInternalId: Map<string, SerializedTestResultItem>): vscode.TestResultSnapshot => ({
...TestItem.toPlain(item.item),
taskStates: item.tasks.map(t => ({
state: t.state,
duration: t.duration,
messages: t.messages.map(TestMessage.to),
})),
children: item.children
.map(c => byInternalId.get(c))
.filter(isDefined)
.map(c => convertTestResultItem(c, byInternalId)),
});
const convertTestResultItem = (item: SerializedTestResultItem, byInternalId: Map<string, SerializedTestResultItem>): vscode.TestResultSnapshot => {
const snapshot: vscode.TestResultSnapshot = ({
...TestItem.toPlain(item.item),
parent: undefined,
taskStates: item.tasks.map(t => ({
state: t.state as number as types.TestResultState,
duration: t.duration,
messages: t.messages
.filter((m): m is ITestErrorMessage => m.type === TestMessageType.Error)
.map(TestMessage.to),
})),
children: item.children
.map(c => byInternalId.get(c))
.filter(isDefined)
.map(c => convertTestResultItem(c, byInternalId))
});
for (const child of snapshot.children) {
(child as any).parent = snapshot;
}
return snapshot;
};
export function to(serialized: ISerializedTestResults): vscode.TestRunResult {
const roots: SerializedTestResultItem[] = [];
const byInternalId = new Map<string, SerializedTestResultItem>();
for (const item of serialized.items) {
byInternalId.set(item.item.extId, item);
if (item.direct) {
if (serialized.request.targets.some(t => t.controllerId === item.controllerId && t.testIds.includes(item.item.extId))) {
roots.push(item);
}
}
@@ -1760,6 +1777,45 @@ export namespace TestResults {
}
}
export namespace TestCoverage {
function fromCoveredCount(count: vscode.CoveredCount): ICoveredCount {
return { covered: count.covered, total: count.covered };
}
function fromLocation(location: vscode.Range | vscode.Position) {
return 'line' in location ? Position.from(location) : Range.from(location);
}
export function fromDetailed(coverage: vscode.DetailedCoverage): CoverageDetails {
if ('branches' in coverage) {
return {
count: coverage.executionCount,
location: fromLocation(coverage.location),
type: DetailType.Statement,
branches: coverage.branches.length
? coverage.branches.map(b => ({ count: b.executionCount, location: b.location && fromLocation(b.location) }))
: undefined,
};
} else {
return {
type: DetailType.Function,
count: coverage.executionCount,
location: fromLocation(coverage.location),
};
}
}
export function fromFile(coverage: vscode.FileCoverage): IFileCoverage {
return {
uri: coverage.uri,
statement: fromCoveredCount(coverage.statementCoverage),
branch: coverage.branchCoverage && fromCoveredCount(coverage.branchCoverage),
function: coverage.functionCoverage && fromCoveredCount(coverage.functionCoverage),
details: coverage.detailedCoverage?.map(fromDetailed),
};
}
}
export namespace CodeActionTriggerKind {
export function to(value: modes.CodeActionTriggerType): types.CodeActionTriggerKind {
@@ -1772,3 +1828,44 @@ export namespace CodeActionTriggerKind {
}
}
}
export namespace TypeHierarchyItem {
export function to(item: extHostProtocol.ITypeHierarchyItemDto): types.TypeHierarchyItem {
const result = new types.TypeHierarchyItem(
SymbolKind.to(item.kind),
item.name,
item.detail || '',
URI.revive(item.uri),
Range.to(item.range),
Range.to(item.selectionRange)
);
result._sessionId = item._sessionId;
result._itemId = item._itemId;
return result;
}
export function from(item: vscode.TypeHierarchyItem, sessionId?: string, itemId?: string): extHostProtocol.ITypeHierarchyItemDto {
sessionId = sessionId ?? (<types.TypeHierarchyItem>item)._sessionId;
itemId = itemId ?? (<types.TypeHierarchyItem>item)._itemId;
if (sessionId === undefined || itemId === undefined) {
throw new Error('invalid item');
}
return {
_sessionId: sessionId,
_itemId: itemId,
kind: SymbolKind.from(item.kind),
name: item.name,
detail: item.detail ?? '',
uri: item.uri,
range: Range.from(item.range),
selectionRange: Range.from(item.selectionRange),
tags: item.tags?.map(SymbolTag.from)
};
}
}

View File

@@ -6,20 +6,19 @@
import { asArray, coalesceInPlace, equals } from 'vs/base/common/arrays';
import { illegalArgument } from 'vs/base/common/errors';
import { IRelativePattern } from 'vs/base/common/glob';
import { isMarkdownString, MarkdownString as BaseMarkdownString } from 'vs/base/common/htmlContent';
import { ReadonlyMapView, ResourceMap } from 'vs/base/common/map';
import { normalizeMimeType } from 'vs/base/common/mime';
import { MarkdownString as BaseMarkdownString } from 'vs/base/common/htmlContent';
import { ResourceMap } from 'vs/base/common/map';
import { Mimes, normalizeMimeType } from 'vs/base/common/mime';
import { isArray, isStringArray } from 'vs/base/common/types';
import { URI } from 'vs/base/common/uri';
import { generateUuid } from 'vs/base/common/uuid';
import { FileSystemProviderErrorCode, markAsFileSystemProviderError } from 'vs/platform/files/common/files';
import { RemoteAuthorityResolverErrorCode } from 'vs/platform/remote/common/remoteAuthorityResolver';
import { getPrivateApiFor, ExtHostTestItemEventType, IExtHostTestItemApi } from 'vs/workbench/api/common/extHostTestingPrivateApi';
import { CellEditType, ICellEditOperation } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { CellEditType, ICellPartialMetadataEdit, IDocumentMetadataEdit } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import type * as vscode from 'vscode';
function es5ClassCompat(target: Function): any {
// @ts-ignore - {{SQL CARBON EDIT}}
///@ts-expect-error
function _() { return Reflect.construct(target, arguments, this.constructor); }
Object.defineProperty(_, 'name', Object.getOwnPropertyDescriptor(target, 'name')!);
Object.setPrototypeOf(_, target);
@@ -588,9 +587,7 @@ export const enum FileEditType {
File = 1,
Text = 2,
Cell = 3,
CellOutput = 4,
CellReplace = 5,
CellOutputItem = 6
}
export interface IFileOperation {
@@ -611,7 +608,7 @@ export interface IFileTextEdit {
export interface IFileCellEdit {
_type: FileEditType.Cell;
uri: URI;
edit?: ICellEditOperation;
edit?: ICellPartialMetadataEdit | IDocumentMetadataEdit;
notebookMetadata?: Record<string, any>;
metadata?: vscode.WorkspaceEditEntryMetadata;
}
@@ -625,28 +622,8 @@ export interface ICellEdit {
cells: vscode.NotebookCellData[];
}
export interface ICellOutputEdit {
_type: FileEditType.CellOutput;
uri: URI;
index: number;
append: boolean;
newOutputs?: NotebookCellOutput[];
newMetadata?: Record<string, any>;
metadata?: vscode.WorkspaceEditEntryMetadata;
}
export interface ICellOutputItemsEdit {
_type: FileEditType.CellOutputItem;
uri: URI;
index: number;
outputId: string;
append: boolean;
newOutputItems?: NotebookCellOutputItem[];
metadata?: vscode.WorkspaceEditEntryMetadata;
}
type WorkspaceEditEntry = IFileOperation | IFileTextEdit | IFileCellEdit | ICellEdit | ICellOutputEdit | ICellOutputItemsEdit;
type WorkspaceEditEntry = IFileOperation | IFileTextEdit | IFileCellEdit | ICellEdit;
@es5ClassCompat
export class WorkspaceEdit implements vscode.WorkspaceEdit {
@@ -1019,20 +996,18 @@ export class Diagnostic {
@es5ClassCompat
export class Hover {
public contents: vscode.MarkdownString[] | vscode.MarkedString[];
public contents: (vscode.MarkdownString | vscode.MarkedString)[];
public range: Range | undefined;
constructor(
contents: vscode.MarkdownString | vscode.MarkedString | vscode.MarkdownString[] | vscode.MarkedString[],
contents: vscode.MarkdownString | vscode.MarkedString | (vscode.MarkdownString | vscode.MarkedString)[],
range?: Range
) {
if (!contents) {
throw new Error('Illegal argument, contents must be defined');
}
if (Array.isArray(contents)) {
this.contents = <vscode.MarkdownString[] | vscode.MarkedString[]>contents;
} else if (isMarkdownString(contents)) {
this.contents = [contents];
this.contents = contents;
} else {
this.contents = [contents];
}
@@ -1267,6 +1242,7 @@ export class CallHierarchyItem {
_itemId?: string;
kind: SymbolKind;
tags?: SymbolTag[];
name: string;
detail?: string;
uri: URI;
@@ -1304,6 +1280,13 @@ export class CallHierarchyOutgoingCall {
}
}
export enum LanguageStatusSeverity {
Information = 0,
Warning = 1,
Error = 2
}
@es5ClassCompat
export class CodeLens {
@@ -1356,6 +1339,10 @@ export class MarkdownString implements vscode.MarkdownString {
return this.#delegate.supportThemeIcons;
}
set supportThemeIcons(value: boolean | undefined) {
this.#delegate.supportThemeIcons = value;
}
appendText(value: string): vscode.MarkdownString {
this.#delegate.appendText(value);
return this;
@@ -1487,18 +1474,15 @@ export enum CompletionItemTag {
}
export interface CompletionItemLabel {
name: string;
parameters?: string;
qualifier?: string;
type?: string;
label: string;
detail?: string;
description?: string;
}
@es5ClassCompat
export class CompletionItem implements vscode.CompletionItem {
label: string;
label2?: CompletionItemLabel;
label: string | CompletionItemLabel;
kind?: CompletionItemKind;
tags?: CompletionItemTag[];
detail?: string;
@@ -1514,7 +1498,7 @@ export class CompletionItem implements vscode.CompletionItem {
additionalTextEdits?: TextEdit[];
command?: vscode.Command;
constructor(label: string, kind?: CompletionItemKind) {
constructor(label: string | CompletionItemLabel, kind?: CompletionItemKind) {
this.label = label;
this.kind = kind;
}
@@ -1522,7 +1506,6 @@ export class CompletionItem implements vscode.CompletionItem {
toJSON(): any {
return {
label: this.label,
label2: this.label2,
kind: this.kind && CompletionItemKind[this.kind],
detail: this.detail,
documentation: this.documentation,
@@ -1729,6 +1712,39 @@ export enum SourceControlInputBoxValidationType {
Information = 2
}
export class TerminalLink implements vscode.TerminalLink {
constructor(
public startIndex: number,
public length: number,
public tooltip?: string
) {
if (typeof startIndex !== 'number' || startIndex < 0) {
throw illegalArgument('startIndex');
}
if (typeof length !== 'number' || length < 1) {
throw illegalArgument('length');
}
if (tooltip !== undefined && typeof tooltip !== 'string') {
throw illegalArgument('tooltip');
}
}
}
export enum TerminalLocation {
Panel = 0,
Editor = 1,
}
export class TerminalProfile implements vscode.TerminalProfile {
constructor(
public options: vscode.TerminalOptions | vscode.ExtensionTerminalOptions
) {
if (typeof options !== 'object') {
illegalArgument('options');
}
}
}
export enum TaskRevealKind {
Always = 1,
@@ -1748,6 +1764,7 @@ export enum TaskPanelKind {
@es5ClassCompat
export class TaskGroup implements vscode.TaskGroup {
isDefault?: boolean;
private _id: string;
public static Clean: TaskGroup = new TaskGroup('clean', 'Clean');
@@ -2894,10 +2911,8 @@ export class FileDecoration {
badge?: string;
tooltip?: string;
color?: vscode.ThemeColor;
priority?: number;
propagate?: boolean;
constructor(badge?: string, tooltip?: string, color?: ThemeColor) {
this.badge = badge;
this.tooltip = tooltip;
@@ -3009,14 +3024,16 @@ export class NotebookCellData {
kind: NotebookCellKind;
value: string;
languageId: string;
mime?: string;
outputs?: vscode.NotebookCellOutput[];
metadata?: Record<string, any>;
executionSummary?: vscode.NotebookCellExecutionSummary;
constructor(kind: NotebookCellKind, value: string, languageId: string, outputs?: vscode.NotebookCellOutput[], metadata?: Record<string, any>, executionSummary?: vscode.NotebookCellExecutionSummary) {
constructor(kind: NotebookCellKind, value: string, languageId: string, mime?: string, outputs?: vscode.NotebookCellOutput[], metadata?: Record<string, any>, executionSummary?: vscode.NotebookCellExecutionSummary) {
this.kind = kind;
this.value = value;
this.languageId = languageId;
this.mime = mime;
this.outputs = outputs ?? [];
this.metadata = metadata;
this.executionSummary = executionSummary;
@@ -3072,7 +3089,7 @@ export class NotebookCellOutputItem {
static #encoder = new TextEncoder();
static text(value: string, mime: string = 'text/plain'): NotebookCellOutputItem {
static text(value: string, mime: string = Mimes.text): NotebookCellOutputItem {
const bytes = NotebookCellOutputItem.#encoder.encode(String(value));
return new NotebookCellOutputItem(bytes, mime);
}
@@ -3088,7 +3105,7 @@ export class NotebookCellOutputItem {
) {
const mimeNormalized = normalizeMimeType(mime, true);
if (!mimeNormalized) {
throw new Error('INVALID mime type, must not be empty or falsy: ' + mime);
throw new Error(`INVALID mime type: ${mime}. Must be in the format "type/subtype[;optionalparameter]"`);
}
this.mime = mimeNormalized;
}
@@ -3275,7 +3292,6 @@ export class PortAttributes {
//#region Testing
export enum TestResultState {
Unset = 0,
Queued = 1,
Running = 2,
Passed = 3,
@@ -3284,126 +3300,23 @@ export enum TestResultState {
Errored = 6
}
export enum TestMessageSeverity {
Error = 0,
Warning = 1,
Information = 2,
Hint = 3
export enum TestRunProfileKind {
Run = 1,
Debug = 2,
Coverage = 3,
}
export enum TestItemStatus {
Pending = 0,
Resolved = 1,
@es5ClassCompat
export class TestRunRequest implements vscode.TestRunRequest {
constructor(
public readonly include?: vscode.TestItem[],
public readonly exclude?: vscode.TestItem[] | undefined,
public readonly profile?: vscode.TestRunProfile,
) { }
}
const testItemPropAccessor = <K extends keyof vscode.TestItem<never>>(
api: IExtHostTestItemApi,
key: K,
defaultValue: vscode.TestItem<never>[K],
equals: (a: vscode.TestItem<never>[K], b: vscode.TestItem<never>[K]) => boolean
) => {
let value = defaultValue;
return {
enumerable: true,
configurable: false,
get() {
return value;
},
set(newValue: vscode.TestItem<never>[K]) {
if (!equals(value, newValue)) {
value = newValue;
api.bus.fire([ExtHostTestItemEventType.SetProp, key, newValue]);
}
},
};
};
const strictEqualComparator = <T>(a: T, b: T) => a === b;
const rangeComparator = (a: vscode.Range | undefined, b: vscode.Range | undefined) => {
if (a === b) { return true; }
if (!a || !b) { return false; }
return a.isEqual(b);
};
export class TestItemImpl implements vscode.TestItem<unknown> {
public readonly id!: string;
public readonly uri!: vscode.Uri | undefined;
public readonly children!: ReadonlyMap<string, TestItemImpl>;
public readonly parent!: TestItemImpl | undefined;
public range!: vscode.Range | undefined;
public description!: string | undefined;
public runnable!: boolean;
public debuggable!: boolean;
public error!: string | vscode.MarkdownString;
public status!: vscode.TestItemStatus;
/** Extension-owned resolve handler */
public resolveHandler?: (token: vscode.CancellationToken) => void;
constructor(id: string, public label: string, uri: vscode.Uri | undefined, public data: unknown) {
const api = getPrivateApiFor(this);
Object.defineProperties(this, {
id: {
value: id,
enumerable: true,
writable: false,
},
uri: {
value: uri,
enumerable: true,
writable: false,
},
parent: {
enumerable: false,
get: () => api.parent,
},
children: {
value: new ReadonlyMapView(api.children),
enumerable: true,
writable: false,
},
range: testItemPropAccessor(api, 'range', undefined, rangeComparator),
description: testItemPropAccessor(api, 'description', undefined, strictEqualComparator),
runnable: testItemPropAccessor(api, 'runnable', true, strictEqualComparator),
debuggable: testItemPropAccessor(api, 'debuggable', false, strictEqualComparator),
status: testItemPropAccessor(api, 'status', TestItemStatus.Resolved, strictEqualComparator),
error: testItemPropAccessor(api, 'error', undefined, strictEqualComparator),
});
}
public invalidate() {
getPrivateApiFor(this).bus.fire([ExtHostTestItemEventType.Invalidated]);
}
public dispose() {
const api = getPrivateApiFor(this);
if (api.parent) {
getPrivateApiFor(api.parent).children.delete(this.id);
}
api.bus.fire([ExtHostTestItemEventType.Disposed]);
}
public addChild(child: vscode.TestItem<unknown>) {
if (!(child instanceof TestItemImpl)) {
throw new Error('Test child must be created through vscode.test.createTestItem()');
}
const api = getPrivateApiFor(this);
if (api.children.has(child.id)) {
throw new Error(`Attempted to insert a duplicate test item ID ${child.id}`);
}
api.children.set(child.id, child);
api.bus.fire([ExtHostTestItemEventType.NewChild, child]);
}
}
@es5ClassCompat
export class TestMessage implements vscode.TestMessage {
public severity = TestMessageSeverity.Error;
public expectedOutput?: string;
public actualOutput?: string;
@@ -3417,6 +3330,94 @@ export class TestMessage implements vscode.TestMessage {
constructor(public message: string | vscode.MarkdownString) { }
}
@es5ClassCompat
export class TestTag implements vscode.TestTag {
constructor(
public readonly id: string,
public readonly label?: string,
) {
if (/\s/.test(id)) {
throw new Error(`Test tag ID "${id}" may not include whitespace`);
}
}
}
//#endregion
//#region Test Coverage
@es5ClassCompat
export class CoveredCount implements vscode.CoveredCount {
constructor(public covered: number, public total: number) { }
}
@es5ClassCompat
export class FileCoverage implements vscode.FileCoverage {
public static fromDetails(uri: vscode.Uri, details: vscode.DetailedCoverage[]): vscode.FileCoverage {
const statements = new CoveredCount(0, 0);
const branches = new CoveredCount(0, 0);
const fn = new CoveredCount(0, 0);
for (const detail of details) {
if ('branches' in detail) {
statements.total += 1;
statements.covered += detail.executionCount > 0 ? 1 : 0;
for (const branch of detail.branches) {
branches.total += 1;
branches.covered += branch.executionCount > 0 ? 1 : 0;
}
} else {
fn.total += 1;
fn.covered += detail.executionCount > 0 ? 1 : 0;
}
}
const coverage = new FileCoverage(
uri,
statements,
branches.total > 0 ? branches : undefined,
fn.total > 0 ? fn : undefined,
);
coverage.detailedCoverage = details;
return coverage;
}
detailedCoverage?: vscode.DetailedCoverage[];
constructor(
public readonly uri: vscode.Uri,
public statementCoverage: vscode.CoveredCount,
public branchCoverage?: vscode.CoveredCount,
public functionCoverage?: vscode.CoveredCount,
) { }
}
@es5ClassCompat
export class StatementCoverage implements vscode.StatementCoverage {
constructor(
public executionCount: number,
public location: Position | Range,
public branches: vscode.BranchCoverage[] = [],
) { }
}
@es5ClassCompat
export class BranchCoverage implements vscode.BranchCoverage {
constructor(
public executionCount: number,
public location: Position | Range,
) { }
}
@es5ClassCompat
export class FunctionCoverage implements vscode.FunctionCoverage {
constructor(
public executionCount: number,
public location: Position | Range,
) { }
}
//#endregion
export enum ExternalUriOpenerPriority {
@@ -3437,5 +3438,28 @@ export enum PortAutoForwardAction {
OpenBrowser = 2,
OpenPreview = 3,
Silent = 4,
Ignore = 5
Ignore = 5,
OpenBrowserOnce = 6
}
export class TypeHierarchyItem {
_sessionId?: string;
_itemId?: string;
kind: SymbolKind;
tags?: SymbolTag[];
name: string;
detail?: string;
uri: URI;
range: Range;
selectionRange: Range;
constructor(kind: SymbolKind, name: string, detail: string, uri: URI, range: Range, selectionRange: Range) {
this.kind = kind;
this.name = name;
this.detail = detail;
this.uri = uri;
this.range = range;
this.selectionRange = selectionRange;
}
}

View File

@@ -11,7 +11,7 @@ import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'
import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters';
import { serializeWebviewOptions, ExtHostWebview, ExtHostWebviews, toExtensionData, shouldSerializeBuffersForPostMessage } from 'vs/workbench/api/common/extHostWebview';
import { IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
import { EditorGroupColumn } from 'vs/workbench/common/editor';
import { EditorGroupColumn } from 'vs/workbench/services/editor/common/editorGroupColumn';
import type * as vscode from 'vscode';
import * as extHostProtocol from './extHost.protocol';
import * as extHostTypes from './extHostTypes';

View File

@@ -15,7 +15,7 @@ interface IJSONValidationExtensionPoint {
const configurationExtPoint = ExtensionsRegistry.registerExtensionPoint<IJSONValidationExtensionPoint[]>({
extensionPoint: 'jsonValidation',
defaultExtensionKind: 'workspace',
defaultExtensionKind: ['workspace', 'web'],
jsonSchema: {
description: nls.localize('contributes.jsonValidation', 'Contributes json schema configuration.'),
type: 'array',

View File

@@ -183,27 +183,40 @@ const apiMenus: IAPIMenu[] = [
{
key: 'notebook/toolbar',
id: MenuId.NotebookToolbar,
description: localize('notebook.toolbar', "The contributed notebook toolbar menu"),
proposed: true
description: localize('notebook.toolbar', "The contributed notebook toolbar menu")
},
*/
{
key: 'notebook/toolbar/right',
id: MenuId.NotebookRightToolbar,
description: localize('notebook.toolbar.right', "The contributed notebook right toolbar menu"),
key: 'notebook/cell/title',
id: MenuId.NotebookCellTitle,
description: localize('notebook.cell.title', "The contributed notebook cell title menu")
},
{
key: 'notebook/cell/execute',
id: MenuId.NotebookCellExecute,
description: localize('notebook.cell.execute', "The contributed notebook cell execution menu")
},
{
key: 'interactive/toolbar',
id: MenuId.InteractiveToolbar,
description: localize('interactive.toolbar', "The contributed interactive toolbar menu"),
proposed: true
},
{
key: 'notebook/cell/title',
id: MenuId.NotebookCellTitle,
description: localize('notebook.cell.title', "The contributed notebook cell title menu"),
key: 'interactive/cell/title',
id: MenuId.InteractiveCellTitle,
description: localize('interactive.cell.title', "The contributed interactive cell title menu"),
proposed: true
},
{
key: 'testing/item/context',
id: MenuId.TestItem,
description: localize('testing.item.title', "The contributed test item menu"),
proposed: true
description: localize('testing.item.context', "The contributed test item menu"),
},
{
key: 'testing/item/gutter',
id: MenuId.TestItemGutter,
description: localize('testing.item.gutter.title', "The menu for a gutter decoration for a test item"),
},
{
key: 'extension/context',
@@ -282,6 +295,12 @@ const apiMenus: IAPIMenu[] = [
description: locConstants.menusExtensionPointDataGridContext
},
// {{SQL CARBON EDIT}} end menu entries
{
key: 'file/newFile',
id: MenuId.NewFile,
description: localize('file.newFile', "The 'New File...' quick pick, shown on welcome page and File menu."),
supportsSubmenus: false,
},
{
key: 'editor/inlineCompletions/actions',
id: MenuId.InlineCompletionsActions,
@@ -575,11 +594,11 @@ namespace schema {
type: 'string'
},
shortTitle: {
description: localize('vscode.extension.contributes.commandType.shortTitle', 'Short title by which the command is represented in the UI'),
markdownDescription: localize('vscode.extension.contributes.commandType.shortTitle', '(Optional) Short title by which the command is represented in the UI. Menus pick either `title` or `shortTitle` depending on the context in which they show commands.'),
type: 'string'
},
category: {
description: localize('vscode.extension.contributes.commandType.category', '(Optional) Category string by the command is grouped in the UI'),
description: localize('vscode.extension.contributes.commandType.category', '(Optional) Category string by which the command is grouped in the UI'),
type: 'string'
},
enablement: {
@@ -656,7 +675,9 @@ commandsExtensionPoint.setHandler(extensions => {
bucket.push({
id: command,
title,
source: extension.description.displayName ?? extension.description.name,
shortTitle: extension.description.enableProposedApi ? shortTitle : undefined,
tooltip: extension.description.enableProposedApi ? title : undefined,
category,
precondition: ContextKeyExpr.deserialize(enablement),
icon: absoluteIcon

View File

@@ -82,6 +82,11 @@ export interface TaskHandleDTO {
workspaceFolder: UriComponents | string;
}
export interface TaskGroupDTO {
isDefault?: boolean;
_id: string;
}
export interface TaskDTO {
_id: string;
name?: string;
@@ -89,7 +94,7 @@ export interface TaskDTO {
definition: TaskDefinitionDTO;
isBackground?: boolean;
source: TaskSourceDTO;
group?: string;
group?: TaskGroupDTO;
detail?: string;
presentationOptions?: TaskPresentationOptionsDTO;
problemMatchers: string[];

View File

@@ -3,6 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { CharCode } from 'vs/base/common/charCode';
import { Schemas } from 'vs/base/common/network';
import { URI } from 'vs/base/common/uri';
import type * as vscode from 'vscode';
@@ -57,9 +58,27 @@ export function asWebviewUri(
return URI.from({
scheme: Schemas.https,
authority: `${resource.scheme}+${resource.authority}.${webviewRootResourceAuthority}`,
authority: `${resource.scheme}+${encodeAuthority(resource.authority)}.${webviewRootResourceAuthority}`,
path: resource.path,
fragment: resource.fragment,
query: resource.query,
});
}
function encodeAuthority(authority: string): string {
return authority.replace(/./g, char => {
const code = char.charCodeAt(0);
if (
(code >= CharCode.a && code <= CharCode.z)
|| (code >= CharCode.A && code <= CharCode.Z)
|| (code >= CharCode.Digit0 && code <= CharCode.Digit9)
) {
return char;
}
return '-' + code.toString(16).padStart(4, '0');
});
}
export function decodeAuthority(authority: string) {
return authority.replace(/-([0-9a-f]{4})/g, (_, code) => String.fromCharCode(parseInt(code, 16)));
}

View File

@@ -20,6 +20,8 @@ import { IExtHostTask } from 'vs/workbench/api/common/extHostTask';
import { IExtHostTerminalService } from 'vs/workbench/api/common/extHostTerminalService';
import { IExtHostTunnelService } from 'vs/workbench/api/common/extHostTunnelService';
import { ILogService } from 'vs/platform/log/common/log';
import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths';
import { ExtensionStoragePaths } from 'vs/workbench/api/node/extHostStoragePaths';
// #########################################################################
// ### ###
@@ -29,6 +31,7 @@ import { ILogService } from 'vs/platform/log/common/log';
registerSingleton(IExtHostExtensionService, ExtHostExtensionService);
registerSingleton(ILogService, ExtHostLogService);
registerSingleton(IExtensionStoragePaths, ExtensionStoragePaths);
// registerSingleton(IExtHostDebugService, ExtHostDebugService); {{SQL CARBON EDIT}}
registerSingleton(IExtHostOutputService, ExtHostOutputService2);

View File

@@ -6,7 +6,7 @@
import * as nls from 'vs/nls';
import type * as vscode from 'vscode';
import * as platform from 'vs/base/common/platform';
import { DebugAdapterExecutable } from 'vs/workbench/api/common/extHostTypes';
import { DebugAdapterExecutable, ThemeIcon } from 'vs/workbench/api/common/extHostTypes';
import { ExecutableDebugAdapter, SocketDebugAdapter, NamedPipeDebugAdapter } from 'vs/workbench/contrib/debug/node/debugAdapter';
import { AbstractDebugAdapter } from 'vs/workbench/contrib/debug/common/abstractDebugAdapter';
import { IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
@@ -98,6 +98,7 @@ export class ExtHostDebugService extends ExtHostDebugServiceBase {
shellArgs: shellArgs,
cwd: args.cwd,
name: terminalName,
iconPath: new ThemeIcon('debug'),
};
giveShellTimeToInitialize = true;
terminal = this._terminalService.createTerminalFromOptions(options, {

View File

@@ -17,6 +17,7 @@ import { ILogService } from 'vs/platform/log/common/log';
import { createRotatingLogger } from 'vs/platform/log/node/spdlogLog';
import { Logger } from 'spdlog';
import { ByteSize } from 'vs/platform/files/common/files';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
class OutputAppender {
@@ -43,8 +44,8 @@ class ExtHostOutputChannelBackedByFile extends AbstractExtHostOutputChannel {
private _appender: OutputAppender;
constructor(name: string, appender: OutputAppender, proxy: MainThreadOutputServiceShape) {
super(name, false, URI.file(appender.file), proxy);
constructor(name: string, appender: OutputAppender, extensionId: string, proxy: MainThreadOutputServiceShape) {
super(name, false, URI.file(appender.file), extensionId, proxy);
this._appender = appender;
}
@@ -95,17 +96,17 @@ export class ExtHostOutputService2 extends ExtHostOutputService {
}
}
override createOutputChannel(name: string): vscode.OutputChannel {
override createOutputChannel(name: string, extension: IExtensionDescription): vscode.OutputChannel {
name = name.trim();
if (!name) {
throw new Error('illegal argument `name`. must not be falsy');
}
const extHostOutputChannel = this._doCreateOutChannel(name);
const extHostOutputChannel = this._doCreateOutChannel(name, extension);
extHostOutputChannel.then(channel => channel._id.then(id => this._channels.set(id, channel)));
return new LazyOutputChannel(name, extHostOutputChannel);
}
private async _doCreateOutChannel(name: string): Promise<AbstractExtHostOutputChannel> {
private async _doCreateOutChannel(name: string, extension: IExtensionDescription): Promise<AbstractExtHostOutputChannel> {
try {
const outputDirPath = join(this._logsLocation.fsPath, `output_logging_${toLocalISOString(new Date()).replace(/-|:|\.\d+Z$/g, '')}`);
const exists = await SymlinkSupport.existsDirectory(outputDirPath);
@@ -115,11 +116,11 @@ export class ExtHostOutputService2 extends ExtHostOutputService {
const fileName = `${this._namePool++}-${name.replace(/[\\/:\*\?"<>\|]/g, '')}`;
const file = URI.file(join(outputDirPath, `${fileName}.log`));
const appender = await OutputAppender.create(fileName, file.fsPath);
return new ExtHostOutputChannelBackedByFile(name, appender, this._proxy);
return new ExtHostOutputChannelBackedByFile(name, appender, extension.identifier.value, this._proxy);
} catch (error) {
// Do not crash if logger cannot be created
this.logService.error(error);
return new ExtHostPushOutputChannel(name, this._proxy);
return new ExtHostPushOutputChannel(name, extension.identifier.value, this._proxy);
}
}
}

View File

@@ -4,21 +4,21 @@
*--------------------------------------------------------------------------------------------*/
import { IDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { Schemas } from 'vs/base/common/network';
import { URI } from 'vs/base/common/uri';
import * as pfs from 'vs/base/node/pfs';
import { ILogService } from 'vs/platform/log/common/log';
import { IFileQuery, IRawFileQuery, ISearchCompleteStats, isSerializedFileMatch, ISerializedSearchProgressItem, ITextQuery } from 'vs/workbench/services/search/common/search';
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
import { ExtHostSearch, reviveQuery } from 'vs/workbench/api/common/extHostSearch';
import { IURITransformerService } from 'vs/workbench/api/common/extHostUriTransformerService';
import { IFileQuery, IRawFileQuery, ISearchCompleteStats, ISerializedSearchProgressItem, isSerializedFileMatch, ITextQuery } from 'vs/workbench/services/search/common/search';
import { TextSearchManager } from 'vs/workbench/services/search/common/textSearchManager';
import { SearchService } from 'vs/workbench/services/search/node/rawSearchService';
import { RipgrepSearchProvider } from 'vs/workbench/services/search/node/ripgrepSearchProvider';
import { OutputChannel } from 'vs/workbench/services/search/node/ripgrepSearchUtils';
import type * as vscode from 'vscode';
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
import { IURITransformerService } from 'vs/workbench/api/common/extHostUriTransformerService';
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
import { ExtHostSearch, reviveQuery } from 'vs/workbench/api/common/extHostSearch';
import { Schemas } from 'vs/base/common/network';
import { NativeTextSearchManager } from 'vs/workbench/services/search/node/textSearchManager';
import { TextSearchManager } from 'vs/workbench/services/search/common/textSearchManager';
import type * as vscode from 'vscode';
export class NativeExtHostSearch extends ExtHostSearch {
@@ -42,10 +42,14 @@ export class NativeExtHostSearch extends ExtHostSearch {
}
}
override $enableExtensionHostSearch(): void {
this._registerEHSearchProviders();
}
private _registerEHSearchProviders(): void {
const outputChannel = new OutputChannel('RipgrepSearchEH', this._logService);
this.registerTextSearchProvider(Schemas.file, new RipgrepSearchProvider(outputChannel));
this.registerInternalFileSearchProvider(Schemas.file, new SearchService());
this.registerInternalFileSearchProvider(Schemas.file, new SearchService('fileSearchProvider'));
}
private registerInternalFileSearchProvider(scheme: string, provider: SearchService): IDisposable {
@@ -100,6 +104,6 @@ export class NativeExtHostSearch extends ExtHostSearch {
}
protected override createTextSearchManager(query: ITextQuery, provider: vscode.TextSearchProvider): TextSearchManager {
return new NativeTextSearchManager(query, provider);
return new NativeTextSearchManager(query, provider, undefined, 'textSearchProvider');
}
}

View File

@@ -0,0 +1,289 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as fs from 'fs';
import * as path from 'path';
import { URI } from 'vs/base/common/uri';
import { ExtensionStoragePaths as CommonExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths';
import { Disposable } from 'vs/base/common/lifecycle';
import { Schemas } from 'vs/base/common/network';
import { IntervalTimer, timeout } from 'vs/base/common/async';
import { ILogService } from 'vs/platform/log/common/log';
export class ExtensionStoragePaths extends CommonExtensionStoragePaths {
private _workspaceStorageLock: Lock | null = null;
protected override async _getWorkspaceStorageURI(storageName: string): Promise<URI> {
const workspaceStorageURI = await super._getWorkspaceStorageURI(storageName);
if (workspaceStorageURI.scheme !== Schemas.file) {
return workspaceStorageURI;
}
if (this._environment.skipWorkspaceStorageLock) {
this._logService.info(`Skipping acquiring lock for ${workspaceStorageURI.fsPath}.`);
return workspaceStorageURI;
}
const workspaceStorageBase = workspaceStorageURI.fsPath;
let attempt = 0;
do {
let workspaceStoragePath: string;
if (attempt === 0) {
workspaceStoragePath = workspaceStorageBase;
} else {
workspaceStoragePath = (
/[/\\]$/.test(workspaceStorageBase)
? `${workspaceStorageBase.substr(0, workspaceStorageBase.length - 1)}-${attempt}`
: `${workspaceStorageBase}-${attempt}`
);
}
await mkdir(workspaceStoragePath);
const lockfile = path.join(workspaceStoragePath, 'vscode.lock');
const lock = await tryAcquireLock(this._logService, lockfile, false);
if (lock) {
this._workspaceStorageLock = lock;
process.on('exit', () => {
lock.dispose();
});
return URI.file(workspaceStoragePath);
}
attempt++;
} while (attempt < 10);
// just give up
return workspaceStorageURI;
}
override onWillDeactivateAll(): void {
// the lock will be released soon
if (this._workspaceStorageLock) {
this._workspaceStorageLock.setWillRelease(6000);
}
}
}
async function mkdir(dir: string): Promise<void> {
try {
await fs.promises.stat(dir);
return;
} catch {
// doesn't exist, that's OK
}
try {
await fs.promises.mkdir(dir, { recursive: true });
} catch {
}
}
const MTIME_UPDATE_TIME = 1000; // 1s
const STALE_LOCK_TIME = 10 * 60 * 1000; // 10 minutes
class Lock extends Disposable {
private readonly _timer: IntervalTimer;
constructor(
private readonly logService: ILogService,
private readonly filename: string
) {
super();
this._timer = this._register(new IntervalTimer());
this._timer.cancelAndSet(async () => {
const contents = await readLockfileContents(logService, filename);
if (!contents || contents.pid !== process.pid) {
// we don't hold the lock anymore ...
logService.info(`Lock '${filename}': The lock was lost unexpectedly.`);
this._timer.cancel();
}
try {
await fs.promises.utimes(filename, new Date(), new Date());
} catch (err) {
logService.error(err);
logService.info(`Lock '${filename}': Could not update mtime.`);
}
}, MTIME_UPDATE_TIME);
}
public override dispose(): void {
super.dispose();
try { fs.unlinkSync(this.filename); } catch (err) { }
}
public async setWillRelease(timeUntilReleaseMs: number): Promise<void> {
this.logService.info(`Lock '${this.filename}': Marking the lockfile as scheduled to be released in ${timeUntilReleaseMs} ms.`);
try {
const contents: ILockfileContents = {
pid: process.pid,
willReleaseAt: Date.now() + timeUntilReleaseMs
};
await fs.promises.writeFile(this.filename, JSON.stringify(contents), { flag: 'w' });
} catch (err) {
this.logService.error(err);
}
}
}
/**
* Attempt to acquire a lock on a directory.
* This does not use the real `flock`, but uses a file.
* @returns a disposable if the lock could be acquired or null if it could not.
*/
async function tryAcquireLock(logService: ILogService, filename: string, isSecondAttempt: boolean): Promise<Lock | null> {
try {
const contents: ILockfileContents = {
pid: process.pid,
willReleaseAt: 0
};
await fs.promises.writeFile(filename, JSON.stringify(contents), { flag: 'wx' });
} catch (err) {
logService.error(err);
}
// let's see if we got the lock
const contents = await readLockfileContents(logService, filename);
if (!contents || contents.pid !== process.pid) {
// we didn't get the lock
if (isSecondAttempt) {
logService.info(`Lock '${filename}': Could not acquire lock, giving up.`);
return null;
}
logService.info(`Lock '${filename}': Could not acquire lock, checking if the file is stale.`);
return checkStaleAndTryAcquireLock(logService, filename);
}
// we got the lock
logService.info(`Lock '${filename}': Lock acquired.`);
return new Lock(logService, filename);
}
interface ILockfileContents {
pid: number;
willReleaseAt: number | undefined;
}
/**
* @returns 0 if the pid cannot be read
*/
async function readLockfileContents(logService: ILogService, filename: string): Promise<ILockfileContents | null> {
let contents: Buffer;
try {
contents = await fs.promises.readFile(filename);
} catch (err) {
// cannot read the file
logService.error(err);
return null;
}
try {
return JSON.parse(String(contents));
} catch (err) {
// cannot parse the file
logService.error(err);
return null;
}
}
/**
* @returns 0 if the mtime cannot be read
*/
async function readmtime(logService: ILogService, filename: string): Promise<number> {
let stats: fs.Stats;
try {
stats = await fs.promises.stat(filename);
} catch (err) {
// cannot read the file stats to check if it is stale or not
logService.error(err);
return 0;
}
return stats.mtime.getTime();
}
function processExists(pid: number): boolean {
try {
process.kill(pid, 0); // throws an exception if the process doesn't exist anymore.
return true;
} catch (e) {
return false;
}
}
async function checkStaleAndTryAcquireLock(logService: ILogService, filename: string): Promise<Lock | null> {
const contents = await readLockfileContents(logService, filename);
if (!contents) {
logService.info(`Lock '${filename}': Could not read pid of lock holder.`);
return tryDeleteAndAcquireLock(logService, filename);
}
if (contents.willReleaseAt) {
let timeUntilRelease = contents.willReleaseAt - Date.now();
if (timeUntilRelease < 5000) {
if (timeUntilRelease > 0) {
logService.info(`Lock '${filename}': The lockfile is scheduled to be released in ${timeUntilRelease} ms.`);
} else {
logService.info(`Lock '${filename}': The lockfile is scheduled to have been released.`);
}
while (timeUntilRelease > 0) {
await timeout(Math.min(100, timeUntilRelease));
const mtime = await readmtime(logService, filename);
if (mtime === 0) {
// looks like the lock was released
return tryDeleteAndAcquireLock(logService, filename);
}
timeUntilRelease = contents.willReleaseAt - Date.now();
}
return tryDeleteAndAcquireLock(logService, filename);
}
}
if (!processExists(contents.pid)) {
logService.info(`Lock '${filename}': The pid ${contents.pid} appears to be gone.`);
return tryDeleteAndAcquireLock(logService, filename);
}
const mtime1 = await readmtime(logService, filename);
const elapsed1 = Date.now() - mtime1;
if (elapsed1 <= STALE_LOCK_TIME) {
// the lock does not look stale
logService.info(`Lock '${filename}': The lock does not look stale, elapsed: ${elapsed1} ms, giving up.`);
return null;
}
// the lock holder updates the mtime every 1s.
// let's give it a chance to update the mtime
// in case of a wake from sleep or something similar
logService.info(`Lock '${filename}': The lock looks stale, waiting for 2s.`);
await timeout(2000);
const mtime2 = await readmtime(logService, filename);
const elapsed2 = Date.now() - mtime2;
if (elapsed2 <= STALE_LOCK_TIME) {
// the lock does not look stale
logService.info(`Lock '${filename}': The lock does not look stale, elapsed: ${elapsed2} ms, giving up.`);
return null;
}
// the lock looks stale
logService.info(`Lock '${filename}': The lock looks stale even after waiting for 2s.`);
return tryDeleteAndAcquireLock(logService, filename);
}
async function tryDeleteAndAcquireLock(logService: ILogService, filename: string): Promise<Lock | null> {
logService.info(`Lock '${filename}': Deleting a stale lock.`);
try {
await fs.promises.unlink(filename);
} catch (err) {
// cannot delete the file
// maybe the file is already deleted
}
return tryAcquireLock(logService, filename, true);
}

View File

@@ -14,7 +14,7 @@ import * as tasks from '../common/shared/tasks';
import { ExtHostVariableResolverService } from 'vs/workbench/api/common/extHostDebugService';
import { IExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
import { IExtHostConfiguration } from 'vs/workbench/api/common/extHostConfiguration';
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { IWorkspaceFolder, WorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { IExtHostTerminalService } from 'vs/workbench/api/common/extHostTerminalService';
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
@@ -24,6 +24,8 @@ import { Schemas } from 'vs/base/common/network';
import { ILogService } from 'vs/platform/log/common/log';
import { IExtHostApiDeprecationService } from 'vs/workbench/api/common/extHostApiDeprecationService';
import { IExtHostEditorTabs } from 'vs/workbench/api/common/extHostEditorTabs';
import * as resources from 'vs/base/common/resources';
import { homedir } from 'os';
export class ExtHostTask extends ExtHostTaskBase {
private _variableResolver: ExtHostVariableResolverService | undefined;
@@ -37,7 +39,7 @@ export class ExtHostTask extends ExtHostTaskBase {
@IExtHostTerminalService extHostTerminalService: IExtHostTerminalService,
@ILogService logService: ILogService,
@IExtHostApiDeprecationService deprecationService: IExtHostApiDeprecationService,
@IExtHostEditorTabs private readonly editorTabs: IExtHostEditorTabs
@IExtHostEditorTabs private readonly editorTabs: IExtHostEditorTabs,
) {
super(extHostRpc, initData, workspaceService, editorService, configurationService, extHostTerminalService, logService, deprecationService);
if (initData.remote.isRemote && initData.remote.authority) {
@@ -134,6 +136,22 @@ export class ExtHostTask extends ExtHostTaskBase {
return this._variableResolver;
}
private async getAFolder(workspaceFolders: vscode.WorkspaceFolder[] | undefined): Promise<IWorkspaceFolder> {
let folder = (workspaceFolders && workspaceFolders.length > 0) ? workspaceFolders[0] : undefined;
if (!folder) {
const userhome = URI.file(homedir());
folder = new WorkspaceFolder({ uri: userhome, name: resources.basename(userhome), index: 0 });
}
return {
uri: folder.uri,
name: folder.name,
index: folder.index,
toResource: () => {
throw new Error('Not implemented');
}
};
}
public async $resolveVariables(uriComponents: UriComponents, toResolve: { process?: { name: string; cwd?: string; path?: string }, variables: string[] }): Promise<{ process?: string, variables: { [key: string]: string; } }> {
const uri: URI = URI.revive(uriComponents);
const result = {
@@ -141,19 +159,18 @@ export class ExtHostTask extends ExtHostTaskBase {
variables: Object.create(null)
};
const workspaceFolder = await this._workspaceProvider.resolveWorkspaceFolder(uri);
const workspaceFolders = await this._workspaceProvider.getWorkspaceFolders2();
if (!workspaceFolders || !workspaceFolder) {
throw new Error('Unexpected: Tasks can only be run in a workspace folder');
}
const workspaceFolders = (await this._workspaceProvider.getWorkspaceFolders2()) ?? [];
const resolver = await this.getVariableResolver(workspaceFolders);
const ws: IWorkspaceFolder = {
const ws: IWorkspaceFolder = workspaceFolder ? {
uri: workspaceFolder.uri,
name: workspaceFolder.name,
index: workspaceFolder.index,
toResource: () => {
throw new Error('Not implemented');
}
};
} : await this.getAFolder(workspaceFolders);
for (let variable of toResolve.variables) {
result.variables[variable] = await resolver.resolveAsync(ws, variable);
}

View File

@@ -23,7 +23,21 @@ export class ExtHostTerminalService extends BaseExtHostTerminalService {
public createTerminalFromOptions(options: vscode.TerminalOptions, internalOptions?: ITerminalInternalOptions): vscode.Terminal {
const terminal = new ExtHostTerminal(this._proxy, generateUuid(), options, options.name);
this._terminals.push(terminal);
terminal.create(options, internalOptions);
terminal.create(options, this._serializeParentTerminal(options, internalOptions));
return terminal.value;
}
private _serializeParentTerminal(options: vscode.TerminalOptions, internalOptions?: ITerminalInternalOptions): ITerminalInternalOptions {
internalOptions = internalOptions ? internalOptions : {};
if (options.location && typeof options.location === 'object' && 'parentTerminal' in options.location) {
const parentTerminal = options.location.parentTerminal;
if (parentTerminal) {
const parentExtHostTerminal = this._terminals.find(t => t.value === parentTerminal);
if (parentExtHostTerminal) {
internalOptions.resolvedExtHostIdentifier = parentExtHostTerminal._id;
}
}
}
return internalOptions;
}
}

View File

@@ -16,7 +16,7 @@ import * as types from 'vs/workbench/api/common/extHostTypes';
import { isLinux } from 'vs/base/common/platform';
import { IExtHostTunnelService, TunnelDto } from 'vs/workbench/api/common/extHostTunnelService';
import { Event, Emitter } from 'vs/base/common/event';
import { TunnelOptions, TunnelCreationOptions, ProvidedPortAttributes, ProvidedOnAutoForward } from 'vs/platform/remote/common/tunnel';
import { TunnelOptions, TunnelCreationOptions, ProvidedPortAttributes, ProvidedOnAutoForward, isLocalhost, isAllInterfaces } from 'vs/platform/remote/common/tunnel';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { MovingAverage } from 'vs/base/common/numbers';
import { CandidatePort } from 'vs/workbench/services/remote/common/remoteExplorerService';
@@ -270,7 +270,7 @@ export class ExtHostTunnelService extends Disposable implements IExtHostTunnelSe
let oldPorts: { host: string, port: number, detail?: string }[] | undefined = undefined;
while (this._candidateFindingEnabled) {
const startTime = new Date().getTime();
const newPorts = await this.findCandidatePorts();
const newPorts = (await this.findCandidatePorts()).filter(candidate => (isLocalhost(candidate.host) || isAllInterfaces(candidate.host)));
this.logService.trace(`ForwardedPorts: (ExtHostTunnelService) found candidate ports ${newPorts.map(port => port.port).join(', ')}`);
const timeTaken = new Date().getTime() - startTime;
movingAverage.update(timeTaken);

View File

@@ -6,6 +6,7 @@
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { ILogService } from 'vs/platform/log/common/log';
import { IExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService';
import { ExtensionStoragePaths, IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths';
import { ExtHostExtensionService } from 'vs/workbench/api/worker/extHostExtensionService';
import { ExtHostLogService } from 'vs/workbench/api/worker/extHostLogService';
@@ -17,3 +18,4 @@ import { ExtHostLogService } from 'vs/workbench/api/worker/extHostLogService';
registerSingleton(IExtHostExtensionService, ExtHostExtensionService);
registerSingleton(ILogService, ExtHostLogService);
registerSingleton(IExtensionStoragePaths, ExtensionStoragePaths);

View File

@@ -12,6 +12,7 @@ import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensio
import { ExtensionRuntime } from 'vs/workbench/api/common/extHostTypes';
import { timeout } from 'vs/base/common/async';
import { MainContext, MainThreadConsoleShape } from 'vs/workbench/api/common/extHost.protocol';
import { FileAccess } from 'vs/base/common/network';
namespace TrustedFunction {
@@ -91,7 +92,7 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService {
if (extensionId) {
performance.mark(`code/extHost/willFetchExtensionCode/${extensionId.value}`);
}
const response = await fetch(module.toString(true));
const response = await fetch(FileAccess.asBrowserUri(module).toString(true));
if (extensionId) {
performance.mark(`code/extHost/didFetchExtensionCode/${extensionId.value}`);
}