Merge from vscode 2c306f762bf9c3db82dc06c7afaa56ef46d72f79 (#14050)

* Merge from vscode 2c306f762bf9c3db82dc06c7afaa56ef46d72f79

* Fix breaks

* Extension management fixes

* Fix breaks in windows bundling

* Fix/skip failing tests

* Update distro

* Add clear to nuget.config

* Add hygiene task

* Bump distro

* Fix hygiene issue

* Add build to hygiene exclusion

* Update distro

* Update hygiene

* Hygiene exclusions

* Update tsconfig

* Bump distro for server breaks

* Update build config

* Update darwin path

* Add done calls to notebook tests

* Skip failing tests

* Disable smoke tests
This commit is contained in:
Karl Burtram
2021-02-09 16:15:05 -08:00
committed by GitHub
parent 6f192f9af5
commit ce612a3d96
1929 changed files with 68012 additions and 34564 deletions

View File

@@ -6,7 +6,7 @@
import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
import { Registry } from 'vs/platform/registry/common/platform';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
// --- other interested parties
import { JSONValidationExtensionPoint } from 'vs/workbench/api/common/jsonValidationExtensionPoint';
@@ -64,6 +64,7 @@ import './mainThreadLabelService';
import './mainThreadTunnelService';
import './mainThreadAuthentication';
import './mainThreadTimeline';
import './mainThreadTesting';
import 'vs/workbench/api/common/apiCommands';
export class ExtensionPoints implements IWorkbenchContribution {

View File

@@ -10,17 +10,19 @@ import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { IAuthenticationService, AllowedExtension, readAllowedExtensions, getAuthenticationProviderActivationEvent } from 'vs/workbench/services/authentication/browser/authenticationService';
import { ExtHostAuthenticationShape, ExtHostContext, IExtHostContext, MainContext, MainThreadAuthenticationShape } from '../common/extHost.protocol';
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import Severity from 'vs/base/common/severity';
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { IStorageKeysSyncRegistryService } from 'vs/platform/userDataSync/common/storageKeys';
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
import { fromNow } from 'vs/base/common/date';
import { ActivationKind, IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { Platform, platform } from 'vs/base/common/platform';
import { isWeb } from 'vs/base/common/platform';
import { IEncryptionService } from 'vs/workbench/services/encryption/common/encryptionService';
import { IProductService } from 'vs/platform/product/common/productService';
import { ICredentialsService } from 'vs/workbench/services/credentials/common/credentials';
const VSO_ALLOWED_EXTENSIONS = ['github.vscode-pull-request-github', 'github.vscode-pull-request-github-insiders', 'vscode.git', 'ms-vsonline.vsonline', 'vscode.github-browser', 'ms-vscode.github-browser'];
const VSO_ALLOWED_EXTENSIONS = ['github.vscode-pull-request-github', 'github.vscode-pull-request-github-insiders', 'vscode.git', 'ms-vsonline.vsonline', 'vscode.github-browser', 'ms-vscode.github-browser', 'github.codespaces'];
interface IAccountUsage {
extensionId: string;
@@ -67,7 +69,7 @@ function addAccountUsage(storageService: IStorageService, providerId: string, ac
});
}
storageService.store(accountKey, JSON.stringify(usages), StorageScope.GLOBAL);
storageService.store(accountKey, JSON.stringify(usages), StorageScope.GLOBAL, StorageTarget.MACHINE);
}
export class MainThreadAuthenticationProvider extends Disposable {
@@ -80,7 +82,6 @@ export class MainThreadAuthenticationProvider extends Disposable {
public readonly label: string,
public readonly supportsMultipleAccounts: boolean,
private readonly notificationService: INotificationService,
private readonly storageKeysSyncRegistryService: IStorageKeysSyncRegistryService,
private readonly storageService: IStorageService,
private readonly quickInputService: IQuickInputService,
private readonly dialogService: IDialogService
@@ -97,9 +98,15 @@ export class MainThreadAuthenticationProvider extends Disposable {
}
public manageTrustedExtensions(accountName: string) {
const allowedExtensions = readAllowedExtensions(this.storageService, this.id, accountName);
if (!allowedExtensions.length) {
this.dialogService.show(Severity.Info, nls.localize('noTrustedExtensions', "This account has not been used by any extensions."), []);
return;
}
const quickPick = this.quickInputService.createQuickPick<{ label: string, description: string, extension: AllowedExtension }>();
quickPick.canSelectMany = true;
const allowedExtensions = readAllowedExtensions(this.storageService, this.id, accountName);
const usages = readAccountUsages(this.storageService, this.id, accountName);
const items = allowedExtensions.map(extension => {
const usage = usages.find(usage => extension.id === usage.extensionId);
@@ -119,7 +126,7 @@ export class MainThreadAuthenticationProvider extends Disposable {
quickPick.onDidAccept(() => {
const updatedAllowedList = quickPick.selectedItems.map(item => item.extension);
this.storageService.store(`${this.id}-${accountName}`, JSON.stringify(updatedAllowedList), StorageScope.GLOBAL);
this.storageService.store(`${this.id}-${accountName}`, JSON.stringify(updatedAllowedList), StorageScope.GLOBAL, StorageTarget.USER);
quickPick.dispose();
});
@@ -150,8 +157,6 @@ export class MainThreadAuthenticationProvider extends Disposable {
} else {
this._accounts.set(session.account.label, [session.id]);
}
this.storageKeysSyncRegistryService.registerStorageKey({ key: `${this.id}-${session.account.label}`, version: 1 });
}
async signOut(accountName: string): Promise<void> {
@@ -168,6 +173,7 @@ export class MainThreadAuthenticationProvider extends Disposable {
if (result.confirmed) {
sessionsForAccount?.forEach(sessionId => this.logout(sessionId));
removeAccountUsage(this.storageService, this.id, accountName);
this.storageService.remove(`${this.id}-${accountName}`, StorageScope.GLOBAL);
}
}
@@ -217,10 +223,12 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
@IDialogService private readonly dialogService: IDialogService,
@IStorageService private readonly storageService: IStorageService,
@INotificationService private readonly notificationService: INotificationService,
@IStorageKeysSyncRegistryService private readonly storageKeysSyncRegistryService: IStorageKeysSyncRegistryService,
@IRemoteAgentService private readonly remoteAgentService: IRemoteAgentService,
@IQuickInputService private readonly quickInputService: IQuickInputService,
@IExtensionService private readonly extensionService: IExtensionService
@IExtensionService private readonly extensionService: IExtensionService,
@ICredentialsService private readonly credentialsService: ICredentialsService,
@IEncryptionService private readonly encryptionService: IEncryptionService,
@IProductService private readonly productService: IProductService
) {
super();
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostAuthentication);
@@ -242,6 +250,13 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
this._register(this.authenticationService.onDidChangeDeclaredProviders(e => {
this._proxy.$setProviders(e);
}));
// {{SQL CARBON EDIT}} - avoid null reference exception
if (this.credentialsService.onDidChangePassword) {
this._register(this.credentialsService.onDidChangePassword(_ => {
this._proxy.$onDidChangePassword();
}));
}
}
$getProviderIds(): Promise<string[]> {
@@ -249,7 +264,7 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
}
async $registerAuthenticationProvider(id: string, label: string, supportsMultipleAccounts: boolean): Promise<void> {
const provider = new MainThreadAuthenticationProvider(this._proxy, id, label, supportsMultipleAccounts, this.notificationService, this.storageKeysSyncRegistryService, this.storageService, this.quickInputService, this.dialogService);
const provider = new MainThreadAuthenticationProvider(this._proxy, id, label, supportsMultipleAccounts, this.notificationService, this.storageService, this.quickInputService, this.dialogService);
await provider.initialize();
this.authenticationService.registerAuthenticationProvider(id, provider);
}
@@ -373,10 +388,10 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
const allowList = readAllowedExtensions(this.storageService, providerId, accountName);
if (!allowList.find(allowed => allowed.id === extensionId)) {
allowList.push({ id: extensionId, name: extensionName });
this.storageService.store(`${providerId}-${accountName}`, JSON.stringify(allowList), StorageScope.GLOBAL);
this.storageService.store(`${providerId}-${accountName}`, JSON.stringify(allowList), StorageScope.GLOBAL, StorageTarget.USER);
}
this.storageService.store(`${extensionName}-${providerId}`, session.id, StorageScope.GLOBAL);
this.storageService.store(`${extensionName}-${providerId}`, session.id, StorageScope.GLOBAL, StorageTarget.MACHINE);
quickPick.dispose();
resolve(session);
@@ -405,7 +420,7 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
const remoteConnection = this.remoteAgentService.getConnection();
const isVSO = remoteConnection !== null
? remoteConnection.remoteAuthority.startsWith('vsonline')
: platform === Platform.Web;
: isWeb;
if (isVSO && VSO_ALLOWED_EXTENSIONS.includes(extensionId)) {
addAccountUsage(this.storageService, providerId, accountName, extensionId, extensionName);
@@ -425,7 +440,7 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
if (allow) {
addAccountUsage(this.storageService, providerId, accountName, extensionId, extensionName);
allowList.push({ id: extensionId, name: extensionName });
this.storageService.store(`${providerId}-${accountName}`, JSON.stringify(allowList), StorageScope.GLOBAL);
this.storageService.store(`${providerId}-${accountName}`, JSON.stringify(allowList), StorageScope.GLOBAL, StorageTarget.USER);
}
return allow;
@@ -448,9 +463,52 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
const allowList = readAllowedExtensions(this.storageService, providerId, accountName);
if (!allowList.find(allowed => allowed.id === extensionId)) {
allowList.push({ id: extensionId, name: extensionName });
this.storageService.store(`${providerId}-${accountName}`, JSON.stringify(allowList), StorageScope.GLOBAL);
this.storageService.store(`${providerId}-${accountName}`, JSON.stringify(allowList), StorageScope.GLOBAL, StorageTarget.USER);
}
this.storageService.store(`${extensionName}-${providerId}`, sessionId, StorageScope.GLOBAL);
this.storageService.store(`${extensionName}-${providerId}`, sessionId, StorageScope.GLOBAL, StorageTarget.MACHINE);
addAccountUsage(this.storageService, providerId, accountName, extensionId, extensionName);
}
private getFullKey(extensionId: string): string {
return `${this.productService.urlProtocol}${extensionId}`;
}
async $getPassword(extensionId: string, key: string): Promise<string | undefined> {
const fullKey = this.getFullKey(extensionId);
const password = await this.credentialsService.getPassword(fullKey, key);
const decrypted = password && await this.encryptionService.decrypt(password);
if (decrypted) {
try {
const value = JSON.parse(decrypted);
if (value.extensionId === extensionId) {
return value.content;
}
} catch (_) {
throw new Error('Cannot get password');
}
}
return undefined;
}
async $setPassword(extensionId: string, key: string, value: string): Promise<void> {
const fullKey = this.getFullKey(extensionId);
const toEncrypt = JSON.stringify({
extensionId,
content: value
});
const encrypted = await this.encryptionService.encrypt(toEncrypt);
return this.credentialsService.setPassword(fullKey, key, encrypted);
}
async $deletePassword(extensionId: string, key: string): Promise<void> {
try {
const fullKey = this.getFullKey(extensionId);
await this.credentialsService.deletePassword(fullKey, key);
} catch (_) {
throw new Error('Cannot delete password');
}
}
}

View File

@@ -37,8 +37,8 @@ export class MainThreadBulkEdits implements MainThreadBulkEditsShape {
dispose(): void { }
$tryApplyWorkspaceEdit(dto: IWorkspaceEditDto): Promise<boolean> {
$tryApplyWorkspaceEdit(dto: IWorkspaceEditDto, undoRedoGroupId?: number): Promise<boolean> {
const edits = reviveWorkspaceEditDto2(dto);
return this._bulkEditService.apply(edits).then(() => true, _err => false);
return this._bulkEditService.apply(edits, { undoRedoGroupId }).then(() => true, _err => false);
}
}

View File

@@ -14,7 +14,7 @@ import { IActiveCodeEditor, IViewZone } from 'vs/editor/browser/editorBrowser';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { isEqual } from 'vs/base/common/resources';
// todo@joh move these things back into something like contrib/insets
// todo@jrieken move these things back into something like contrib/insets
class EditorWebviewZone implements IViewZone {
readonly domNode: HTMLElement;
@@ -73,7 +73,7 @@ export class MainThreadEditorInsets implements MainThreadEditorInsetsShape {
async $createEditorInset(handle: number, id: string, uri: UriComponents, line: number, height: number, options: modes.IWebviewOptions, extensionId: ExtensionIdentifier, extensionLocation: UriComponents): Promise<void> {
let editor: IActiveCodeEditor | undefined;
id = id.substr(0, id.indexOf(',')); //todo@joh HACK
id = id.substr(0, id.indexOf(',')); //todo@jrieken HACK
for (const candidate of this._editorService.listCodeEditors()) {
if (candidate.getId() === id && candidate.hasModel() && isEqual(candidate.getModel().uri, URI.revive(uri))) {

View File

@@ -34,23 +34,23 @@ export class MainThreadCommands implements MainThreadCommandsShape {
this._generateCommandsDocumentationRegistration.dispose();
}
private _generateCommandsDocumentation(): Promise<void> {
return this._proxy.$getContributedCommandHandlerDescriptions().then(result => {
// add local commands
const commands = CommandsRegistry.getCommands();
for (const [id, command] of commands) {
if (command.description) {
result[id] = command.description;
}
}
private async _generateCommandsDocumentation(): Promise<void> {
const result = await this._proxy.$getContributedCommandHandlerDescriptions();
// print all as markdown
const all: string[] = [];
for (let id in result) {
all.push('`' + id + '` - ' + _generateMarkdown(result[id]));
// add local commands
const commands = CommandsRegistry.getCommands();
for (const [id, command] of commands) {
if (command.description) {
result[id] = command.description;
}
console.log(all.join('\n'));
});
}
// print all as markdown
const all: string[] = [];
for (let id in result) {
all.push('`' + id + '` - ' + _generateMarkdown(result[id]));
}
console.log(all.join('\n'));
}
$registerCommand(id: string): void {

View File

@@ -21,6 +21,8 @@ import { ViewContainer, IViewContainersRegistry, Extensions as ViewExtensions, V
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneContainer';
import { Codicon } from 'vs/base/common/codicons';
import { registerIcon } from 'vs/platform/theme/common/iconRegistry';
import { localize } from 'vs/nls';
export class MainThreadCommentThread implements modes.CommentThread {
@@ -84,6 +86,17 @@ export class MainThreadCommentThread implements modes.CommentThread {
return this._range;
}
private readonly _onDidChangeCanReply = new Emitter<boolean>();
get onDidChangeCanReply(): Event<boolean> { return this._onDidChangeCanReply.event; }
set canReply(state: boolean) {
this._canReply = state;
this._onDidChangeCanReply.fire(this._canReply);
}
get canReply() {
return this._canReply;
}
private readonly _onDidChangeRange = new Emitter<IRange>();
public onDidChangeRange = this._onDidChangeRange.event;
@@ -112,7 +125,8 @@ export class MainThreadCommentThread implements modes.CommentThread {
public extensionId: string,
public threadId: string,
public resource: string,
private _range: IRange
private _range: IRange,
private _canReply: boolean
) {
this._isDisposed = false;
}
@@ -126,6 +140,7 @@ export class MainThreadCommentThread implements modes.CommentThread {
if (modified('contextValue')) { this._contextValue = changes.contextValue; }
if (modified('comments')) { this._comments = changes.comments; }
if (modified('collapseState')) { this._collapsibleState = changes.collapseState; }
if (modified('canReply')) { this.canReply = changes.canReply!; }
}
dispose() {
@@ -214,7 +229,8 @@ export class MainThreadCommentController {
extensionId,
threadId,
URI.revive(resource).toString(),
range
range,
true
);
this._threads.set(commentThreadHandle, thread);
@@ -337,6 +353,9 @@ export class MainThreadCommentController {
}
}
const commentsViewIcon = registerIcon('comments-view-icon', Codicon.commentDiscussion, localize('commentsViewIcon', 'View icon of the comments view.'));
@extHostNamedCustomer(MainContext.MainThreadComments)
export class MainThreadComments extends Disposable implements MainThreadCommentsShape {
private readonly _proxy: ExtHostCommentsShape;
@@ -458,7 +477,7 @@ export class MainThreadComments extends Disposable implements MainThreadComments
ctorDescriptor: new SyncDescriptor(ViewPaneContainer, [COMMENTS_VIEW_ID, { mergeViewWithContainerWhenSingleView: true, donotShowContainerTitleWhenMergedWithContainer: true }]),
storageId: COMMENTS_VIEW_TITLE,
hideIfEmpty: true,
icon: Codicon.commentDiscussion.classNames,
icon: commentsViewIcon,
order: 10,
}, ViewContainerLocation.Panel);
@@ -468,7 +487,7 @@ export class MainThreadComments extends Disposable implements MainThreadComments
canToggleVisibility: false,
ctorDescriptor: new SyncDescriptor(CommentsPanel),
canMoveView: true,
containerIcon: Codicon.commentDiscussion.classNames,
containerIcon: commentsViewIcon,
focusCommand: {
id: 'workbench.action.focusCommentsPanel'
}

View File

@@ -11,6 +11,7 @@ import { Disposable, DisposableStore, IDisposable, IReference } from 'vs/base/co
import { Schemas } from 'vs/base/common/network';
import { basename } from 'vs/base/common/path';
import { isEqual, isEqualOrParent, toLocalResource } from 'vs/base/common/resources';
import { multibyteAwareBtoa } from 'vs/base/browser/dom';
import { URI, UriComponents } from 'vs/base/common/uri';
import * as modes from 'vs/editor/common/modes';
import { localize } from 'vs/nls';
@@ -22,8 +23,7 @@ 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 } from 'vs/workbench/api/common/shared/editor';
import { IRevertOptions, ISaveOptions } from 'vs/workbench/common/editor';
import { editorGroupToViewColumn, IRevertOptions, ISaveOptions } from 'vs/workbench/common/editor';
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';
@@ -346,10 +346,12 @@ class MainThreadCustomEditorModel extends Disposable implements ICustomEditorMod
}
private static toWorkingCopyResource(viewType: string, resource: URI) {
const authority = viewType.replace(/[^a-z0-9\-_]/gi, '-');
const path = `/${multibyteAwareBtoa(resource.with({ query: null, fragment: null }).toString(true))}`;
return URI.from({
scheme: Schemas.vscodeCustomEditor,
authority: viewType,
path: resource.path,
authority: authority,
path: path,
query: JSON.stringify(resource.toJSON()),
});
}
@@ -359,7 +361,7 @@ class MainThreadCustomEditorModel extends Disposable implements ICustomEditorMod
}
public get capabilities(): WorkingCopyCapabilities {
return WorkingCopyCapabilities.None;
return this.isUntitled() ? WorkingCopyCapabilities.Untitled : WorkingCopyCapabilities.None;
}
public isDirty(): boolean {
@@ -372,6 +374,10 @@ class MainThreadCustomEditorModel extends Disposable implements ICustomEditorMod
return this._fromBackup;
}
private isUntitled() {
return this._editorResource.scheme === Schemas.untitled;
}
private readonly _onDidChangeDirty: Emitter<void> = this._register(new Emitter<void>());
readonly onDidChangeDirty: Event<void> = this._onDidChangeDirty.event;
@@ -501,7 +507,7 @@ class MainThreadCustomEditorModel extends Disposable implements ICustomEditorMod
return undefined;
}
if (this._editorResource.scheme === Schemas.untitled) {
if (this.isUntitled()) {
const targetUri = await this.suggestUntitledSavePath(options);
if (!targetUri) {
return undefined;
@@ -515,28 +521,31 @@ class MainThreadCustomEditorModel extends Disposable implements ICustomEditorMod
this._ongoingSave?.cancel();
this._ongoingSave = savePromise;
this.change(() => {
this._isDirtyFromContentChange = false;
this._savePoint = this._currentEditIndex;
this._fromBackup = false;
});
try {
await savePromise;
if (this._ongoingSave === savePromise) { // Make sure we are still doing the same save
this.change(() => {
this._isDirtyFromContentChange = false;
this._savePoint = this._currentEditIndex;
this._fromBackup = false;
});
}
} finally {
if (this._ongoingSave === savePromise) {
if (this._ongoingSave === savePromise) { // Make sure we are still doing the same save
this._ongoingSave = undefined;
}
}
return this._editorResource;
}
private suggestUntitledSavePath(options: ISaveOptions | undefined): Promise<URI | undefined> {
if (this._editorResource.scheme !== Schemas.untitled) {
if (!this.isUntitled()) {
throw new Error('Resource is not untitled');
}
const remoteAuthority = this._environmentService.configuration.remoteAuthority;
const remoteAuthority = this._environmentService.remoteAuthority;
const localResource = toLocalResource(this._editorResource, remoteAuthority, this._pathService.defaultUriScheme);
return this._fileDialogService.pickFileToSave(localResource, options?.availableFileSystems);
@@ -557,7 +566,7 @@ class MainThreadCustomEditorModel extends Disposable implements ICustomEditorMod
}
}
public async backup(): Promise<IWorkingCopyBackup> {
public async backup(token: CancellationToken): Promise<IWorkingCopyBackup> {
const editors = this._getEditors();
if (!editors.length) {
throw new Error('No editors found for resource, cannot back up');
@@ -594,6 +603,10 @@ class MainThreadCustomEditorModel extends Disposable implements ICustomEditorMod
this._proxy.$backup(this._editorResource.toJSON(), this.viewType, token)));
this._hotExitState = pendingState;
token.onCancellationRequested(() => {
pendingState.operation.cancel();
});
try {
const backupId = await pendingState.operation;
// Make sure state has not changed in the meantime

View File

@@ -82,7 +82,7 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
// RPC methods (MainThreadDebugServiceShape)
public $registerDebugTypes(debugTypes: string[]) {
this._toDispose.add(this.debugService.getConfigurationManager().registerDebugAdapterFactory(debugTypes, this));
this._toDispose.add(this.debugService.getAdapterManager().registerDebugAdapterFactory(debugTypes, this));
}
public $startBreakpointEvents(): void {
@@ -138,7 +138,7 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
logMessage: l.logMessage
}
);
this.debugService.addBreakpoints(uri.revive(dto.uri), rawbps, 'extension');
this.debugService.addBreakpoints(uri.revive(dto.uri), rawbps);
} else if (dto.type === 'function') {
this.debugService.addFunctionBreakpoint(dto.functionName, dto.id);
} else if (dto.type === 'data') {
@@ -155,7 +155,7 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
return Promise.resolve();
}
public $registerDebugConfigurationProvider(debugType: string, providerTriggerKind: DebugConfigurationProviderTriggerKind, hasProvide: boolean, hasResolve: boolean, hasResolve2: boolean, hasProvideDebugAdapter: boolean, handle: number): Promise<void> {
public $registerDebugConfigurationProvider(debugType: string, providerTriggerKind: DebugConfigurationProviderTriggerKind, hasProvide: boolean, hasResolve: boolean, hasResolve2: boolean, handle: number): Promise<void> {
const provider = <IDebugConfigurationProvider>{
type: debugType,
@@ -176,12 +176,6 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
return this._proxy.$resolveDebugConfigurationWithSubstitutedVariables(handle, folder, config, token);
};
}
if (hasProvideDebugAdapter) {
console.info('DebugConfigurationProvider.debugAdapterExecutable is deprecated and will be removed soon; please use DebugAdapterDescriptorFactory.createDebugAdapterDescriptor instead.');
provider.debugAdapterExecutable = (folder) => {
return this._proxy.$legacyDebugAdapterExecutable(handle, folder);
};
}
this._debugConfigurationProviders.set(handle, provider);
this._toDispose.add(this.debugService.getConfigurationManager().registerDebugConfigurationProvider(provider));
@@ -205,7 +199,7 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
}
};
this._debugAdapterDescriptorFactories.set(handle, provider);
this._toDispose.add(this.debugService.getConfigurationManager().registerDebugAdapterDescriptorFactory(provider));
this._toDispose.add(this.debugService.getAdapterManager().registerDebugAdapterDescriptorFactory(provider));
return Promise.resolve(undefined);
}
@@ -214,7 +208,7 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
const provider = this._debugAdapterDescriptorFactories.get(handle);
if (provider) {
this._debugAdapterDescriptorFactories.delete(handle);
this.debugService.getConfigurationManager().unregisterDebugAdapterDescriptorFactory(provider);
this.debugService.getAdapterManager().unregisterDebugAdapterDescriptorFactory(provider);
}
}

View File

@@ -92,9 +92,9 @@ export class MainThreadDecorations implements MainThreadDecorationsShape {
if (!data) {
return undefined;
}
const [weight, bubble, tooltip, letter, themeColor] = data;
const [bubble, tooltip, letter, themeColor] = data;
return <IDecorationData>{
weight: weight ?? 0,
weight: 10,
bubble: bubble ?? false,
color: themeColor?.id,
tooltip,

View File

@@ -38,7 +38,8 @@ export class MainThreadDialogs implements MainThreadDiaglogsShape {
canSelectFolders: options?.canSelectFolders,
canSelectMany: options?.canSelectMany,
defaultUri: options?.defaultUri ? URI.revive(options.defaultUri) : undefined,
title: options?.title || undefined
title: options?.title || undefined,
availableFileSystems: []
};
if (options?.filters) {
result.filters = [];

View File

@@ -273,7 +273,7 @@ export class MainThreadDocuments extends Disposable implements MainThreadDocumen
}
private _handleUntitledScheme(uri: URI): Promise<URI> {
const asLocalUri = toLocalResource(uri, this._environmentService.configuration.remoteAuthority, this._pathService.defaultUriScheme);
const asLocalUri = toLocalResource(uri, this._environmentService.remoteAuthority, this._pathService.defaultUriScheme);
return this._fileService.resolve(asLocalUri).then(stats => {
// don't create a new file ontop of an existing file
return Promise.reject(new Error('file already exists'));

View File

@@ -19,7 +19,6 @@ import { MainThreadDocuments } from 'vs/workbench/api/browser/mainThreadDocument
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 { EditorViewColumn, editorGroupToViewColumn } from 'vs/workbench/api/common/shared/editor';
import { BaseTextEditor } from 'vs/workbench/browser/parts/editor/textEditor';
import { IEditorPane } from 'vs/workbench/common/editor';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
@@ -31,41 +30,9 @@ import { IWorkingCopyFileService } from 'vs/workbench/services/workingCopy/commo
import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
import { IPathService } from 'vs/workbench/services/path/common/pathService';
import { editorGroupToViewColumn, EditorViewColumn } from 'vs/workbench/api/common/shared/editor';
import { diffSets, diffMaps } from 'vs/base/common/collections';
namespace delta {
export function ofSets<T>(before: Set<T>, after: Set<T>): { removed: T[], added: T[] } {
const removed: T[] = [];
const added: T[] = [];
for (let element of before) {
if (!after.has(element)) {
removed.push(element);
}
}
for (let element of after) {
if (!before.has(element)) {
added.push(element);
}
}
return { removed, added };
}
export function ofMaps<K, V>(before: Map<K, V>, after: Map<K, V>): { removed: V[], added: V[] } {
const removed: V[] = [];
const added: V[] = [];
for (let [index, value] of before) {
if (!after.has(index)) {
removed.push(value);
}
}
for (let [index, value] of after) {
if (!before.has(index)) {
added.push(value);
}
}
return { removed, added };
}
}
class TextEditorSnapshot {
@@ -118,8 +85,8 @@ class DocumentAndEditorState {
undefined, after.activeEditor
);
}
const documentDelta = delta.ofSets(before.documents, after.documents);
const editorDelta = delta.ofMaps(before.textEditors, after.textEditors);
const documentDelta = diffSets(before.documents, after.documents);
const editorDelta = diffMaps(before.textEditors, after.textEditors);
const oldActiveEditor = before.activeEditor !== after.activeEditor ? before.activeEditor : undefined;
const newActiveEditor = before.activeEditor !== after.activeEditor ? after.activeEditor : undefined;

View File

@@ -3,7 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { localize } from 'vs/nls';
import { disposed } from 'vs/base/common/errors';
import { IDisposable, dispose, DisposableStore } from 'vs/base/common/lifecycle';
import { equals as objectEquals } from 'vs/base/common/objects';
@@ -15,18 +14,14 @@ 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 { IEditorOptions, ITextEditorOptions, IResourceEditorInput, EditorActivation } from 'vs/platform/editor/common/editor';
import { ITextEditorOptions, IResourceEditorInput, EditorActivation } from 'vs/platform/editor/common/editor';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { IOpenerService } from 'vs/platform/opener/common/opener';
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 { EditorViewColumn, editorGroupToViewColumn, viewColumnToEditorGroup } from 'vs/workbench/api/common/shared/editor';
import { editorGroupToViewColumn, EditorGroupColumn, viewColumnToEditorGroup } from 'vs/workbench/common/editor';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
import { openEditorWith } from 'vs/workbench/services/editor/common/editorOpenWith';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService';
import { revive } from 'vs/base/common/marshalling';
@@ -162,7 +157,7 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
return this._documentsAndEditors.findTextEditorIdFor(editor);
}
async $tryShowEditor(id: string, position?: EditorViewColumn): Promise<void> {
async $tryShowEditor(id: string, position?: EditorGroupColumn): Promise<void> {
const mainThreadEditor = this._documentsAndEditors.getEditor(id);
if (mainThreadEditor) {
const model = mainThreadEditor.getModel();
@@ -298,63 +293,6 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
// --- commands
CommandsRegistry.registerCommand('_workbench.open', async function (accessor: ServicesAccessor, args: [URI, IEditorOptions, EditorViewColumn, string?]) {
const editorService = accessor.get(IEditorService);
const editorGroupService = accessor.get(IEditorGroupsService);
const openerService = accessor.get(IOpenerService);
const [resource, options, position, label] = args;
if (options || typeof position === 'number') {
// use editor options or editor view column as a hint to use the editor service for opening
await editorService.openEditor({ resource, options, label }, viewColumnToEditorGroup(editorGroupService, position));
return;
}
if (resource && resource.scheme === 'command') {
// do not allow to execute commands from here
return;
}
// finally, delegate to opener service
await openerService.open(resource);
});
CommandsRegistry.registerCommand('_workbench.openWith', (accessor: ServicesAccessor, args: [URI, string, ITextEditorOptions | undefined, EditorViewColumn | undefined]) => {
const editorService = accessor.get(IEditorService);
const editorGroupsService = accessor.get(IEditorGroupsService);
const configurationService = accessor.get(IConfigurationService);
const quickInputService = accessor.get(IQuickInputService);
const [resource, id, options, position] = args;
const group = editorGroupsService.getGroup(viewColumnToEditorGroup(editorGroupsService, position)) ?? editorGroupsService.activeGroup;
const textOptions: ITextEditorOptions = options ? { ...options, override: false } : { override: false };
const input = editorService.createEditorInput({ resource });
return openEditorWith(input, id, textOptions, group, editorService, configurationService, quickInputService);
});
CommandsRegistry.registerCommand('_workbench.diff', async function (accessor: ServicesAccessor, args: [URI, URI, string, string, IEditorOptions, EditorViewColumn]) {
const editorService = accessor.get(IEditorService);
const editorGroupService = accessor.get(IEditorGroupsService);
let [leftResource, rightResource, label, description, options, position] = args;
if (!options || typeof options !== 'object') {
options = {
preserveFocus: false
};
}
if (!label) {
label = localize('diffLeftRightLabel', "{0} ⟷ {1}", leftResource.toString(true), rightResource.toString(true));
}
await editorService.openEditor({ leftResource, rightResource, label, description, options }, viewColumnToEditorGroup(editorGroupService, position));
});
CommandsRegistry.registerCommand('_workbench.revertAllDirty', async function (accessor: ServicesAccessor) {
const environmentService = accessor.get(IEnvironmentService);
if (!environmentService.extensionTestsLocationURI) {

View File

@@ -50,7 +50,7 @@ export class MainThreadExtensionService implements MainThreadExtensionServiceSha
$activateExtension(extensionId: ExtensionIdentifier, reason: ExtensionActivationReason): Promise<void> {
return this._extensionService._activateById(extensionId, reason);
}
$onWillActivateExtension(extensionId: ExtensionIdentifier): void {
async $onWillActivateExtension(extensionId: ExtensionIdentifier): Promise<void> {
this._extensionService._onWillActivateExtension(extensionId);
}
$onDidActivateExtension(extensionId: ExtensionIdentifier, codeLoadingTime: number, activateCallTime: number, activateResolvedTime: number, activationReason: ExtensionActivationReason): void {

View File

@@ -26,6 +26,9 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape {
const infoProxy = extHostContext.getProxy(ExtHostContext.ExtHostFileSystemInfo);
for (let entry of _fileService.listCapabilities()) {
infoProxy.$acceptProviderInfos(entry.scheme, entry.capabilities);
}
this._disposables.add(_fileService.onDidChangeFileSystemProviderRegistrations(e => infoProxy.$acceptProviderInfos(e.scheme, e.provider?.capabilities ?? null)));
this._disposables.add(_fileService.onDidChangeFileSystemProviderCapabilities(e => infoProxy.$acceptProviderInfos(e.scheme, e.provider.capabilities)));
}
@@ -36,7 +39,7 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape {
this._fileProvider.clear();
}
$registerFileSystemProvider(handle: number, scheme: string, capabilities: FileSystemProviderCapabilities): void {
async $registerFileSystemProvider(handle: number, scheme: string, capabilities: FileSystemProviderCapabilities): Promise<void> {
this._fileProvider.set(handle, new RemoteFileSystemProvider(this._fileService, scheme, capabilities, handle, this._proxy));
}

View File

@@ -54,11 +54,13 @@ export class MainThreadFileSystemEventService {
// BEFORE file operation
workingCopyFileService.addFileOperationParticipant({
participate: (files, operation, progress, timeout, token) => {
return proxy.$onWillRunFileOperation(operation, files, timeout, token);
this._listener.add(workingCopyFileService.addFileOperationParticipant({
participate: async (files, operation, undoRedoGroupId, isUndoing, _progress, timeout, token) => {
if (!isUndoing) {
return proxy.$onWillRunFileOperation(operation, files, undoRedoGroupId, timeout, token);
}
}
});
}));
// AFTER file operation
this._listener.add(workingCopyFileService.onDidRunWorkingCopyFileOperation(e => proxy.$onDidRunFileOperation(e.operation, e.files)));
@@ -75,7 +77,7 @@ Registry.as<IConfigurationRegistry>(Extensions.Configuration).registerConfigurat
properties: {
'files.participants.timeout': {
type: 'number',
default: 5000,
default: 60000,
markdownDescription: localize('files.participants.timeout', "Timeout in milliseconds after which file participants for create, rename, and delete are cancelled. Use `0` to disable participants."),
}
}

View File

@@ -5,7 +5,7 @@
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { MainContext, MainThreadKeytarShape, IExtHostContext } from 'vs/workbench/api/common/extHost.protocol';
import { ICredentialsService } from 'vs/platform/credentials/common/credentials';
import { ICredentialsService } from 'vs/workbench/services/credentials/common/credentials';
@extHostNamedCustomer(MainContext.MainThreadKeytar)
export class MainThreadKeytar implements MainThreadKeytarShape {

View File

@@ -166,16 +166,15 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
$registerCodeLensSupport(handle: number, selector: IDocumentFilterDto[], eventHandle: number | undefined): void {
const provider = <modes.CodeLensProvider>{
provideCodeLenses: (model: ITextModel, token: CancellationToken): Promise<modes.CodeLensList | undefined> => {
return this._proxy.$provideCodeLenses(handle, model.uri, token).then(listDto => {
if (!listDto) {
return undefined;
}
return {
lenses: listDto.lenses,
dispose: () => listDto.cacheId && this._proxy.$releaseCodeLenses(handle, listDto.cacheId)
};
});
provideCodeLenses: async (model: ITextModel, token: CancellationToken): Promise<modes.CodeLensList | undefined> => {
const listDto = await this._proxy.$provideCodeLenses(handle, model.uri, token);
if (!listDto) {
return undefined;
}
return {
lenses: listDto.lenses,
dispose: () => listDto.cacheId && this._proxy.$releaseCodeLenses(handle, listDto.cacheId)
};
},
resolveCodeLens: (_model: ITextModel, codeLens: modes.CodeLens, token: CancellationToken): Promise<modes.CodeLens | undefined> => {
return this._proxy.$resolveCodeLens(handle, codeLens, token);
@@ -262,14 +261,12 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
}));
}
// --- on type rename
// --- linked editing
$registerOnTypeRenameProvider(handle: number, selector: IDocumentFilterDto[], wordPattern?: IRegExpDto): void {
const revivedWordPattern = wordPattern ? MainThreadLanguageFeatures._reviveRegExp(wordPattern) : undefined;
this._registrations.set(handle, modes.OnTypeRenameProviderRegistry.register(selector, <modes.OnTypeRenameProvider>{
wordPattern: revivedWordPattern,
provideOnTypeRenameRanges: async (model: ITextModel, position: EditorPosition, token: CancellationToken): Promise<{ ranges: IRange[]; wordPattern?: RegExp; } | undefined> => {
const res = await this._proxy.$provideOnTypeRenameRanges(handle, model.uri, position, token);
$registerLinkedEditingRangeProvider(handle: number, selector: IDocumentFilterDto[]): void {
this._registrations.set(handle, modes.LinkedEditingRangeProviderRegistry.register(selector, <modes.LinkedEditingRangeProvider>{
provideLinkedEditingRanges: async (model: ITextModel, position: EditorPosition, token: CancellationToken): Promise<modes.LinkedEditingRanges | undefined> => {
const res = await this._proxy.$provideLinkedEditingRanges(handle, model.uri, position, token);
if (res) {
return {
ranges: res.ranges,
@@ -293,8 +290,8 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
// --- quick fix
$registerQuickFixSupport(handle: number, selector: IDocumentFilterDto[], metadata: ICodeActionProviderMetadataDto, displayName: string): void {
this._registrations.set(handle, modes.CodeActionProviderRegistry.register(selector, <modes.CodeActionProvider>{
$registerQuickFixSupport(handle: number, selector: IDocumentFilterDto[], metadata: ICodeActionProviderMetadataDto, displayName: string, supportsResolve: boolean): void {
const provider: modes.CodeActionProvider = {
provideCodeActions: async (model: ITextModel, rangeOrSelection: EditorRange | Selection, context: modes.CodeActionContext, token: CancellationToken): Promise<modes.CodeActionList | undefined> => {
const listDto = await this._proxy.$provideCodeActions(handle, model.uri, rangeOrSelection, context, token);
if (!listDto) {
@@ -312,7 +309,17 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
providedCodeActionKinds: metadata.providedKinds,
documentation: metadata.documentation,
displayName
}));
};
if (supportsResolve) {
provider.resolveCodeAction = async (codeAction: modes.CodeAction, token: CancellationToken): Promise<modes.CodeAction> => {
const data = await this._proxy.$resolveCodeAction(handle, (<ICodeActionDto>codeAction).cacheId!, token);
codeAction.edit = reviveWorkspaceEditDto(data);
return codeAction;
};
}
this._registrations.set(handle, modes.CodeActionProviderRegistry.register(selector, provider));
}
// --- formatting
@@ -432,27 +439,25 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
};
}
$registerSuggestSupport(handle: number, selector: IDocumentFilterDto[], triggerCharacters: string[], supportsResolveDetails: boolean, extensionId: ExtensionIdentifier): void {
$registerSuggestSupport(handle: number, selector: IDocumentFilterDto[], triggerCharacters: string[], supportsResolveDetails: boolean, displayName: string): void {
const provider: modes.CompletionItemProvider = {
triggerCharacters,
_debugDisplayName: extensionId.value,
provideCompletionItems: (model: ITextModel, position: EditorPosition, context: modes.CompletionContext, token: CancellationToken): Promise<modes.CompletionList | undefined> => {
return this._proxy.$provideCompletionItems(handle, model.uri, position, context, token).then(result => {
if (!result) {
// {{SQL CARBON EDIT}} @todo anthonydresser 4/12/19 required because of strict null checks
return undefined;
}
return {
suggestions: result[ISuggestResultDtoField.completions].map(d => MainThreadLanguageFeatures._inflateSuggestDto(result[ISuggestResultDtoField.defaultRanges], d)),
incomplete: result[ISuggestResultDtoField.isIncomplete] || false,
dispose: () => {
if (typeof result.x === 'number') {
this._proxy.$releaseCompletionItems(handle, result.x);
}
_debugDisplayName: displayName,
provideCompletionItems: async (model: ITextModel, position: EditorPosition, context: modes.CompletionContext, token: CancellationToken): Promise<modes.CompletionList | undefined> => {
const result = await this._proxy.$provideCompletionItems(handle, model.uri, position, context, token);
if (!result) {
return <any>result;
}
return {
suggestions: result[ISuggestResultDtoField.completions].map(d => MainThreadLanguageFeatures._inflateSuggestDto(result[ISuggestResultDtoField.defaultRanges], d)),
incomplete: result[ISuggestResultDtoField.isIncomplete] || false,
duration: result[ISuggestResultDtoField.duration],
dispose: () => {
if (typeof result.x === 'number') {
this._proxy.$releaseCompletionItems(handle, result.x);
}
};
});
}
};
}
};
if (supportsResolveDetails) {
@@ -563,13 +568,27 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
// --- folding
$registerFoldingRangeProvider(handle: number, selector: IDocumentFilterDto[]): void {
const proxy = this._proxy;
this._registrations.set(handle, modes.FoldingRangeProviderRegistry.register(selector, <modes.FoldingRangeProvider>{
$registerFoldingRangeProvider(handle: number, selector: IDocumentFilterDto[], eventHandle: number | undefined): void {
const provider = <modes.FoldingRangeProvider>{
provideFoldingRanges: (model, context, token) => {
return proxy.$provideFoldingRanges(handle, model.uri, context, token);
return this._proxy.$provideFoldingRanges(handle, model.uri, context, token);
}
}));
};
if (typeof eventHandle === 'number') {
const emitter = new Emitter<modes.FoldingRangeProvider>();
this._registrations.set(eventHandle, emitter);
provider.onDidChange = emitter.event;
}
this._registrations.set(handle, modes.FoldingRangeProviderRegistry.register(selector, provider));
}
$emitFoldingRangeEvent(eventHandle: number, event?: any): void {
const obj = this._registrations.get(eventHandle);
if (obj instanceof Emitter) {
obj.fire(event);
}
}
// -- smart select

View File

@@ -5,58 +5,36 @@
import * as DOM from 'vs/base/browser/dom';
import { CancellationToken } from 'vs/base/common/cancellation';
import { diffMaps, diffSets } from 'vs/base/common/collections';
import { Emitter } from 'vs/base/common/event';
import { combinedDisposable, Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
import { IRelativePattern } from 'vs/base/common/glob';
import { combinedDisposable, Disposable, DisposableStore, dispose, IDisposable, IReference } from 'vs/base/common/lifecycle';
import { ResourceMap } from 'vs/base/common/map';
import { Schemas } from 'vs/base/common/network';
import { IExtUri } from 'vs/base/common/resources';
import { URI, UriComponents } from 'vs/base/common/uri';
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { EditorActivation, ITextEditorOptions } from 'vs/platform/editor/common/editor';
import { ILogService } from 'vs/platform/log/common/log';
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { viewColumnToEditorGroup } from 'vs/workbench/common/editor';
import { INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
import { INotebookCellStatusBarService } from 'vs/workbench/contrib/notebook/common/notebookCellStatusBarService';
import { ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER, CellEditType, DisplayOrderKey, ICellEditOperation, ICellRange, IEditor, IMainCellDto, INotebookDocumentFilter, NotebookCellOutputsSplice, NotebookCellsChangeType, NOTEBOOK_DISPLAY_ORDER, TransientMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER, CellEditType, DisplayOrderKey, ICellEditOperation, ICellRange, IEditor, IMainCellDto, INotebookDecorationRenderOptions, INotebookDocumentFilter, INotebookEditorModel, INotebookExclusiveDocumentFilter, NotebookCellOutputsSplice, NotebookCellsChangeType, NOTEBOOK_DISPLAY_ORDER, TransientMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { INotebookEditorModelResolverService } from 'vs/workbench/contrib/notebook/common/notebookEditorModelResolverService';
import { IMainNotebookController, INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IEditorGroup, IEditorGroupsService, preferredSideBySideGroupDirection } from 'vs/workbench/services/editor/common/editorGroupsService';
import { openEditorWith } from 'vs/workbench/services/editor/common/editorOpenWith';
import { IEditorService, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService';
import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity';
import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService';
import { ExtHostContext, ExtHostNotebookShape, IExtHostContext, INotebookCellStatusBarEntryDto, INotebookDocumentsAndEditorsDelta, INotebookModelAddedData, MainContext, MainThreadNotebookShape, NotebookEditorRevealType, NotebookExtensionDescription } from '../common/extHost.protocol';
import { ExtHostContext, ExtHostNotebookShape, IExtHostContext, INotebookCellStatusBarEntryDto, INotebookDocumentsAndEditorsDelta, INotebookDocumentShowOptions, INotebookModelAddedData, MainContext, MainThreadNotebookShape, NotebookEditorRevealType, NotebookExtensionDescription } from '../common/extHost.protocol';
class DocumentAndEditorState {
static ofSets<T>(before: Set<T>, after: Set<T>): { removed: T[], added: T[] } {
const removed: T[] = [];
const added: T[] = [];
before.forEach(element => {
if (!after.has(element)) {
removed.push(element);
}
});
after.forEach(element => {
if (!before.has(element)) {
added.push(element);
}
});
return { removed, added };
}
static ofMaps<K, V>(before: Map<K, V>, after: Map<K, V>): { removed: V[], added: V[] } {
const removed: V[] = [];
const added: V[] = [];
before.forEach((value, index) => {
if (!after.has(index)) {
removed.push(value);
}
});
after.forEach((value, index) => {
if (!before.has(index)) {
added.push(value);
}
});
return { removed, added };
}
static compute(before: DocumentAndEditorState | undefined, after: DocumentAndEditorState): INotebookDocumentsAndEditorsDelta {
if (!before) {
const apiEditors = [];
@@ -71,8 +49,8 @@ class DocumentAndEditorState {
visibleEditors: [...after.visibleEditors].map(editor => editor[0])
};
}
const documentDelta = DocumentAndEditorState.ofSets(before.documents, after.documents);
const editorDelta = DocumentAndEditorState.ofMaps(before.textEditors, after.textEditors);
const documentDelta = diffSets(before.documents, after.documents);
const editorDelta = diffMaps(before.textEditors, after.textEditors);
const addedAPIEditors = editorDelta.added.map(add => ({
id: add.getId(),
documentUri: add.uri!,
@@ -85,7 +63,7 @@ class DocumentAndEditorState {
// const oldActiveEditor = before.activeEditor !== after.activeEditor ? before.activeEditor : undefined;
const newActiveEditor = before.activeEditor !== after.activeEditor ? after.activeEditor : undefined;
const visibleEditorDelta = DocumentAndEditorState.ofMaps(before.visibleEditors, after.visibleEditors);
const visibleEditorDelta = diffMaps(before.visibleEditors, after.visibleEditors);
return {
addedDocuments: documentDelta.added.map((e: NotebookTextModel): INotebookModelAddedData => {
@@ -104,6 +82,7 @@ class DocumentAndEditorState {
outputs: cell.outputs,
metadata: cell.metadata
})),
contentOptions: e.transientOptions,
// attachedEditor: editorId ? {
// id: editorId,
// selections: document.textModel.selections
@@ -140,19 +119,27 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
private _editorEventListenersMapping: Map<string, DisposableStore> = new Map();
private _documentEventListenersMapping: ResourceMap<DisposableStore> = new ResourceMap();
private readonly _cellStatusBarEntries: Map<number, IDisposable> = new Map();
private readonly _modelReferenceCollection: BoundModelReferenceCollection;
constructor(
extHostContext: IExtHostContext,
@INotebookService private _notebookService: INotebookService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@IEditorService private readonly editorService: IEditorService,
@IEditorGroupsService private readonly editorGroupsService: IEditorGroupsService,
@IEditorGroupsService private readonly _editorGroupService: IEditorGroupsService,
@IAccessibilityService private readonly accessibilityService: IAccessibilityService,
@IQuickInputService private readonly quickInputService: IQuickInputService,
@ILogService private readonly logService: ILogService,
@INotebookCellStatusBarService private readonly cellStatusBarService: INotebookCellStatusBarService,
@IWorkingCopyService private readonly _workingCopyService: IWorkingCopyService,
@INotebookEditorModelResolverService private readonly _notebookModelResolverService: INotebookEditorModelResolverService,
@IUriIdentityService private readonly _uriIdentityService: IUriIdentityService,
) {
super();
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostNotebook);
this._modelReferenceCollection = new BoundModelReferenceCollection(this._uriIdentityService.extUri);
this._register(this._modelReferenceCollection);
this.registerListeners();
}
@@ -161,8 +148,7 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
if (!textModel) {
return false;
}
this._notebookService.transformEditsOutputs(textModel, cellEdits);
return textModel.applyEdits(modelVersionId, cellEdits, true, undefined, () => undefined);
return textModel.applyEdits(modelVersionId, cellEdits, true, undefined, () => undefined, undefined);
}
private _isDeltaEmpty(delta: INotebookDocumentsAndEditorsDelta) {
@@ -403,9 +389,9 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
const editors = new Map<string, IEditor>();
this._notebookService.listNotebookEditors().forEach(editor => {
if (editor.hasModel()) {
if (editor.textModel) {
editors.set(editor.getId(), editor);
documentEditorsMap.set(editor.textModel!.uri.toString(), editor);
documentEditorsMap.set(editor.textModel.uri.toString(), editor);
}
});
@@ -424,7 +410,7 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
documents.add(document);
});
if (!activeEditor && focusedNotebookEditor && focusedNotebookEditor.hasModel()) {
if (!activeEditor && focusedNotebookEditor && focusedNotebookEditor.textModel) {
activeEditor = focusedNotebookEditor.getId();
}
@@ -443,24 +429,35 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
// }
}
async $registerNotebookProvider(extension: NotebookExtensionDescription, viewType: string, supportBackup: boolean, options: { transientOutputs: boolean; transientMetadata: TransientMetadata }): Promise<void> {
async $registerNotebookProvider(extension: NotebookExtensionDescription, viewType: string, supportBackup: boolean, options: {
transientOutputs: boolean;
transientMetadata: TransientMetadata;
viewOptions?: { displayName: string; filenamePattern: (string | IRelativePattern | INotebookExclusiveDocumentFilter)[]; exclusive: boolean; };
}): Promise<void> {
let contentOptions = { transientOutputs: options.transientOutputs, transientMetadata: options.transientMetadata };
const controller: IMainNotebookController = {
supportBackup,
options,
get options() {
return contentOptions;
},
set options(newOptions) {
contentOptions.transientMetadata = newOptions.transientMetadata;
contentOptions.transientOutputs = newOptions.transientOutputs;
},
viewOptions: options.viewOptions,
reloadNotebook: async (mainthreadTextModel: NotebookTextModel) => {
const data = await this._proxy.$resolveNotebookData(viewType, mainthreadTextModel.uri);
mainthreadTextModel.updateLanguages(data.languages);
mainthreadTextModel.metadata = data.metadata;
mainthreadTextModel.transientOptions = options;
mainthreadTextModel.transientOptions = contentOptions;
const edits: ICellEditOperation[] = [
{ editType: CellEditType.Replace, index: 0, count: mainthreadTextModel.cells.length, cells: data.cells }
];
this._notebookService.transformEditsOutputs(mainthreadTextModel, edits);
await new Promise(resolve => {
DOM.scheduleAtNextAnimationFrame(() => {
const ret = mainthreadTextModel!.applyEdits(mainthreadTextModel!.versionId, edits, true, undefined, () => undefined);
const ret = mainthreadTextModel!.applyEdits(mainthreadTextModel!.versionId, edits, true, undefined, () => undefined, undefined);
resolve(ret);
});
});
@@ -469,7 +466,7 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
const data = await this._proxy.$resolveNotebookData(viewType, uri, backupId);
return {
data,
transientOptions: options
transientOptions: contentOptions
};
},
resolveNotebookEditor: async (viewType: string, uri: URI, editorId: string) => {
@@ -494,6 +491,19 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
return;
}
async $updateNotebookProviderOptions(viewType: string, options?: { transientOutputs: boolean; transientMetadata: TransientMetadata; }): Promise<void> {
const provider = this._notebookProviders.get(viewType);
if (provider && options) {
provider.controller.options = options;
this._notebookService.listNotebookDocuments().forEach(document => {
if (document.viewType === viewType) {
document.transientOptions = provider.controller.options;
}
});
}
}
async $unregisterNotebookProvider(viewType: string): Promise<void> {
const entry = this._notebookProviders.get(viewType);
if (entry) {
@@ -570,7 +580,6 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
return;
}
this._notebookService.transformSpliceOutputs(textModel, splices);
const cell = textModel.cells.find(cell => cell.handle === cellHandle);
if (!cell) {
@@ -583,7 +592,7 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
index: textModel.cells.indexOf(cell),
splices
}
], true, undefined, () => undefined);
], true, undefined, () => undefined, undefined);
}
async $postMessage(editorId: string, forRendererId: string | undefined, value: any): Promise<boolean> {
@@ -618,7 +627,7 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
{
editType: CellEditType.Unknown
}
], true, undefined, () => undefined);
], true, undefined, () => undefined, undefined);
}
}
@@ -626,8 +635,11 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
const editor = this._notebookService.listNotebookEditors().find(editor => editor.getId() === id);
if (editor && editor.isNotebookEditor) {
const notebookEditor = editor as INotebookEditor;
if (!notebookEditor.hasModel()) {
return;
}
const viewModel = notebookEditor.viewModel;
const cell = viewModel?.viewCells[range.start];
const cell = viewModel.viewCells[range.start];
if (!cell) {
return;
}
@@ -648,6 +660,22 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
}
}
$registerNotebookEditorDecorationType(key: string, options: INotebookDecorationRenderOptions) {
this._notebookService.registerEditorDecorationType(key, options);
}
$removeNotebookEditorDecorationType(key: string) {
this._notebookService.removeEditorDecorationType(key);
}
$trySetDecorations(id: string, range: ICellRange, key: string) {
const editor = this._notebookService.listNotebookEditors().find(editor => editor.getId() === id);
if (editor && editor.isNotebookEditor) {
const notebookEditor = editor as INotebookEditor;
notebookEditor.setEditorDecorations(key, range);
}
}
async $setStatusBarEntry(id: number, rawStatusBarEntry: INotebookCellStatusBarEntryDto): Promise<void> {
const statusBarEntry = {
...rawStatusBarEntry,
@@ -665,4 +693,100 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
this.cellStatusBarService.addEntry(statusBarEntry));
}
}
async $tryOpenDocument(uriComponents: UriComponents, viewType?: string): Promise<URI> {
const uri = URI.revive(uriComponents);
const ref = await this._notebookModelResolverService.resolve(uri, viewType);
this._modelReferenceCollection.add(uri, ref);
return uri;
}
async $tryShowNotebookDocument(resource: UriComponents, viewType: string, options: INotebookDocumentShowOptions): Promise<string> {
const editorOptions: ITextEditorOptions = {
preserveFocus: options.preserveFocus,
pinned: options.pinned,
// selection: options.selection,
// 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: false,
};
const columnArg = viewColumnToEditorGroup(this._editorGroupService, options.position);
let group: IEditorGroup | undefined = undefined;
if (columnArg === SIDE_GROUP) {
const direction = preferredSideBySideGroupDirection(this.configurationService);
let neighbourGroup = this.editorGroupsService.findGroup({ direction });
if (!neighbourGroup) {
neighbourGroup = this.editorGroupsService.addGroup(this.editorGroupsService.activeGroup, direction);
}
group = neighbourGroup;
} else {
group = this.editorGroupsService.getGroup(viewColumnToEditorGroup(this.editorGroupsService, columnArg)) ?? this.editorGroupsService.activeGroup;
}
const input = this.editorService.createEditorInput({ resource: URI.revive(resource), options: editorOptions });
// TODO: handle options.selection
const editorPane = await openEditorWith(input, viewType, options, group, this.editorService, this.configurationService, this.quickInputService);
const notebookEditor = (editorPane as unknown as { isNotebookEditor?: boolean })?.isNotebookEditor ? (editorPane!.getControl() as INotebookEditor) : undefined;
if (notebookEditor) {
if (notebookEditor.viewModel && options.selection && notebookEditor.viewModel.viewCells[options.selection.start]) {
const focusedCell = notebookEditor.viewModel.viewCells[options.selection.start];
notebookEditor.revealInCenterIfOutsideViewport(focusedCell);
notebookEditor.selectElement(focusedCell);
}
return notebookEditor.getId();
} else {
throw new Error(`Notebook Editor creation failure for documenet ${resource}`);
}
}
}
export class BoundModelReferenceCollection {
private _data = new Array<{ uri: URI, dispose(): void }>();
constructor(
private readonly _extUri: IExtUri,
private readonly _maxAge: number = 1000 * 60 * 3,
) {
//
}
dispose(): void {
this._data = dispose(this._data);
}
remove(uri: URI): void {
for (const entry of [...this._data] /* copy array because dispose will modify it */) {
if (this._extUri.isEqualOrParent(entry.uri, uri)) {
entry.dispose();
}
}
}
add(uri: URI, ref: IReference<INotebookEditorModel>): void {
let handle: any;
let entry: { uri: URI, dispose(): void };
const dispose = () => {
const idx = this._data.indexOf(entry);
if (idx >= 0) {
ref.dispose();
clearTimeout(handle);
this._data.splice(idx, 1);
}
};
handle = setTimeout(dispose, this._maxAge);
entry = { uri, dispose };
this._data.push(entry);
}
}

View File

@@ -22,7 +22,7 @@ export class MainThreadRemoteConnectionData extends Disposable {
super();
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostExtensionService);
const remoteAuthority = this._environmentService.configuration.remoteAuthority;
const remoteAuthority = this._environmentService.remoteAuthority;
if (remoteAuthority) {
this._register(remoteAuthorityResolverService.onDidChangeConnectionData(() => {
const connectionData = remoteAuthorityResolverService.getConnectionData(remoteAuthority);

View File

@@ -6,7 +6,7 @@
import { URI, UriComponents } from 'vs/base/common/uri';
import { Event, Emitter } from 'vs/base/common/event';
import { IDisposable, DisposableStore, combinedDisposable } from 'vs/base/common/lifecycle';
import { ISCMService, ISCMRepository, ISCMProvider, ISCMResource, ISCMResourceGroup, ISCMResourceDecorations, IInputValidation } from 'vs/workbench/contrib/scm/common/scm';
import { ISCMService, ISCMRepository, ISCMProvider, ISCMResource, ISCMResourceGroup, ISCMResourceDecorations, IInputValidation, ISCMViewService } from 'vs/workbench/contrib/scm/common/scm';
import { ExtHostContext, MainThreadSCMShape, ExtHostSCMShape, SCMProviderFeatures, SCMRawResourceSplices, SCMGroupFeatures, MainContext, IExtHostContext } from '../common/extHost.protocol';
import { Command } from 'vs/editor/common/modes';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
@@ -68,7 +68,8 @@ class MainThreadSCMResource implements ISCMResource {
readonly sourceUri: URI,
readonly resourceGroup: ISCMResourceGroup,
readonly decorations: ISCMResourceDecorations,
readonly contextValue: string | undefined
readonly contextValue: string | undefined,
readonly command: Command | undefined
) { }
open(preserveFocus: boolean): Promise<void> {
@@ -133,8 +134,7 @@ class MainThreadSCMProvider implements ISCMProvider {
private readonly _handle: number,
private readonly _contextValue: string,
private readonly _label: string,
private readonly _rootUri: URI | undefined,
@ISCMService scmService: ISCMService
private readonly _rootUri: URI | undefined
) { }
$updateSourceControl(features: SCMProviderFeatures): void {
@@ -202,7 +202,7 @@ class MainThreadSCMProvider implements ISCMProvider {
for (const [start, deleteCount, rawResources] of groupSlices) {
const resources = rawResources.map(rawResource => {
const [handle, sourceUri, icons, tooltip, strikeThrough, faded, contextValue] = rawResource;
const [handle, sourceUri, icons, tooltip, strikeThrough, faded, contextValue, command] = rawResource;
const icon = icons[0];
const iconDark = icons[1] || icon;
const decorations = {
@@ -221,7 +221,8 @@ class MainThreadSCMProvider implements ISCMProvider {
URI.revive(sourceUri),
group,
decorations,
contextValue || undefined
contextValue || undefined,
command
);
});
@@ -274,7 +275,8 @@ export class MainThreadSCM implements MainThreadSCMShape {
constructor(
extHostContext: IExtHostContext,
@ISCMService private readonly scmService: ISCMService
@ISCMService private readonly scmService: ISCMService,
@ISCMViewService private readonly scmViewService: ISCMViewService
) {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostSCM);
}
@@ -290,19 +292,23 @@ export class MainThreadSCM implements MainThreadSCMShape {
}
$registerSourceControl(handle: number, id: string, label: string, rootUri: UriComponents | undefined): void {
const provider = new MainThreadSCMProvider(this._proxy, handle, id, label, rootUri ? URI.revive(rootUri) : undefined, this.scmService);
const provider = new MainThreadSCMProvider(this._proxy, handle, id, label, rootUri ? URI.revive(rootUri) : undefined);
const repository = this.scmService.registerSCMProvider(provider);
this._repositories.set(handle, repository);
const disposable = combinedDisposable(
Event.filter(repository.onDidChangeSelection, selected => selected)(_ => this._proxy.$setSelectedSourceControl(handle)),
repository.input.onDidChange(value => this._proxy.$onInputBoxValueChange(handle, value))
Event.filter(this.scmViewService.onDidFocusRepository, r => r === repository)(_ => this._proxy.$setSelectedSourceControl(handle)),
repository.input.onDidChange(({ value }) => this._proxy.$onInputBoxValueChange(handle, value))
);
if (repository.selected) {
if (this.scmViewService.focusedRepository === repository) {
setTimeout(() => this._proxy.$setSelectedSourceControl(handle), 0);
}
if (repository.input.value) {
setTimeout(() => this._proxy.$onInputBoxValueChange(handle, repository.input.value), 0);
}
this._repositoryDisposables.set(handle, disposable);
}
@@ -394,7 +400,7 @@ export class MainThreadSCM implements MainThreadSCMShape {
return;
}
repository.input.value = value;
repository.input.setValue(value, false);
}
$setInputBoxPlaceholder(sourceControlHandle: number, placeholder: string): void {

View File

@@ -27,7 +27,7 @@ export class MainThreadStatusBar implements MainThreadStatusBarShape {
this.entries.clear();
}
$setEntry(id: number, statusId: string, statusName: string, text: string, tooltip: string | undefined, command: Command | undefined, color: string | ThemeColor | undefined, alignment: MainThreadStatusBarAlignment, priority: number | undefined, accessibilityInformation: IAccessibilityInformation): void {
$setEntry(id: number, statusId: string, statusName: 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 {
// if there are icons in the text use the tooltip for the aria label
let ariaLabel: string;
let role: string | undefined = undefined;
@@ -37,7 +37,7 @@ export class MainThreadStatusBar implements MainThreadStatusBarShape {
} else {
ariaLabel = text ? text.replace(MainThreadStatusBar.CODICON_REGEXP, (_match, codiconName) => codiconName) : '';
}
const entry: IStatusbarEntry = { text, tooltip, command, color, ariaLabel, role };
const entry: IStatusbarEntry = { text, tooltip, command, color, backgroundColor, ariaLabel, role };
if (typeof priority === 'undefined') {
priority = 0;

View File

@@ -3,27 +3,31 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { MainThreadStorageShape, MainContext, IExtHostContext, ExtHostStorageShape, ExtHostContext } from '../common/extHost.protocol';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { IDisposable } from 'vs/base/common/lifecycle';
import { IExtensionIdWithVersion, IExtensionsStorageSyncService } from 'vs/platform/userDataSync/common/extensionsStorageSync';
@extHostNamedCustomer(MainContext.MainThreadStorage)
export class MainThreadStorage implements MainThreadStorageShape {
private readonly _storageService: IStorageService;
private readonly _extensionsStorageSyncService: IExtensionsStorageSyncService;
private readonly _proxy: ExtHostStorageShape;
private readonly _storageListener: IDisposable;
private readonly _sharedStorageKeysToWatch: Map<string, boolean> = new Map<string, boolean>();
constructor(
extHostContext: IExtHostContext,
@IStorageService storageService: IStorageService
@IStorageService storageService: IStorageService,
@IExtensionsStorageSyncService extensionsStorageSyncService: IExtensionsStorageSyncService,
) {
this._storageService = storageService;
this._extensionsStorageSyncService = extensionsStorageSyncService;
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostStorage);
this._storageListener = this._storageService.onDidChangeStorage(e => {
this._storageListener = this._storageService.onDidChangeValue(e => {
const shared = e.scope === StorageScope.GLOBAL;
if (shared && this._sharedStorageKeysToWatch.has(e.key)) {
try {
@@ -62,10 +66,15 @@ export class MainThreadStorage implements MainThreadStorageShape {
let jsonValue: string;
try {
jsonValue = JSON.stringify(value);
this._storageService.store(key, jsonValue, shared ? StorageScope.GLOBAL : StorageScope.WORKSPACE);
// Extension state is synced separately through extensions
this._storageService.store(key, jsonValue, shared ? StorageScope.GLOBAL : StorageScope.WORKSPACE, StorageTarget.MACHINE);
} catch (err) {
return Promise.reject(err);
}
return Promise.resolve(undefined);
}
$registerExtensionStorageKeysToSync(extension: IExtensionIdWithVersion, keys: string[]): void {
this._extensionsStorageSyncService.setKeysForSync(extension, keys);
}
}

View File

@@ -53,7 +53,7 @@ namespace TaskProcessStartedDTO {
}
namespace TaskProcessEndedDTO {
export function from(value: TaskExecution, exitCode: number): TaskProcessEndedDTO {
export function from(value: TaskExecution, exitCode: number | undefined): TaskProcessEndedDTO {
return {
id: value.id,
exitCode
@@ -429,12 +429,11 @@ export class MainThreadTask implements MainThreadTaskShape {
} else if (event.kind === TaskEventKind.ProcessStarted) {
this._proxy.$onDidStartTaskProcess(TaskProcessStartedDTO.from(task.getTaskExecution(), event.processId!));
} else if (event.kind === TaskEventKind.ProcessEnded) {
this._proxy.$onDidEndTaskProcess(TaskProcessEndedDTO.from(task.getTaskExecution(), event.exitCode!));
this._proxy.$onDidEndTaskProcess(TaskProcessEndedDTO.from(task.getTaskExecution(), event.exitCode));
} else if (event.kind === TaskEventKind.End) {
this._proxy.$OnDidEndTask(TaskExecutionDTO.from(task.getTaskExecution()));
}
});
this._taskService.setJsonTasksSupported(Promise.resolve(this._proxy.$jsonTasksSupported()));
}
public dispose(): void {

View File

@@ -63,7 +63,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
this._toDispose.add(_terminalService.onInstanceRequestSpawnExtHostProcess(request => this._onRequestSpawnExtHostProcess(request)));
this._toDispose.add(_terminalService.onInstanceRequestStartExtensionTerminal(e => this._onRequestStartExtensionTerminal(e)));
this._toDispose.add(_terminalService.onActiveInstanceChanged(instance => this._onActiveTerminalChanged(instance ? instance.id : null)));
this._toDispose.add(_terminalService.onInstanceTitleChanged(instance => this._onTitleChanged(instance.id, instance.title)));
this._toDispose.add(_terminalService.onInstanceTitleChanged(instance => instance && this._onTitleChanged(instance.id, instance.title)));
this._toDispose.add(_terminalService.configHelper.onWorkspacePermissionsChanged(isAllowed => this._onWorkspacePermissionsChanged(isAllowed)));
this._toDispose.add(_terminalService.onRequestAvailableShells(e => this._onRequestAvailableShells(e)));
@@ -111,7 +111,8 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
env: launchConfig.env,
strictEnv: launchConfig.strictEnv,
hideFromUser: launchConfig.hideFromUser,
isExtensionTerminal: launchConfig.isExtensionTerminal
isExtensionTerminal: launchConfig.isExtensionTerminal,
isFeatureTerminal: launchConfig.isFeatureTerminal
};
const terminal = this._terminalService.createTerminal(shellLaunchConfig);
return Promise.resolve({

View File

@@ -0,0 +1,77 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
import { getTestSubscriptionKey, RunTestsRequest, RunTestsResult, TestsDiff } from 'vs/workbench/contrib/testing/common/testCollection';
import { ITestService } from 'vs/workbench/contrib/testing/common/testService';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { ExtHostContext, ExtHostTestingResource, ExtHostTestingShape, IExtHostContext, MainContext, MainThreadTestingShape } from '../common/extHost.protocol';
import { URI, UriComponents } from 'vs/base/common/uri';
@extHostNamedCustomer(MainContext.MainThreadTesting)
export class MainThreadTesting extends Disposable implements MainThreadTestingShape {
private readonly proxy: ExtHostTestingShape;
private readonly testSubscriptions = new Map<string, IDisposable>();
constructor(
extHostContext: IExtHostContext,
@ITestService private readonly testService: ITestService,
) {
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)));
}
/**
* @inheritdoc
*/
public $registerTestProvider(id: string) {
this.testService.registerTestController(id, {
runTests: req => this.proxy.$runTestsForProvider(req),
});
}
/**
* @inheritdoc
*/
public $unregisterTestProvider(id: string) {
this.testService.unregisterTestController(id);
}
/**
* @inheritdoc
*/
$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);
}
/**
* @inheritdoc
*/
public $unsubscribeFromDiffs(resource: ExtHostTestingResource, uriComponents: UriComponents): void {
const key = getTestSubscriptionKey(resource, URI.revive(uriComponents));
this.testSubscriptions.get(key)?.dispose();
this.testSubscriptions.delete(key);
}
/**
* @inheritdoc
*/
public $publishDiff(resource: ExtHostTestingResource, uri: UriComponents, diff: TestsDiff): void {
this.testService.publishDiff(resource, URI.revive(uri), diff);
}
public $runTests(req: RunTestsRequest): Promise<RunTestsResult> {
return this.testService.runTests(req);
}
public dispose() {
// no-op
}
}

View File

@@ -56,14 +56,14 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie
});
}
$reveal(treeViewId: string, item: ITreeItem, parentChain: ITreeItem[], options: IRevealOptions): Promise<void> {
this.logService.trace('MainThreadTreeViews#$reveal', treeViewId, item, parentChain, options);
$reveal(treeViewId: string, itemInfo: { item: ITreeItem, parentChain: ITreeItem[] } | undefined, options: IRevealOptions): Promise<void> {
this.logService.trace('MainThreadTreeViews#$reveal', treeViewId, itemInfo?.item, itemInfo?.parentChain, options);
return this.viewsService.openView(treeViewId, options.focus)
.then(() => {
const viewer = this.getTreeView(treeViewId);
if (viewer) {
return this.reveal(viewer, this._dataProviders.get(treeViewId)!, item, parentChain, options);
if (viewer && itemInfo) {
return this.reveal(viewer, this._dataProviders.get(treeViewId)!, itemInfo.item, itemInfo.parentChain, options);
}
return undefined;
});
@@ -93,12 +93,13 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie
}
}
$setTitle(treeViewId: string, title: string): void {
this.logService.trace('MainThreadTreeViews#$setTitle', treeViewId, title);
$setTitle(treeViewId: string, title: string, description: string | undefined): void {
this.logService.trace('MainThreadTreeViews#$setTitle', treeViewId, title, description);
const viewer = this.getTreeView(treeViewId);
if (viewer) {
viewer.title = title;
viewer.description = description;
}
}

View File

@@ -6,8 +6,8 @@
import { MainThreadTunnelServiceShape, IExtHostContext, MainContext, ExtHostContext, ExtHostTunnelServiceShape } from 'vs/workbench/api/common/extHost.protocol';
import { TunnelDto } from 'vs/workbench/api/common/extHostTunnelService';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { IRemoteExplorerService, MakeAddress } from 'vs/workbench/services/remote/common/remoteExplorerService';
import { ITunnelProvider, ITunnelService, TunnelOptions } from 'vs/platform/remote/common/tunnel';
import { IRemoteExplorerService, makeAddress } from 'vs/workbench/services/remote/common/remoteExplorerService';
import { ITunnelProvider, ITunnelService, TunnelCreationOptions, TunnelOptions } from 'vs/platform/remote/common/tunnel';
import { Disposable } from 'vs/base/common/lifecycle';
import type { TunnelDescription } from 'vs/platform/remote/common/remoteAuthorityResolver';
@@ -26,8 +26,8 @@ export class MainThreadTunnelService extends Disposable implements MainThreadTun
this._register(tunnelService.onTunnelClosed(() => this._proxy.$onDidTunnelsChange()));
}
async $openTunnel(tunnelOptions: TunnelOptions): Promise<TunnelDto | undefined> {
const tunnel = await this.remoteExplorerService.forward(tunnelOptions.remoteAddress, tunnelOptions.localAddressPort, tunnelOptions.label);
async $openTunnel(tunnelOptions: TunnelOptions, source: string): Promise<TunnelDto | undefined> {
const tunnel = await this.remoteExplorerService.forward(tunnelOptions.remoteAddress, tunnelOptions.localAddressPort, tunnelOptions.label, source);
if (tunnel) {
return TunnelDto.fromServiceTunnel(tunnel);
}
@@ -47,8 +47,8 @@ export class MainThreadTunnelService extends Disposable implements MainThreadTun
});
}
async $registerCandidateFinder(): Promise<void> {
this.remoteExplorerService.registerCandidateFinder(() => this._proxy.$findCandidatePorts());
async $onFoundNewCandidates(candidates: { host: string, port: number, detail: string }[]): Promise<void> {
this.remoteExplorerService.onFoundNewCandidates(candidates);
}
async $tunnelServiceReady(): Promise<void> {
@@ -57,19 +57,17 @@ export class MainThreadTunnelService extends Disposable implements MainThreadTun
async $setTunnelProvider(): Promise<void> {
const tunnelProvider: ITunnelProvider = {
forwardPort: (tunnelOptions: TunnelOptions) => {
const forward = this._proxy.$forwardPort(tunnelOptions);
forwardPort: (tunnelOptions: TunnelOptions, tunnelCreationOptions: TunnelCreationOptions) => {
const forward = this._proxy.$forwardPort(tunnelOptions, tunnelCreationOptions);
if (forward) {
return forward.then(tunnel => {
return {
tunnelRemotePort: tunnel.remoteAddress.port,
tunnelRemoteHost: tunnel.remoteAddress.host,
localAddress: typeof tunnel.localAddress === 'string' ? tunnel.localAddress : MakeAddress(tunnel.localAddress.host, tunnel.localAddress.port),
localAddress: typeof tunnel.localAddress === 'string' ? tunnel.localAddress : makeAddress(tunnel.localAddress.host, tunnel.localAddress.port),
tunnelLocalPort: typeof tunnel.localAddress !== 'string' ? tunnel.localAddress.port : undefined,
dispose: (silent: boolean) => {
if (!silent) {
this._proxy.$closeTunnel({ host: tunnel.remoteAddress.host, port: tunnel.remoteAddress.port });
}
dispose: (silent?: boolean) => {
this._proxy.$closeTunnel({ host: tunnel.remoteAddress.host, port: tunnel.remoteAddress.port }, silent);
}
};
});
@@ -80,22 +78,6 @@ export class MainThreadTunnelService extends Disposable implements MainThreadTun
this.tunnelService.setTunnelProvider(tunnelProvider);
}
async $setCandidateFilter(): Promise<void> {
this._register(this.remoteExplorerService.setCandidateFilter(async (candidates: { host: string, port: number, detail: string }[]): Promise<{ host: string, port: number, detail: string }[]> => {
const filters: boolean[] = await this._proxy.$filterCandidates(candidates);
const filteredCandidates: { host: string, port: number, detail: string }[] = [];
if (filters.length !== candidates.length) {
return candidates;
}
for (let i = 0; i < candidates.length; i++) {
if (filters[i]) {
filteredCandidates.push(candidates[i]);
}
}
return filteredCandidates;
}));
}
dispose(): void {
}

View File

@@ -9,8 +9,7 @@ import { URI, UriComponents } from 'vs/base/common/uri';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { MainThreadWebviews, reviveWebviewExtension, reviveWebviewOptions } from 'vs/workbench/api/browser/mainThreadWebviews';
import * as extHostProtocol from 'vs/workbench/api/common/extHost.protocol';
import { editorGroupToViewColumn, EditorViewColumn, viewColumnToEditorGroup } from 'vs/workbench/api/common/shared/editor';
import { IEditorInput } from 'vs/workbench/common/editor';
import { editorGroupToViewColumn, EditorGroupColumn, IEditorInput, viewColumnToEditorGroup } from 'vs/workbench/common/editor';
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
import { WebviewIcons } from 'vs/workbench/contrib/webview/browser/webview';
import { WebviewInput } from 'vs/workbench/contrib/webviewPanel/browser/webviewEditorInput';
@@ -128,9 +127,7 @@ export class MainThreadWebviewPanels extends Disposable implements extHostProtoc
dispose() {
super.dispose();
for (const disposable of this._editorProviders.values()) {
disposable.dispose();
}
dispose(this._editorProviders.values());
this._editorProviders.clear();
}
@@ -152,7 +149,7 @@ export class MainThreadWebviewPanels extends Disposable implements extHostProtoc
handle: extHostProtocol.WebviewHandle,
viewType: string,
title: string,
showOptions: { viewColumn?: EditorViewColumn, preserveFocus?: boolean; },
showOptions: { viewColumn?: EditorGroupColumn, preserveFocus?: boolean; },
options: WebviewInputOptions
): void {
const mainThreadShowOptions: ICreateWebViewShowOptions = Object.create(null);

View File

@@ -5,8 +5,8 @@
import { CancellationToken } from 'vs/base/common/cancellation';
import { onUnexpectedError } from 'vs/base/common/errors';
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
import { MainThreadWebviews } from 'vs/workbench/api/browser/mainThreadWebviews';
import { Disposable, dispose, IDisposable } from 'vs/base/common/lifecycle';
import { MainThreadWebviews, reviveWebviewExtension } from 'vs/workbench/api/browser/mainThreadWebviews';
import * as extHostProtocol from 'vs/workbench/api/common/extHost.protocol';
import { IWebviewViewService, WebviewView } from 'vs/workbench/contrib/webviewView/browser/webviewViewService';
@@ -28,6 +28,15 @@ export class MainThreadWebviewsViews extends Disposable implements extHostProtoc
this._proxy = context.getProxy(extHostProtocol.ExtHostContext.ExtHostWebviewViews);
}
dispose() {
super.dispose();
dispose(this._webviewViewProviders.values());
this._webviewViewProviders.clear();
dispose(this._webviewViews.values());
}
public $setWebviewViewTitle(handle: extHostProtocol.WebviewHandle, value: string | undefined): void {
const webviewView = this.getWebviewView(handle);
webviewView.title = value;
@@ -43,12 +52,18 @@ export class MainThreadWebviewsViews extends Disposable implements extHostProtoc
webviewView.show(preserveFocus);
}
public $registerWebviewViewProvider(viewType: string, options?: { retainContextWhenHidden?: boolean }): void {
public $registerWebviewViewProvider(
extensionData: extHostProtocol.WebviewExtensionDescription,
viewType: string,
options?: { retainContextWhenHidden?: boolean }
): void {
if (this._webviewViewProviders.has(viewType)) {
throw new Error(`View provider for ${viewType} already registered`);
}
this._webviewViewService.register(viewType, {
const extension = reviveWebviewExtension(extensionData);
const registration = this._webviewViewService.register(viewType, {
resolve: async (webviewView: WebviewView, cancellation: CancellationToken) => {
const handle = webviewView.webview.id;
@@ -64,6 +79,8 @@ export class MainThreadWebviewsViews extends Disposable implements extHostProtoc
}
}
webviewView.webview.extension = extension;
if (options) {
webviewView.webview.options = options;
}
@@ -85,6 +102,8 @@ export class MainThreadWebviewsViews extends Disposable implements extHostProtoc
}
}
});
this._webviewViewProviders.set(viewType, registration);
}
public $unregisterWebviewViewProvider(viewType: string): void {

View File

@@ -8,18 +8,18 @@ import { forEach } from 'vs/base/common/collections';
import { IJSONSchema } from 'vs/base/common/jsonSchema';
import * as resources from 'vs/base/common/resources';
import { ExtensionMessageCollector, ExtensionsRegistry, IExtensionPoint, IExtensionPointUser } from 'vs/workbench/services/extensions/common/extensionsRegistry';
import { ViewContainer, IViewsRegistry, ITreeViewDescriptor, IViewContainersRegistry, Extensions as ViewContainerExtensions, TEST_VIEW_CONTAINER_ID, IViewDescriptor, ViewContainerLocation } from 'vs/workbench/common/views';
import { TreeViewPane } from 'vs/workbench/browser/parts/views/treeView';
import { ViewContainer, IViewsRegistry, ITreeViewDescriptor, IViewContainersRegistry, Extensions as ViewContainerExtensions, TEST_VIEW_CONTAINER_ID, IViewDescriptor, ViewContainerLocation, testViewIcon } from 'vs/workbench/common/views';
import { CustomTreeView, TreeViewPane } from 'vs/workbench/browser/parts/views/treeView';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { coalesce, } from 'vs/base/common/arrays';
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
import { Registry } from 'vs/platform/registry/common/platform';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { VIEWLET_ID as EXPLORER } from 'vs/workbench/contrib/files/common/files';
import { VIEWLET_ID as SCM } from 'vs/workbench/contrib/scm/common/scm';
import { VIEWLET_ID as DEBUG } from 'vs/workbench/contrib/debug/common/debug';
import { VIEWLET_ID as REMOTE } from 'vs/workbench/contrib/remote/common/remote.contribution';
import { VIEWLET_ID as REMOTE } from 'vs/workbench/contrib/remote/browser/remoteExplorer';
import { VIEWLET_ID as NOTEBOOK } from 'sql/workbench/contrib/notebook/browser/notebookExplorer/notebookExplorerViewlet'; // {{SQL CARBON EDIT}}
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { URI } from 'vs/base/common/uri';
@@ -27,13 +27,12 @@ import { ViewletRegistry, Extensions as ViewletExtensions, ShowViewletAction } f
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions';
import { IWorkbenchActionRegistry, Extensions as ActionExtensions, CATEGORIES } from 'vs/workbench/common/actions';
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
import { ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneContainer';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { Codicon } from 'vs/base/common/codicons';
import { CustomTreeView } from 'vs/workbench/contrib/views/browser/treeView';
import { WebviewViewPane } from 'vs/workbench/contrib/webviewView/browser/webviewViewPane';
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
export interface IUserFriendlyViewsContainerDescriptor {
id: string;
@@ -329,7 +328,7 @@ class ViewsExtensionHandler implements IWorkbenchContribution {
private registerTestViewContainer(): void {
const title = localize('test', "Test");
const icon = Codicon.beaker.classNames;
const icon = testViewIcon;
this.registerCustomViewContainer(TEST_VIEW_CONTAINER_ID, title, icon, TEST_VIEW_CONTAINER_ORDER, undefined, ViewContainerLocation.Sidebar);
}
@@ -364,7 +363,9 @@ class ViewsExtensionHandler implements IWorkbenchContribution {
private registerCustomViewContainers(containers: IUserFriendlyViewsContainerDescriptor[], extension: IExtensionDescription, order: number, existingViewContainers: ViewContainer[], location: ViewContainerLocation): number {
containers.forEach(descriptor => {
const icon = resources.joinPath(extension.extensionLocation, descriptor.icon);
const themeIcon = ThemeIcon.fromString(descriptor.icon);
const icon = themeIcon || resources.joinPath(extension.extensionLocation, descriptor.icon);
const id = `workbench.view.extension.${descriptor.id}`;
const viewContainer = this.registerCustomViewContainer(id, descriptor.title, icon, order++, extension.identifier, location);
@@ -384,7 +385,7 @@ class ViewsExtensionHandler implements IWorkbenchContribution {
return order;
}
private registerCustomViewContainer(id: string, title: string, icon: URI | string, order: number, extensionId: ExtensionIdentifier | undefined, location: ViewContainerLocation): ViewContainer {
private registerCustomViewContainer(id: string, title: string, icon: URI | ThemeIcon, order: number, extensionId: ExtensionIdentifier | undefined, location: ViewContainerLocation): ViewContainer {
let viewContainer = this.viewContainersRegistry.get(id);
if (!viewContainer) {
@@ -416,7 +417,7 @@ class ViewsExtensionHandler implements IWorkbenchContribution {
registry.registerWorkbenchAction(
SyncActionDescriptor.create(OpenCustomViewletAction, id, localize('showViewlet', "Show {0}", title)),
`View: Show ${title}`,
localize('view', "View")
CATEGORIES.View.value
);
}
@@ -478,7 +479,11 @@ class ViewsExtensionHandler implements IWorkbenchContribution {
? container.viewOrderDelegate.getOrder(item.group)
: undefined;
const icon = item.icon ? resources.joinPath(extension.description.extensionLocation, item.icon) : undefined;
let icon: ThemeIcon | URI | undefined;
if (typeof item.icon === 'string') {
icon = ThemeIcon.fromString(item.icon) || resources.joinPath(extension.description.extensionLocation, item.icon);
}
const initialVisibility = this.convertInitialVisibility(item.visibility);
const type = this.getViewType(item.type);
@@ -487,11 +492,6 @@ class ViewsExtensionHandler implements IWorkbenchContribution {
return null;
}
if (type === ViewType.Webview && !extension.description.enableProposedApi) {
collector.error(localize('webviewViewsRequireProposed', "Webview views are proposed api and are only supported when running out of dev or with the following command line switch: --enable-proposed-api"));
return null;
}
const viewDescriptor = <ICustomTreeViewDescriptor>{
type: type,
ctorDescriptor: type === ViewType.Tree ? new SyncDescriptor(TreeViewPane) : new SyncDescriptor(WebviewViewPane),
@@ -501,7 +501,7 @@ class ViewsExtensionHandler implements IWorkbenchContribution {
containerIcon: icon || viewContainer?.icon,
containerTitle: item.contextualTitle || viewContainer?.name,
canToggleVisibility: true,
canMoveView: true,
canMoveView: viewContainer?.id !== REMOTE,
treeView: type === ViewType.Tree ? this.instantiationService.createInstance(CustomTreeView, item.id, item.name) : undefined,
collapsed: this.showCollapsed(container) || initialVisibility === InitialVisibility.Collapsed,
order: order,