chore(vscode): update to 1.54.2

This commit is contained in:
Joe Previte
2021-03-11 10:27:10 -07:00
1459 changed files with 53404 additions and 51004 deletions

View File

@@ -11,6 +11,7 @@ import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle
// --- other interested parties
import { JSONValidationExtensionPoint } from 'vs/workbench/api/common/jsonValidationExtensionPoint';
import { ColorExtensionPoint } from 'vs/workbench/services/themes/common/colorExtensionPoint';
import { IconExtensionPoint, IconFontExtensionPoint } from 'vs/workbench/services/themes/common/iconExtensionPoint';
import { TokenClassificationExtensionPoints } from 'vs/workbench/services/themes/common/tokenClassificationExtensionPoint';
import { LanguageConfigurationFileHandler } from 'vs/workbench/contrib/codeEditor/browser/languageConfigurationExtensionPoint';
@@ -79,6 +80,8 @@ export class ExtensionPoints implements IWorkbenchContribution {
// Classes that handle extension points...
this.instantiationService.createInstance(JSONValidationExtensionPoint);
this.instantiationService.createInstance(ColorExtensionPoint);
this.instantiationService.createInstance(IconExtensionPoint);
this.instantiationService.createInstance(IconFontExtensionPoint);
this.instantiationService.createInstance(TokenClassificationExtensionPoints);
this.instantiationService.createInstance(LanguageConfigurationFileHandler);
}

View File

@@ -7,72 +7,17 @@ import { Disposable } from 'vs/base/common/lifecycle';
import * as modes from 'vs/editor/common/modes';
import * as nls from 'vs/nls';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { IAuthenticationService, AllowedExtension, readAllowedExtensions, getAuthenticationProviderActivationEvent } from 'vs/workbench/services/authentication/browser/authenticationService';
import { IAuthenticationService, AllowedExtension, readAllowedExtensions, getAuthenticationProviderActivationEvent, addAccountUsage, readAccountUsages, removeAccountUsage } 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, 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 { 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 { isWeb } from 'vs/base/common/platform';
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;
extensionName: string;
lastUsed: number;
}
function readAccountUsages(storageService: IStorageService, providerId: string, accountName: string,): IAccountUsage[] {
const accountKey = `${providerId}-${accountName}-usages`;
const storedUsages = storageService.get(accountKey, StorageScope.GLOBAL);
let usages: IAccountUsage[] = [];
if (storedUsages) {
try {
usages = JSON.parse(storedUsages);
} catch (e) {
// ignore
}
}
return usages;
}
function removeAccountUsage(storageService: IStorageService, providerId: string, accountName: string): void {
const accountKey = `${providerId}-${accountName}-usages`;
storageService.remove(accountKey, StorageScope.GLOBAL);
}
function addAccountUsage(storageService: IStorageService, providerId: string, accountName: string, extensionId: string, extensionName: string) {
const accountKey = `${providerId}-${accountName}-usages`;
const usages = readAccountUsages(storageService, providerId, accountName);
const existingUsageIndex = usages.findIndex(usage => usage.extensionId === extensionId);
if (existingUsageIndex > -1) {
usages.splice(existingUsageIndex, 1, {
extensionId,
extensionName,
lastUsed: Date.now()
});
} else {
usages.push({
extensionId,
extensionName,
lastUsed: Date.now()
});
}
storageService.store(accountKey, JSON.stringify(usages), StorageScope.GLOBAL, StorageTarget.MACHINE);
}
export class MainThreadAuthenticationProvider extends Disposable {
private _accounts = new Map<string, string[]>(); // Map account name to session ids
private _sessions = new Map<string, string>(); // Map account id to name
constructor(
private readonly _proxy: ExtHostAuthenticationShape,
public readonly id: string,
@@ -85,15 +30,6 @@ export class MainThreadAuthenticationProvider extends Disposable {
) {
super();
}
public async initialize(): Promise<void> {
return this.registerCommandsAndContextMenuItems();
}
public hasSessions(): boolean {
return !!this._sessions.size;
}
public manageTrustedExtensions(accountName: string) {
const allowedExtensions = readAllowedExtensions(this.storageService, this.id, accountName);
@@ -117,7 +53,7 @@ export class MainThreadAuthenticationProvider extends Disposable {
});
quickPick.items = items;
quickPick.selectedItems = items;
quickPick.selectedItems = items.filter(item => item.extension.allowed === undefined || item.extension.allowed);
quickPick.title = nls.localize('manageTrustedExtensions', "Manage Trusted Extensions");
quickPick.placeholder = nls.localize('manageExensions', "Choose which extensions can access this account");
@@ -135,77 +71,40 @@ export class MainThreadAuthenticationProvider extends Disposable {
quickPick.show();
}
private async registerCommandsAndContextMenuItems(): Promise<void> {
try {
const sessions = await this._proxy.$getSessions(this.id);
sessions.forEach(session => this.registerSession(session));
} catch (_) {
// Ignore
}
}
private registerSession(session: modes.AuthenticationSession) {
this._sessions.set(session.id, session.account.label);
const existingSessionsForAccount = this._accounts.get(session.account.label);
if (existingSessionsForAccount) {
this._accounts.set(session.account.label, existingSessionsForAccount.concat(session.id));
return;
} else {
this._accounts.set(session.account.label, [session.id]);
}
}
async signOut(accountName: string): Promise<void> {
async removeAccountSessions(accountName: string, sessions: modes.AuthenticationSession[]): Promise<void> {
const accountUsages = readAccountUsages(this.storageService, this.id, accountName);
const sessionsForAccount = this._accounts.get(accountName);
const result = await this.dialogService.confirm({
title: nls.localize('signOutConfirm', "Sign out of {0}", accountName),
message: accountUsages.length
? nls.localize('signOutMessagve', "The account {0} has been used by: \n\n{1}\n\n Sign out of these features?", accountName, accountUsages.map(usage => usage.extensionName).join('\n'))
: nls.localize('signOutMessageSimple', "Sign out of {0}?", accountName)
});
const result = await this.dialogService.show(
Severity.Info,
accountUsages.length
? nls.localize('signOutMessagve', "The account '{0}' has been used by: \n\n{1}\n\n Sign out from these extensions?", accountName, accountUsages.map(usage => usage.extensionName).join('\n'))
: nls.localize('signOutMessageSimple', "Sign out of '{0}'?", accountName),
[
nls.localize('signOut', "Sign out"),
nls.localize('cancel', "Cancel")
],
{
cancelId: 1
});
if (result.confirmed) {
sessionsForAccount?.forEach(sessionId => this.logout(sessionId));
if (result.choice === 0) {
const removeSessionPromises = sessions.map(session => this.removeSession(session.id));
await Promise.all(removeSessionPromises);
removeAccountUsage(this.storageService, this.id, accountName);
this.storageService.remove(`${this.id}-${accountName}`, StorageScope.GLOBAL);
}
}
async getSessions(): Promise<ReadonlyArray<modes.AuthenticationSession>> {
return this._proxy.$getSessions(this.id);
async getSessions(scopes?: string[]) {
return this._proxy.$getSessions(this.id, scopes);
}
async updateSessionItems(event: modes.AuthenticationSessionsChangeEvent): Promise<void> {
const { added, removed } = event;
const session = await this._proxy.$getSessions(this.id);
const addedSessions = session.filter(session => added.some(id => id === session.id));
removed.forEach(sessionId => {
const accountName = this._sessions.get(sessionId);
if (accountName) {
this._sessions.delete(sessionId);
let sessionsForAccount = this._accounts.get(accountName) || [];
const sessionIndex = sessionsForAccount.indexOf(sessionId);
sessionsForAccount.splice(sessionIndex);
if (!sessionsForAccount.length) {
this._accounts.delete(accountName);
}
}
});
addedSessions.forEach(session => this.registerSession(session));
createSession(scopes: string[]): Promise<modes.AuthenticationSession> {
return this._proxy.$createSession(this.id, scopes);
}
login(scopes: string[]): Promise<modes.AuthenticationSession> {
return this._proxy.$login(this.id, scopes);
}
async logout(sessionId: string): Promise<void> {
await this._proxy.$logout(this.id, sessionId);
async removeSession(sessionId: string): Promise<void> {
await this._proxy.$removeSession(this.id, sessionId);
this.notificationService.info(nls.localize('signedOut', "Successfully signed out."));
}
}
@@ -220,7 +119,6 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
@IDialogService private readonly dialogService: IDialogService,
@IStorageService private readonly storageService: IStorageService,
@INotificationService private readonly notificationService: INotificationService,
@IRemoteAgentService private readonly remoteAgentService: IRemoteAgentService,
@IQuickInputService private readonly quickInputService: IQuickInputService,
@IExtensionService private readonly extensionService: IExtensionService
) {
@@ -228,7 +126,7 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostAuthentication);
this._register(this.authenticationService.onDidChangeSessions(e => {
this._proxy.$onDidChangeAuthenticationSessions(e.providerId, e.label, e.event);
this._proxy.$onDidChangeAuthenticationSessions(e.providerId, e.label);
}));
this._register(this.authenticationService.onDidRegisterAuthenticationProvider(info => {
@@ -246,13 +144,8 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
}));
}
$getProviderIds(): Promise<string[]> {
return Promise.resolve(this.authenticationService.getProviderIds());
}
async $registerAuthenticationProvider(id: string, label: string, supportsMultipleAccounts: boolean): Promise<void> {
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);
}
@@ -268,172 +161,10 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
this.authenticationService.sessionsUpdate(id, event);
}
$getSessions(id: string): Promise<ReadonlyArray<modes.AuthenticationSession>> {
return this.authenticationService.getSessions(id);
$removeSession(providerId: string, sessionId: string): Promise<void> {
return this.authenticationService.removeSession(providerId, sessionId);
}
$login(providerId: string, scopes: string[]): Promise<modes.AuthenticationSession> {
return this.authenticationService.login(providerId, scopes);
}
$logout(providerId: string, sessionId: string): Promise<void> {
return this.authenticationService.logout(providerId, sessionId);
}
async $requestNewSession(providerId: string, scopes: string[], extensionId: string, extensionName: string): Promise<void> {
return this.authenticationService.requestNewSession(providerId, scopes, extensionId, extensionName);
}
async $getSession(providerId: string, scopes: string[], extensionId: string, extensionName: string, options: { createIfNone: boolean, clearSessionPreference: boolean }): Promise<modes.AuthenticationSession | undefined> {
const orderedScopes = scopes.sort().join(' ');
const sessions = (await this.$getSessions(providerId)).filter(session => session.scopes.slice().sort().join(' ') === orderedScopes);
const label = this.authenticationService.getLabel(providerId);
if (sessions.length) {
if (!this.authenticationService.supportsMultipleAccounts(providerId)) {
const session = sessions[0];
const allowed = await this.$getSessionsPrompt(providerId, session.account.label, label, extensionId, extensionName);
if (allowed) {
return session;
} else {
throw new Error('User did not consent to login.');
}
}
// On renderer side, confirm consent, ask user to choose between accounts if multiple sessions are valid
const selected = await this.$selectSession(providerId, label, extensionId, extensionName, sessions, scopes, !!options.clearSessionPreference);
return sessions.find(session => session.id === selected.id);
} else {
if (options.createIfNone) {
const isAllowed = await this.$loginPrompt(label, extensionName);
if (!isAllowed) {
throw new Error('User did not consent to login.');
}
const session = await this.authenticationService.login(providerId, scopes);
await this.$setTrustedExtensionAndAccountPreference(providerId, session.account.label, extensionId, extensionName, session.id);
return session;
} else {
await this.$requestNewSession(providerId, scopes, extensionId, extensionName);
return undefined;
}
}
}
async $selectSession(providerId: string, providerName: string, extensionId: string, extensionName: string, potentialSessions: modes.AuthenticationSession[], scopes: string[], clearSessionPreference: boolean): Promise<modes.AuthenticationSession> {
if (!potentialSessions.length) {
throw new Error('No potential sessions found');
}
if (clearSessionPreference) {
this.storageService.remove(`${extensionName}-${providerId}`, StorageScope.GLOBAL);
} else {
const existingSessionPreference = this.storageService.get(`${extensionName}-${providerId}`, StorageScope.GLOBAL);
if (existingSessionPreference) {
const matchingSession = potentialSessions.find(session => session.id === existingSessionPreference);
if (matchingSession) {
const allowed = await this.$getSessionsPrompt(providerId, matchingSession.account.label, providerName, extensionId, extensionName);
if (allowed) {
return matchingSession;
}
}
}
}
return new Promise((resolve, reject) => {
const quickPick = this.quickInputService.createQuickPick<{ label: string, session?: modes.AuthenticationSession }>();
quickPick.ignoreFocusOut = true;
const items: { label: string, session?: modes.AuthenticationSession }[] = potentialSessions.map(session => {
return {
label: session.account.label,
session
};
});
items.push({
label: nls.localize('useOtherAccount', "Sign in to another account")
});
quickPick.items = items;
quickPick.title = nls.localize(
{
key: 'selectAccount',
comment: ['The placeholder {0} is the name of an extension. {1} is the name of the type of account, such as Microsoft or GitHub.']
},
"The extension '{0}' wants to access a {1} account",
extensionName,
providerName);
quickPick.placeholder = nls.localize('getSessionPlateholder', "Select an account for '{0}' to use or Esc to cancel", extensionName);
quickPick.onDidAccept(async _ => {
const selected = quickPick.selectedItems[0];
const session = selected.session ?? await this.authenticationService.login(providerId, scopes);
const accountName = session.account.label;
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, StorageTarget.USER);
}
this.storageService.store(`${extensionName}-${providerId}`, session.id, StorageScope.GLOBAL, StorageTarget.MACHINE);
quickPick.dispose();
resolve(session);
});
quickPick.onDidHide(_ => {
if (!quickPick.selectedItems[0]) {
reject('User did not consent to account access');
}
quickPick.dispose();
});
quickPick.show();
});
}
async $getSessionsPrompt(providerId: string, accountName: string, providerName: string, extensionId: string, extensionName: string): Promise<boolean> {
const allowList = readAllowedExtensions(this.storageService, providerId, accountName);
const extensionData = allowList.find(extension => extension.id === extensionId);
if (extensionData) {
addAccountUsage(this.storageService, providerId, accountName, extensionId, extensionName);
return true;
}
const remoteConnection = this.remoteAgentService.getConnection();
const isVSO = remoteConnection !== null
? remoteConnection.remoteAuthority.startsWith('vsonline') || remoteConnection.remoteAuthority.startsWith('codespaces')
: isWeb;
if (isVSO && VSO_ALLOWED_EXTENSIONS.includes(extensionId)) {
addAccountUsage(this.storageService, providerId, accountName, extensionId, extensionName);
return true;
}
const { choice } = await this.dialogService.show(
Severity.Info,
nls.localize('confirmAuthenticationAccess', "The extension '{0}' wants to access the {1} account '{2}'.", extensionName, providerName, accountName),
[nls.localize('allow', "Allow"), nls.localize('cancel', "Cancel")],
{
cancelId: 1
}
);
const allow = choice === 0;
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, StorageTarget.USER);
}
return allow;
}
async $loginPrompt(providerName: string, extensionName: string): Promise<boolean> {
private async loginPrompt(providerName: string, extensionName: string): Promise<boolean> {
const { choice } = await this.dialogService.show(
Severity.Info,
nls.localize('confirmLogin', "The extension '{0}' wants to sign in using {1}.", extensionName, providerName),
@@ -446,14 +177,94 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
return choice === 0;
}
async $setTrustedExtensionAndAccountPreference(providerId: string, accountName: string, extensionId: string, extensionName: string, sessionId: string): Promise<void> {
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, StorageTarget.USER);
private async setTrustedExtensionAndAccountPreference(providerId: string, accountName: string, extensionId: string, extensionName: string, sessionId: string): Promise<void> {
this.authenticationService.updatedAllowedExtension(providerId, accountName, extensionId, extensionName, true);
this.storageService.store(`${extensionName}-${providerId}`, sessionId, StorageScope.GLOBAL, StorageTarget.MACHINE);
}
private async selectSession(providerId: string, extensionId: string, extensionName: string, scopes: string[], potentialSessions: readonly modes.AuthenticationSession[], clearSessionPreference: boolean, silent: boolean): Promise<modes.AuthenticationSession | undefined> {
if (!potentialSessions.length) {
throw new Error('No potential sessions found');
}
this.storageService.store(`${extensionName}-${providerId}`, sessionId, StorageScope.GLOBAL, StorageTarget.MACHINE);
addAccountUsage(this.storageService, providerId, accountName, extensionId, extensionName);
if (clearSessionPreference) {
this.storageService.remove(`${extensionName}-${providerId}`, StorageScope.GLOBAL);
} else {
const existingSessionPreference = this.storageService.get(`${extensionName}-${providerId}`, StorageScope.GLOBAL);
if (existingSessionPreference) {
const matchingSession = potentialSessions.find(session => session.id === existingSessionPreference);
if (matchingSession) {
const allowed = this.authenticationService.isAccessAllowed(providerId, matchingSession.account.label, extensionId);
if (!allowed) {
if (!silent) {
const didAcceptPrompt = await this.authenticationService.showGetSessionPrompt(providerId, matchingSession.account.label, extensionId, extensionName);
if (!didAcceptPrompt) {
throw new Error('User did not consent to login.');
}
} else {
this.authenticationService.requestSessionAccess(providerId, extensionId, extensionName, scopes, potentialSessions);
return undefined;
}
}
return matchingSession;
}
}
}
if (silent) {
this.authenticationService.requestSessionAccess(providerId, extensionId, extensionName, scopes, potentialSessions);
return undefined;
}
return this.authenticationService.selectSession(providerId, extensionId, extensionName, scopes, potentialSessions);
}
async $getSession(providerId: string, scopes: string[], extensionId: string, extensionName: string, options: { createIfNone: boolean, clearSessionPreference: boolean }): Promise<modes.AuthenticationSession | undefined> {
const sessions = await this.authenticationService.getSessions(providerId, scopes, true);
const silent = !options.createIfNone;
let session: modes.AuthenticationSession | undefined;
if (sessions.length) {
if (!this.authenticationService.supportsMultipleAccounts(providerId)) {
session = sessions[0];
const allowed = this.authenticationService.isAccessAllowed(providerId, session.account.label, extensionId);
if (!allowed) {
if (!silent) {
const didAcceptPrompt = await this.authenticationService.showGetSessionPrompt(providerId, session.account.label, extensionId, extensionName);
if (!didAcceptPrompt) {
throw new Error('User did not consent to login.');
}
} else if (allowed !== false) {
this.authenticationService.requestSessionAccess(providerId, extensionId, extensionName, scopes, [session]);
return undefined;
} else {
return undefined;
}
}
} else {
return this.selectSession(providerId, extensionId, extensionName, scopes, sessions, !!options.clearSessionPreference, silent);
}
} else {
if (!silent) {
const providerName = await this.authenticationService.getLabel(providerId);
const isAllowed = await this.loginPrompt(providerName, extensionName);
if (!isAllowed) {
throw new Error('User did not consent to login.');
}
session = await this.authenticationService.createSession(providerId, scopes, true);
await this.setTrustedExtensionAndAccountPreference(providerId, session.account.label, extensionId, extensionName, session.id);
} else {
await this.authenticationService.requestNewSession(providerId, scopes, extensionId, extensionName);
}
}
if (session) {
addAccountUsage(this.storageService, providerId, session.account.label, extensionId, extensionName);
}
return session;
}
}

View File

@@ -26,10 +26,9 @@ import { IExtensionManifest } from 'vs/workbench/workbench.web.api';
// this class contains the commands that the CLI server is reying on
CommandsRegistry.registerCommand('_remoteCLI.openExternal', function (accessor: ServicesAccessor, uri: UriComponents, options: { allowTunneling?: boolean }) {
// TODO: discuss martin, ben where to put this
CommandsRegistry.registerCommand('_remoteCLI.openExternal', function (accessor: ServicesAccessor, uri: UriComponents | string) {
const openerService = accessor.get(IOpenerService);
openerService.open(URI.revive(uri), { openExternal: true, allowTunneling: options?.allowTunneling === true });
openerService.open(isString(uri) ? uri : URI.revive(uri), { openExternal: true, allowTunneling: true });
});
interface ManageExtensionsArgs {
@@ -100,7 +99,7 @@ class RemoteExtensionCLIManagementService extends ExtensionManagementCLIService
protected validateExtensionKind(manifest: IExtensionManifest, output: CLIOutput): boolean {
if (!canExecuteOnWorkspace(manifest, this.productService, this.configurationService)) {
output.log(localize('cannot be installed', "Cannot install '{0}' because this extension has defined that it cannot run on the remote server.", getExtensionId(manifest.publisher, manifest.name)));
output.log(localize('cannot be installed', "Cannot install the '{0}' extension because it is declared to not run in this setup.", getExtensionId(manifest.publisher, manifest.name)));
return false;
}
return true;

View File

@@ -473,7 +473,7 @@ export class MainThreadComments extends Disposable implements MainThreadComments
if (!commentsViewAlreadyRegistered) {
const VIEW_CONTAINER: ViewContainer = Registry.as<IViewContainersRegistry>(ViewExtensions.ViewContainersRegistry).registerViewContainer({
id: COMMENTS_VIEW_ID,
name: COMMENTS_VIEW_TITLE,
title: COMMENTS_VIEW_TITLE,
ctorDescriptor: new SyncDescriptor(ViewPaneContainer, [COMMENTS_VIEW_ID, { mergeViewWithContainerWhenSingleView: true, donotShowContainerTitleWhenMergedWithContainer: true }]),
storageId: COMMENTS_VIEW_TITLE,
hideIfEmpty: true,

View File

@@ -75,8 +75,8 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
return Promise.resolve(this._proxy.$substituteVariables(folder ? folder.uri : undefined, config));
}
runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments): Promise<number | undefined> {
return this._proxy.$runInTerminal(args);
runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments, sessionId: string): Promise<number | undefined> {
return this._proxy.$runInTerminal(args, sessionId);
}
// RPC methods (MainThreadDebugServiceShape)

View File

@@ -13,7 +13,6 @@ import { ITextModelService } from 'vs/editor/common/services/resolverService';
import { IFileService, FileOperation } from 'vs/platform/files/common/files';
import { MainThreadDocumentsAndEditors } from 'vs/workbench/api/browser/mainThreadDocumentsAndEditors';
import { ExtHostContext, ExtHostDocumentsShape, IExtHostContext, MainThreadDocumentsShape } from 'vs/workbench/api/common/extHost.protocol';
import { ITextEditorModel } from 'vs/workbench/common/editor';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { toLocalResource, extUri, IExtUri } from 'vs/base/common/resources';
@@ -47,8 +46,8 @@ export class BoundModelReferenceCollection {
}
}
add(uri: URI, ref: IReference<ITextEditorModel>): void {
const length = ref.object.textEditorModel.getValueLength();
add(uri: URI, ref: IReference<any>, length: number = 0): void {
// const length = ref.object.textEditorModel.getValueLength();
let handle: any;
let entry: { uri: URI, length: number, dispose(): void };
const dispose = () => {
@@ -267,7 +266,7 @@ export class MainThreadDocuments extends Disposable implements MainThreadDocumen
private _handleAsResourceInput(uri: URI): Promise<URI> {
return this._textModelResolverService.createModelReference(uri).then(ref => {
this._modelReferenceCollection.add(uri, ref);
this._modelReferenceCollection.add(uri, ref, ref.object.textEditorModel.getValueLength());
return ref.object.textEditorModel.uri;
});
}

View File

@@ -79,7 +79,6 @@ export class MainThreadTextEditorProperties {
return {
insertSpaces: modelOptions.insertSpaces,
tabSize: modelOptions.tabSize,
indentSize: modelOptions.indentSize,
cursorStyle: cursorStyle,
lineNumbers: lineNumbers
};
@@ -146,7 +145,6 @@ export class MainThreadTextEditorProperties {
}
return (
a.tabSize === b.tabSize
&& a.indentSize === b.indentSize
&& a.insertSpaces === b.insertSpaces
&& a.cursorStyle === b.cursorStyle
&& a.lineNumbers === b.lineNumbers
@@ -377,13 +375,6 @@ export class MainThreadTextEditor {
if (typeof newConfiguration.tabSize !== 'undefined') {
newOpts.tabSize = newConfiguration.tabSize;
}
if (typeof newConfiguration.indentSize !== 'undefined') {
if (newConfiguration.indentSize === 'tabSize') {
newOpts.indentSize = newOpts.tabSize || creationOpts.tabSize;
} else {
newOpts.indentSize = newConfiguration.indentSize;
}
}
this._model.updateOptions(newOpts);
}

View File

@@ -14,7 +14,7 @@ import { ISelection } from 'vs/editor/common/core/selection';
import { IDecorationOptions, IDecorationRenderOptions, ILineChange } from 'vs/editor/common/editorCommon';
import { ISingleEditOperation } from 'vs/editor/common/model';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { ITextEditorOptions, IResourceEditorInput, EditorActivation } from 'vs/platform/editor/common/editor';
import { ITextEditorOptions, IResourceEditorInput, EditorActivation, EditorOverride } from 'vs/platform/editor/common/editor';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { MainThreadDocumentsAndEditors } from 'vs/workbench/api/browser/mainThreadDocumentsAndEditors';
import { MainThreadTextEditor } from 'vs/workbench/api/browser/mainThreadEditor';
@@ -142,7 +142,7 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
// preserve pre 1.38 behaviour to not make group active when preserveFocus: true
// but make sure to restore the editor to fix https://github.com/microsoft/vscode/issues/79633
activation: options.preserveFocus ? EditorActivation.RESTORE : undefined,
override: false
override: EditorOverride.DISABLED
};
const input: IResourceEditorInput = {

View File

@@ -129,13 +129,13 @@ export class MainThreadFileSystemEventService {
}
} else {
if (operation === FileOperation.CREATE) {
message = localize('ask.N.create', "{0} extensions want to make refactoring changes with this file creation", data.extensionNames.length);
message = localize({ key: 'ask.N.create', comment: ['{0} is a number, e.g "3 extensions want..."'] }, "{0} extensions want to make refactoring changes with this file creation", data.extensionNames.length);
} else if (operation === FileOperation.COPY) {
message = localize('ask.N.copy', "{0} extensions want to make refactoring changes with this file copy", data.extensionNames.length);
message = localize({ key: 'ask.N.copy', comment: ['{0} is a number, e.g "3 extensions want..."'] }, "{0} extensions want to make refactoring changes with this file copy", data.extensionNames.length);
} else if (operation === FileOperation.MOVE) {
message = localize('ask.N.move', "{0} extensions want to make refactoring changes with this file move", data.extensionNames.length);
message = localize({ key: 'ask.N.move', comment: ['{0} is a number, e.g "3 extensions want..."'] }, "{0} extensions want to make refactoring changes with this file move", data.extensionNames.length);
} else /* if (operation === FileOperation.DELETE) */ {
message = localize('ask.N.delete', "{0} extensions want to make refactoring changes with this file deletion", data.extensionNames.length);
message = localize({ key: 'ask.N.delete', comment: ['{0} is a number, e.g "3 extensions want..."'] }, "{0} extensions want to make refactoring changes with this file deletion", data.extensionNames.length);
}
}

View File

@@ -250,6 +250,31 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
}));
}
// --- inline values
$registerInlineValuesProvider(handle: number, selector: IDocumentFilterDto[], eventHandle: number | undefined): void {
const provider = <modes.InlineValuesProvider>{
provideInlineValues: (model: ITextModel, viewPort: EditorRange, context: modes.InlineValueContext, token: CancellationToken): Promise<modes.InlineValue[] | undefined> => {
return this._proxy.$provideInlineValues(handle, model.uri, viewPort, context, token);
}
};
if (typeof eventHandle === 'number') {
const emitter = new Emitter<void>();
this._registrations.set(eventHandle, emitter);
provider.onDidChangeInlineValues = emitter.event;
}
this._registrations.set(handle, modes.InlineValuesProviderRegistry.register(selector, provider));
}
$emitInlineValuesEvent(eventHandle: number, event?: any): void {
const obj = this._registrations.get(eventHandle);
if (obj instanceof Emitter) {
obj.fire(event);
}
}
// --- occurrences
$registerDocumentHighlightProvider(handle: number, selector: IDocumentFilterDto[]): void {
@@ -727,7 +752,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
const languageIdentifier = this._modeService.getLanguageIdentifier(languageId);
if (languageIdentifier) {
this._registrations.set(handle, LanguageConfigurationRegistry.register(languageIdentifier, configuration));
this._registrations.set(handle, LanguageConfigurationRegistry.register(languageIdentifier, configuration, 100));
}
}

View File

@@ -11,6 +11,7 @@ import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { IPosition } from 'vs/editor/common/core/position';
import { IRange, Range } from 'vs/editor/common/core/range';
import { StandardTokenType } from 'vs/editor/common/modes';
import { ITextModelService } from 'vs/editor/common/services/resolverService';
@extHostNamedCustomer(MainContext.MainThreadLanguages)
export class MainThreadLanguages implements MainThreadLanguagesShape {
@@ -18,7 +19,8 @@ export class MainThreadLanguages implements MainThreadLanguagesShape {
constructor(
_extHostContext: IExtHostContext,
@IModeService private readonly _modeService: IModeService,
@IModelService private readonly _modelService: IModelService
@IModelService private readonly _modelService: IModelService,
@ITextModelService private _resolverService: ITextModelService,
) {
}
@@ -30,18 +32,20 @@ export class MainThreadLanguages implements MainThreadLanguagesShape {
return Promise.resolve(this._modeService.getRegisteredModes());
}
$changeLanguage(resource: UriComponents, languageId: string): Promise<void> {
const uri = URI.revive(resource);
const model = this._modelService.getModel(uri);
if (!model) {
return Promise.reject(new Error('Invalid uri'));
}
async $changeLanguage(resource: UriComponents, languageId: string): Promise<void> {
const languageIdentifier = this._modeService.getLanguageIdentifier(languageId);
if (!languageIdentifier || languageIdentifier.language !== languageId) {
return Promise.reject(new Error(`Unknown language id: ${languageId}`));
}
this._modelService.setMode(model, this._modeService.create(languageId));
return Promise.resolve(undefined);
const uri = URI.revive(resource);
const ref = await this._resolverService.createModelReference(uri);
try {
this._modelService.setMode(ref.object.textEditorModel, this._modeService.create(languageId));
} finally {
ref.dispose();
}
}
async $tokensAtPosition(resource: UriComponents, position: IPosition): Promise<undefined | { type: StandardTokenType, range: IRange }> {

View File

@@ -8,14 +8,14 @@ import { ILogService, LogLevel } from 'vs/platform/log/common/log';
import { IDisposable } from 'vs/base/common/lifecycle';
import { IExtHostContext, ExtHostContext, MainThreadLogShape, MainContext } from 'vs/workbench/api/common/extHost.protocol';
import { UriComponents, URI } from 'vs/base/common/uri';
import { FileLogService } from 'vs/platform/log/common/fileLogService';
import { FileLogger } from 'vs/platform/log/common/fileLog';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { basename } from 'vs/base/common/path';
@extHostNamedCustomer(MainContext.MainThreadLog)
export class MainThreadLogService implements MainThreadLogShape {
private readonly _loggers = new Map<string, FileLogService>();
private readonly _loggers = new Map<string, FileLogger>();
private readonly _logListener: IDisposable;
constructor(
@@ -40,7 +40,7 @@ export class MainThreadLogService implements MainThreadLogShape {
const uri = URI.revive(file);
let logger = this._loggers.get(uri.toString());
if (!logger) {
logger = this._instaService.createInstance(FileLogService, basename(file.path), URI.revive(file), this._logService.getLevel());
logger = this._instaService.createInstance(FileLogger, basename(file.path), URI.revive(file), this._logService.getLevel());
this._loggers.set(uri.toString(), logger);
}
logger.log(level, message);

View File

@@ -3,60 +3,46 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
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 { IRelativePattern } from 'vs/base/common/glob';
import { combinedDisposable, Disposable, DisposableStore, dispose, IDisposable, IReference } from 'vs/base/common/lifecycle';
import { combinedDisposable, Disposable, DisposableStore, dispose, IDisposable } 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 { isEqual } 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 { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { EditorActivation, ITextEditorOptions, EditorOverride } from 'vs/platform/editor/common/editor';
import { ILogService } from 'vs/platform/log/common/log';
import { BoundModelReferenceCollection } from 'vs/workbench/api/browser/mainThreadDocuments';
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, INotebookDecorationRenderOptions, INotebookDocumentFilter, INotebookEditorModel, INotebookExclusiveDocumentFilter, NotebookCellOutputsSplice, NotebookCellsChangeType, NOTEBOOK_DISPLAY_ORDER, TransientMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { ICellEditOperation, ICellRange, IEditor, IMainCellDto, INotebookDecorationRenderOptions, INotebookDocumentFilter, INotebookExclusiveDocumentFilter, INotebookKernel, NotebookCellsChangeType, 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 { 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, INotebookDocumentShowOptions, INotebookModelAddedData, MainContext, MainThreadNotebookShape, NotebookEditorRevealType, NotebookExtensionDescription } from '../common/extHost.protocol';
import { ExtHostContext, ExtHostNotebookShape, IExtHostContext, INotebookCellStatusBarEntryDto, INotebookDocumentsAndEditorsDelta, INotebookDocumentShowOptions, INotebookEditorAddData, INotebookModelAddedData, MainContext, MainThreadNotebookShape, NotebookEditorRevealType, NotebookExtensionDescription } from '../common/extHost.protocol';
class DocumentAndEditorState {
static compute(before: DocumentAndEditorState | undefined, after: DocumentAndEditorState): INotebookDocumentsAndEditorsDelta {
if (!before) {
const apiEditors = [];
for (let id in after.textEditors) {
const editor = after.textEditors.get(id)!;
apiEditors.push({ id, documentUri: editor.uri!, selections: editor!.getSelectionHandles(), visibleRanges: editor.visibleRanges });
}
return {
addedDocuments: [],
addedEditors: apiEditors,
addedDocuments: [...after.documents].map(DocumentAndEditorState._asModelAddData),
addedEditors: [...after.textEditors.values()].map(DocumentAndEditorState._asEditorAddData),
visibleEditors: [...after.visibleEditors].map(editor => editor[0])
};
}
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!,
selections: add.getSelectionHandles(),
visibleRanges: add.visibleRanges
}));
const addedAPIEditors = editorDelta.added.map(DocumentAndEditorState._asEditorAddData);
const removedAPIEditors = editorDelta.removed.map(removed => removed.getId());
@@ -66,29 +52,7 @@ class DocumentAndEditorState {
const visibleEditorDelta = diffMaps(before.visibleEditors, after.visibleEditors);
return {
addedDocuments: documentDelta.added.map((e: NotebookTextModel): INotebookModelAddedData => {
return {
viewType: e.viewType,
uri: e.uri,
metadata: e.metadata,
versionId: e.versionId,
cells: e.cells.map(cell => ({
handle: cell.handle,
uri: cell.uri,
source: cell.textBuffer.getLinesContent(),
eol: cell.textBuffer.getEOL(),
language: cell.language,
cellKind: cell.cellKind,
outputs: cell.outputs,
metadata: cell.metadata
})),
contentOptions: e.transientOptions,
// attachedEditor: editorId ? {
// id: editorId,
// selections: document.textModel.selections
// } : undefined
};
}),
addedDocuments: documentDelta.added.map(DocumentAndEditorState._asModelAddData),
removedDocuments: documentDelta.removed.map(e => e.uri),
addedEditors: addedAPIEditors,
removedEditors: removedAPIEditors,
@@ -107,42 +71,90 @@ class DocumentAndEditorState {
) {
//
}
private static _asModelAddData(e: NotebookTextModel): INotebookModelAddedData {
return {
viewType: e.viewType,
uri: e.uri,
metadata: e.metadata,
versionId: e.versionId,
cells: e.cells.map(cell => ({
handle: cell.handle,
uri: cell.uri,
source: cell.textBuffer.getLinesContent(),
eol: cell.textBuffer.getEOL(),
language: cell.language,
cellKind: cell.cellKind,
outputs: cell.outputs,
metadata: cell.metadata
})),
contentOptions: e.transientOptions,
};
}
private static _asEditorAddData(add: IEditor): INotebookEditorAddData {
return {
id: add.getId(),
documentUri: add.uri!,
selections: add.getSelections(),
visibleRanges: add.visibleRanges
};
}
}
@extHostNamedCustomer(MainContext.MainThreadNotebook)
export class MainThreadNotebooks extends Disposable implements MainThreadNotebookShape {
private readonly _proxy: ExtHostNotebookShape;
private readonly _notebookProviders = new Map<string, { controller: IMainNotebookController, disposable: IDisposable }>();
private readonly _notebookKernelProviders = new Map<number, { extension: NotebookExtensionDescription, emitter: Emitter<URI | undefined>, provider: IDisposable }>();
private readonly _proxy: ExtHostNotebookShape;
private _toDisposeOnEditorRemove = new Map<string, IDisposable>();
private _currentState?: DocumentAndEditorState;
private _editorEventListenersMapping: Map<string, DisposableStore> = new Map();
private _documentEventListenersMapping: ResourceMap<DisposableStore> = new ResourceMap();
private readonly _toDisposeOnEditorRemove = new Map<string, IDisposable>();
private readonly _editorEventListenersMapping: Map<string, DisposableStore> = new Map();
private readonly _documentEventListenersMapping: ResourceMap<DisposableStore> = new ResourceMap();
private readonly _cellStatusBarEntries: Map<number, IDisposable> = new Map();
private readonly _modelReferenceCollection: BoundModelReferenceCollection;
private _currentState?: DocumentAndEditorState;
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,
@ILogService private readonly logService: ILogService,
@INotebookCellStatusBarService private readonly cellStatusBarService: INotebookCellStatusBarService,
@IWorkingCopyService private readonly _workingCopyService: IWorkingCopyService,
@INotebookService private _notebookService: INotebookService,
@IConfigurationService private readonly _configurationService: IConfigurationService,
@IEditorService private readonly _editorService: IEditorService,
@IEditorGroupsService private readonly _editorGroupsService: IEditorGroupsService,
@ILogService private readonly _logService: ILogService,
@INotebookCellStatusBarService private readonly _cellStatusBarService: INotebookCellStatusBarService,
@INotebookEditorModelResolverService private readonly _notebookModelResolverService: INotebookEditorModelResolverService,
@IUriIdentityService private readonly _uriIdentityService: IUriIdentityService,
@IInstantiationService private readonly _instantiationService: IInstantiationService,
@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();
}
dispose(): void {
super.dispose();
this._modelReferenceCollection.dispose();
// remove all notebook providers
for (let item of this._notebookProviders.values()) {
item.disposable.dispose();
}
// remove all kernel providers
for (let item of this._notebookKernelProviders.values()) {
item.emitter.dispose();
item.provider.dispose();
}
dispose(this._editorEventListenersMapping.values());
dispose(this._documentEventListenersMapping.values());
dispose(this._toDisposeOnEditorRemove.values());
dispose(this._cellStatusBarEntries.values());
}
async $tryApplyEdits(_viewType: string, resource: UriComponents, modelVersionId: number, cellEdits: ICellEditOperation[]): Promise<boolean> {
const textModel = this._notebookService.getNotebookTextModel(URI.from(resource));
if (!textModel) {
@@ -188,6 +200,22 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
}
registerListeners() {
// forward changes to dirty state
// todo@rebornix todo@mjbvz this seem way too complicated... is there an easy way to
// the actual resource from a working copy?
this._register(this._workingCopyService.onDidChangeDirty(e => {
if (e.resource.scheme !== Schemas.vscodeNotebook) {
return;
}
for (const notebook of this._notebookService.getNotebookTextModels()) {
if (isEqual(notebook.uri.with({ scheme: Schemas.vscodeNotebook }), e.resource)) {
this._proxy.$acceptDirtyStateChanged(notebook.uri, e.isDirty());
break;
}
}
}));
this._notebookService.listNotebookEditors().forEach((e) => {
this._addNotebookEditor(e);
});
@@ -216,8 +244,7 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
}));
disposableStore.add(editor.onDidChangeSelection(() => {
const selectionHandles = editor.getSelectionHandles();
this._proxy.$acceptEditorPropertiesChanged(editor.getId(), { visibleRanges: null, selections: { selections: selectionHandles } });
this._proxy.$acceptEditorPropertiesChanged(editor.getId(), { visibleRanges: null, selections: { selections: editor.getSelections() } });
}));
this._editorEventListenersMapping.set(editor.getId(), disposableStore);
@@ -326,27 +353,7 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
this._proxy.$acceptModelSaved(e);
}));
const updateOrder = () => {
let userOrder = this.configurationService.getValue<string[]>(DisplayOrderKey);
this._proxy.$acceptDisplayOrder({
defaultOrder: this.accessibilityService.isScreenReaderOptimized() ? ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER : NOTEBOOK_DISPLAY_ORDER,
userOrder: userOrder
});
};
updateOrder();
this._register(this.configurationService.onDidChangeConfiguration(e => {
if (e.affectedKeys.indexOf(DisplayOrderKey) >= 0) {
updateOrder();
}
}));
this._register(this.accessibilityService.onDidChangeScreenReaderOptimized(() => {
updateOrder();
}));
const activeEditorPane = this.editorService.activeEditorPane as any | undefined;
const activeEditorPane = this._editorService.activeEditorPane as any | undefined;
const notebookEditor = activeEditorPane?.isNotebookEditor ? activeEditorPane.getControl() : undefined;
this._updateState(notebookEditor);
}
@@ -359,7 +366,7 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
}),
));
const activeEditorPane = this.editorService.activeEditorPane as any | undefined;
const activeEditorPane = this._editorService.activeEditorPane as any | undefined;
const notebookEditor = activeEditorPane?.isNotebookEditor ? activeEditorPane.getControl() : undefined;
this._updateState(notebookEditor);
}
@@ -379,7 +386,7 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
private async _updateState(focusedNotebookEditor?: IEditor) {
let activeEditor: string | null = null;
const activeEditorPane = this.editorService.activeEditorPane as any | undefined;
const activeEditorPane = this._editorService.activeEditorPane as any | undefined;
if (activeEditorPane?.isNotebookEditor) {
const notebookEditor = (activeEditorPane.getControl() as INotebookEditor);
activeEditor = notebookEditor && notebookEditor.hasModel() ? notebookEditor!.getId() : null;
@@ -396,7 +403,7 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
});
const visibleEditorsMap = new Map<string, IEditor>();
this.editorService.visibleEditorPanes.forEach(editor => {
this._editorService.visibleEditorPanes.forEach(editor => {
if ((editor as any).isNotebookEditor) {
const nbEditorWidget = (editor as any).getControl() as INotebookEditor;
if (nbEditorWidget && editors.has(nbEditorWidget.getId())) {
@@ -425,11 +432,11 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
// if (!isEmptyChange) {
this._currentState = newState;
await this._emitDelta(delta);
this._emitDelta(delta);
// }
}
async $registerNotebookProvider(extension: NotebookExtensionDescription, viewType: string, supportBackup: boolean, options: {
async $registerNotebookProvider(extension: NotebookExtensionDescription, viewType: string, options: {
transientOutputs: boolean;
transientMetadata: TransientMetadata;
viewOptions?: { displayName: string; filenamePattern: (string | IRelativePattern | INotebookExclusiveDocumentFilter)[]; exclusive: boolean; };
@@ -437,7 +444,6 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
let contentOptions = { transientOutputs: options.transientOutputs, transientMetadata: options.transientMetadata };
const controller: IMainNotebookController = {
supportBackup,
get options() {
return contentOptions;
},
@@ -446,24 +452,8 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
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 = contentOptions;
const edits: ICellEditOperation[] = [
{ editType: CellEditType.Replace, index: 0, count: mainthreadTextModel.cells.length, cells: data.cells }
];
await new Promise(resolve => {
DOM.scheduleAtNextAnimationFrame(() => {
const ret = mainthreadTextModel!.applyEdits(mainthreadTextModel!.versionId, edits, true, undefined, () => undefined, undefined);
resolve(ret);
});
});
},
resolveNotebookDocument: async (viewType: string, uri: URI, backupId?: string) => {
const data = await this._proxy.$resolveNotebookData(viewType, uri, backupId);
openNotebook: async (viewType: string, uri: URI, backupId?: string) => {
const data = await this._proxy.$openNotebook(viewType, uri, backupId);
return {
data,
transientOptions: contentOptions
@@ -482,13 +472,12 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
return this._proxy.$saveNotebookAs(viewType, uri, target, token);
},
backup: async (uri: URI, token: CancellationToken) => {
return this._proxy.$backup(viewType, uri, token);
return this._proxy.$backupNotebook(viewType, uri, token);
}
};
const disposable = this._notebookService.registerNotebookController(viewType, extension, controller);
this._notebookProviders.set(viewType, { controller, disposable });
return;
}
async $updateNotebookProviderOptions(viewType: string, options?: { transientOutputs: boolean; transientMetadata: TransientMetadata; }): Promise<void> {
@@ -515,38 +504,46 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
async $registerNotebookKernelProvider(extension: NotebookExtensionDescription, handle: number, documentFilter: INotebookDocumentFilter): Promise<void> {
const emitter = new Emitter<URI | undefined>();
const that = this;
const provider = this._notebookService.registerNotebookKernelProvider({
providerExtensionId: extension.id.value,
providerDescription: extension.description,
onDidChangeKernels: emitter.event,
selector: documentFilter,
provideKernels: async (uri: URI, token: CancellationToken) => {
const kernels = await that._proxy.$provideNotebookKernels(handle, uri, token);
return kernels.map(kernel => {
return {
...kernel,
providerHandle: handle
};
});
},
resolveKernel: (editorId: string, uri: URI, kernelId: string, token: CancellationToken) => {
return that._proxy.$resolveNotebookKernel(handle, editorId, uri, kernelId, token);
},
executeNotebook: (uri: URI, kernelId: string, cellHandle: number | undefined) => {
this.logService.debug('MainthreadNotebooks.registerNotebookKernelProvider#executeNotebook', uri.path, kernelId, cellHandle);
return that._proxy.$executeNotebookKernelFromProvider(handle, uri, kernelId, cellHandle);
},
cancelNotebook: (uri: URI, kernelId: string, cellHandle: number | undefined) => {
this.logService.debug('MainthreadNotebooks.registerNotebookKernelProvider#cancelNotebook', uri.path, kernelId, cellHandle);
return that._proxy.$cancelNotebookKernelFromProvider(handle, uri, kernelId, cellHandle);
},
provideKernels: async (uri: URI, token: CancellationToken): Promise<INotebookKernel[]> => {
const result: INotebookKernel[] = [];
const kernelsDto = await that._proxy.$provideNotebookKernels(handle, uri, token);
for (const dto of kernelsDto) {
result.push({
id: dto.id,
friendlyId: dto.friendlyId,
label: dto.label,
extension: dto.extension,
extensionLocation: URI.revive(dto.extensionLocation),
providerHandle: dto.providerHandle,
description: dto.description,
detail: dto.detail,
isPreferred: dto.isPreferred,
preloads: dto.preloads?.map(u => URI.revive(u)),
supportedLanguages: dto.supportedLanguages,
resolve: (uri: URI, editorId: string, token: CancellationToken): Promise<void> => {
this._logService.debug('MainthreadNotebooks.resolveNotebookKernel', uri.path, dto.friendlyId);
return this._proxy.$resolveNotebookKernel(handle, editorId, uri, dto.friendlyId, token);
},
executeNotebookCell: (uri: URI, cellHandle: number | undefined): Promise<void> => {
this._logService.debug('MainthreadNotebooks.executeNotebookCell', uri.path, dto.friendlyId, cellHandle);
return this._proxy.$executeNotebookKernelFromProvider(handle, uri, dto.friendlyId, cellHandle);
},
cancelNotebookCell: (uri: URI, cellHandle: number | undefined): Promise<void> => {
this._logService.debug('MainthreadNotebooks.cancelNotebookCell', uri.path, dto.friendlyId, cellHandle);
return this._proxy.$cancelNotebookKernelFromProvider(handle, uri, dto.friendlyId, cellHandle);
}
});
}
return result;
}
});
this._notebookKernelProviders.set(handle, {
extension,
emitter,
provider
});
this._notebookKernelProviders.set(handle, { extension, emitter, provider });
return;
}
@@ -566,35 +563,6 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
entry?.emitter.fire(uriComponents ? URI.revive(uriComponents) : undefined);
}
async $updateNotebookLanguages(viewType: string, resource: UriComponents, languages: string[]): Promise<void> {
this.logService.debug('MainThreadNotebooks#updateNotebookLanguages', resource.path, languages);
const textModel = this._notebookService.getNotebookTextModel(URI.from(resource));
textModel?.updateLanguages(languages);
}
async $spliceNotebookCellOutputs(viewType: string, resource: UriComponents, cellHandle: number, splices: NotebookCellOutputsSplice[]): Promise<void> {
this.logService.debug('MainThreadNotebooks#spliceNotebookCellOutputs', resource.path, cellHandle);
const textModel = this._notebookService.getNotebookTextModel(URI.from(resource));
if (!textModel) {
return;
}
const cell = textModel.cells.find(cell => cell.handle === cellHandle);
if (!cell) {
return;
}
textModel.applyEdits(textModel.versionId, [
{
editType: CellEditType.OutputsSplice,
index: textModel.cells.indexOf(cell),
splices
}
], true, undefined, () => undefined, undefined);
}
async $postMessage(editorId: string, forRendererId: string | undefined, value: any): Promise<boolean> {
const editor = this._notebookService.getNotebookEditor(editorId) as INotebookEditor | undefined;
if (editor?.isNotebookEditor) {
@@ -605,32 +573,6 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
return false;
}
$onUndoableContentChange(resource: UriComponents, viewType: string, editId: number, label: string | undefined): void {
const textModel = this._notebookService.getNotebookTextModel(URI.from(resource));
if (textModel) {
textModel.handleUnknownUndoableEdit(label, () => {
const isDirty = this._workingCopyService.isDirty(textModel.uri.with({ scheme: Schemas.vscodeNotebook }));
return this._proxy.$undoNotebook(textModel.viewType, textModel.uri, editId, isDirty);
}, () => {
const isDirty = this._workingCopyService.isDirty(textModel.uri.with({ scheme: Schemas.vscodeNotebook }));
return this._proxy.$redoNotebook(textModel.viewType, textModel.uri, editId, isDirty);
});
}
}
$onContentChange(resource: UriComponents, viewType: string): void {
const textModel = this._notebookService.getNotebookTextModel(URI.from(resource));
if (textModel) {
textModel.applyEdits(textModel.versionId, [
{
editType: CellEditType.Unknown
}
], true, undefined, () => undefined, undefined);
}
}
async $tryRevealRange(id: string, range: ICellRange, revealType: NotebookEditorRevealType) {
const editor = this._notebookService.listNotebookEditors().find(editor => editor.getId() === id);
if (editor && editor.isNotebookEditor) {
@@ -687,9 +629,7 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
}
if (statusBarEntry.visible) {
this._cellStatusBarEntries.set(
id,
this.cellStatusBarService.addEntry(statusBarEntry));
this._cellStatusBarEntries.set(id, this._cellStatusBarService.addEntry(statusBarEntry));
}
}
@@ -702,6 +642,15 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
return uri;
}
async $trySaveDocument(uriComponents: UriComponents) {
const uri = URI.revive(uriComponents);
const ref = await this._notebookModelResolverService.resolve(uri);
const saveResult = await ref.object.save();
ref.dispose();
return saveResult;
}
async $tryShowNotebookDocument(resource: UriComponents, viewType: string, options: INotebookDocumentShowOptions): Promise<string> {
const editorOptions: ITextEditorOptions = {
preserveFocus: options.preserveFocus,
@@ -710,36 +659,36 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
// 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,
override: EditorOverride.DISABLED,
};
const columnArg = viewColumnToEditorGroup(this._editorGroupService, options.position);
const columnArg = viewColumnToEditorGroup(this._editorGroupsService, options.position);
let group: IEditorGroup | undefined = undefined;
if (columnArg === SIDE_GROUP) {
const direction = preferredSideBySideGroupDirection(this.configurationService);
const direction = preferredSideBySideGroupDirection(this._configurationService);
let neighbourGroup = this.editorGroupsService.findGroup({ direction });
let neighbourGroup = this._editorGroupsService.findGroup({ direction });
if (!neighbourGroup) {
neighbourGroup = this.editorGroupsService.addGroup(this.editorGroupsService.activeGroup, direction);
neighbourGroup = this._editorGroupsService.addGroup(this._editorGroupsService.activeGroup, direction);
}
group = neighbourGroup;
} else {
group = this.editorGroupsService.getGroup(viewColumnToEditorGroup(this.editorGroupsService, columnArg)) ?? this.editorGroupsService.activeGroup;
group = this._editorGroupsService.getGroup(viewColumnToEditorGroup(this._editorGroupsService, columnArg)) ?? this._editorGroupsService.activeGroup;
}
const input = this.editorService.createEditorInput({ resource: URI.revive(resource), options: editorOptions });
const input = this._editorService.createEditorInput({ resource: URI.revive(resource), options: editorOptions });
// TODO: handle options.selection
const editorPane = await this._instantiationService.invokeFunction(openEditorWith, input, viewType, options, group);
const editorPane = await this._editorService.openEditor(input, { ...options, override: viewType }, group);
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);
notebookEditor.focusElement(focusedCell);
}
return notebookEditor.getId();
} else {
@@ -747,45 +696,3 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
}
}
}
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

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { DisposableStore, Disposable, IDisposable } from 'vs/base/common/lifecycle';
import { IShellLaunchConfig, ITerminalProcessExtHostProxy, ISpawnExtHostProcessRequest, ITerminalDimensions, IAvailableShellsRequest, IDefaultShellAndArgsRequest, IStartExtensionTerminalRequest, ITerminalConfiguration, TERMINAL_CONFIG_SECTION } from 'vs/workbench/contrib/terminal/common/terminal';
import { ITerminalProcessExtHostProxy, ISpawnExtHostProcessRequest, IAvailableShellsRequest, IDefaultShellAndArgsRequest, IStartExtensionTerminalRequest, ITerminalConfiguration, TERMINAL_CONFIG_SECTION } from 'vs/workbench/contrib/terminal/common/terminal';
import { ExtHostContext, ExtHostTerminalServiceShape, MainThreadTerminalServiceShape, MainContext, IExtHostContext, IShellLaunchConfigDto, TerminalLaunchConfig, ITerminalDimensionsDto, TerminalIdentifier } from 'vs/workbench/api/common/extHost.protocol';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { URI } from 'vs/base/common/uri';
@@ -12,11 +12,12 @@ import { StopWatch } from 'vs/base/common/stopwatch';
import { ITerminalInstanceService, ITerminalService, ITerminalInstance, ITerminalExternalLinkProvider, ITerminalLink } from 'vs/workbench/contrib/terminal/browser/terminal';
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { TerminalDataBufferer } from 'vs/workbench/contrib/terminal/common/terminalDataBuffering';
import { IEnvironmentVariableService, ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { TerminalDataBufferer } from 'vs/platform/terminal/common/terminalDataBuffering';
import { deserializeEnvironmentVariableCollection, serializeEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariableShared';
import { ILogService } from 'vs/platform/log/common/log';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IEnvironmentVariableService, ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { IShellLaunchConfig, ITerminalDimensions } from 'vs/platform/terminal/common/terminal';
@extHostNamedCustomer(MainContext.MainThreadTerminalService)
export class MainThreadTerminalService implements MainThreadTerminalServiceShape {
@@ -130,6 +131,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
strictEnv: launchConfig.strictEnv,
hideFromUser: launchConfig.hideFromUser,
isExtensionTerminal: launchConfig.isExtensionTerminal,
isExtensionOwnedTerminal: launchConfig.isExtensionOwnedTerminal,
extHostTerminalId: extHostTerminalId,
isFeatureTerminal: launchConfig.isFeatureTerminal
};

View File

@@ -4,11 +4,13 @@
*--------------------------------------------------------------------------------------------*/
import { CancellationToken } from 'vs/base/common/cancellation';
import { Disposable, IDisposable, MutableDisposable } from 'vs/base/common/lifecycle';
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
import { isDefined } from 'vs/base/common/types';
import { URI, UriComponents } from 'vs/base/common/uri';
import { Range } from 'vs/editor/common/core/range';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { getTestSubscriptionKey, RunTestsRequest, RunTestsResult, TestDiffOpType, TestsDiff } from 'vs/workbench/contrib/testing/common/testCollection';
import { ITestResultService } from 'vs/workbench/contrib/testing/common/testResultService';
import { getTestSubscriptionKey, ISerializedTestResults, ITestState, RunTestsRequest, TestDiffOpType, TestsDiff } from 'vs/workbench/contrib/testing/common/testCollection';
import { HydratedTestResult, ITestResultService, LiveTestResult } from 'vs/workbench/contrib/testing/common/testResultService';
import { ITestService } from 'vs/workbench/contrib/testing/common/testService';
import { ExtHostContext, ExtHostTestingResource, ExtHostTestingShape, IExtHostContext, MainContext, MainThreadTestingShape } from '../common/extHost.protocol';
@@ -18,12 +20,7 @@ const reviveDiff = (diff: TestsDiff) => {
const item = entry[1];
if (item.item.location) {
item.item.location.uri = URI.revive(item.item.location.uri);
}
for (const message of item.item.state.messages) {
if (message.location) {
message.location.uri = URI.revive(message.location.uri);
}
item.item.location.range = Range.lift(item.item.location.range);
}
}
}
@@ -33,49 +30,92 @@ const reviveDiff = (diff: TestsDiff) => {
export class MainThreadTesting extends Disposable implements MainThreadTestingShape {
private readonly proxy: ExtHostTestingShape;
private readonly testSubscriptions = new Map<string, IDisposable>();
private readonly testProviderRegistrations = new Map<string, IDisposable>();
constructor(
extHostContext: IExtHostContext,
@ITestService private readonly testService: ITestService,
@ITestResultService resultService: ITestResultService,
@ITestResultService private readonly resultService: ITestResultService,
) {
super();
this.proxy = extHostContext.getProxy(ExtHostContext.ExtHostTesting);
this._register(this.testService.onShouldSubscribe(args => this.proxy.$subscribeToTests(args.resource, args.uri)));
this._register(this.testService.onShouldUnsubscribe(args => this.proxy.$unsubscribeFromTests(args.resource, args.uri)));
const testCompleteListener = this._register(new MutableDisposable());
this._register(resultService.onNewTestResult(results => {
testCompleteListener.value = results.onComplete(() => this.proxy.$publishTestResults({ tests: results.tests }));
const prevResults = resultService.results.map(r => r.toJSON()).filter(isDefined);
if (prevResults.length) {
this.proxy.$publishTestResults(prevResults);
}
this._register(resultService.onResultsChanged(evt => {
const results = 'completed' in evt ? evt.completed : ('inserted' in evt ? evt.inserted : undefined);
const serialized = results?.toJSON();
if (serialized) {
this.proxy.$publishTestResults([serialized]);
}
}));
testService.updateRootProviderCount(1);
const lastCompleted = resultService.results.find(r => !r.isComplete);
if (lastCompleted) {
this.proxy.$publishTestResults({ tests: lastCompleted.tests });
}
for (const { resource, uri } of this.testService.subscriptions) {
this.proxy.$subscribeToTests(resource, uri);
}
}
/**
* @inheritdoc
*/
$publishExtensionProvidedResults(results: ISerializedTestResults, persist: boolean): void {
this.resultService.push(new HydratedTestResult(results, persist));
}
/**
* @inheritdoc
*/
$retireTest(extId: string): void {
for (const result of this.resultService.results) {
if (result instanceof LiveTestResult) {
result.retire(extId);
}
}
}
/**
* @inheritdoc
*/
$updateTestStateInRun(runId: string, testId: string, state: ITestState): void {
const r = this.resultService.getResult(runId);
if (r && r instanceof LiveTestResult) {
for (const message of state.messages) {
if (message.location) {
message.location.uri = URI.revive(message.location.uri);
message.location.range = Range.lift(message.location.range);
}
}
r.updateState(testId, state);
}
}
/**
* @inheritdoc
*/
public $registerTestProvider(id: string) {
this.testService.registerTestController(id, {
const disposable = this.testService.registerTestController(id, {
runTests: (req, token) => this.proxy.$runTestsForProvider(req, token),
lookupTest: test => this.proxy.$lookupTest(test),
});
this.testProviderRegistrations.set(id, disposable);
}
/**
* @inheritdoc
*/
public $unregisterTestProvider(id: string) {
this.testService.unregisterTestController(id);
this.testProviderRegistrations.get(id)?.dispose();
this.testProviderRegistrations.delete(id);
}
/**
@@ -105,11 +145,13 @@ export class MainThreadTesting extends Disposable implements MainThreadTestingSh
this.testService.publishDiff(resource, URI.revive(uri), diff);
}
public $runTests(req: RunTestsRequest, token: CancellationToken): Promise<RunTestsResult> {
return this.testService.runTests(req, token);
public async $runTests(req: RunTestsRequest, token: CancellationToken): Promise<string> {
const result = await this.testService.runTests(req, token);
return result.id;
}
public dispose() {
super.dispose();
this.testService.updateRootProviderCount(-1);
for (const subscription of this.testSubscriptions.values()) {
subscription.dispose();

View File

@@ -31,7 +31,7 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostTreeViews);
}
$registerTreeViewDataProvider(treeViewId: string, options: { showCollapseAll: boolean, canSelectMany: boolean }): void {
async $registerTreeViewDataProvider(treeViewId: string, options: { showCollapseAll: boolean, canSelectMany: boolean }): Promise<void> {
this.logService.trace('MainThreadTreeViews#$registerTreeViewDataProvider', treeViewId, options);
this.extensionService.whenInstalledExtensionsRegistered().then(() => {

View File

@@ -4,17 +4,17 @@
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import { MainThreadTunnelServiceShape, IExtHostContext, MainContext, ExtHostContext, ExtHostTunnelServiceShape } from 'vs/workbench/api/common/extHost.protocol';
import { MainThreadTunnelServiceShape, IExtHostContext, MainContext, ExtHostContext, ExtHostTunnelServiceShape, CandidatePortSource } from 'vs/workbench/api/common/extHost.protocol';
import { TunnelDto } from 'vs/workbench/api/common/extHostTunnelService';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { CandidatePort, IRemoteExplorerService, makeAddress } from 'vs/workbench/services/remote/common/remoteExplorerService';
import { CandidatePort, IRemoteExplorerService, makeAddress, PORT_AUTO_FORWARD_SETTING, PORT_AUTO_SOURCE_SETTING, PORT_AUTO_SOURCE_SETTING_OUTPUT } from 'vs/workbench/services/remote/common/remoteExplorerService';
import { ITunnelProvider, ITunnelService, TunnelCreationOptions, TunnelProviderFeatures, TunnelOptions, RemoteTunnel, isPortPrivileged } from 'vs/platform/remote/common/tunnel';
import { Disposable } from 'vs/base/common/lifecycle';
import type { TunnelDescription } from 'vs/platform/remote/common/remoteAuthorityResolver';
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { PORT_AUTO_FORWARD_SETTING } from 'vs/workbench/contrib/remote/browser/tunnelView';
import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ILogService } from 'vs/platform/log/common/log';
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
@extHostNamedCustomer(MainContext.MainThreadTunnelService)
export class MainThreadTunnelService extends Disposable implements MainThreadTunnelServiceShape {
@@ -27,7 +27,8 @@ export class MainThreadTunnelService extends Disposable implements MainThreadTun
@ITunnelService private readonly tunnelService: ITunnelService,
@INotificationService private readonly notificationService: INotificationService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@ILogService private readonly logService: ILogService
@ILogService private readonly logService: ILogService,
@IRemoteAgentService private readonly remoteAgentService: IRemoteAgentService
) {
super();
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostTunnelService);
@@ -35,7 +36,8 @@ export class MainThreadTunnelService extends Disposable implements MainThreadTun
this._register(tunnelService.onTunnelClosed(() => this._proxy.$onDidTunnelsChange()));
}
async $setCandidateFinder(): Promise<void> {
async $setRemoteTunnelService(processId: number): Promise<void> {
this.remoteExplorerService.namedProcesses.set(processId, 'Code Extension Host');
if (this.remoteExplorerService.portsFeaturesEnabled) {
this._proxy.$registerCandidateFinder(this.configurationService.getValue(PORT_AUTO_FORWARD_SETTING));
} else {
@@ -131,6 +133,32 @@ export class MainThreadTunnelService extends Disposable implements MainThreadTun
});
}
async $setCandidatePortSource(source: CandidatePortSource): Promise<void> {
// Must wait for the remote environment before trying to set settings there.
this.remoteAgentService.getEnvironment().then(() => {
switch (source) {
case CandidatePortSource.None: {
const autoDetectionEnablement = this.configurationService.inspect(PORT_AUTO_FORWARD_SETTING);
if (autoDetectionEnablement.userRemote === undefined) {
// Only update the remote setting if the user hasn't already set it.
this.configurationService.updateValue(PORT_AUTO_FORWARD_SETTING, false, ConfigurationTarget.USER_REMOTE);
}
break;
}
case CandidatePortSource.Output: {
const candidatePortSourceSetting = this.configurationService.inspect(PORT_AUTO_SOURCE_SETTING);
if (candidatePortSourceSetting.userRemote === undefined) {
// Only update the remote setting if the user hasn't already set it.
this.configurationService.updateValue(PORT_AUTO_SOURCE_SETTING, PORT_AUTO_SOURCE_SETTING_OUTPUT, ConfigurationTarget.USER_REMOTE);
}
break;
}
default: // Do nothing, the defaults for these settings should be used.
}
}).catch(() => {
// The remote failed to get setup. Errors from that area will already be surfaced to the user.
});
}
dispose(): void {

View File

@@ -56,7 +56,7 @@ export class MainThreadUriOpeners extends Disposable implements MainThreadUriOpe
return;
}
await this.extensionService.activateByEvent(`onUriOpen:${targetUri.scheme}`);
await this.extensionService.activateByEvent(`onOpenExternalUri:${targetUri.scheme}`);
for (const [id, openerMetadata] of this._registeredOpeners) {
if (openerMetadata.schemes.has(targetUri.scheme)) {
@@ -87,7 +87,10 @@ export class MainThreadUriOpeners extends Disposable implements MainThreadUriOpe
this.notificationService.notify({
severity: Severity.Error,
message: localize('openerFailedMessage', 'Could not open uri with \'{0}\': {1}', id, e.toString()),
message: localize({
key: 'openerFailedMessage',
comment: ['{0} is the id of the opener. {1} is the url being opened.'],
}, 'Could not open uri with \'{0}\': {1}', id, e.toString()),
actions: {
primary: [
openDefaultAction
@@ -117,7 +120,7 @@ export class MainThreadUriOpeners extends Disposable implements MainThreadUriOpe
extensionId,
});
this._contributedExternalUriOpenersStore.add(id, extensionId.value);
this._contributedExternalUriOpenersStore.didRegisterOpener(id, extensionId.value);
}
async $unregisterUriOpener(id: string): Promise<void> {

View File

@@ -16,6 +16,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
import { ILabelService } from 'vs/platform/label/common/label';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { IRequestService } from 'vs/platform/request/common/request';
import { WorkspaceTrustStateChangeEvent, IWorkspaceTrustService, WorkspaceTrustState } from 'vs/platform/workspace/common/workspaceTrust';
import { IWorkspace, IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { isUntitledWorkspace } from 'vs/platform/workspaces/common/workspaces';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
@@ -45,19 +46,21 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {
@IInstantiationService private readonly _instantiationService: IInstantiationService,
@ILabelService private readonly _labelService: ILabelService,
@IEnvironmentService private readonly _environmentService: IEnvironmentService,
@IFileService fileService: IFileService
@IFileService fileService: IFileService,
@IWorkspaceTrustService private readonly _workspaceTrustService: IWorkspaceTrustService
) {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostWorkspace);
const workspace = this._contextService.getWorkspace();
// The workspace file is provided be a unknown file system provider. It might come
// from the extension host. So initialize now knowing that `rootPath` is undefined.
if (workspace.configuration && !isNative && !fileService.canHandleResource(workspace.configuration)) {
this._proxy.$initializeWorkspace(this.getWorkspaceData(workspace));
this._proxy.$initializeWorkspace(this.getWorkspaceData(workspace), this.getWorkspaceTrustState());
} else {
this._contextService.getCompleteWorkspace().then(workspace => this._proxy.$initializeWorkspace(this.getWorkspaceData(workspace)));
this._contextService.getCompleteWorkspace().then(workspace => this._proxy.$initializeWorkspace(this.getWorkspaceData(workspace), this.getWorkspaceTrustState()));
}
this._contextService.onDidChangeWorkspaceFolders(this._onDidChangeWorkspace, this, this._toDispose);
this._contextService.onDidChangeWorkbenchState(this._onDidChangeWorkspace, this, this._toDispose);
this._workspaceTrustService.onDidChangeTrustState(this._onDidChangeWorkspaceTrustState, this, this._toDispose);
}
dispose(): void {
@@ -202,4 +205,18 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {
$resolveProxy(url: string): Promise<string | undefined> {
return this._requestService.resolveProxy(url);
}
// --- trust ---
$requireWorkspaceTrust(modal?: boolean): Promise<WorkspaceTrustState> {
return this._workspaceTrustService.requireWorkspaceTrust({ modal: modal ?? true });
}
private getWorkspaceTrustState(): WorkspaceTrustState {
return this._workspaceTrustService.getWorkspaceTrustState();
}
private _onDidChangeWorkspaceTrustState(state: WorkspaceTrustStateChangeEvent): void {
this._proxy.$onDidChangeWorkspaceTrustState(state);
}
}

View File

@@ -9,7 +9,6 @@ import { IJSONSchema } from 'vs/base/common/jsonSchema';
import * as resources from 'vs/base/common/resources';
import { URI } from 'vs/base/common/uri';
import { localize } from 'vs/nls';
import { registerAction2 } from 'vs/platform/actions/common/actions';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
@@ -18,8 +17,7 @@ import { Registry } from 'vs/platform/registry/common/platform';
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
import { CustomTreeView, TreeViewPane } from 'vs/workbench/browser/parts/views/treeView';
import { ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneContainer';
import { Extensions as ViewletExtensions, ShowViewletAction2, ViewletRegistry } from 'vs/workbench/browser/viewlet';
import { CATEGORIES } from 'vs/workbench/common/actions';
import { Extensions as ViewletExtensions, ViewletRegistry } from 'vs/workbench/browser/viewlet';
import { Extensions as WorkbenchExtensions, IWorkbenchContribution, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions';
import { Extensions as ViewContainerExtensions, ITreeViewDescriptor, IViewContainersRegistry, IViewDescriptor, IViewsRegistry, ViewContainer, ViewContainerLocation } from 'vs/workbench/common/views';
import { VIEWLET_ID as DEBUG } from 'vs/workbench/contrib/debug/common/debug';
@@ -158,6 +156,7 @@ const viewDescriptor: IJSONSchema = {
const remoteViewDescriptor: IJSONSchema = {
type: 'object',
required: ['id', 'name'],
properties: {
id: {
description: localize('vscode.extension.contributes.view.id', 'Identifier of the view. This should be unique across all views. It is recommended to include your extension id as part of the view id. Use this to register a data provider through `vscode.window.registerTreeDataProviderForView` API. Also to trigger activating your extension by registering `onView:${id}` event to `activationEvents`.'),
@@ -374,7 +373,7 @@ class ViewsExtensionHandler implements IWorkbenchContribution {
viewContainer = this.viewContainersRegistry.registerViewContainer({
id,
name: title, extensionId,
title, extensionId,
ctorDescriptor: new SyncDescriptor(
ViewPaneContainer,
[id, { mergeViewWithContainerWhenSingleView: true }]
@@ -384,16 +383,6 @@ class ViewsExtensionHandler implements IWorkbenchContribution {
icon,
}, location);
// Register Action to Open Viewlet
registerAction2(class OpenCustomViewletAction extends ShowViewletAction2 {
constructor() {
super({ id, f1: true, title: localize('showViewlet', "Show {0}", title), category: CATEGORIES.View.value });
}
protected viewletId() {
return id;
}
});
}
return viewContainer;
@@ -474,7 +463,7 @@ class ViewsExtensionHandler implements IWorkbenchContribution {
name: item.name,
when: ContextKeyExpr.deserialize(item.when),
containerIcon: icon || viewContainer?.icon,
containerTitle: item.contextualTitle || viewContainer?.name,
containerTitle: item.contextualTitle || viewContainer?.title,
canToggleVisibility: true,
canMoveView: viewContainer?.id !== REMOTE,
treeView: type === ViewType.Tree ? this.instantiationService.createInstance(CustomTreeView, item.id, item.name) : undefined,

View File

@@ -15,7 +15,7 @@ import { OverviewRulerLane } from 'vs/editor/common/model';
import * as languageConfiguration from 'vs/editor/common/modes/languageConfiguration';
import { score } from 'vs/editor/common/modes/languageSelector';
import * as files from 'vs/platform/files/common/files';
import { ExtHostContext, MainContext, ExtHostLogServiceShape, UIKind } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostContext, MainContext, ExtHostLogServiceShape, UIKind, CandidatePortSource } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostApiCommands } from 'vs/workbench/api/common/extHostApiCommands';
import { ExtHostClipboard } from 'vs/workbench/api/common/extHostClipboard';
import { IExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
@@ -35,7 +35,7 @@ import { ExtHostLanguages } from 'vs/workbench/api/common/extHostLanguages';
import { ExtHostMessageService } from 'vs/workbench/api/common/extHostMessageService';
import { IExtHostOutputService } from 'vs/workbench/api/common/extHostOutput';
import { ExtHostProgress } from 'vs/workbench/api/common/extHostProgress';
import { ExtHostQuickOpen } from 'vs/workbench/api/common/extHostQuickOpen';
import { createExtHostQuickOpen } from 'vs/workbench/api/common/extHostQuickOpen';
import { ExtHostSCM } from 'vs/workbench/api/common/extHostSCM';
import { ExtHostStatusBar } from 'vs/workbench/api/common/extHostStatusBar';
import { IExtHostStorage } from 'vs/workbench/api/common/extHostStorage';
@@ -48,7 +48,7 @@ import { ExtHostUrls } from 'vs/workbench/api/common/extHostUrls';
import { ExtHostWebviews } from 'vs/workbench/api/common/extHostWebview';
import { IExtHostWindow } from 'vs/workbench/api/common/extHostWindow';
import { IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
import { throwProposedApiError, checkProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions';
import { throwProposedApiError, checkProposedApiEnabled, checkRequiresWorkspaceTrust } from 'vs/workbench/services/extensions/common/extensions';
import { ProxyIdentifier } from 'vs/workbench/services/extensions/common/proxyIdentifier';
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry';
import type * as vscode from 'vscode';
@@ -147,7 +147,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
const extHostLanguageFeatures = rpcProtocol.set(ExtHostContext.ExtHostLanguageFeatures, new ExtHostLanguageFeatures(rpcProtocol, uriTransformer, extHostDocuments, extHostCommands, extHostDiagnostics, extHostLogService, extHostApiDeprecation));
const extHostFileSystem = rpcProtocol.set(ExtHostContext.ExtHostFileSystem, new ExtHostFileSystem(rpcProtocol, extHostLanguageFeatures));
const extHostFileSystemEvent = rpcProtocol.set(ExtHostContext.ExtHostFileSystemEventService, new ExtHostFileSystemEventService(rpcProtocol, extHostLogService, extHostDocumentsAndEditors));
const extHostQuickOpen = rpcProtocol.set(ExtHostContext.ExtHostQuickOpen, new ExtHostQuickOpen(rpcProtocol, extHostWorkspace, extHostCommands));
const extHostQuickOpen = rpcProtocol.set(ExtHostContext.ExtHostQuickOpen, createExtHostQuickOpen(rpcProtocol, extHostWorkspace, extHostCommands));
const extHostSCM = rpcProtocol.set(ExtHostContext.ExtHostSCM, new ExtHostSCM(rpcProtocol, extHostCommands, extHostLogService));
const extHostComment = rpcProtocol.set(ExtHostContext.ExtHostComments, new ExtHostComments(rpcProtocol, extHostCommands, extHostDocuments));
const extHostProgress = rpcProtocol.set(ExtHostContext.ExtHostProgress, new ExtHostProgress(rpcProtocol.getProxy(MainContext.MainThreadProgress)));
@@ -198,10 +198,11 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
} else if (typeof selector === 'string') {
informOnce(selector);
} else {
if (typeof selector.scheme === 'undefined') {
const filter = selector as vscode.DocumentFilter; // TODO: microsoft/TypeScript#42768
if (typeof filter.scheme === 'undefined') {
informOnce(selector);
}
if (!extension.enableProposedApi && typeof selector.exclusive === 'boolean') {
if (!extension.enableProposedApi && typeof filter.exclusive === 'boolean') {
throwProposedApiError(extension);
}
}
@@ -217,7 +218,6 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
return extHostAuthentication.onDidChangeSessions;
},
registerAuthenticationProvider(id: string, label: string, provider: vscode.AuthenticationProvider, options?: vscode.AuthenticationProviderOptions): vscode.Disposable {
checkProposedApiEnabled(extension);
return extHostAuthentication.registerAuthenticationProvider(id, label, provider, options);
},
get onDidChangeAuthenticationProviders(): Event<vscode.AuthenticationProvidersChangeEvent> {
@@ -230,7 +230,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
},
logout(providerId: string, sessionId: string): Thenable<void> {
checkProposedApiEnabled(extension);
return extHostAuthentication.logout(providerId, sessionId);
return extHostAuthentication.removeSession(providerId, sessionId);
}
};
@@ -262,7 +262,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
registerDiffInformationCommand: (id: string, callback: (diff: vscode.LineChange[], ...args: any[]) => any, thisArg?: any): vscode.Disposable => {
checkProposedApiEnabled(extension);
return extHostCommands.registerCommand(true, id, async (...args: any[]): Promise<any> => {
const activeTextEditor = extHostEditors.getActiveTextEditor();
const activeTextEditor = extHostDocumentsAndEditors.activeEditor(true);
if (!activeTextEditor) {
extHostLogService.warn('Cannot execute ' + id + ' because there is no active text editor.');
return undefined;
@@ -288,9 +288,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
get appName() { return initData.environment.appName; },
get appRoot() { return initData.environment.appRoot?.fsPath ?? ''; },
get uriScheme() { return initData.environment.appUriScheme; },
get clipboard(): vscode.Clipboard {
return extHostClipboard;
},
get clipboard(): vscode.Clipboard { return extHostClipboard.value; },
get shell() {
return extHostTerminalService.getDefaultShell(false, configProvider);
},
@@ -340,13 +338,17 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
checkProposedApiEnabled(extension);
return extHostTesting.runTests(provider);
},
publishTestResult(results, persist = true) {
checkProposedApiEnabled(extension);
return extHostTesting.publishExtensionProvidedResults(results, persist);
},
get onDidChangeTestResults() {
checkProposedApiEnabled(extension);
return extHostTesting.onLastResultsChanged;
return extHostTesting.onResultsChanged;
},
get testResults() {
checkProposedApiEnabled(extension);
return extHostTesting.lastResults;
return extHostTesting.results;
},
};
@@ -411,6 +413,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
registerEvaluatableExpressionProvider(selector: vscode.DocumentSelector, provider: vscode.EvaluatableExpressionProvider): vscode.Disposable {
return extHostLanguageFeatures.registerEvaluatableExpressionProvider(extension, checkSelector(selector), provider, extension.identifier);
},
registerInlineValuesProvider(selector: vscode.DocumentSelector, provider: vscode.InlineValuesProvider): vscode.Disposable {
checkProposedApiEnabled(extension);
return extHostLanguageFeatures.registerInlineValuesProvider(extension, checkSelector(selector), provider, extension.identifier);
},
registerDocumentHighlightProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentHighlightProvider): vscode.Disposable {
return extHostLanguageFeatures.registerDocumentHighlightProvider(extension, checkSelector(selector), provider);
},
@@ -570,7 +576,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
showSaveDialog(options) {
return extHostDialogs.showSaveDialog(options);
},
createStatusBarItem(alignmentOrOptions?: vscode.StatusBarAlignment | vscode.window.StatusBarItemOptions, priority?: number): vscode.StatusBarItem {
createStatusBarItem(alignmentOrOptions?: vscode.StatusBarAlignment | vscode.StatusBarItemOptions, priority?: number): vscode.StatusBarItem {
let id: string;
let name: string;
let alignment: number | undefined;
@@ -831,7 +837,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
return extHostFileSystem.registerFileSystemProvider(extension.identifier, scheme, provider, options);
},
get fs() {
return extHostConsumerFileSystem;
return extHostConsumerFileSystem.value;
},
registerFileSearchProvider: (scheme: string, provider: vscode.FileSearchProvider) => {
checkProposedApiEnabled(extension);
@@ -883,11 +889,23 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
onDidChangeTunnels: (listener, thisArg?, disposables?) => {
checkProposedApiEnabled(extension);
return extHostTunnelService.onDidChangeTunnels(listener, thisArg, disposables);
},
registerTimelineProvider: (scheme: string | string[], provider: vscode.TimelineProvider) => {
checkProposedApiEnabled(extension);
return extHostTimeline.registerTimelineProvider(scheme, provider, extension.identifier, extHostCommands.converter);
},
get trustState() {
checkProposedApiEnabled(extension);
checkRequiresWorkspaceTrust(extension);
return extHostWorkspace.trustState;
},
requireWorkspaceTrust: (modal?: boolean) => {
checkProposedApiEnabled(extension);
checkRequiresWorkspaceTrust(extension);
return extHostWorkspace.requireWorkspaceTrust(modal);
},
onDidChangeWorkspaceTrustState: (listener, thisArgs?, disposables?) => {
return extHostWorkspace.onDidChangeWorkspaceTrustState(listener, thisArgs, disposables);
}
};
@@ -1119,6 +1137,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
CallHierarchyOutgoingCall: extHostTypes.CallHierarchyOutgoingCall,
CancellationError: errors.CancellationError,
CancellationTokenSource: CancellationTokenSource,
CandidatePortSource: CandidatePortSource,
CodeAction: extHostTypes.CodeAction,
CodeActionKind: extHostTypes.CodeActionKind,
CodeActionTrigger: extHostTypes.CodeActionTrigger,
@@ -1155,6 +1174,9 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
EndOfLine: extHostTypes.EndOfLine,
EnvironmentVariableMutatorType: extHostTypes.EnvironmentVariableMutatorType,
EvaluatableExpression: extHostTypes.EvaluatableExpression,
InlineValueText: extHostTypes.InlineValueText,
InlineValueVariableLookup: extHostTypes.InlineValueVariableLookup,
InlineValueEvaluatableExpression: extHostTypes.InlineValueEvaluatableExpression,
EventEmitter: Emitter,
ExtensionKind: extHostTypes.ExtensionKind,
ExtensionMode: extHostTypes.ExtensionMode,
@@ -1168,7 +1190,6 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
FunctionBreakpoint: extHostTypes.FunctionBreakpoint,
Hover: extHostTypes.Hover,
IndentAction: languageConfiguration.IndentAction,
InlineHint: extHostTypes.InlineHint,
Location: extHostTypes.Location,
MarkdownString: extHostTypes.MarkdownString,
OverviewRulerLane: OverviewRulerLane,
@@ -1218,6 +1239,12 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
ViewColumn: extHostTypes.ViewColumn,
WorkspaceEdit: extHostTypes.WorkspaceEdit,
// proposed api types
get InlineHint() {
return extHostTypes.InlineHint;
},
get InlineHintKind() {
return extHostTypes.InlineHintKind;
},
get RemoteAuthorityResolverError() {
// checkProposedApiEnabled(extension);
return extHostTypes.RemoteAuthorityResolverError;
@@ -1238,18 +1265,23 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
// checkProposedApiEnabled(extension);
return extHostTypes.TimelineItem;
},
get CellKind() {
// checkProposedApiEnabled(extension);
return extHostTypes.CellKind;
get NotebookCellRange() {
return extHostTypes.NotebookCellRange;
},
get CellOutputKind() {
get NotebookCellKind() {
// checkProposedApiEnabled(extension);
return extHostTypes.CellOutputKind;
return extHostTypes.NotebookCellKind;
},
get NotebookCellRunState() {
// checkProposedApiEnabled(extension);
return extHostTypes.NotebookCellRunState;
},
get NotebookDocumentMetadata() {
return extHostTypes.NotebookDocumentMetadata;
},
get NotebookCellMetadata() {
return extHostTypes.NotebookCellMetadata;
},
get NotebookRunState() {
// checkProposedApiEnabled(extension);
return extHostTypes.NotebookRunState;
@@ -1282,19 +1314,19 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
// checkProposedApiEnabled(extension);
return extHostTypes.TestMessageSeverity;
},
get TestState() {
get WorkspaceTrustState() {
// checkProposedApiEnabled(extension);
return extHostTypes.TestState;
},
return extHostTypes.WorkspaceTrustState;
}
};
};
}
class Extension<T> implements vscode.Extension<T> {
private _extensionService: IExtHostExtensionService;
private _originExtensionId: ExtensionIdentifier;
private _identifier: ExtensionIdentifier;
#extensionService: IExtHostExtensionService;
#originExtensionId: ExtensionIdentifier;
#identifier: ExtensionIdentifier;
readonly id: string;
readonly extensionUri: URI;
@@ -1303,9 +1335,9 @@ class Extension<T> implements vscode.Extension<T> {
readonly extensionKind: vscode.ExtensionKind;
constructor(extensionService: IExtHostExtensionService, originExtensionId: ExtensionIdentifier, description: IExtensionDescription, kind: extHostTypes.ExtensionKind) {
this._extensionService = extensionService;
this._originExtensionId = originExtensionId;
this._identifier = description.identifier;
this.#extensionService = extensionService;
this.#originExtensionId = originExtensionId;
this.#identifier = description.identifier;
this.id = description.identifier.value;
this.extensionUri = description.extensionLocation;
this.extensionPath = path.normalize(originalFSPath(description.extensionLocation));
@@ -1314,17 +1346,17 @@ class Extension<T> implements vscode.Extension<T> {
}
get isActive(): boolean {
return this._extensionService.isActivated(this._identifier);
return this.#extensionService.isActivated(this.#identifier);
}
get exports(): T {
if (this.packageJSON.api === 'none') {
return undefined!; // Strict nulloverride - Public api
}
return <T>this._extensionService.getExtensionExports(this._identifier);
return <T>this.#extensionService.getExtensionExports(this.#identifier);
}
activate(): Thenable<T> {
return this._extensionService.activateByIdWithErrors(this._identifier, { startup: false, extensionId: this._originExtensionId, activationEvent: 'api' }).then(() => this.exports);
return this.#extensionService.activateByIdWithErrors(this.#identifier, { startup: false, extensionId: this.#originExtensionId, activationEvent: 'api' }).then(() => this.exports);
}
}

View File

@@ -41,7 +41,6 @@ import * as tasks from 'vs/workbench/api/common/shared/tasks';
import { IRevealOptions, ITreeItem } from 'vs/workbench/common/views';
import { IAdapterDescriptor, IConfig, IDebugSessionReplMode } from 'vs/workbench/contrib/debug/common/debug';
import { ITextQueryBuilderOptions } from 'vs/workbench/contrib/search/common/queryBuilder';
import { ITerminalDimensions, IShellLaunchConfig, ITerminalLaunchError } from 'vs/workbench/contrib/terminal/common/terminal';
import { ActivationKind, ExtensionActivationError, ExtensionHostKind } from 'vs/workbench/services/extensions/common/extensions';
import { createExtHostContextProxyIdentifier as createExtId, createMainContextProxyIdentifier as createMainId, IRPCProtocol } from 'vs/workbench/services/extensions/common/proxyIdentifier';
import * as search from 'vs/workbench/services/search/common/search';
@@ -51,15 +50,17 @@ import { TunnelDto } from 'vs/workbench/api/common/extHostTunnelService';
import { TunnelCreationOptions, TunnelProviderFeatures, TunnelOptions } from 'vs/platform/remote/common/tunnel';
import { Timeline, TimelineChangeEvent, TimelineOptions, TimelineProviderDescriptor, InternalTimelineOptions } from 'vs/workbench/contrib/timeline/common/timeline';
import { revive } from 'vs/base/common/marshalling';
import { IProcessedOutput, INotebookDisplayOrder, NotebookCellMetadata, NotebookDocumentMetadata, ICellEditOperation, NotebookCellsChangedEventDto, NotebookDataDto, IMainCellDto, INotebookDocumentFilter, INotebookKernelInfoDto2, TransientMetadata, INotebookCellStatusBarEntry, ICellRange, INotebookDecorationRenderOptions, INotebookExclusiveDocumentFilter } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { NotebookCellMetadata, NotebookDocumentMetadata, ICellEditOperation, NotebookCellsChangedEventDto, NotebookDataDto, IMainCellDto, INotebookDocumentFilter, TransientMetadata, INotebookCellStatusBarEntry, ICellRange, INotebookDecorationRenderOptions, INotebookExclusiveDocumentFilter, IOutputDto } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { CallHierarchyItem } from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
import { Dto } from 'vs/base/common/types';
import { ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { DebugConfigurationProviderTriggerKind } from 'vs/workbench/api/common/extHostTypes';
import { DebugConfigurationProviderTriggerKind, WorkspaceTrustState } from 'vs/workbench/api/common/extHostTypes';
import { IAccessibilityInformation } from 'vs/platform/accessibility/common/accessibility';
import { IExtensionIdWithVersion } from 'vs/platform/userDataSync/common/extensionsStorageSync';
import { InternalTestItem, InternalTestResults, RunTestForProviderRequest, RunTestsRequest, RunTestsResult, TestIdWithProvider, TestsDiff } from 'vs/workbench/contrib/testing/common/testCollection';
import { InternalTestItem, ITestState, RunTestForProviderRequest, RunTestsRequest, TestIdWithProvider, TestsDiff, ISerializedTestResults } from 'vs/workbench/contrib/testing/common/testCollection';
import { CandidatePort } from 'vs/workbench/services/remote/common/remoteExplorerService';
import { WorkspaceTrustStateChangeEvent } from 'vs/platform/workspace/common/workspaceTrust';
import { ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { IShellLaunchConfig, ITerminalDimensions, ITerminalLaunchError } from 'vs/platform/terminal/common/terminal';
export interface IEnvironment {
isExtensionDevelopmentDebug: boolean;
@@ -165,18 +166,9 @@ export interface MainThreadAuthenticationShape extends IDisposable {
$registerAuthenticationProvider(id: string, label: string, supportsMultipleAccounts: boolean): void;
$unregisterAuthenticationProvider(id: string): void;
$ensureProvider(id: string): Promise<void>;
$getProviderIds(): Promise<string[]>;
$sendDidChangeSessions(providerId: string, event: modes.AuthenticationSessionsChangeEvent): void;
$getSession(providerId: string, scopes: string[], extensionId: string, extensionName: string, options: { createIfNone?: boolean, clearSessionPreference?: boolean }): Promise<modes.AuthenticationSession | undefined>;
$selectSession(providerId: string, providerName: string, extensionId: string, extensionName: string, potentialSessions: modes.AuthenticationSession[], scopes: string[], clearSessionPreference: boolean): Promise<modes.AuthenticationSession>;
$getSessionsPrompt(providerId: string, accountName: string, providerName: string, extensionId: string, extensionName: string): Promise<boolean>;
$loginPrompt(providerName: string, extensionName: string): Promise<boolean>;
$setTrustedExtensionAndAccountPreference(providerId: string, accountName: string, extensionId: string, extensionName: string, sessionId: string): Promise<void>;
$requestNewSession(providerId: string, scopes: string[], extensionId: string, extensionName: string): Promise<void>;
$getSessions(providerId: string): Promise<ReadonlyArray<modes.AuthenticationSession>>;
$login(providerId: string, scopes: string[]): Promise<modes.AuthenticationSession>;
$logout(providerId: string, sessionId: string): Promise<void>;
$removeSession(providerId: string, sessionId: string): Promise<void>;
}
export interface MainThreadSecretStateShape extends IDisposable {
@@ -237,7 +229,6 @@ export interface MainThreadDocumentsShape extends IDisposable {
export interface ITextEditorConfigurationUpdate {
tabSize?: number | 'auto';
indentSize?: number | 'tabSize';
insertSpaces?: boolean | 'auto';
cursorStyle?: TextEditorCursorStyle;
lineNumbers?: RenderLineNumbersType;
@@ -245,7 +236,6 @@ export interface ITextEditorConfigurationUpdate {
export interface IResolvedTextEditorConfiguration {
tabSize: number;
indentSize: number;
insertSpaces: boolean;
cursorStyle: TextEditorCursorStyle;
lineNumbers: RenderLineNumbersType;
@@ -295,7 +285,7 @@ export interface MainThreadTextEditorsShape extends IDisposable {
}
export interface MainThreadTreeViewsShape extends IDisposable {
$registerTreeViewDataProvider(treeViewId: string, options: { showCollapseAll: boolean, canSelectMany: boolean; }): void;
$registerTreeViewDataProvider(treeViewId: string, options: { showCollapseAll: boolean, canSelectMany: boolean; }): Promise<void>;
$refresh(treeViewId: string, itemsToRefresh?: { [treeItemHandle: string]: ITreeItem; }): Promise<void>;
$reveal(treeViewId: string, itemInfo: { item: ITreeItem, parentChain: ITreeItem[] } | undefined, options: IRevealOptions): Promise<void>;
$setMessage(treeViewId: string, message: string): void;
@@ -388,6 +378,8 @@ export interface MainThreadLanguageFeaturesShape extends IDisposable {
$registerTypeDefinitionSupport(handle: number, selector: IDocumentFilterDto[]): void;
$registerHoverProvider(handle: number, selector: IDocumentFilterDto[]): void;
$registerEvaluatableExpressionProvider(handle: number, selector: IDocumentFilterDto[]): void;
$registerInlineValuesProvider(handle: number, selector: IDocumentFilterDto[], eventHandle: number | undefined): void;
$emitInlineValuesEvent(eventHandle: number, event?: any): void;
$registerDocumentHighlightProvider(handle: number, selector: IDocumentFilterDto[]): void;
$registerLinkedEditingRangeProvider(handle: number, selector: IDocumentFilterDto[]): void;
$registerReferenceSupport(handle: number, selector: IDocumentFilterDto[]): void;
@@ -467,6 +459,7 @@ export interface TerminalLaunchConfig {
hideFromUser?: boolean;
isExtensionTerminal?: boolean;
isFeatureTerminal?: boolean;
isExtensionOwnedTerminal?: boolean;
}
export interface MainThreadTerminalServiceShape extends IDisposable {
@@ -755,7 +748,7 @@ export interface ICellDto {
source: string[];
language: string;
cellKind: CellKind;
outputs: IProcessedOutput[];
outputs: IOutputDto[];
metadata?: NotebookCellMetadata;
}
@@ -768,7 +761,7 @@ export type NotebookCellsSplice = [
export type NotebookCellOutputsSplice = [
number /* start */,
number /* delete count */,
IProcessedOutput[]
IOutputDto[]
];
export enum NotebookEditorRevealType {
@@ -788,7 +781,7 @@ export interface INotebookDocumentShowOptions {
export type INotebookCellStatusBarEntryDto = Dto<INotebookCellStatusBarEntry>;
export interface MainThreadNotebookShape extends IDisposable {
$registerNotebookProvider(extension: NotebookExtensionDescription, viewType: string, supportBackup: boolean, options: {
$registerNotebookProvider(extension: NotebookExtensionDescription, viewType: string, options: {
transientOutputs: boolean;
transientMetadata: TransientMetadata;
viewOptions?: { displayName: string; filenamePattern: (string | IRelativePattern | INotebookExclusiveDocumentFilter)[]; exclusive: boolean; };
@@ -798,9 +791,8 @@ export interface MainThreadNotebookShape extends IDisposable {
$registerNotebookKernelProvider(extension: NotebookExtensionDescription, handle: number, documentFilter: INotebookDocumentFilter): Promise<void>;
$unregisterNotebookKernelProvider(handle: number): Promise<void>;
$onNotebookKernelChange(handle: number, uri: UriComponents | undefined): void;
$trySaveDocument(uri: UriComponents): Promise<boolean>;
$tryApplyEdits(viewType: string, resource: UriComponents, modelVersionId: number, edits: ICellEditOperation[]): Promise<boolean>;
$updateNotebookLanguages(viewType: string, resource: UriComponents, languages: string[]): Promise<void>;
$spliceNotebookCellOutputs(viewType: string, resource: UriComponents, cellHandle: number, splices: NotebookCellOutputsSplice[]): Promise<void>;
$postMessage(editorId: string, forRendererId: string | undefined, value: any): Promise<boolean>;
$setStatusBarEntry(id: number, statusBarEntry: INotebookCellStatusBarEntryDto): Promise<void>;
$tryOpenDocument(uriComponents: UriComponents, viewType?: string): Promise<URI>;
@@ -809,8 +801,6 @@ export interface MainThreadNotebookShape extends IDisposable {
$registerNotebookEditorDecorationType(key: string, options: INotebookDecorationRenderOptions): void;
$removeNotebookEditorDecorationType(key: string): void;
$trySetDecorations(id: string, range: ICellRange, decorationKey: string): void;
$onUndoableContentChange(resource: UriComponents, viewType: string, editId: number, label: string | undefined): void;
$onContentChange(resource: UriComponents, viewType: string): void;
}
export interface MainThreadUrlsShape extends IDisposable {
@@ -844,6 +834,7 @@ export interface MainThreadWorkspaceShape extends IDisposable {
$saveAll(includeUntitled?: boolean): Promise<boolean>;
$updateWorkspaceFolders(extensionName: string, index: number, deleteCount: number, workspaceFoldersToAdd: { uri: UriComponents, name?: string; }[]): Promise<void>;
$resolveProxy(url: string): Promise<string | undefined>;
$requireWorkspaceTrust(modal?: boolean): Promise<WorkspaceTrustState>
}
export interface IFileChangeDto {
@@ -1003,14 +994,21 @@ export interface MainThreadWindowShape extends IDisposable {
$asExternalUri(uri: UriComponents, options: IOpenUriOptions): Promise<UriComponents>;
}
export enum CandidatePortSource {
None = 0,
Process = 1,
Output = 2
}
export interface MainThreadTunnelServiceShape extends IDisposable {
$openTunnel(tunnelOptions: TunnelOptions, source: string | undefined): Promise<TunnelDto | undefined>;
$closeTunnel(remote: { host: string, port: number }): Promise<void>;
$getTunnels(): Promise<TunnelDescription[]>;
$setTunnelProvider(features: TunnelProviderFeatures): Promise<void>;
$setCandidateFinder(): Promise<void>;
$setRemoteTunnelService(processId: number): Promise<void>;
$setCandidateFilter(): Promise<void>;
$onFoundNewCandidates(candidates: { host: string, port: number, detail: string }[]): Promise<void>;
$setCandidatePortSource(source: CandidatePortSource): Promise<void>;
}
export interface MainThreadTimelineShape extends IDisposable {
@@ -1106,9 +1104,10 @@ export interface ExtHostTreeViewsShape {
}
export interface ExtHostWorkspaceShape {
$initializeWorkspace(workspace: IWorkspaceData | null): void;
$initializeWorkspace(workspace: IWorkspaceData | null, trustState: WorkspaceTrustState): void;
$acceptWorkspaceData(workspace: IWorkspaceData | null): void;
$handleTextSearchResult(result: search.IRawFileMatch2, requestId: number): void;
$onDidChangeWorkspaceTrustState(state: WorkspaceTrustStateChangeEvent): void;
}
export interface ExtHostFileSystemInfoShape {
@@ -1137,11 +1136,10 @@ export interface ExtHostLabelServiceShape {
}
export interface ExtHostAuthenticationShape {
$getSessions(id: string): Promise<ReadonlyArray<modes.AuthenticationSession>>;
$getSessionAccessToken(id: string, sessionId: string): Promise<string>;
$login(id: string, scopes: string[]): Promise<modes.AuthenticationSession>;
$logout(id: string, sessionId: string): Promise<void>;
$onDidChangeAuthenticationSessions(id: string, label: string, event: modes.AuthenticationSessionsChangeEvent): Promise<void>;
$getSessions(id: string, scopes?: string[]): Promise<ReadonlyArray<modes.AuthenticationSession>>;
$createSession(id: string, scopes: string[]): Promise<modes.AuthenticationSession>;
$removeSession(id: string, sessionId: string): Promise<void>;
$onDidChangeAuthenticationSessions(id: string, label: string): Promise<void>;
$onDidChangeAuthenticationProviders(added: modes.AuthenticationProviderInformation[], removed: modes.AuthenticationProviderInformation[]): Promise<void>;
$setProviders(providers: modes.AuthenticationProviderInformation[]): Promise<void>;
}
@@ -1313,9 +1311,10 @@ export interface ISignatureHelpContextDto {
export interface IInlineHintDto {
text: string;
range: IRange;
hoverMessage?: string;
kind: modes.InlineHintKind;
whitespaceBefore?: boolean;
whitespaceAfter?: boolean;
hoverMessage?: string;
}
export interface IInlineHintsDto {
@@ -1478,6 +1477,10 @@ export interface ILinkedEditingRangesDto {
wordPattern?: IRegExpDto;
}
export interface IInlineValueContextDto {
stoppedLocation: IRange;
}
export interface ExtHostLanguageFeaturesShape {
$provideDocumentSymbols(handle: number, resource: UriComponents, token: CancellationToken): Promise<modes.DocumentSymbol[] | undefined>;
$provideCodeLenses(handle: number, resource: UriComponents, token: CancellationToken): Promise<ICodeLensListDto | undefined>;
@@ -1489,6 +1492,7 @@ export interface ExtHostLanguageFeaturesShape {
$provideTypeDefinition(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<IDefinitionLinkDto[]>;
$provideHover(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<modes.Hover | undefined>;
$provideEvaluatableExpression(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<modes.EvaluatableExpression | undefined>;
$provideInlineValues(handle: number, resource: UriComponents, range: IRange, context: modes.InlineValueContext, token: CancellationToken): Promise<modes.InlineValue[] | undefined>;
$provideDocumentHighlights(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<modes.DocumentHighlight[] | undefined>;
$provideLinkedEditingRanges(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<ILinkedEditingRangesDto | undefined>;
$provideReferences(handle: number, resource: UriComponents, position: IPosition, context: modes.ReferenceContext, token: CancellationToken): Promise<ILocationDto[] | undefined>;
@@ -1681,7 +1685,7 @@ export type IDebugSessionDto = IDebugSessionFullDto | DebugSessionUUID;
export interface ExtHostDebugServiceShape {
$substituteVariables(folder: UriComponents | undefined, config: IConfig): Promise<IConfig>;
$runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments): Promise<number | undefined>;
$runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments, sessionId: string): Promise<number | undefined>;
$startDASession(handle: number, session: IDebugSessionDto): Promise<void>;
$stopDASession(handle: number): Promise<void>;
$sendDAMessage(handle: number, message: DebugProtocol.ProtocolMessage): void;
@@ -1739,17 +1743,11 @@ export interface ExtHostCommentsShape {
}
export interface INotebookSelectionChangeEvent {
// handles
selections: number[];
}
export interface INotebookCellVisibleRange {
start: number;
end: number;
selections: ICellRange[];
}
export interface INotebookVisibleRangesEvent {
ranges: INotebookCellVisibleRange[];
ranges: ICellRange[];
}
export interface INotebookEditorPropertiesChangeData {
@@ -1767,14 +1765,13 @@ export interface INotebookModelAddedData {
cells: IMainCellDto[],
viewType: string;
metadata?: NotebookDocumentMetadata;
attachedEditor?: { id: string; selections: number[]; visibleRanges: ICellRange[] }
contentOptions: { transientOutputs: boolean; transientMetadata: TransientMetadata; }
}
export interface INotebookEditorAddData {
id: string;
documentUri: UriComponents;
selections: number[];
selections: ICellRange[];
visibleRanges: ICellRange[];
}
@@ -1787,27 +1784,38 @@ export interface INotebookDocumentsAndEditorsDelta {
visibleEditors?: string[];
}
export interface INotebookKernelInfoDto2 {
id?: string;
friendlyId: string;
label: string;
extension: ExtensionIdentifier;
extensionLocation: UriComponents;
providerHandle?: number;
description?: string;
detail?: string;
isPreferred?: boolean;
preloads?: UriComponents[];
supportedLanguages?: string[]
}
export interface ExtHostNotebookShape {
$resolveNotebookData(viewType: string, uri: UriComponents, backupId?: string): Promise<NotebookDataDto>;
$resolveNotebookEditor(viewType: string, uri: UriComponents, editorId: string): Promise<void>;
$acceptNotebookActiveKernelChange(event: { uri: UriComponents, providerHandle: number | undefined, kernelFriendlyId: string | undefined }): void;
$provideNotebookKernels(handle: number, uri: UriComponents, token: CancellationToken): Promise<INotebookKernelInfoDto2[]>;
$resolveNotebookKernel(handle: number, editorId: string, uri: UriComponents, kernelId: string, token: CancellationToken): Promise<void>;
$executeNotebookKernelFromProvider(handle: number, uri: UriComponents, kernelId: string, cellHandle: number | undefined): Promise<void>;
$cancelNotebookKernelFromProvider(handle: number, uri: UriComponents, kernelId: string, cellHandle: number | undefined): Promise<void>;
$onDidReceiveMessage(editorId: string, rendererId: string | undefined, message: unknown): void;
$openNotebook(viewType: string, uri: UriComponents, backupId?: string): Promise<NotebookDataDto>;
$saveNotebook(viewType: string, uri: UriComponents, token: CancellationToken): Promise<boolean>;
$saveNotebookAs(viewType: string, uri: UriComponents, target: UriComponents, token: CancellationToken): Promise<boolean>;
$backup(viewType: string, uri: UriComponents, cancellation: CancellationToken): Promise<string | undefined>;
$acceptDisplayOrder(displayOrder: INotebookDisplayOrder): void;
$acceptNotebookActiveKernelChange(event: { uri: UriComponents, providerHandle: number | undefined, kernelFriendlyId: string | undefined }): void;
$onDidReceiveMessage(editorId: string, rendererId: string | undefined, message: unknown): void;
$backupNotebook(viewType: string, uri: UriComponents, cancellation: CancellationToken): Promise<string>;
$acceptModelChanged(uriComponents: UriComponents, event: NotebookCellsChangedEventDto, isDirty: boolean): void;
$acceptDirtyStateChanged(uriComponents: UriComponents, isDirty: boolean): void;
$acceptModelSaved(uriComponents: UriComponents): void;
$acceptEditorPropertiesChanged(id: string, data: INotebookEditorPropertiesChangeData): void;
$acceptDocumentPropertiesChanged(uriComponents: UriComponents, data: INotebookDocumentPropertiesChangeData): void;
$acceptDocumentAndEditorsDelta(delta: INotebookDocumentsAndEditorsDelta): void;
$undoNotebook(viewType: string, uri: UriComponents, editId: number, isDirty: boolean): Promise<void>;
$redoNotebook(viewType: string, uri: UriComponents, editId: number, isDirty: boolean): Promise<void>;
$acceptEditorPropertiesChanged(id: string, data: INotebookEditorPropertiesChangeData): void;
}
export interface ExtHostStorageShape {
@@ -1839,12 +1847,12 @@ export const enum ExtHostTestingResource {
}
export interface ExtHostTestingShape {
$runTestsForProvider(req: RunTestForProviderRequest, token: CancellationToken): Promise<RunTestsResult>;
$runTestsForProvider(req: RunTestForProviderRequest, token: CancellationToken): Promise<void>;
$subscribeToTests(resource: ExtHostTestingResource, uri: UriComponents): void;
$unsubscribeFromTests(resource: ExtHostTestingResource, uri: UriComponents): void;
$lookupTest(test: TestIdWithProvider): Promise<InternalTestItem | undefined>;
$acceptDiff(resource: ExtHostTestingResource, uri: UriComponents, diff: TestsDiff): void;
$publishTestResults(results: InternalTestResults): void;
$publishTestResults(results: ISerializedTestResults[]): void;
}
export interface MainThreadTestingShape {
@@ -1853,7 +1861,10 @@ export interface MainThreadTestingShape {
$subscribeToDiffs(resource: ExtHostTestingResource, uri: UriComponents): void;
$unsubscribeFromDiffs(resource: ExtHostTestingResource, uri: UriComponents): void;
$publishDiff(resource: ExtHostTestingResource, uri: UriComponents, diff: TestsDiff): void;
$runTests(req: RunTestsRequest, token: CancellationToken): Promise<RunTestsResult>;
$updateTestStateInRun(runId: string, testId: string, state: ITestState): void;
$runTests(req: RunTestsRequest, token: CancellationToken): Promise<string>;
$publishExtensionProvidedResults(results: ISerializedTestResults, persist: boolean): void;
$retireTest(extId: string): void;
}
// --- proxy identifiers

View File

@@ -117,7 +117,7 @@ const newCommands: ApiCommand[] = [
// -- selection range
new ApiCommand(
'vscode.executeSelectionRangeProvider', '_executeSelectionRangeProvider', 'Execute selection range provider.',
[ApiCommandArgument.Uri, new ApiCommandArgument<types.Position[], IPosition[]>('position', 'A positions in a text document', v => Array.isArray(v) && v.every(v => types.Position.isPosition(v)), v => v.map(typeConverters.Position.from))],
[ApiCommandArgument.Uri, new ApiCommandArgument<types.Position[], IPosition[]>('position', 'A position in a text document', v => Array.isArray(v) && v.every(v => types.Position.isPosition(v)), v => v.map(typeConverters.Position.from))],
new ApiCommandResult<IRange[][], types.SelectionRange[]>('A promise that resolves to an array of ranges.', result => {
return result.map(ranges => {
let node: types.SelectionRange | undefined;
@@ -359,9 +359,17 @@ const newCommands: ApiCommand[] = [
};
}))
),
// --- debug support
new ApiCommand(
'vscode.executeInlineValueProvider', '_executeInlineValueProvider', 'Execute inline value provider',
[ApiCommandArgument.Uri, ApiCommandArgument.Range],
new ApiCommandResult<modes.InlineValue[], vscode.InlineValue[]>('A promise that resolves to an array of InlineValue objects', result => {
return result.map(typeConverters.InlineValue.to);
})
),
// --- open'ish commands
new ApiCommand(
'vscode.open', '_workbench.open', 'Opens the provided resource in the editor. Can be a text or binary file, or a http(s) url. If you need more control over the options for opening a text file, use vscode.window.showTextDocument instead.',
'vscode.open', '_workbench.open', 'Opens the provided resource in the editor. Can be a text or binary file, or an http(s) URL. If you need more control over the options for opening a text file, use vscode.window.showTextDocument instead.',
[
ApiCommandArgument.Uri,
new ApiCommandArgument<vscode.ViewColumn | typeConverters.TextEditorOpenOptions | undefined, [number?, ITextEditorOptions?] | undefined>('columnOrOptions', 'Either the column in which to open or editor options, see vscode.TextDocumentShowOptions',
@@ -388,7 +396,7 @@ const newCommands: ApiCommand[] = [
'vscode.diff', '_workbench.diff', 'Opens the provided resources in the diff editor to compare their contents.',
[
ApiCommandArgument.Uri.with('left', 'Left-hand side resource of the diff editor'),
ApiCommandArgument.Uri.with('right', 'Rigth-hand side resource of the diff editor'),
ApiCommandArgument.Uri.with('right', 'Right-hand side resource of the diff editor'),
ApiCommandArgument.String.with('title', 'Human readable title for the diff editor').optional(),
new ApiCommandArgument<typeConverters.TextEditorOpenOptions | undefined, [number?, ITextEditorOptions?] | undefined>('columnOrOptions', 'Either the column in which to open or editor options, see vscode.TextDocumentShowOptions',
v => v === undefined || typeof v === 'object',

View File

@@ -83,54 +83,17 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape {
private async _getSession(requestingExtension: IExtensionDescription, extensionId: string, providerId: string, scopes: string[], options: vscode.AuthenticationGetSessionOptions = {}): Promise<vscode.AuthenticationSession | undefined> {
await this._proxy.$ensureProvider(providerId);
const providerData = this._authenticationProviders.get(providerId);
const extensionName = requestingExtension.displayName || requestingExtension.name;
if (!providerData) {
return this._proxy.$getSession(providerId, scopes, extensionId, extensionName, options);
}
const orderedScopes = scopes.sort().join(' ');
const sessions = (await providerData.provider.getSessions()).filter(session => session.scopes.slice().sort().join(' ') === orderedScopes);
let session: vscode.AuthenticationSession | undefined = undefined;
if (sessions.length) {
if (!providerData.options.supportsMultipleAccounts) {
session = sessions[0];
const allowed = await this._proxy.$getSessionsPrompt(providerId, session.account.label, providerData.label, extensionId, extensionName);
if (!allowed) {
throw new Error('User did not consent to login.');
}
} else {
// On renderer side, confirm consent, ask user to choose between accounts if multiple sessions are valid
const selected = await this._proxy.$selectSession(providerId, providerData.label, extensionId, extensionName, sessions, scopes, !!options.clearSessionPreference);
session = sessions.find(session => session.id === selected.id);
}
} else {
if (options.createIfNone) {
const isAllowed = await this._proxy.$loginPrompt(providerData.label, extensionName);
if (!isAllowed) {
throw new Error('User did not consent to login.');
}
session = await providerData.provider.login(scopes);
await this._proxy.$setTrustedExtensionAndAccountPreference(providerId, session.account.label, extensionId, extensionName, session.id);
} else {
await this._proxy.$requestNewSession(providerId, scopes, extensionId, extensionName);
}
}
return session;
return this._proxy.$getSession(providerId, scopes, extensionId, extensionName, options);
}
async logout(providerId: string, sessionId: string): Promise<void> {
async removeSession(providerId: string, sessionId: string): Promise<void> {
const providerData = this._authenticationProviders.get(providerId);
if (!providerData) {
return this._proxy.$logout(providerId, sessionId);
return this._proxy.$removeSession(providerId, sessionId);
}
return providerData.provider.logout(sessionId);
return providerData.provider.removeSession(sessionId);
}
registerAuthenticationProvider(id: string, label: string, provider: vscode.AuthenticationProvider, options?: vscode.AuthenticationProviderOptions): vscode.Disposable {
@@ -148,7 +111,11 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape {
}
const listener = provider.onDidChangeSessions(e => {
this._proxy.$sendDidChangeSessions(id, e);
this._proxy.$sendDidChangeSessions(id, {
added: e.added ?? [],
changed: e.changed ?? [],
removed: e.removed ?? []
});
});
this._proxy.$registerAuthenticationProvider(id, label, options?.supportsMultipleAccounts ?? false);
@@ -166,50 +133,35 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape {
});
}
$login(providerId: string, scopes: string[]): Promise<modes.AuthenticationSession> {
$createSession(providerId: string, scopes: string[]): Promise<modes.AuthenticationSession> {
const providerData = this._authenticationProviders.get(providerId);
if (providerData) {
return Promise.resolve(providerData.provider.login(scopes));
return Promise.resolve(providerData.provider.createSession(scopes));
}
throw new Error(`Unable to find authentication provider with handle: ${providerId}`);
}
$logout(providerId: string, sessionId: string): Promise<void> {
$removeSession(providerId: string, sessionId: string): Promise<void> {
const providerData = this._authenticationProviders.get(providerId);
if (providerData) {
return Promise.resolve(providerData.provider.logout(sessionId));
return Promise.resolve(providerData.provider.removeSession(sessionId));
}
throw new Error(`Unable to find authentication provider with handle: ${providerId}`);
}
$getSessions(providerId: string): Promise<ReadonlyArray<modes.AuthenticationSession>> {
$getSessions(providerId: string, scopes?: string[]): Promise<ReadonlyArray<modes.AuthenticationSession>> {
const providerData = this._authenticationProviders.get(providerId);
if (providerData) {
return Promise.resolve(providerData.provider.getSessions());
return Promise.resolve(providerData.provider.getSessions(scopes));
}
throw new Error(`Unable to find authentication provider with handle: ${providerId}`);
}
async $getSessionAccessToken(providerId: string, sessionId: string): Promise<string> {
const providerData = this._authenticationProviders.get(providerId);
if (providerData) {
const sessions = await providerData.provider.getSessions();
const session = sessions.find(session => session.id === sessionId);
if (session) {
return session.accessToken;
}
throw new Error(`Unable to find session with id: ${sessionId}`);
}
throw new Error(`Unable to find authentication provider with handle: ${providerId}`);
}
$onDidChangeAuthenticationSessions(id: string, label: string, event: modes.AuthenticationSessionsChangeEvent) {
this._onDidChangeSessions.fire({ provider: { id, label }, ...event });
$onDidChangeAuthenticationSessions(id: string, label: string) {
this._onDidChangeSessions.fire({ provider: { id, label } });
return Promise.resolve();
}

View File

@@ -3,22 +3,22 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IMainContext, MainContext, MainThreadClipboardShape } from 'vs/workbench/api/common/extHost.protocol';
import { IMainContext, MainContext } from 'vs/workbench/api/common/extHost.protocol';
import type * as vscode from 'vscode';
export class ExtHostClipboard implements vscode.Clipboard {
export class ExtHostClipboard {
private readonly _proxy: MainThreadClipboardShape;
readonly value: vscode.Clipboard;
constructor(mainContext: IMainContext) {
this._proxy = mainContext.getProxy(MainContext.MainThreadClipboard);
}
readText(): Promise<string> {
return this._proxy.$readText();
}
writeText(value: string): Promise<void> {
return this._proxy.$writeText(value);
const proxy = mainContext.getProxy(MainContext.MainThreadClipboard);
this.value = Object.freeze({
readText() {
return proxy.$readText();
},
writeText(value: string) {
return proxy.$writeText(value);
}
});
}
}

View File

@@ -44,8 +44,8 @@ export class ExtHostEditorInsets implements ExtHostEditorInsetsShape {
createWebviewEditorInset(editor: vscode.TextEditor, line: number, height: number, options: vscode.WebviewOptions | undefined, extension: IExtensionDescription): vscode.WebviewEditorInset {
let apiEditor: ExtHostTextEditor | undefined;
for (const candidate of this._editors.getVisibleTextEditors()) {
if (candidate === editor) {
for (const candidate of this._editors.getVisibleTextEditors(true)) {
if (candidate.value === editor) {
apiEditor = <ExtHostTextEditor>candidate;
break;
}
@@ -121,7 +121,7 @@ export class ExtHostEditorInsets implements ExtHostEditorInsetsShape {
}
};
this._proxy.$createEditorInset(handle, apiEditor.id, apiEditor.document.uri, line + 1, height, options || {}, extension.identifier, extension.extensionLocation);
this._proxy.$createEditorInset(handle, apiEditor.id, apiEditor.value.document.uri, line + 1, height, options || {}, extension.identifier, extension.extensionLocation);
this._insets.set(handle, { editor, inset, onDidReceiveMessage });
return inset;

View File

@@ -213,6 +213,14 @@ export class ExtHostCommands implements ExtHostCommandsShape {
try {
return await callback.apply(thisArg, args);
} catch (err) {
// The indirection-command from the converter can fail when invoking the actual
// command and in that case it is better to blame the correct command
if (id === this.converter.delegatingCommandId) {
const actual = this.converter.getActualCommand(...args);
if (actual) {
id = actual.command;
}
}
this._logService.error(err, id);
throw new Error(`Running the contributed command: '${id}' failed.`);
}
@@ -257,7 +265,7 @@ export const IExtHostCommands = createDecorator<IExtHostCommands>('IExtHostComma
export class CommandsConverter {
private readonly _delegatingCommandId: string;
readonly delegatingCommandId: string = `_vscode_delegate_cmd_${Date.now().toString(36)}`;
private readonly _cache = new Map<number, vscode.Command>();
private _cachIdPool = 0;
@@ -267,8 +275,7 @@ export class CommandsConverter {
private readonly _lookupApiCommand: (id: string) => ApiCommand | undefined,
private readonly _logService: ILogService
) {
this._delegatingCommandId = `_vscode_delegate_cmd_${Date.now().toString(36)}`;
this._commands.registerCommand(true, this._delegatingCommandId, this._executeConvertedCommand, this);
this._commands.registerCommand(true, this.delegatingCommandId, this._executeConvertedCommand, this);
}
toInternal(command: vscode.Command, disposables: DisposableStore): ICommandDto;
@@ -311,7 +318,7 @@ export class CommandsConverter {
}));
result.$ident = id;
result.id = this._delegatingCommandId;
result.id = this.delegatingCommandId;
result.arguments = [id];
this._logService.trace('CommandsConverter#CREATE', command.command, id);
@@ -335,8 +342,13 @@ export class CommandsConverter {
}
}
getActualCommand(...args: any[]): vscode.Command | undefined {
return this._cache.get(args[0]);
}
private _executeConvertedCommand<R>(...args: any[]): Promise<R> {
const actualCmd = this._cache.get(args[0]);
const actualCmd = this.getActualCommand(...args);
this._logService.trace('CommandsConverter#EXECUTE', args[0], actualCmd ? actualCmd.command : 'MISSING');
if (!actualCmd) {

View File

@@ -89,7 +89,7 @@ export abstract class ExtHostDebugServiceBase implements IExtHostDebugService, E
get onDidReceiveDebugSessionCustomEvent(): Event<vscode.DebugSessionCustomEvent> { return this._onDidReceiveDebugSessionCustomEvent.event; }
private _activeDebugConsole: ExtHostDebugConsole;
get activeDebugConsole(): ExtHostDebugConsole { return this._activeDebugConsole; }
get activeDebugConsole(): vscode.DebugConsole { return this._activeDebugConsole.value; }
private _breakpoints: Map<string, vscode.Breakpoint>;
private _breakpointEventsActive: boolean;
@@ -361,7 +361,7 @@ export abstract class ExtHostDebugServiceBase implements IExtHostDebugService, E
// RPC methods (ExtHostDebugServiceShape)
public async $runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments): Promise<number | undefined> {
public async $runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments, sessionId: string): Promise<number | undefined> {
return Promise.resolve(undefined);
}
@@ -911,20 +911,20 @@ export class ExtHostDebugSession implements vscode.DebugSession {
}
}
export class ExtHostDebugConsole implements vscode.DebugConsole {
export class ExtHostDebugConsole {
private _debugServiceProxy: MainThreadDebugServiceShape;
readonly value: vscode.DebugConsole;
constructor(proxy: MainThreadDebugServiceShape) {
this._debugServiceProxy = proxy;
}
append(value: string): void {
this._debugServiceProxy.$appendDebugConsole(value);
}
appendLine(value: string): void {
this.append(value + '\n');
this.value = Object.freeze({
append(value: string): void {
proxy.$appendDebugConsole(value);
},
appendLine(value: string): void {
this.append(value + '\n');
}
});
}
}
@@ -945,6 +945,9 @@ export class ExtHostVariableResolverService extends AbstractVariableResolverServ
getConfigurationValue: (folderUri: URI | undefined, section: string): string | undefined => {
return configurationService.getConfiguration(undefined, folderUri).get<string>(section);
},
getAppRoot: (): string | undefined => {
return env ? env['VSCODE_CWD'] : undefined;
},
getExecPath: (): string | undefined => {
return env ? env['VSCODE_EXEC_PATH'] : undefined;
},

View File

@@ -18,6 +18,7 @@ import { ILogService } from 'vs/platform/log/common/log';
import { ResourceMap } from 'vs/base/common/map';
import { Schemas } from 'vs/base/common/network';
import { Iterable } from 'vs/base/common/iterator';
import { Lazy } from 'vs/base/common/lazy';
class Reference<T> {
private _count = 0;
@@ -49,13 +50,13 @@ export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsSha
private readonly _onDidAddDocuments = new Emitter<ExtHostDocumentData[]>();
private readonly _onDidRemoveDocuments = new Emitter<ExtHostDocumentData[]>();
private readonly _onDidChangeVisibleTextEditors = new Emitter<ExtHostTextEditor[]>();
private readonly _onDidChangeActiveTextEditor = new Emitter<ExtHostTextEditor | undefined>();
private readonly _onDidChangeVisibleTextEditors = new Emitter<vscode.TextEditor[]>();
private readonly _onDidChangeActiveTextEditor = new Emitter<vscode.TextEditor | undefined>();
readonly onDidAddDocuments: Event<ExtHostDocumentData[]> = this._onDidAddDocuments.event;
readonly onDidRemoveDocuments: Event<ExtHostDocumentData[]> = this._onDidRemoveDocuments.event;
readonly onDidChangeVisibleTextEditors: Event<ExtHostTextEditor[]> = this._onDidChangeVisibleTextEditors.event;
readonly onDidChangeActiveTextEditor: Event<ExtHostTextEditor | undefined> = this._onDidChangeActiveTextEditor.event;
readonly onDidChangeVisibleTextEditors: Event<vscode.TextEditor[]> = this._onDidChangeVisibleTextEditors.event;
readonly onDidChangeActiveTextEditor: Event<vscode.TextEditor | undefined> = this._onDidChangeActiveTextEditor.event;
constructor(
@IExtHostRpcService private readonly _extHostRpc: IExtHostRpcService,
@@ -135,7 +136,7 @@ export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsSha
data.id,
this._extHostRpc.getProxy(MainContext.MainThreadTextEditors),
this._logService,
documentData,
new Lazy(() => documentData.document),
data.selections.map(typeConverters.Selection.to),
data.options,
data.visibleRanges.map(range => typeConverters.Range.to(range)),
@@ -162,7 +163,7 @@ export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsSha
}
if (delta.removedEditors || delta.addedEditors) {
this._onDidChangeVisibleTextEditors.fire(this.allEditors());
this._onDidChangeVisibleTextEditors.fire(this.allEditors().map(editor => editor.value));
}
if (delta.newActiveEditor !== undefined) {
this._onDidChangeActiveTextEditor.fire(this.activeEditor());
@@ -181,11 +182,17 @@ export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsSha
return this._editors.get(id);
}
activeEditor(): ExtHostTextEditor | undefined {
activeEditor(): vscode.TextEditor | undefined;
activeEditor(internal: true): ExtHostTextEditor | undefined;
activeEditor(internal?: true): vscode.TextEditor | ExtHostTextEditor | undefined {
if (!this._activeEditorId) {
return undefined;
}
const editor = this._editors.get(this._activeEditorId);
if (internal) {
return editor;
} else {
return this._editors.get(this._activeEditorId);
return editor?.value;
}
}

View File

@@ -388,6 +388,7 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme
const extensionMode = extensionDescription.isUnderDevelopment
? (this._initData.environment.extensionTestsLocationURI ? ExtensionMode.Test : ExtensionMode.Development)
: ExtensionMode.Production;
const installAge = Date.now() - new Date(this._initData.telemetryInfo.firstSessionDate).getTime();
this._logService.trace(`ExtensionService#loadExtensionContext ${extensionDescription.identifier.value}`);
@@ -412,10 +413,22 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme
get storageUri() { return that._storagePath.workspaceValue(extensionDescription); },
get globalStorageUri() { return that._storagePath.globalValue(extensionDescription); },
get extensionMode() { return extensionMode; },
get extensionId() {
checkProposedApiEnabled(extensionDescription);
return extensionDescription.identifier.value;
},
get extensionVersion() {
checkProposedApiEnabled(extensionDescription);
return extensionDescription.version;
},
get extensionRuntime() {
checkProposedApiEnabled(extensionDescription);
return that.extensionRuntime;
},
get isNewInstall() {
checkProposedApiEnabled(extensionDescription);
return isNaN(installAge) ? false : installAge < 1000 * 60 * 60 * 24; // installAge is less than a day;
},
get environmentVariableCollection() { return that._extHostTerminalService.getEnvironmentVariableCollection(extensionDescription); }
});
});

View File

@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { MainThreadFileSystemShape, MainContext } from './extHost.protocol';
import { MainContext } from './extHost.protocol';
import * as vscode from 'vscode';
import * as files from 'vs/platform/files/common/files';
import { FileSystemError } from 'vs/workbench/api/common/extHostTypes';
@@ -12,49 +12,51 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
import { IExtHostFileSystemInfo } from 'vs/workbench/api/common/extHostFileSystemInfo';
export class ExtHostConsumerFileSystem implements vscode.FileSystem {
export class ExtHostConsumerFileSystem {
readonly _serviceBrand: undefined;
private readonly _proxy: MainThreadFileSystemShape;
readonly value: vscode.FileSystem;
constructor(
@IExtHostRpcService extHostRpc: IExtHostRpcService,
@IExtHostFileSystemInfo private readonly _fileSystemInfo: IExtHostFileSystemInfo,
@IExtHostFileSystemInfo fileSystemInfo: IExtHostFileSystemInfo,
) {
this._proxy = extHostRpc.getProxy(MainContext.MainThreadFileSystem);
}
const proxy = extHostRpc.getProxy(MainContext.MainThreadFileSystem);
stat(uri: vscode.Uri): Promise<vscode.FileStat> {
return this._proxy.$stat(uri).catch(ExtHostConsumerFileSystem._handleError);
}
readDirectory(uri: vscode.Uri): Promise<[string, vscode.FileType][]> {
return this._proxy.$readdir(uri).catch(ExtHostConsumerFileSystem._handleError);
}
createDirectory(uri: vscode.Uri): Promise<void> {
return this._proxy.$mkdir(uri).catch(ExtHostConsumerFileSystem._handleError);
}
async readFile(uri: vscode.Uri): Promise<Uint8Array> {
return this._proxy.$readFile(uri).then(buff => buff.buffer).catch(ExtHostConsumerFileSystem._handleError);
}
writeFile(uri: vscode.Uri, content: Uint8Array): Promise<void> {
return this._proxy.$writeFile(uri, VSBuffer.wrap(content)).catch(ExtHostConsumerFileSystem._handleError);
}
delete(uri: vscode.Uri, options?: { recursive?: boolean; useTrash?: boolean; }): Promise<void> {
return this._proxy.$delete(uri, { ...{ recursive: false, useTrash: false }, ...options }).catch(ExtHostConsumerFileSystem._handleError);
}
rename(oldUri: vscode.Uri, newUri: vscode.Uri, options?: { overwrite?: boolean; }): Promise<void> {
return this._proxy.$rename(oldUri, newUri, { ...{ overwrite: false }, ...options }).catch(ExtHostConsumerFileSystem._handleError);
}
copy(source: vscode.Uri, destination: vscode.Uri, options?: { overwrite?: boolean; }): Promise<void> {
return this._proxy.$copy(source, destination, { ...{ overwrite: false }, ...options }).catch(ExtHostConsumerFileSystem._handleError);
}
isWritableFileSystem(scheme: string): boolean | undefined {
const capabilities = this._fileSystemInfo.getCapabilities(scheme);
if (typeof capabilities === 'number') {
return !(capabilities & files.FileSystemProviderCapabilities.Readonly);
}
return undefined;
this.value = Object.freeze({
stat(uri: vscode.Uri): Promise<vscode.FileStat> {
return proxy.$stat(uri).catch(ExtHostConsumerFileSystem._handleError);
},
readDirectory(uri: vscode.Uri): Promise<[string, vscode.FileType][]> {
return proxy.$readdir(uri).catch(ExtHostConsumerFileSystem._handleError);
},
createDirectory(uri: vscode.Uri): Promise<void> {
return proxy.$mkdir(uri).catch(ExtHostConsumerFileSystem._handleError);
},
async readFile(uri: vscode.Uri): Promise<Uint8Array> {
return proxy.$readFile(uri).then(buff => buff.buffer).catch(ExtHostConsumerFileSystem._handleError);
},
writeFile(uri: vscode.Uri, content: Uint8Array): Promise<void> {
return proxy.$writeFile(uri, VSBuffer.wrap(content)).catch(ExtHostConsumerFileSystem._handleError);
},
delete(uri: vscode.Uri, options?: { recursive?: boolean; useTrash?: boolean; }): Promise<void> {
return proxy.$delete(uri, { ...{ recursive: false, useTrash: false }, ...options }).catch(ExtHostConsumerFileSystem._handleError);
},
rename(oldUri: vscode.Uri, newUri: vscode.Uri, options?: { overwrite?: boolean; }): Promise<void> {
return proxy.$rename(oldUri, newUri, { ...{ overwrite: false }, ...options }).catch(ExtHostConsumerFileSystem._handleError);
},
copy(source: vscode.Uri, destination: vscode.Uri, options?: { overwrite?: boolean; }): Promise<void> {
return proxy.$copy(source, destination, { ...{ overwrite: false }, ...options }).catch(ExtHostConsumerFileSystem._handleError);
},
isWritableFileSystem(scheme: string): boolean | undefined {
const capabilities = fileSystemInfo.getCapabilities(scheme);
if (typeof capabilities === 'number') {
return !(capabilities & files.FileSystemProviderCapabilities.Readonly);
}
return undefined;
}
});
}
private static _handleError(err: any): never {

View File

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

View File

@@ -291,6 +291,24 @@ class EvaluatableExpressionAdapter {
}
}
class InlineValuesAdapter {
constructor(
private readonly _documents: ExtHostDocuments,
private readonly _provider: vscode.InlineValuesProvider,
) { }
public provideInlineValues(resource: URI, viewPort: IRange, context: extHostProtocol.IInlineValueContextDto, token: CancellationToken): Promise<modes.InlineValue[] | undefined> {
const doc = this._documents.getDocument(resource);
return asPromise(() => this._provider.provideInlineValues(doc, typeConvert.Range.to(viewPort), typeConvert.InlineValueContext.to(context), token)).then(value => {
if (Array.isArray(value)) {
return value.map(iv => typeConvert.InlineValue.from(iv));
}
return undefined;
});
}
}
class DocumentHighlightAdapter {
constructor(
@@ -1334,7 +1352,8 @@ type Adapter = DocumentSymbolAdapter | CodeLensAdapter | DefinitionAdapter | Hov
| RangeFormattingAdapter | OnTypeFormattingAdapter | NavigateTypeAdapter | RenameAdapter
| SuggestAdapter | SignatureHelpAdapter | LinkProviderAdapter | ImplementationAdapter
| TypeDefinitionAdapter | ColorProviderAdapter | FoldingProviderAdapter | DeclarationAdapter
| SelectionRangeAdapter | CallHierarchyAdapter | DocumentSemanticTokensAdapter | DocumentRangeSemanticTokensAdapter | EvaluatableExpressionAdapter
| SelectionRangeAdapter | CallHierarchyAdapter | DocumentSemanticTokensAdapter | DocumentRangeSemanticTokensAdapter
| EvaluatableExpressionAdapter | InlineValuesAdapter
| LinkedEditingRangeAdapter | InlineHintsAdapter;
class AdapterData {
@@ -1568,6 +1587,27 @@ export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageF
return this._withAdapter(handle, EvaluatableExpressionAdapter, adapter => adapter.provideEvaluatableExpression(URI.revive(resource), position, token), undefined);
}
// --- debug inline values
registerInlineValuesProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.InlineValuesProvider, extensionId?: ExtensionIdentifier): vscode.Disposable {
const eventHandle = typeof provider.onDidChangeInlineValues === 'function' ? this._nextHandle() : undefined;
const handle = this._addNewAdapter(new InlineValuesAdapter(this._documents, provider), extension);
this._proxy.$registerInlineValuesProvider(handle, this._transformDocumentSelector(selector), eventHandle);
let result = this._createDisposable(handle);
if (eventHandle !== undefined) {
const subscription = provider.onDidChangeInlineValues!(_ => this._proxy.$emitInlineValuesEvent(eventHandle));
result = Disposable.from(result, subscription);
}
return result;
}
$provideInlineValues(handle: number, resource: UriComponents, range: IRange, context: extHostProtocol.IInlineValueContextDto, token: CancellationToken): Promise<modes.InlineValue[] | undefined> {
return this._withAdapter(handle, InlineValuesAdapter, adapter => adapter.provideInlineValues(URI.revive(resource), range, context, token), undefined);
}
// --- occurrences
registerDocumentHighlightProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.DocumentHighlightProvider): vscode.Disposable {

View File

@@ -5,11 +5,11 @@
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
import { Emitter, Event } from 'vs/base/common/event';
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
import { URI, UriComponents } from 'vs/base/common/uri';
import * as UUID from 'vs/base/common/uuid';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { ExtHostNotebookShape, ICommandDto, IMainContext, IModelAddedData, INotebookDocumentPropertiesChangeData, INotebookDocumentsAndEditorsDelta, INotebookDocumentShowOptions, INotebookEditorPropertiesChangeData, MainContext, MainThreadBulkEditsShape, MainThreadNotebookShape } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostNotebookShape, ICommandDto, IMainContext, IModelAddedData, INotebookDocumentPropertiesChangeData, INotebookDocumentsAndEditorsDelta, INotebookDocumentShowOptions, INotebookEditorPropertiesChangeData, INotebookKernelInfoDto2, MainContext, MainThreadNotebookShape } from 'vs/workbench/api/common/extHost.protocol';
import { ILogService } from 'vs/platform/log/common/log';
import { CommandsConverter, ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
@@ -17,7 +17,7 @@ import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePa
import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters';
import * as extHostTypes from 'vs/workbench/api/common/extHostTypes';
import { asWebviewUri, WebviewInitData } from 'vs/workbench/api/common/shared/webview';
import { addIdToOutput, CellStatusbarAlignment, CellUri, INotebookCellStatusBarEntry, INotebookDisplayOrder, INotebookExclusiveDocumentFilter, INotebookKernelInfoDto2, NotebookCellMetadata, NotebookCellsChangedEventDto, NotebookCellsChangeType, NotebookDataDto, notebookDocumentMetadataDefaults } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { CellStatusbarAlignment, CellUri, ICellRange, INotebookCellStatusBarEntry, INotebookExclusiveDocumentFilter, NotebookCellMetadata, NotebookCellsChangedEventDto, NotebookCellsChangeType, NotebookDataDto, notebookDocumentMetadataDefaults } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import * as vscode from 'vscode';
import { ResourceMap } from 'vs/base/common/map';
import { ExtHostCell, ExtHostNotebookDocument } from './extHostNotebookDocument';
@@ -25,6 +25,7 @@ import { ExtHostNotebookEditor } from './extHostNotebookEditor';
import { IdGenerator } from 'vs/base/common/idGenerator';
import { IRelativePattern } from 'vs/base/common/glob';
import { assertIsDefined } from 'vs/base/common/types';
import { hash } from 'vs/base/common/hash';
class ExtHostWebviewCommWrapper extends Disposable {
private readonly _onDidReceiveDocumentMessage = new Emitter<any>();
@@ -71,15 +72,9 @@ class ExtHostWebviewCommWrapper extends Disposable {
}
}
export interface ExtHostNotebookOutputRenderingHandler {
outputDisplayOrder: INotebookDisplayOrder | undefined;
}
export class ExtHostNotebookKernelProviderAdapter extends Disposable {
private _kernelToFriendlyId = new Map<vscode.NotebookKernel, string>();
private _friendlyIdToKernel = new Map<string, vscode.NotebookKernel>();
private _kernelToFriendlyId = new ResourceMap<Map<vscode.NotebookKernel, string>>();
private _friendlyIdToKernel = new ResourceMap<Map<string, vscode.NotebookKernel>>();
constructor(
private readonly _proxy: MainThreadNotebookShape,
private readonly _handle: number,
@@ -103,16 +98,16 @@ export class ExtHostNotebookKernelProviderAdapter extends Disposable {
let kernel_unique_pool = 0;
const kernelFriendlyIdCache = new Set<string>();
const kernelToFriendlyId = this._kernelToFriendlyId.get(document.uri);
const transformedData: INotebookKernelInfoDto2[] = data.map(kernel => {
let friendlyId = this._kernelToFriendlyId.get(kernel);
let friendlyId = kernelToFriendlyId?.get(kernel);
if (friendlyId === undefined) {
if (kernel.id && kernelFriendlyIdCache.has(kernel.id)) {
friendlyId = `${this._extension.identifier.value}_${kernel.id}_${kernel_unique_pool++}`;
} else {
friendlyId = `${this._extension.identifier.value}_${kernel.id || UUID.generateUuid()}`;
}
this._kernelToFriendlyId.set(kernel, friendlyId);
}
newMap.set(kernel, friendlyId);
@@ -123,29 +118,31 @@ export class ExtHostNotebookKernelProviderAdapter extends Disposable {
label: kernel.label,
extension: this._extension.identifier,
extensionLocation: this._extension.extensionLocation,
providerHandle: this._handle,
description: kernel.description,
detail: kernel.detail,
isPreferred: kernel.isPreferred,
preloads: kernel.preloads
preloads: kernel.preloads,
supportedLanguages: kernel.supportedLanguages
};
});
this._kernelToFriendlyId = newMap;
this._friendlyIdToKernel.clear();
this._kernelToFriendlyId.forEach((value, key) => {
this._friendlyIdToKernel.set(value, key);
this._kernelToFriendlyId.set(document.uri, newMap);
const friendlyIdToKernel = new Map<string, vscode.NotebookKernel>();
newMap.forEach((value, key) => {
friendlyIdToKernel.set(value, key);
});
this._friendlyIdToKernel.set(document.uri, friendlyIdToKernel);
return transformedData;
}
getKernelByFriendlyId(kernelId: string) {
return this._friendlyIdToKernel.get(kernelId);
getKernelByFriendlyId(uri: URI, kernelId: string) {
return this._friendlyIdToKernel.get(uri)?.get(kernelId);
}
async resolveNotebook(kernelId: string, document: ExtHostNotebookDocument, webview: vscode.NotebookCommunication, token: CancellationToken) {
const kernel = this._friendlyIdToKernel.get(kernelId);
const kernel = this._friendlyIdToKernel.get(document.uri)?.get(kernelId);
if (kernel && this._provider.resolveKernel) {
return this._provider.resolveKernel(kernel, document.notebookDocument, webview, token);
@@ -153,7 +150,7 @@ export class ExtHostNotebookKernelProviderAdapter extends Disposable {
}
async executeNotebook(kernelId: string, document: ExtHostNotebookDocument, cell: ExtHostCell | undefined) {
const kernel = this._friendlyIdToKernel.get(kernelId);
const kernel = this._friendlyIdToKernel.get(document.uri)?.get(kernelId);
if (!kernel) {
return;
@@ -167,7 +164,7 @@ export class ExtHostNotebookKernelProviderAdapter extends Disposable {
}
async cancelNotebook(kernelId: string, document: ExtHostNotebookDocument, cell: ExtHostCell | undefined) {
const kernel = this._friendlyIdToKernel.get(kernelId);
const kernel = this._friendlyIdToKernel.get(document.uri)?.get(kernelId);
if (!kernel) {
return;
@@ -191,30 +188,35 @@ async function withToken(cb: (token: CancellationToken) => any) {
}
}
export class NotebookEditorDecorationType implements vscode.NotebookEditorDecorationType {
export class NotebookEditorDecorationType {
private static readonly _Keys = new IdGenerator('NotebookEditorDecorationType');
private _proxy: MainThreadNotebookShape;
public key: string;
readonly value: vscode.NotebookEditorDecorationType;
constructor(proxy: MainThreadNotebookShape, options: vscode.NotebookDecorationRenderOptions) {
this.key = NotebookEditorDecorationType._Keys.nextId();
this._proxy = proxy;
this._proxy.$registerNotebookEditorDecorationType(this.key, typeConverters.NotebookDecorationRenderOptions.from(options));
}
const key = NotebookEditorDecorationType._Keys.nextId();
proxy.$registerNotebookEditorDecorationType(key, typeConverters.NotebookDecorationRenderOptions.from(options));
public dispose(): void {
this._proxy.$removeNotebookEditorDecorationType(this.key);
this.value = {
key,
dispose() {
proxy.$removeNotebookEditorDecorationType(key);
}
};
}
}
export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostNotebookOutputRenderingHandler {
type NotebookContentProviderData = {
readonly provider: vscode.NotebookContentProvider;
readonly extension: IExtensionDescription;
};
export class ExtHostNotebookController implements ExtHostNotebookShape {
private static _notebookKernelProviderHandlePool: number = 0;
private readonly _proxy: MainThreadNotebookShape;
private readonly _mainThreadBulkEdits: MainThreadBulkEditsShape;
private readonly _notebookContentProviders = new Map<string, { readonly provider: vscode.NotebookContentProvider, readonly extension: IExtensionDescription; }>();
private readonly _notebookContentProviders = new Map<string, NotebookContentProviderData>();
private readonly _notebookKernelProviders = new Map<number, ExtHostNotebookKernelProviderAdapter>();
private readonly _documents = new ResourceMap<ExtHostNotebookDocument>();
private readonly _editors = new Map<string, { editor: ExtHostNotebookEditor; }>();
@@ -237,16 +239,13 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
private readonly _onDidChangeActiveNotebookEditor = new Emitter<vscode.NotebookEditor | undefined>();
readonly onDidChangeActiveNotebookEditor = this._onDidChangeActiveNotebookEditor.event;
private _outputDisplayOrder: INotebookDisplayOrder | undefined;
get outputDisplayOrder(): INotebookDisplayOrder | undefined {
return this._outputDisplayOrder;
}
private _activeNotebookEditor: ExtHostNotebookEditor | undefined;
get activeNotebookEditor() {
return this._activeNotebookEditor;
get activeNotebookEditor(): vscode.NotebookEditor | undefined {
return this._activeNotebookEditor?.editor;
}
private _visibleNotebookEditors: ExtHostNotebookEditor[] = [];
get visibleNotebookEditors(): vscode.NotebookEditor[] {
return this._visibleNotebookEditors.map(editor => editor.editor);
}
private _onDidOpenNotebookDocument = new Emitter<vscode.NotebookDocument>();
@@ -254,8 +253,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
private _onDidCloseNotebookDocument = new Emitter<vscode.NotebookDocument>();
onDidCloseNotebookDocument: Event<vscode.NotebookDocument> = this._onDidCloseNotebookDocument.event;
private _onDidSaveNotebookDocument = new Emitter<vscode.NotebookDocument>();
onDidSaveNotebookDocument: Event<vscode.NotebookDocument> = this._onDidCloseNotebookDocument.event;
visibleNotebookEditors: ExtHostNotebookEditor[] = [];
onDidSaveNotebookDocument: Event<vscode.NotebookDocument> = this._onDidSaveNotebookDocument.event;
private _onDidChangeActiveNotebookKernel = new Emitter<{ document: vscode.NotebookDocument, kernel: vscode.NotebookKernel | undefined; }>();
onDidChangeActiveNotebookKernel = this._onDidChangeActiveNotebookKernel.event;
private _onDidChangeVisibleNotebookEditors = new Emitter<vscode.NotebookEditor[]>();
@@ -270,7 +268,6 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
private readonly _extensionStoragePaths: IExtensionStoragePaths,
) {
this._proxy = mainContext.getProxy(MainContext.MainThreadNotebook);
this._mainThreadBulkEdits = mainContext.getProxy(MainContext.MainThreadBulkEdits);
this._commandsConverter = commands.converter;
commands.registerArgumentProcessor({
@@ -299,6 +296,22 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
return this._documents.get(uri);
}
private _getNotebookDocument(uri: URI): ExtHostNotebookDocument {
const result = this._documents.get(uri);
if (!result) {
throw new Error(`NO notebook document for '${uri}'`);
}
return result;
}
private _getProviderData(viewType: string): NotebookContentProviderData {
const result = this._notebookContentProviders.get(viewType);
if (!result) {
throw new Error(`NO provider for '${viewType}'`);
}
return result;
}
registerNotebookContentProvider(
extension: IExtensionDescription,
viewType: string,
@@ -319,32 +332,14 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
}
this._notebookContentProviders.set(viewType, { extension, provider });
const listeners: vscode.Disposable[] = [];
listeners.push(provider.onDidChangeNotebook
? provider.onDidChangeNotebook(e => {
const document = this._documents.get(URI.revive(e.document.uri));
if (!document) {
throw new Error(`Notebook document ${e.document.uri.toString()} not found`);
}
if (isEditEvent(e)) {
const editId = document.addEdit(e);
this._proxy.$onUndoableContentChange(e.document.uri, viewType, editId, e.label);
} else {
this._proxy.$onContentChange(e.document.uri, viewType);
}
})
: Disposable.None);
listeners.push(provider.onDidChangeNotebookContentOptions
? provider.onDidChangeNotebookContentOptions(() => {
let listener: IDisposable | undefined;
if (provider.onDidChangeNotebookContentOptions) {
listener = provider.onDidChangeNotebookContentOptions(() => {
this._proxy.$updateNotebookProviderOptions(viewType, provider.options);
})
: Disposable.None);
const supportBackup = !!provider.backupNotebook;
});
}
const viewOptionsFilenamePattern = options?.viewOptions?.filenamePattern
.map(pattern => typeConverters.NotebookExclusiveDocumentPattern.from(pattern))
@@ -354,14 +349,14 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
console.warn(`Notebook content provider view options file name pattern is invalid ${options?.viewOptions?.filenamePattern}`);
}
this._proxy.$registerNotebookProvider({ id: extension.identifier, location: extension.extensionLocation, description: extension.description }, viewType, supportBackup, {
this._proxy.$registerNotebookProvider({ id: extension.identifier, location: extension.extensionLocation, description: extension.description }, viewType, {
transientOutputs: options?.transientOutputs || false,
transientMetadata: options?.transientMetadata || {},
viewOptions: options?.viewOptions && viewOptionsFilenamePattern ? { displayName: options.viewOptions.displayName, filenamePattern: viewOptionsFilenamePattern, exclusive: options.viewOptions.exclusive || false } : undefined
});
return new extHostTypes.Disposable(() => {
listeners.forEach(d => d.dispose());
listener?.dispose();
this._notebookContentProviders.delete(viewType);
this._proxy.$unregisterNotebookProvider(viewType);
});
@@ -384,15 +379,14 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
}
createNotebookEditorDecorationType(options: vscode.NotebookDecorationRenderOptions): vscode.NotebookEditorDecorationType {
return new NotebookEditorDecorationType(this._proxy, options);
return new NotebookEditorDecorationType(this._proxy, options).value;
}
async openNotebookDocument(uriComponents: UriComponents, viewType?: string): Promise<vscode.NotebookDocument> {
const cached = this._documents.get(URI.revive(uriComponents));
if (cached) {
return Promise.resolve(cached.notebookDocument);
return cached.notebookDocument;
}
await this._proxy.$tryOpenDocument(uriComponents, viewType);
const document = this._documents.get(URI.revive(uriComponents));
return assertIsDefined(document?.notebookDocument);
@@ -420,7 +414,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
resolvedOptions = {
position: typeConverters.ViewColumn.from(options.viewColumn),
preserveFocus: options.preserveFocus,
selection: options.selection,
selection: options.selection && typeConverters.NotebookCellRange.from(options.selection),
pinned: typeof options.preview === 'boolean' ? !options.preview : undefined
};
} else {
@@ -433,7 +427,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
const editor = editorId && this._editors.get(editorId)?.editor;
if (editor) {
return editor;
return editor.editor;
}
if (editorId) {
@@ -459,26 +453,6 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
});
}
async $resolveNotebookData(viewType: string, uri: UriComponents, backupId?: string): Promise<NotebookDataDto> {
const provider = this._notebookContentProviders.get(viewType);
if (!provider) {
throw new Error(`NO provider for '${viewType}'`);
}
const data = await provider.provider.openNotebook(URI.revive(uri), { backupId });
return {
metadata: {
...notebookDocumentMetadataDefaults,
...data.metadata
},
languages: data.languages,
cells: data.cells.map(cell => ({
...cell,
outputs: cell.outputs.map(o => addIdToOutput(o))
})),
};
}
async $resolveNotebookEditor(viewType: string, uri: UriComponents, editorId: string): Promise<void> {
const provider = this._notebookContentProviders.get(viewType);
const revivedUri = URI.revive(uri);
@@ -516,75 +490,53 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
});
}
// --- open, save, saveAs, backup
async $openNotebook(viewType: string, uri: UriComponents, backupId?: string): Promise<NotebookDataDto> {
const { provider } = this._getProviderData(viewType);
const data = await provider.openNotebook(URI.revive(uri), { backupId });
return {
metadata: {
...notebookDocumentMetadataDefaults,
...data.metadata
},
cells: data.cells.map(typeConverters.NotebookCellData.from),
};
}
async $saveNotebook(viewType: string, uri: UriComponents, token: CancellationToken): Promise<boolean> {
const document = this._documents.get(URI.revive(uri));
if (!document) {
return false;
}
if (this._notebookContentProviders.has(viewType)) {
await this._notebookContentProviders.get(viewType)!.provider.saveNotebook(document.notebookDocument, token);
return true;
}
return false;
const document = this._getNotebookDocument(URI.revive(uri));
const { provider } = this._getProviderData(viewType);
await provider.saveNotebook(document.notebookDocument, token);
return true;
}
async $saveNotebookAs(viewType: string, uri: UriComponents, target: UriComponents, token: CancellationToken): Promise<boolean> {
const document = this._documents.get(URI.revive(uri));
if (!document) {
return false;
}
if (this._notebookContentProviders.has(viewType)) {
await this._notebookContentProviders.get(viewType)!.provider.saveNotebookAs(URI.revive(target), document.notebookDocument, token);
return true;
}
return false;
const document = this._getNotebookDocument(URI.revive(uri));
const { provider } = this._getProviderData(viewType);
await provider.saveNotebookAs(URI.revive(target), document.notebookDocument, token);
return true;
}
async $undoNotebook(viewType: string, uri: UriComponents, editId: number, isDirty: boolean): Promise<void> {
const document = this._documents.get(URI.revive(uri));
if (!document) {
return;
}
private _backupIdPool: number = 0;
document.undo(editId, isDirty);
async $backupNotebook(viewType: string, uri: UriComponents, cancellation: CancellationToken): Promise<string> {
const document = this._getNotebookDocument(URI.revive(uri));
const provider = this._getProviderData(viewType);
}
const storagePath = this._extensionStoragePaths.workspaceValue(provider.extension) ?? this._extensionStoragePaths.globalValue(provider.extension);
const fileName = String(hash([document.uri.toString(), this._backupIdPool++]));
const backupUri = URI.joinPath(storagePath, fileName);
async $redoNotebook(viewType: string, uri: UriComponents, editId: number, isDirty: boolean): Promise<void> {
const document = this._documents.get(URI.revive(uri));
if (!document) {
return;
}
document.redo(editId, isDirty);
}
async $backup(viewType: string, uri: UriComponents, cancellation: CancellationToken): Promise<string | undefined> {
const document = this._documents.get(URI.revive(uri));
const provider = this._notebookContentProviders.get(viewType);
if (document && provider && provider.provider.backupNotebook) {
const backup = await provider.provider.backupNotebook(document.notebookDocument, { destination: document.getNewBackupUri() }, cancellation);
document.updateBackup(backup);
return backup.id;
}
return;
}
$acceptDisplayOrder(displayOrder: INotebookDisplayOrder): void {
this._outputDisplayOrder = displayOrder;
const backup = await provider.provider.backupNotebook(document.notebookDocument, { destination: backupUri }, cancellation);
document.updateBackup(backup);
return backup.id;
}
$acceptNotebookActiveKernelChange(event: { uri: UriComponents, providerHandle: number | undefined, kernelFriendlyId: string | undefined; }) {
if (event.providerHandle !== undefined) {
this._withAdapter(event.providerHandle, event.uri, async (adapter, document) => {
const kernel = event.kernelFriendlyId ? adapter.getKernelByFriendlyId(event.kernelFriendlyId) : undefined;
const kernel = event.kernelFriendlyId ? adapter.getKernelByFriendlyId(URI.revive(event.uri), event.kernelFriendlyId) : undefined;
this._editors.forEach(editor => {
if (editor.editor.notebookData === document) {
editor.editor._acceptKernel(kernel);
@@ -595,36 +547,23 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
}
}
// TODO@rebornix: remove document - editor one on one mapping
private _getEditorFromURI(uriComponents: UriComponents) {
const uriStr = URI.revive(uriComponents).toString();
let editor: { editor: ExtHostNotebookEditor; } | undefined;
this._editors.forEach(e => {
if (e.editor.document.uri.toString() === uriStr) {
editor = e;
}
});
return editor;
}
$onDidReceiveMessage(editorId: string, forRendererType: string | undefined, message: any): void {
this._webviewComm.get(editorId)?.onDidReceiveMessage(forRendererType, message);
}
$acceptModelChanged(uriComponents: UriComponents, event: NotebookCellsChangedEventDto, isDirty: boolean): void {
const document = this._documents.get(URI.revive(uriComponents));
if (document) {
document.acceptModelChanged(event, isDirty);
}
$acceptModelChanged(uri: UriComponents, event: NotebookCellsChangedEventDto, isDirty: boolean): void {
const document = this._getNotebookDocument(URI.revive(uri));
document.acceptModelChanged(event, isDirty);
}
public $acceptModelSaved(uriComponents: UriComponents): void {
const document = this._documents.get(URI.revive(uriComponents));
if (document) {
// this.$acceptDirtyStateChanged(uriComponents, false);
this._onDidSaveNotebookDocument.fire(document.notebookDocument);
}
$acceptDirtyStateChanged(uri: UriComponents, isDirty: boolean): void {
const document = this._getNotebookDocument(URI.revive(uri));
document.acceptModelChanged({ rawEvents: [], versionId: document.notebookDocument.version }, isDirty);
}
$acceptModelSaved(uri: UriComponents): void {
const document = this._getNotebookDocument(URI.revive(uri));
this._onDidSaveNotebookDocument.fire(document.notebookDocument);
}
$acceptEditorPropertiesChanged(id: string, data: INotebookEditorPropertiesChangeData): void {
@@ -642,42 +581,30 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
}
if (data.visibleRanges) {
editor.editor._acceptVisibleRanges(data.visibleRanges.ranges);
editor.editor._acceptVisibleRanges(data.visibleRanges.ranges.map(typeConverters.NotebookCellRange.to));
this._onDidChangeNotebookEditorVisibleRanges.fire({
notebookEditor: editor.editor,
visibleRanges: editor.editor.visibleRanges
notebookEditor: editor.editor.editor,
visibleRanges: editor.editor.editor.visibleRanges
});
}
if (data.selections) {
if (data.selections.selections.length) {
const firstCell = data.selections.selections[0];
editor.editor.selection = editor.editor.notebookData.getCell(firstCell)?.cell;
} else {
editor.editor.selection = undefined;
}
editor.editor._acceptSelections(data.selections.selections);
this._onDidChangeNotebookEditorSelection.fire({
notebookEditor: editor.editor,
selection: editor.editor.selection
notebookEditor: editor.editor.editor,
selection: editor.editor.editor.selection
});
}
}
$acceptDocumentPropertiesChanged(uriComponents: UriComponents, data: INotebookDocumentPropertiesChangeData): void {
this.logService.debug('ExtHostNotebook#$acceptDocumentPropertiesChanged', uriComponents.path, data);
const editor = this._getEditorFromURI(uriComponents);
if (!editor) {
return;
}
if (data.metadata) {
editor.editor.notebookData.acceptDocumentPropertiesChanged(data);
}
$acceptDocumentPropertiesChanged(uri: UriComponents, data: INotebookDocumentPropertiesChangeData): void {
this.logService.debug('ExtHostNotebook#$acceptDocumentPropertiesChanged', uri.path, data);
const document = this._getNotebookDocument(URI.revive(uri));
document.acceptDocumentPropertiesChanged(data);
}
private _createExtHostEditor(document: ExtHostNotebookDocument, editorId: string, selections: number[], visibleRanges: vscode.NotebookCellRange[]) {
private _createExtHostEditor(document: ExtHostNotebookDocument, editorId: string, selections: ICellRange[], visibleRanges: extHostTypes.NotebookCellRange[]) {
const revivedUri = document.uri;
let webComm = this._webviewComm.get(editorId);
@@ -690,17 +617,10 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
editorId,
document.notebookDocument.viewType,
this._proxy,
webComm.contentProviderComm,
document
);
if (selections.length) {
const firstCell = selections[0];
editor.selection = editor.notebookData.getCell(firstCell)?.cell;
} else {
editor.selection = undefined;
}
editor._acceptSelections(selections);
editor._acceptVisibleRanges(visibleRanges);
this._editors.get(editorId)?.editor.dispose();
@@ -723,7 +643,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
}
for (const e of this._editors.values()) {
if (e.editor.document.uri.toString() === revivedUri.toString()) {
if (e.editor.notebookData.uri.toString() === revivedUri.toString()) {
e.editor.dispose();
this._editors.delete(e.editor.id);
editorChanged = true;
@@ -739,31 +659,37 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
for (const modelData of delta.addedDocuments) {
const uri = URI.revive(modelData.uri);
const viewType = modelData.viewType;
const entry = this._notebookContentProviders.get(viewType);
const storageRoot = entry && (this._extensionStoragePaths.workspaceValue(entry.extension) ?? this._extensionStoragePaths.globalValue(entry.extension));
if (this._documents.has(uri)) {
throw new Error(`adding EXISTING notebook ${uri}`);
}
const that = this;
const document = new ExtHostNotebookDocument(this._proxy, this._documentsAndEditors, this._mainThreadBulkEdits, {
emitModelChange(event: vscode.NotebookCellsChangeEvent): void {
that._onDidChangeNotebookCells.fire(event);
const document = new ExtHostNotebookDocument(
this._proxy,
this._documentsAndEditors,
{
emitModelChange(event: vscode.NotebookCellsChangeEvent): void {
that._onDidChangeNotebookCells.fire(event);
},
emitCellOutputsChange(event: vscode.NotebookCellOutputsChangeEvent): void {
that._onDidChangeCellOutputs.fire(event);
},
emitCellLanguageChange(event: vscode.NotebookCellLanguageChangeEvent): void {
that._onDidChangeCellLanguage.fire(event);
},
emitCellMetadataChange(event: vscode.NotebookCellMetadataChangeEvent): void {
that._onDidChangeCellMetadata.fire(event);
},
emitDocumentMetadataChange(event: vscode.NotebookDocumentMetadataChangeEvent): void {
that._onDidChangeNotebookDocumentMetadata.fire(event);
}
},
emitCellOutputsChange(event: vscode.NotebookCellOutputsChangeEvent): void {
that._onDidChangeCellOutputs.fire(event);
},
emitCellLanguageChange(event: vscode.NotebookCellLanguageChangeEvent): void {
that._onDidChangeCellLanguage.fire(event);
},
emitCellMetadataChange(event: vscode.NotebookCellMetadataChangeEvent): void {
that._onDidChangeCellMetadata.fire(event);
},
emitDocumentMetadataChange(event: vscode.NotebookDocumentMetadataChangeEvent): void {
that._onDidChangeNotebookDocumentMetadata.fire(event);
}
}, viewType, modelData.contentOptions, { ...notebookDocumentMetadataDefaults, ...modelData.metadata }, uri, storageRoot);
viewType,
modelData.contentOptions,
modelData.metadata ? typeConverters.NotebookDocumentMetadata.to(modelData.metadata) : new extHostTypes.NotebookDocumentMetadata(),
uri,
);
document.acceptModelChanged({
versionId: modelData.versionId,
@@ -784,13 +710,6 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
this._documents.get(uri)?.dispose();
this._documents.set(uri, document);
// create editor if populated
if (modelData.attachedEditor) {
this._createExtHostEditor(document, modelData.attachedEditor.id, modelData.attachedEditor.selections, modelData.attachedEditor.visibleRanges);
editorChanged = true;
}
this._documentsAndEditors.$acceptDocumentsAndEditorsDelta({ addedDocuments: addedCellDocuments });
this._onDidOpenNotebookDocument.fire(document.notebookDocument);
@@ -807,7 +726,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
const document = this._documents.get(revivedUri);
if (document) {
this._createExtHostEditor(document, editorModelData.id, editorModelData.selections, editorModelData.visibleRanges);
this._createExtHostEditor(document, editorModelData.id, editorModelData.selections, editorModelData.visibleRanges.map(typeConverters.NotebookCellRange.to));
editorChanged = true;
}
}
@@ -823,7 +742,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
editorChanged = true;
this._editors.delete(editorid);
if (this.activeNotebookEditor?.id === editor.editor.id) {
if (this._activeNotebookEditor?.id === editor.editor.id) {
this._activeNotebookEditor = undefined;
}
@@ -839,16 +758,16 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
}
if (delta.visibleEditors) {
this.visibleNotebookEditors = delta.visibleEditors.map(id => this._editors.get(id)!.editor).filter(editor => !!editor) as ExtHostNotebookEditor[];
this._visibleNotebookEditors = delta.visibleEditors.map(id => this._editors.get(id)!.editor).filter(editor => !!editor) as ExtHostNotebookEditor[];
const visibleEditorsSet = new Set<string>();
this.visibleNotebookEditors.forEach(editor => visibleEditorsSet.add(editor.id));
this._visibleNotebookEditors.forEach(editor => visibleEditorsSet.add(editor.id));
for (const e of this._editors.values()) {
const newValue = visibleEditorsSet.has(e.editor.id);
e.editor._acceptVisibility(newValue);
}
this.visibleNotebookEditors = [...this._editors.values()].map(e => e.editor).filter(e => e.visible);
this._visibleNotebookEditors = [...this._editors.values()].map(e => e.editor).filter(e => e.visible);
this._onDidChangeVisibleNotebookEditors.fire(this.visibleNotebookEditors);
}
@@ -857,7 +776,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
this._activeNotebookEditor = this._editors.get(delta.newActiveEditor)?.editor;
this._activeNotebookEditor?._acceptActive(true);
for (const e of this._editors.values()) {
if (e.editor !== this.activeNotebookEditor) {
if (e.editor !== this._activeNotebookEditor) {
e.editor._acceptActive(false);
}
}
@@ -869,7 +788,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
}
}
this._onDidChangeActiveNotebookEditor.fire(this._activeNotebookEditor);
this._onDidChangeActiveNotebookEditor.fire(this._activeNotebookEditor?.editor);
}
}
@@ -892,11 +811,6 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
}
}
function isEditEvent(e: vscode.NotebookDocumentEditEvent | vscode.NotebookDocumentContentChangeEvent): e is vscode.NotebookDocumentEditEvent {
return typeof (e as vscode.NotebookDocumentEditEvent).undo === 'function'
&& typeof (e as vscode.NotebookDocumentEditEvent).redo === 'function';
}
export class NotebookCellStatusBarItemInternal extends Disposable {
private static NEXT_ID = 0;

View File

@@ -11,7 +11,6 @@ import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
import { PrefixSumComputer } from 'vs/editor/common/viewModel/prefixSumComputer';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { score } from 'vs/editor/common/modes/languageSelector';
import { CellKind } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { ResourceMap } from 'vs/base/common/map';
import { URI } from 'vs/base/common/uri';
import { generateUuid } from 'vs/base/common/uuid';
@@ -76,7 +75,7 @@ export class ExtHostNotebookConcatDocument implements vscode.NotebookConcatTextD
const cellLengths: number[] = [];
const cellLineCounts: number[] = [];
for (const cell of this._notebook.cells) {
if (cell.cellKind === CellKind.Code && (!this._selector || score(this._selector, cell.uri, cell.language, true))) {
if (cell.cellKind === types.NotebookCellKind.Code && (!this._selector || score(this._selector, cell.uri, cell.language, true))) {
this._cellUris.set(cell.uri, this._cells.length);
this._cells.push(cell);
cellLengths.push(cell.document.getText().length + 1);

View File

@@ -4,56 +4,31 @@
*--------------------------------------------------------------------------------------------*/
import { Emitter, Event } from 'vs/base/common/event';
import { hash } from 'vs/base/common/hash';
import { Disposable, DisposableStore, dispose, IDisposable } from 'vs/base/common/lifecycle';
import { Disposable, DisposableStore, dispose } from 'vs/base/common/lifecycle';
import { Schemas } from 'vs/base/common/network';
import { joinPath } from 'vs/base/common/resources';
import { ISplice } from 'vs/base/common/sequence';
import { URI } from 'vs/base/common/uri';
import * as UUID from 'vs/base/common/uuid';
import { CellKind, INotebookDocumentPropertiesChangeData, IWorkspaceCellEditDto, MainThreadBulkEditsShape, MainThreadNotebookShape, NotebookCellOutputsSplice, WorkspaceEditType } from 'vs/workbench/api/common/extHost.protocol';
import { CellKind, INotebookDocumentPropertiesChangeData, MainThreadNotebookShape } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostDocumentsAndEditors, IExtHostModelAddedData } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
import { CellEditType, CellOutputKind, diff, IMainCellDto, IProcessedOutput, NotebookCellMetadata, NotebookCellsChangedEventDto, NotebookCellsChangeType, NotebookCellsSplice2, notebookDocumentMetadataDefaults } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import * as extHostTypeConverters from 'vs/workbench/api/common/extHostTypeConverters';
import * as extHostTypes from 'vs/workbench/api/common/extHostTypes';
import { IMainCellDto, IOutputDto, IOutputItemDto, NotebookCellMetadata, NotebookCellsChangedEventDto, NotebookCellsChangeType, NotebookCellsSplice2, notebookDocumentMetadataDefaults } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import * as vscode from 'vscode';
import { Cache } from './cache';
interface IObservable<T> {
proxy: T;
onDidChange: Event<void>;
}
function getObservable<T extends Object>(obj: T): IObservable<T> {
const onDidChange = new Emitter<void>();
const proxy = new Proxy(obj, {
set(target: T, p: PropertyKey, value: any, _receiver: any): boolean {
target[p as keyof T] = value;
onDidChange.fire();
return true;
}
});
return {
proxy,
onDidChange: onDidChange.event
};
}
class RawContentChangeEvent {
constructor(readonly start: number, readonly deletedCount: number, readonly deletedItems: ExtHostCell[], readonly items: ExtHostCell[]) { }
constructor(readonly start: number, readonly deletedCount: number, readonly deletedItems: vscode.NotebookCell[], readonly items: ExtHostCell[]) { }
static asApiEvent(event: RawContentChangeEvent): vscode.NotebookCellsChangeData {
return Object.freeze({
start: event.start,
deletedCount: event.deletedCount,
deletedItems: event.deletedItems.map(data => data.cell),
deletedItems: event.deletedItems,
items: event.items.map(data => data.cell)
});
}
}
export class ExtHostCell extends Disposable {
export class ExtHostCell {
static asModelAddData(notebook: vscode.NotebookDocument, cell: IMainCellDto): IExtHostModelAddedData {
return {
@@ -70,14 +45,8 @@ export class ExtHostCell extends Disposable {
private _onDidDispose = new Emitter<void>();
readonly onDidDispose: Event<void> = this._onDidDispose.event;
private _onDidChangeOutputs = new Emitter<ISplice<IProcessedOutput>[]>();
readonly onDidChangeOutputs: Event<ISplice<IProcessedOutput>[]> = this._onDidChangeOutputs.event;
private _outputs: any[];
private _outputMapping = new WeakMap<vscode.CellOutput, string | undefined /* output ID */>();
private _metadata: vscode.NotebookCellMetadata;
private _metadataChangeListener: IDisposable;
private _outputs: extHostTypes.NotebookCellOutput[];
private _metadata: extHostTypes.NotebookCellMetadata;
readonly handle: number;
readonly uri: URI;
@@ -86,28 +55,20 @@ export class ExtHostCell extends Disposable {
private _cell: vscode.NotebookCell | undefined;
constructor(
private readonly _mainThreadBulkEdits: MainThreadBulkEditsShape,
private readonly _notebook: ExtHostNotebookDocument,
private readonly _extHostDocument: ExtHostDocumentsAndEditors,
private readonly _cellData: IMainCellDto,
) {
super();
this.handle = _cellData.handle;
this.uri = URI.revive(_cellData.uri);
this.cellKind = _cellData.cellKind;
this._outputs = _cellData.outputs.map(extHostTypeConverters.NotebookCellOutput.to);
this._metadata = extHostTypeConverters.NotebookCellMetadata.to(_cellData.metadata ?? {});
}
this._outputs = _cellData.outputs;
for (const output of this._outputs) {
this._outputMapping.set(output, output.outputId);
delete output.outputId;
}
const observableMetadata = getObservable(_cellData.metadata ?? {});
this._metadata = observableMetadata.proxy;
this._metadataChangeListener = this._register(observableMetadata.onDidChange(() => {
this._updateMetadata();
}));
dispose() {
this._onDidDispose.fire();
this._onDidDispose.dispose();
}
get cell(): vscode.NotebookCell {
@@ -121,81 +82,35 @@ export class ExtHostCell extends Disposable {
get index() { return that._notebook.getCellIndex(that); },
notebook: that._notebook.notebookDocument,
uri: that.uri,
cellKind: this._cellData.cellKind,
cellKind: extHostTypeConverters.NotebookCellKind.to(this._cellData.cellKind),
document: data.document,
get language() { return data!.document.languageId; },
get outputs() { return that._outputs; },
set outputs(value) { that._updateOutputs(value); },
get outputs() { return that._outputs.slice(0); },
set outputs(_value) { throw new Error('Use WorkspaceEdit to update cell outputs.'); },
get metadata() { return that._metadata; },
set metadata(value) {
that.setMetadata(value);
that._updateMetadata();
},
set metadata(_value) { throw new Error('Use WorkspaceEdit to update cell metadata.'); },
});
}
return this._cell;
}
dispose() {
super.dispose();
this._onDidDispose.fire();
setOutputs(newOutputs: IOutputDto[]): void {
this._outputs = newOutputs.map(extHostTypeConverters.NotebookCellOutput.to);
}
setOutputs(newOutputs: vscode.CellOutput[]): void {
this._outputs = newOutputs;
}
private _updateOutputs(newOutputs: vscode.CellOutput[]) {
const rawDiffs = diff<vscode.CellOutput>(this._outputs || [], newOutputs || [], (a) => {
return this._outputMapping.has(a);
});
const transformedDiffs: ISplice<IProcessedOutput>[] = rawDiffs.map(diff => {
for (let i = diff.start; i < diff.start + diff.deleteCount; i++) {
this._outputMapping.delete(this._outputs[i]);
setOutputItems(outputId: string, append: boolean, newOutputItems: IOutputItemDto[]) {
const newItems = newOutputItems.map(extHostTypeConverters.NotebookCellOutputItem.to);
const output = this._outputs.find(op => op.id === outputId);
if (output) {
if (!append) {
output.outputs.length = 0;
}
return {
deleteCount: diff.deleteCount,
start: diff.start,
toInsert: diff.toInsert.map((output): IProcessedOutput => {
if (output.outputKind === CellOutputKind.Rich) {
const uuid = UUID.generateUuid();
this._outputMapping.set(output, uuid);
return { ...output, outputId: uuid };
}
this._outputMapping.set(output, undefined);
return output;
})
};
});
this._outputs = newOutputs;
this._onDidChangeOutputs.fire(transformedDiffs);
output.outputs.push(...newItems);
}
}
setMetadata(newMetadata: vscode.NotebookCellMetadata): void {
// Don't apply metadata defaults here, 'undefined' means 'inherit from document metadata'
this._metadataChangeListener.dispose();
const observableMetadata = getObservable(newMetadata);
this._metadata = observableMetadata.proxy;
this._metadataChangeListener = this._register(observableMetadata.onDidChange(() => {
this._updateMetadata();
}));
}
private _updateMetadata(): Promise<boolean> {
const index = this._notebook.notebookDocument.cells.indexOf(this.cell);
const edit: IWorkspaceCellEditDto = {
_type: WorkspaceEditType.Cell,
metadata: undefined,
resource: this._notebook.uri,
notebookVersionId: this._notebook.notebookDocument.version,
edit: { editType: CellEditType.Metadata, index, metadata: this._metadata }
};
return this._mainThreadBulkEdits.$tryApplyWorkspaceEdit({ edits: [edit] });
setMetadata(newMetadata: NotebookCellMetadata): void {
this._metadata = extHostTypeConverters.NotebookCellMetadata.to(newMetadata);
}
}
@@ -207,10 +122,6 @@ export interface INotebookEventEmitter {
emitCellMetadataChange(event: vscode.NotebookCellMetadataChangeEvent): void;
}
function hashPath(resource: URI): string {
const str = resource.scheme === Schemas.file || resource.scheme === Schemas.untitled ? resource.fsPath : resource.toString();
return hash(str) + '';
}
export class ExtHostNotebookDocument extends Disposable {
@@ -222,35 +133,21 @@ export class ExtHostNotebookDocument extends Disposable {
private _cellDisposableMapping = new Map<number, DisposableStore>();
private _notebook: vscode.NotebookDocument | undefined;
private _metadata: Required<vscode.NotebookDocumentMetadata>;
private _metadataChangeListener: IDisposable;
private _versionId = 0;
private _versionId: number = 0;
private _isDirty: boolean = false;
private _backupCounter = 1;
private _backup?: vscode.NotebookDocumentBackup;
private _disposed = false;
private _languages: string[] = [];
private readonly _edits = new Cache<vscode.NotebookDocumentEditEvent>('notebook documents');
private _disposed: boolean = false;
constructor(
private readonly _proxy: MainThreadNotebookShape,
private readonly _documentsAndEditors: ExtHostDocumentsAndEditors,
private readonly _mainThreadBulkEdits: MainThreadBulkEditsShape,
private readonly _emitter: INotebookEventEmitter,
private readonly _viewType: string,
private readonly _contentOptions: vscode.NotebookDocumentContentOptions,
metadata: Required<vscode.NotebookDocumentMetadata>,
public readonly uri: URI,
private readonly _storagePath: URI | undefined
private _metadata: extHostTypes.NotebookDocumentMetadata,
readonly uri: URI,
) {
super();
const observableMetadata = getObservable(metadata);
this._metadata = observableMetadata.proxy;
this._metadataChangeListener = this._register(observableMetadata.onDidChange(() => {
this._tryUpdateMetadata();
}));
}
dispose() {
@@ -259,36 +156,6 @@ export class ExtHostNotebookDocument extends Disposable {
dispose(this._cellDisposableMapping.values());
}
private _updateMetadata(newMetadata: Required<vscode.NotebookDocumentMetadata>) {
this._metadataChangeListener.dispose();
newMetadata = {
...notebookDocumentMetadataDefaults,
...newMetadata
};
if (this._metadataChangeListener) {
this._metadataChangeListener.dispose();
}
const observableMetadata = getObservable(newMetadata);
this._metadata = observableMetadata.proxy;
this._metadataChangeListener = this._register(observableMetadata.onDidChange(() => {
this._tryUpdateMetadata();
}));
this._tryUpdateMetadata();
}
private _tryUpdateMetadata() {
const edit: IWorkspaceCellEditDto = {
_type: WorkspaceEditType.Cell,
metadata: undefined,
edit: { editType: CellEditType.DocumentMetadata, metadata: this._metadata },
resource: this.uri,
notebookVersionId: this.notebookDocument.version,
};
return this._mainThreadBulkEdits.$tryApplyWorkspaceEdit({ edits: [edit] });
}
get notebookDocument(): vscode.NotebookDocument {
if (!this._notebook) {
@@ -301,29 +168,15 @@ export class ExtHostNotebookDocument extends Disposable {
get isDirty() { return that._isDirty; },
get isUntitled() { return that.uri.scheme === Schemas.untitled; },
get cells(): ReadonlyArray<vscode.NotebookCell> { return that._cells.map(cell => cell.cell); },
get languages() { return that._languages; },
set languages(value: string[]) { that._trySetLanguages(value); },
get metadata() { return that._metadata; },
set metadata(value: Required<vscode.NotebookDocumentMetadata>) { that._updateMetadata(value); },
get contentOptions() { return that._contentOptions; }
set metadata(_value: Required<vscode.NotebookDocumentMetadata>) { throw new Error('Use WorkspaceEdit to update metadata.'); },
get contentOptions() { return that._contentOptions; },
save() { return that._save(); }
});
}
return this._notebook;
}
private _trySetLanguages(newLanguages: string[]) {
this._languages = newLanguages;
this._proxy.$updateNotebookLanguages(this._viewType, this.uri, this._languages);
}
getNewBackupUri(): URI {
if (!this._storagePath) {
throw new Error('Backup requires a valid storage path');
}
const fileName = hashPath(this.uri) + (this._backupCounter++);
return joinPath(this._storagePath, fileName);
}
updateBackup(backup: vscode.NotebookDocumentBackup): void {
this._backup?.delete();
this._backup = backup;
@@ -339,17 +192,7 @@ export class ExtHostNotebookDocument extends Disposable {
...notebookDocumentMetadataDefaults,
...data.metadata
};
if (this._metadataChangeListener) {
this._metadataChangeListener.dispose();
}
const observableMetadata = getObservable(newMetadata);
this._metadata = observableMetadata.proxy;
this._metadataChangeListener = this._register(observableMetadata.onDidChange(() => {
this._tryUpdateMetadata();
}));
this._metadata = this._metadata.with(newMetadata);
this._emitter.emitDocumentMetadataChange({ document: this.notebookDocument });
}
@@ -365,6 +208,8 @@ export class ExtHostNotebookDocument extends Disposable {
this._moveCell(e.index, e.newIdx);
} else if (e.kind === NotebookCellsChangeType.Output) {
this._setCellOutputs(e.index, e.outputs);
} else if (e.kind === NotebookCellsChangeType.OutputItem) {
this._setCellOutputItems(e.index, e.outputId, e.append, e.outputItems);
} else if (e.kind === NotebookCellsChangeType.ChangeLanguage) {
this._changeCellLanguage(e.index, e.language);
} else if (e.kind === NotebookCellsChangeType.ChangeCellMetadata) {
@@ -373,6 +218,13 @@ export class ExtHostNotebookDocument extends Disposable {
});
}
private async _save(): Promise<boolean> {
if (this._disposed) {
return Promise.reject(new Error('Document has been closed'));
}
return this._proxy.$trySaveDocument(this.uri);
}
private _spliceNotebookCells(splices: NotebookCellsSplice2[], initialization: boolean): void {
if (this._disposed) {
return;
@@ -386,7 +238,7 @@ export class ExtHostNotebookDocument extends Disposable {
const cellDtos = splice[2];
const newCells = cellDtos.map(cell => {
const extCell = new ExtHostCell(this._mainThreadBulkEdits, this, this._documentsAndEditors, cell);
const extCell = new ExtHostCell(this, this._documentsAndEditors, cell);
if (!initialization) {
addedCellDocuments.push(ExtHostCell.asModelAddData(this.notebookDocument, cell));
@@ -398,12 +250,6 @@ export class ExtHostNotebookDocument extends Disposable {
this._cellDisposableMapping.set(extCell.handle, store);
}
const store = this._cellDisposableMapping.get(extCell.handle)!;
store.add(extCell.onDidChangeOutputs((diffs) => {
this.eventuallyUpdateCellOutputs(extCell, diffs);
}));
return extCell;
});
@@ -412,12 +258,14 @@ export class ExtHostNotebookDocument extends Disposable {
this._cellDisposableMapping.delete(this._cells[j].handle);
}
const changeEvent = new RawContentChangeEvent(splice[0], splice[1], [], newCells);
const deletedItems = this._cells.splice(splice[0], splice[1], ...newCells);
for (let cell of deletedItems) {
removedCellDocuments.push(cell.uri);
changeEvent.deletedItems.push(cell.cell);
}
contentChangeEvents.push(new RawContentChangeEvent(splice[0], splice[1], deletedItems, newCells));
contentChangeEvents.push(changeEvent);
});
this._documentsAndEditors.acceptDocumentsAndEditorsDelta({
@@ -453,12 +301,18 @@ export class ExtHostNotebookDocument extends Disposable {
});
}
private _setCellOutputs(index: number, outputs: IProcessedOutput[]): void {
private _setCellOutputs(index: number, outputs: IOutputDto[]): void {
const cell = this._cells[index];
cell.setOutputs(outputs);
this._emitter.emitCellOutputsChange({ document: this.notebookDocument, cells: [cell.cell] });
}
private _setCellOutputItems(index: number, outputId: string, append: boolean, outputItems: IOutputItemDto[]): void {
const cell = this._cells[index];
cell.setOutputItems(outputId, append, outputItems);
this._emitter.emitCellOutputsChange({ document: this.notebookDocument, cells: [cell.cell] });
}
private _changeCellLanguage(index: number, language: string): void {
const cell = this._cells[index];
const event: vscode.NotebookCellLanguageChangeEvent = { document: this.notebookDocument, cell: cell.cell, language };
@@ -472,21 +326,8 @@ export class ExtHostNotebookDocument extends Disposable {
this._emitter.emitCellMetadataChange(event);
}
async eventuallyUpdateCellOutputs(cell: ExtHostCell, diffs: ISplice<IProcessedOutput>[]) {
const outputDtos: NotebookCellOutputsSplice[] = diffs.map(diff => {
const outputs = diff.toInsert;
return [diff.start, diff.deleteCount, outputs];
});
if (!outputDtos.length) {
return;
}
await this._proxy.$spliceNotebookCellOutputs(this._viewType, this.uri, cell.handle, outputDtos);
this._emitter.emitCellOutputsChange({
document: this.notebookDocument,
cells: [cell.cell]
});
getCellFromIndex(index: number): ExtHostCell | undefined {
return this._cells[index];
}
getCell(cellHandle: number): ExtHostCell | undefined {
@@ -496,37 +337,4 @@ export class ExtHostNotebookDocument extends Disposable {
getCellIndex(cell: ExtHostCell): number {
return this._cells.indexOf(cell);
}
addEdit(item: vscode.NotebookDocumentEditEvent): number {
return this._edits.add([item]);
}
async undo(editId: number, isDirty: boolean): Promise<void> {
await this.getEdit(editId).undo();
// if (!isDirty) {
// this.disposeBackup();
// }
}
async redo(editId: number, isDirty: boolean): Promise<void> {
await this.getEdit(editId).redo();
// if (!isDirty) {
// this.disposeBackup();
// }
}
private getEdit(editId: number): vscode.NotebookDocumentEditEvent {
const edit = this._edits.get(editId, 0);
if (!edit) {
throw new Error('No edit found');
}
return edit;
}
disposeEdits(editIds: number[]): void {
for (const id of editIds) {
this._edits.delete(id);
}
}
}

View File

@@ -5,13 +5,18 @@
import { readonly } from 'vs/base/common/errors';
import { Emitter, Event } from 'vs/base/common/event';
import { Disposable } from 'vs/base/common/lifecycle';
import { MainThreadNotebookShape } from 'vs/workbench/api/common/extHost.protocol';
import * as extHostTypes from 'vs/workbench/api/common/extHostTypes';
import { addIdToOutput, CellEditType, ICellEditOperation, ICellReplaceEdit, INotebookEditData, notebookDocumentMetadataDefaults } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import * as extHostConverter from 'vs/workbench/api/common/extHostTypeConverters';
import { CellEditType, ICellEditOperation, ICellRange, ICellReplaceEdit, notebookDocumentMetadataDefaults } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import * as vscode from 'vscode';
import { ExtHostNotebookDocument } from './extHostNotebookDocument';
interface INotebookEditData {
documentVersionId: number;
cellEdits: ICellEditOperation[];
}
class NotebookEditorCellEditBuilder implements vscode.NotebookEditorEdit {
private readonly _documentVersionId: number;
@@ -54,17 +59,13 @@ class NotebookEditorCellEditBuilder implements vscode.NotebookEditorEdit {
});
}
replaceCellOutput(index: number, outputs: (vscode.NotebookCellOutput | vscode.CellOutput)[]): void {
replaceCellOutput(index: number, outputs: vscode.NotebookCellOutput[]): void {
this._throwIfFinalized();
this._collectedEdits.push({
editType: CellEditType.Output,
index,
outputs: outputs.map(output => {
if (extHostTypes.NotebookCellOutput.isNotebookCellOutput(output)) {
return addIdToOutput(output.toJSON());
} else {
return addIdToOutput(output);
}
return extHostConverter.NotebookCellOutput.from(output);
})
});
}
@@ -78,62 +79,80 @@ class NotebookEditorCellEditBuilder implements vscode.NotebookEditorEdit {
editType: CellEditType.Replace,
index: from,
count: to - from,
cells: cells.map(data => {
return {
...data,
outputs: data.outputs.map(output => addIdToOutput(output)),
};
})
cells: cells.map(extHostConverter.NotebookCellData.from)
});
}
}
export class ExtHostNotebookEditor extends Disposable implements vscode.NotebookEditor {
export class ExtHostNotebookEditor {
private _selection?: vscode.NotebookCell;
private _selections: vscode.NotebookCellRange[] = [];
//TODO@rebornix noop setter?
selection?: vscode.NotebookCell;
private _visibleRanges: vscode.NotebookCellRange[] = [];
private _visibleRanges: extHostTypes.NotebookCellRange[] = [];
private _viewColumn?: vscode.ViewColumn;
private _active: boolean = false;
private _visible: boolean = false;
private _kernel?: vscode.NotebookKernel;
private _onDidDispose = new Emitter<void>();
private _onDidReceiveMessage = new Emitter<any>();
readonly onDidDispose: Event<void> = this._onDidDispose.event;
readonly onDidReceiveMessage: vscode.Event<any> = this._onDidReceiveMessage.event;
private _hasDecorationsForKey: { [key: string]: boolean; } = Object.create(null);
private _editor: vscode.NotebookEditor | undefined;
constructor(
readonly id: string,
private readonly _viewType: string,
private readonly _proxy: MainThreadNotebookShape,
private readonly _webComm: vscode.NotebookCommunication,
readonly notebookData: ExtHostNotebookDocument,
) {
super();
this._register(this._webComm.onDidReceiveMessage(e => {
this._onDidReceiveMessage.fire(e);
}));
}
get viewColumn(): vscode.ViewColumn | undefined {
return this._viewColumn;
dispose() {
this._onDidDispose.fire();
this._onDidDispose.dispose();
}
set viewColumn(_value) {
throw readonly('viewColumn');
}
get kernel() {
return this._kernel;
}
set kernel(_kernel: vscode.NotebookKernel | undefined) {
throw readonly('kernel');
get editor(): vscode.NotebookEditor {
if (!this._editor) {
const that = this;
this._editor = {
get document() {
return that.notebookData.notebookDocument;
},
get selection() {
return that._selection;
},
get selections() {
return that._selections;
},
get visibleRanges() {
return that._visibleRanges;
},
revealRange(range, revealType) {
that._proxy.$tryRevealRange(that.id, extHostConverter.NotebookCellRange.from(range), revealType ?? extHostTypes.NotebookEditorRevealType.Default);
},
get viewColumn() {
return that._viewColumn;
},
get onDidDispose() {
return that.onDidDispose;
},
edit(callback) {
const edit = new NotebookEditorCellEditBuilder(this.document.version);
callback(edit);
return that._applyEdit(edit.finalize());
},
get kernel() {
return that._kernel;
},
setDecorations(decorationType, range) {
return that.setDecorations(decorationType, range);
}
};
}
return this._editor;
}
_acceptKernel(kernel?: vscode.NotebookKernel) {
@@ -152,18 +171,16 @@ export class ExtHostNotebookEditor extends Disposable implements vscode.Notebook
this._visible = value;
}
get visibleRanges() {
return this._visibleRanges;
}
set visibleRanges(_range: vscode.NotebookCellRange[]) {
throw readonly('visibleRanges');
}
_acceptVisibleRanges(value: vscode.NotebookCellRange[]): void {
_acceptVisibleRanges(value: extHostTypes.NotebookCellRange[]): void {
this._visibleRanges = value;
}
_acceptSelections(selections: ICellRange[]): void {
const primarySelection = selections[0];
this._selection = primarySelection ? this.notebookData.getCellFromIndex(primarySelection.start)?.cell : undefined;
this._selections = selections.map(val => new extHostTypes.NotebookCellRange(val.start, val.end));
}
get active(): boolean {
return this._active;
}
@@ -176,16 +193,6 @@ export class ExtHostNotebookEditor extends Disposable implements vscode.Notebook
this._active = value;
}
get document(): vscode.NotebookDocument {
return this.notebookData.notebookDocument;
}
edit(callback: (editBuilder: NotebookEditorCellEditBuilder) => void): Thenable<boolean> {
const edit = new NotebookEditorCellEditBuilder(this.document.version);
callback(edit);
return this._applyEdit(edit.finalize());
}
private _applyEdit(editData: INotebookEditData): Promise<boolean> {
// return when there is nothing to do
@@ -208,7 +215,7 @@ export class ExtHostNotebookEditor extends Disposable implements vscode.Notebook
if (prev.editType === CellEditType.Replace && editData.cellEdits[i].editType === CellEditType.Replace) {
const edit = editData.cellEdits[i];
if ((edit.editType !== CellEditType.DocumentMetadata && edit.editType !== CellEditType.Unknown) && prev.index === edit.index) {
if ((edit.editType !== CellEditType.DocumentMetadata) && prev.index === edit.index) {
prev.cells.push(...(editData.cellEdits[i] as ICellReplaceEdit).cells);
prev.count += (editData.cellEdits[i] as ICellReplaceEdit).count;
continue;
@@ -219,7 +226,7 @@ export class ExtHostNotebookEditor extends Disposable implements vscode.Notebook
compressedEditsIndex++;
}
return this._proxy.$tryApplyEdits(this._viewType, this.document.uri, editData.documentVersionId, compressedEdits);
return this._proxy.$tryApplyEdits(this._viewType, this.notebookData.uri, editData.documentVersionId, compressedEdits);
}
setDecorations(decorationType: vscode.NotebookEditorDecorationType, range: vscode.NotebookCellRange): void {
@@ -236,25 +243,8 @@ export class ExtHostNotebookEditor extends Disposable implements vscode.Notebook
return this._proxy.$trySetDecorations(
this.id,
range,
extHostConverter.NotebookCellRange.from(range),
decorationType.key
);
}
revealRange(range: vscode.NotebookCellRange, revealType?: extHostTypes.NotebookEditorRevealType) {
this._proxy.$tryRevealRange(this.id, range, revealType || extHostTypes.NotebookEditorRevealType.Default);
}
async postMessage(message: any): Promise<boolean> {
return this._webComm.postMessage(message);
}
asWebviewUri(localResource: vscode.Uri): vscode.Uri {
return this._webComm.asWebviewUri(localResource);
}
dispose() {
this._onDidDispose.fire();
super.dispose();
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -14,14 +14,12 @@ import { DisposableStore } from 'vs/base/common/lifecycle';
export class ExtHostStatusBarEntry implements vscode.StatusBarItem {
private static ID_GEN = 0;
private static ALLOWED_BACKGROUND_COLORS = (() => {
const map = new Map<string, ThemeColor>();
private static ALLOWED_BACKGROUND_COLORS = new Map<string, ThemeColor>(
[['statusBarItem.errorBackground', new ThemeColor('statusBarItem.errorForeground')]]
);
// https://github.com/microsoft/vscode/issues/110214
map.set('statusBarItem.errorBackground', new ThemeColor('statusBarItem.errorForeground'));
return map;
})();
#proxy: MainThreadStatusBarShape;
#commands: CommandsConverter;
private _id: number;
private _alignment: number;
@@ -43,14 +41,13 @@ export class ExtHostStatusBarEntry implements vscode.StatusBarItem {
};
private _timeoutHandle: any;
private _proxy: MainThreadStatusBarShape;
private _commands: CommandsConverter;
private _accessibilityInformation?: vscode.AccessibilityInformation;
constructor(proxy: MainThreadStatusBarShape, commands: CommandsConverter, id: string, name: string, alignment: ExtHostStatusBarAlignment = ExtHostStatusBarAlignment.Left, priority?: number, accessibilityInformation?: vscode.AccessibilityInformation) {
this.#proxy = proxy;
this.#commands = commands;
this._id = ExtHostStatusBarEntry.ID_GEN++;
this._proxy = proxy;
this._commands = commands;
this._statusId = id;
this._statusName = name;
this._alignment = alignment;
@@ -127,12 +124,12 @@ export class ExtHostStatusBarEntry implements vscode.StatusBarItem {
if (typeof command === 'string') {
this._command = {
fromApi: command,
internal: this._commands.toInternal({ title: '', command }, this._internalCommandRegistration),
internal: this.#commands.toInternal({ title: '', command }, this._internalCommandRegistration),
};
} else if (command) {
this._command = {
fromApi: command,
internal: this._commands.toInternal(command, this._internalCommandRegistration),
internal: this.#commands.toInternal(command, this._internalCommandRegistration),
};
} else {
this._command = undefined;
@@ -153,7 +150,7 @@ export class ExtHostStatusBarEntry implements vscode.StatusBarItem {
public hide(): void {
clearTimeout(this._timeoutHandle);
this._visible = false;
this._proxy.$dispose(this.id);
this.#proxy.$dispose(this.id);
}
private update(): void {
@@ -174,7 +171,7 @@ export class ExtHostStatusBarEntry implements vscode.StatusBarItem {
}
// Set to status bar
this._proxy.$setEntry(this.id, this._statusId, this._statusName, this._text, this._tooltip, this._command?.internal, color,
this.#proxy.$setEntry(this.id, this._statusId, this._statusName, this._text, this._tooltip, this._command?.internal, color,
this._backgroundColor, this._alignment === ExtHostStatusBarAlignment.Left ? MainThreadStatusBarAlignment.LEFT : MainThreadStatusBarAlignment.RIGHT,
this._priority, this._accessibilityInformation);
}, 0);

View File

@@ -48,7 +48,7 @@ export class ExtensionStoragePaths implements IExtensionStoragePaths {
const storageUri = URI.joinPath(this._environment.workspaceStorageHome, storageName);
try {
await this._extHostFileSystem.stat(storageUri);
await this._extHostFileSystem.value.stat(storageUri);
this._logService.trace('[ExtHostStorage] storage dir already exists', storageUri);
return storageUri;
} catch {
@@ -57,8 +57,8 @@ export class ExtensionStoragePaths implements IExtensionStoragePaths {
try {
this._logService.trace('[ExtHostStorage] creating dir and metadata-file', storageUri);
await this._extHostFileSystem.createDirectory(storageUri);
await this._extHostFileSystem.writeFile(
await this._extHostFileSystem.value.createDirectory(storageUri);
await this._extHostFileSystem.value.writeFile(
URI.joinPath(storageUri, 'meta.json'),
new TextEncoder().encode(JSON.stringify({
id: this._workspace.id,

View File

@@ -341,7 +341,10 @@ export namespace TaskFilterDTO {
class TaskExecutionImpl implements vscode.TaskExecution {
constructor(private readonly _tasks: ExtHostTaskBase, readonly _id: string, private readonly _task: vscode.Task) {
readonly #tasks: ExtHostTaskBase;
constructor(tasks: ExtHostTaskBase, readonly _id: string, private readonly _task: vscode.Task) {
this.#tasks = tasks;
}
public get task(): vscode.Task {
@@ -349,7 +352,7 @@ class TaskExecutionImpl implements vscode.TaskExecution {
}
public terminate(): void {
this._tasks.terminateTask(this);
this.#tasks.terminateTask(this);
}
public fireDidStartProcess(value: tasks.TaskProcessStartedDTO): void {

View File

@@ -9,18 +9,18 @@ import { ExtHostTerminalServiceShape, MainContext, MainThreadTerminalServiceShap
import { ExtHostConfigProvider } from 'vs/workbench/api/common/extHostConfiguration';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { URI, UriComponents } from 'vs/base/common/uri';
import { ITerminalChildProcess, ITerminalLaunchError, ITerminalDimensionsOverride } from 'vs/workbench/contrib/terminal/common/terminal';
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
import { TerminalDataBufferer } from 'vs/workbench/contrib/terminal/common/terminalDataBuffering';
import { IDisposable, DisposableStore, Disposable } from 'vs/base/common/lifecycle';
import { Disposable as VSCodeDisposable, EnvironmentVariableMutatorType } from './extHostTypes';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { localize } from 'vs/nls';
import { NotSupportedError } from 'vs/base/common/errors';
import { serializeEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariableShared';
import { CancellationTokenSource } from 'vs/base/common/cancellation';
import { generateUuid } from 'vs/base/common/uuid';
import { ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { ITerminalChildProcess, ITerminalDimensionsOverride, ITerminalLaunchError } from 'vs/platform/terminal/common/terminal';
import { TerminalDataBufferer } from 'vs/platform/terminal/common/terminalDataBuffering';
export interface IExtHostTerminalService extends ExtHostTerminalServiceShape, IDisposable {
@@ -47,7 +47,7 @@ export interface IExtHostTerminalService extends ExtHostTerminalServiceShape, ID
export const IExtHostTerminalService = createDecorator<IExtHostTerminalService>('IExtHostTerminalService');
export class ExtHostTerminal implements vscode.Terminal {
export class ExtHostTerminal {
private _disposed: boolean = false;
private _pidPromise: Promise<number | undefined>;
private _cols: number | undefined;
@@ -57,6 +57,8 @@ export class ExtHostTerminal implements vscode.Terminal {
public isOpen: boolean = false;
readonly value: vscode.Terminal;
constructor(
private _proxy: MainThreadTerminalServiceShape,
public _id: TerminalIdentifier,
@@ -65,6 +67,49 @@ export class ExtHostTerminal implements vscode.Terminal {
) {
this._creationOptions = Object.freeze(this._creationOptions);
this._pidPromise = new Promise<number | undefined>(c => this._pidPromiseComplete = c);
const that = this;
this.value = {
get name(): string {
return that._name || '';
},
get processId(): Promise<number | undefined> {
return that._pidPromise;
},
get creationOptions(): Readonly<vscode.TerminalOptions | vscode.ExtensionTerminalOptions> {
return that._creationOptions;
},
get exitStatus(): vscode.TerminalExitStatus | undefined {
return that._exitStatus;
},
sendText(text: string, addNewLine: boolean = true): void {
that._checkDisposed();
that._proxy.$sendText(that._id, text, addNewLine);
},
show(preserveFocus: boolean): void {
that._checkDisposed();
that._proxy.$show(that._id, preserveFocus);
},
hide(): void {
that._checkDisposed();
that._proxy.$hide(that._id);
},
dispose(): void {
if (!that._disposed) {
that._disposed = true;
that._proxy.$dispose(that._id);
}
},
get dimensions(): vscode.TerminalDimensions | undefined {
if (that._cols === undefined || that._rows === undefined) {
return undefined;
}
return {
columns: that._cols,
rows: that._rows
};
}
};
}
public async create(
@@ -75,12 +120,13 @@ export class ExtHostTerminal implements vscode.Terminal {
waitOnExit?: boolean,
strictEnv?: boolean,
hideFromUser?: boolean,
isFeatureTerminal?: boolean
isFeatureTerminal?: boolean,
isExtensionOwnedTerminal?: boolean
): Promise<void> {
if (typeof this._id !== 'string') {
throw new Error('Terminal has already been created');
}
await this._proxy.$createTerminal(this._id, { name: this._name, shellPath, shellArgs, cwd, env, waitOnExit, strictEnv, hideFromUser, isFeatureTerminal });
await this._proxy.$createTerminal(this._id, { name: this._name, shellPath, shellArgs, cwd, env, waitOnExit, strictEnv, hideFromUser, isFeatureTerminal, isExtensionOwnedTerminal });
}
public async createExtensionTerminal(): Promise<number> {
@@ -95,41 +141,16 @@ export class ExtHostTerminal implements vscode.Terminal {
return this._id;
}
public dispose(): void {
if (!this._disposed) {
this._disposed = true;
this._proxy.$dispose(this._id);
}
}
private _checkDisposed() {
if (this._disposed) {
throw new Error('Terminal has already been disposed');
}
}
public get name(): string {
return this._name || '';
}
public set name(name: string) {
this._name = name;
}
public get exitStatus(): vscode.TerminalExitStatus | undefined {
return this._exitStatus;
}
public get dimensions(): vscode.TerminalDimensions | undefined {
if (this._cols === undefined || this._rows === undefined) {
return undefined;
}
return {
columns: this._cols,
rows: this._rows
};
}
public setExitCode(code: number | undefined) {
this._exitStatus = Object.freeze({ code });
}
@@ -147,29 +168,6 @@ export class ExtHostTerminal implements vscode.Terminal {
return true;
}
public get processId(): Promise<number | undefined> {
return this._pidPromise;
}
public get creationOptions(): Readonly<vscode.TerminalOptions | vscode.ExtensionTerminalOptions> {
return this._creationOptions;
}
public sendText(text: string, addNewLine: boolean = true): void {
this._checkDisposed();
this._proxy.$sendText(this._id, text, addNewLine);
}
public show(preserveFocus: boolean): void {
this._checkDisposed();
this._proxy.$show(this._id, preserveFocus);
}
public hide(): void {
this._checkDisposed();
this._proxy.$hide(this._id);
}
public _setProcessId(processId: number | undefined): void {
// The event may fire 2 times when the panel is restored
if (this._pidPromiseComplete) {
@@ -187,6 +185,9 @@ export class ExtHostTerminal implements vscode.Terminal {
}
export class ExtHostPseudoterminal implements ITerminalChildProcess {
readonly id = 0;
readonly shouldPersist = false;
private readonly _onProcessData = new Emitter<string>();
public readonly onProcessData: Event<string> = this._onProcessData.event;
private readonly _onProcessExit = new Emitter<number | undefined>();
@@ -284,8 +285,8 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I
private readonly _terminalLinkCache: Map<number, Map<number, ICachedLinkEntry>> = new Map();
private readonly _terminalLinkCancellationSource: Map<number, CancellationTokenSource> = new Map();
public get activeTerminal(): ExtHostTerminal | undefined { return this._activeTerminal; }
public get terminals(): ExtHostTerminal[] { return this._terminals; }
public get activeTerminal(): vscode.Terminal | undefined { return this._activeTerminal?.value; }
public get terminals(): vscode.Terminal[] { return this._terminals.map(term => term.value); }
protected readonly _onDidCloseTerminal: Emitter<vscode.Terminal> = new Emitter<vscode.Terminal>();
public get onDidCloseTerminal(): Event<vscode.Terminal> { return this._onDidCloseTerminal && this._onDidCloseTerminal.event; }
@@ -336,7 +337,7 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I
this._terminalProcessDisposables[id] = disposable;
});
this._terminals.push(terminal);
return terminal;
return terminal.value;
}
public attachPtyToTerminal(id: number, pty: vscode.Pseudoterminal): void {
@@ -362,7 +363,7 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I
if (terminal) {
this._activeTerminal = terminal;
if (original !== this._activeTerminal) {
this._onDidChangeActiveTerminal.fire(this._activeTerminal);
this._onDidChangeActiveTerminal.fire(this._activeTerminal.value);
}
}
}
@@ -370,7 +371,7 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I
public async $acceptTerminalProcessData(id: number, data: string): Promise<void> {
const terminal = this._getTerminalById(id);
if (terminal) {
this._onDidWriteTerminalData.fire({ terminal, data });
this._onDidWriteTerminalData.fire({ terminal: terminal.value, data });
}
}
@@ -379,8 +380,8 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I
if (terminal) {
if (terminal.setDimensions(cols, rows)) {
this._onDidChangeTerminalDimensions.fire({
terminal: terminal,
dimensions: terminal.dimensions as vscode.TerminalDimensions
terminal: terminal.value,
dimensions: terminal.value.dimensions as vscode.TerminalDimensions
});
}
}
@@ -400,11 +401,11 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I
}
public async $acceptTerminalClosed(id: number, exitCode: number | undefined): Promise<void> {
const index = this._getTerminalObjectIndexById(this.terminals, id);
const index = this._getTerminalObjectIndexById(this._terminals, id);
if (index !== null) {
const terminal = this._terminals.splice(index, 1)[0];
terminal.setExitCode(exitCode);
this._onDidCloseTerminal.fire(terminal);
this._onDidCloseTerminal.fire(terminal.value);
}
}
@@ -414,9 +415,9 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I
const index = this._getTerminalObjectIndexById(this._terminals, extHostTerminalId);
if (index !== null) {
// The terminal has already been created (via createTerminal*), only fire the event
this.terminals[index]._id = id;
this._terminals[index]._id = id;
this._onDidOpenTerminal.fire(this.terminals[index]);
this.terminals[index].isOpen = true;
this._terminals[index].isOpen = true;
return;
}
}
@@ -431,7 +432,7 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I
};
const terminal = new ExtHostTerminal(this._proxy, id, creationOptions, name);
this._terminals.push(terminal);
this._onDidOpenTerminal.fire(terminal);
this._onDidOpenTerminal.fire(terminal.value);
terminal.isOpen = true;
}
@@ -455,7 +456,7 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I
await new Promise<void>(r => {
// Ensure open is called after onDidOpenTerminal
const listener = this.onDidOpenTerminal(async e => {
if (e === terminal) {
if (e === terminal.value) {
listener.dispose();
r();
}
@@ -564,7 +565,7 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I
this._terminalLinkCancellationSource.set(terminalId, cancellationSource);
const result: ITerminalLinkDto[] = [];
const context: vscode.TerminalLinkContext = { terminal, line };
const context: vscode.TerminalLinkContext = { terminal: terminal.value, line };
const promises: vscode.ProviderResult<{ provider: vscode.TerminalLinkProvider, links: vscode.TerminalLink[] }>[] = [];
for (const provider of this._linkProviders) {

View File

@@ -9,6 +9,7 @@ import { CancellationToken } from 'vs/base/common/cancellation';
import { Emitter } from 'vs/base/common/event';
import { once } from 'vs/base/common/functional';
import { DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
import { deepFreeze } from 'vs/base/common/objects';
import { isDefined } from 'vs/base/common/types';
import { URI, UriComponents } from 'vs/base/common/uri';
import { generateUuid } from 'vs/base/common/uuid';
@@ -16,11 +17,11 @@ import { ExtHostTestingResource, ExtHostTestingShape, MainContext, MainThreadTes
import { ExtHostDocumentData } from 'vs/workbench/api/common/extHostDocumentData';
import { IExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
import { TestItem } from 'vs/workbench/api/common/extHostTypeConverters';
import { TestItem, TestResults, TestState } from 'vs/workbench/api/common/extHostTypeConverters';
import { Disposable } from 'vs/workbench/api/common/extHostTypes';
import { IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
import { OwnedTestCollection, SingleUseTestCollection } from 'vs/workbench/contrib/testing/common/ownedTestCollection';
import { AbstractIncrementalTestCollection, EMPTY_TEST_RESULT, IncrementalChangeCollector, IncrementalTestCollectionItem, InternalTestItem, InternalTestItemWithChildren, InternalTestResults, RunTestForProviderRequest, RunTestsResult, TestDiffOpType, TestIdWithProvider, TestsDiff } from 'vs/workbench/contrib/testing/common/testCollection';
import { OwnedTestCollection, SingleUseTestCollection, TestPosition } from 'vs/workbench/contrib/testing/common/ownedTestCollection';
import { AbstractIncrementalTestCollection, IncrementalChangeCollector, IncrementalTestCollectionItem, InternalTestItem, ISerializedTestResults, RunTestForProviderRequest, TestDiffOpType, TestIdWithProvider, TestsDiff } from 'vs/workbench/contrib/testing/common/testCollection';
import type * as vscode from 'vscode';
const getTestSubscriptionKey = (resource: ExtHostTestingResource, uri: URI) => `${resource}:${uri.toString()}`;
@@ -39,8 +40,8 @@ export class ExtHostTesting implements ExtHostTestingShape {
private workspaceObservers: WorkspaceFolderTestObserverFactory;
private textDocumentObservers: TextDocumentTestObserverFactory;
public onLastResultsChanged = this.resultsChangedEmitter.event;
public lastResults?: vscode.TestResults;
public onResultsChanged = this.resultsChangedEmitter.event;
public results: ReadonlyArray<vscode.TestResults> = [];
constructor(@IExtHostRpcService rpc: IExtHostRpcService, @IExtHostDocumentsAndEditors private readonly documents: IExtHostDocumentsAndEditors, @IExtHostWorkspace private readonly workspace: IExtHostWorkspace) {
this.proxy = rpc.getProxy(MainContext.MainThreadTesting);
@@ -88,30 +89,39 @@ export class ExtHostTesting implements ExtHostTestingShape {
* Implements vscode.test.runTests
*/
public async runTests(req: vscode.TestRunOptions<vscode.TestItem>, token = CancellationToken.None) {
await this.proxy.$runTests({
tests: req.tests
// Find workspace items first, then owned tests, then document tests.
// If a test instance exists in both the workspace and document, prefer
// the workspace because it's less ephemeral.
.map(test => this.workspaceObservers.getMirroredTestDataByReference(test)
?? mapFind(this.testSubscriptions.values(), c => c.collection.getTestByReference(test))
?? this.textDocumentObservers.getMirroredTestDataByReference(test))
const testListToProviders = (tests: ReadonlyArray<vscode.TestItem>) =>
tests
.map(this.getInternalTestForReference, this)
.filter(isDefined)
.map(item => ({ providerId: item.providerId, testId: item.id })),
.map(t => ({ providerId: t.providerId, testId: t.item.extId }));
await this.proxy.$runTests({
exclude: req.exclude ? testListToProviders(req.exclude).map(t => t.testId) : undefined,
tests: testListToProviders(req.tests),
debug: req.debug
}, token);
}
/**
* Implements vscode.test.publishTestResults
*/
public publishExtensionProvidedResults(results: vscode.TestResults, persist: boolean): void {
this.proxy.$publishExtensionProvidedResults(TestResults.from(generateUuid(), results), persist);
}
/**
* Updates test results shown to extensions.
* @override
*/
public $publishTestResults(results: InternalTestResults): void {
const convert = (item: InternalTestItemWithChildren): vscode.RequiredTestItem =>
({ ...TestItem.toShallow(item.item), children: item.children.map(convert) });
public $publishTestResults(results: ISerializedTestResults[]): void {
this.results = Object.freeze(
results
.map(r => deepFreeze(TestResults.to(r)))
.concat(this.results)
.sort((a, b) => b.completedAt - a.completedAt)
.slice(0, 32),
);
this.lastResults = { tests: results.tests.map(convert) };
this.resultsChangedEmitter.fire();
}
@@ -172,6 +182,14 @@ export class ExtHostTesting implements ExtHostTestingShape {
collection.addRoot(hierarchy.root, id);
Promise.resolve(hierarchy.discoveredInitialTests).then(() => collection.pushDiff([TestDiffOpType.DeltaDiscoverComplete, -1]));
hierarchy.onDidChangeTest(e => collection.onItemChange(e, id));
hierarchy.onDidInvalidateTest?.(e => {
const internal = collection.getTestByReference(e);
if (!internal) {
console.warn(`Received a TestProvider.onDidInvalidateTest for a test that does not currently exist.`);
} else {
this.proxy.$retireTest(internal.item.extId);
}
});
} catch (e) {
console.error(e);
}
@@ -219,27 +237,49 @@ export class ExtHostTesting implements ExtHostTestingShape {
* providers to be run.
* @override
*/
public async $runTestsForProvider(req: RunTestForProviderRequest, cancellation: CancellationToken): Promise<RunTestsResult> {
public async $runTestsForProvider(req: RunTestForProviderRequest, cancellation: CancellationToken): Promise<void> {
const provider = this.providers.get(req.providerId);
if (!provider || !provider.runTests) {
return EMPTY_TEST_RESULT;
return;
}
const tests = req.ids.map(id => this.ownedTests.getTestById(id)?.actual)
const includeTests = req.ids.map(id => this.ownedTests.getTestById(id)?.[1]).filter(isDefined);
const excludeTests = req.excludeExtIds
.map(id => this.ownedTests.getTestById(id))
.filter(isDefined)
// Only send the actual TestItem's to the user to run.
.map(t => t instanceof TestItemFilteredWrapper ? t.actual : t);
if (!tests.length) {
return EMPTY_TEST_RESULT;
.filter(([tree, exclude]) =>
includeTests.some(include => tree.comparePositions(include, exclude) === TestPosition.IsChild),
);
if (!includeTests.length) {
return;
}
try {
await provider.runTests({ tests, debug: req.debug }, cancellation);
await provider.runTests({
setState: (test, state) => {
// for test providers that don't support excluding natively,
// make sure not to report excluded result otherwise summaries will be off.
for (const [tree, exclude] of excludeTests) {
const e = tree.comparePositions(exclude, test.id);
if (e === TestPosition.IsChild || e === TestPosition.IsSame) {
return;
}
}
this.flushCollectionDiffs();
this.proxy.$updateTestStateInRun(req.runId, test.id, TestState.from(state));
},
tests: includeTests.map(t => TestItemFilteredWrapper.unwrap(t.actual)),
exclude: excludeTests.map(([, t]) => TestItemFilteredWrapper.unwrap(t.actual)),
debug: req.debug,
}, cancellation);
for (const { collection } of this.testSubscriptions.values()) {
collection.flushDiff(); // ensure all states are updated
}
return EMPTY_TEST_RESULT;
return;
} catch (e) {
console.error(e); // so it appears to attached debuggers
throw e;
@@ -252,10 +292,32 @@ export class ExtHostTesting implements ExtHostTestingShape {
return Promise.resolve(undefined);
}
const { actual, previousChildren, previousEquals, ...item } = owned;
const { actual, previousChildren, previousEquals, ...item } = owned[1];
return Promise.resolve(item);
}
/**
* Flushes diff information for all collections to ensure state in the
* main thread is updated.
*/
private flushCollectionDiffs() {
for (const { collection } of this.testSubscriptions.values()) {
collection.flushDiff();
}
}
/**
* Gets the internal test item associated with the reference from the extension.
*/
private getInternalTestForReference(test: vscode.TestItem) {
// Find workspace items first, then owned tests, then document tests.
// If a test instance exists in both the workspace and document, prefer
// the workspace because it's less ephemeral.
return this.workspaceObservers.getMirroredTestDataByReference(test)
?? mapFind(this.testSubscriptions.values(), c => c.collection.getTestByReference(test))
?? this.textDocumentObservers.getMirroredTestDataByReference(test);
}
private createDefaultDocumentTestHierarchy(provider: vscode.TestProvider, document: vscode.TextDocument, folder: vscode.WorkspaceFolder | undefined): vscode.TestHierarchy<vscode.TestItem> | undefined {
if (!folder) {
return;
@@ -266,6 +328,14 @@ export class ExtHostTesting implements ExtHostTestingShape {
return;
}
const onDidInvalidateTest = new Emitter<vscode.TestItem>();
workspaceHierarchy.onDidInvalidateTest?.(node => {
const wrapper = TestItemFilteredWrapper.getWrapperForTestItem(node, document);
if (wrapper.hasNodeMatchingFilter) {
onDidInvalidateTest.fire(wrapper);
}
});
const onDidChangeTest = new Emitter<vscode.TestItem>();
workspaceHierarchy.onDidChangeTest(node => {
const wrapper = TestItemFilteredWrapper.getWrapperForTestItem(node, document);
@@ -308,6 +378,8 @@ export class ExtHostTesting implements ExtHostTestingShape {
onDidChangeTest.dispose();
TestItemFilteredWrapper.removeFilter(document);
},
discoveredInitialTests: workspaceHierarchy.discoveredInitialTests,
onDidInvalidateTest: onDidInvalidateTest.event,
onDidChangeTest: onDidChangeTest.event
};
}
@@ -341,6 +413,14 @@ export class TestItemFilteredWrapper implements vscode.TestItem {
return w;
}
public static unwrap(item: vscode.TestItem) {
return item instanceof TestItemFilteredWrapper ? item.actual : item;
}
public get id() {
return this.actual.id;
}
public get label() {
return this.actual.label;
}
@@ -361,10 +441,6 @@ export class TestItemFilteredWrapper implements vscode.TestItem {
return this.actual.runnable;
}
public get state() {
return this.actual.state;
}
public get children() {
// We only want children that match the filter.
return this.getWrappedChildren().filter(child => child.hasNodeMatchingFilter);
@@ -462,7 +538,7 @@ class MirroredChangeCollector extends IncrementalChangeCollector<MirroredCollect
this.updated.delete(node);
if (node.parent && this.alreadyRemoved.has(node.parent)) {
this.alreadyRemoved.add(node.id);
this.alreadyRemoved.add(node.item.extId);
return;
}
@@ -602,8 +678,7 @@ export class MirroredTestCollection extends AbstractIncrementalTestCollection<Mi
* If the test item is a mirrored test item, returns its underlying ID.
*/
public getMirroredTestDataByReference(item: vscode.TestItem) {
const id = getMirroredItemId(item);
return id ? this.items.get(id) : undefined;
return this.items.get(item.id);
}
/**
@@ -632,12 +707,6 @@ export class MirroredTestCollection extends AbstractIncrementalTestCollection<Mi
}
}
const getMirroredItemId = (item: vscode.TestItem) => {
return (item as any)[MirroredItemId] as string | undefined;
};
const MirroredItemId = Symbol('MirroredItemId');
class TestItemFromMirror implements vscode.RequiredTestItem {
readonly #internal: MirroredCollectionTestItem;
readonly #collection: MirroredTestCollection;
@@ -645,7 +714,6 @@ class TestItemFromMirror implements vscode.RequiredTestItem {
public get id() { return this.#internal.revived.id!; }
public get label() { return this.#internal.revived.label; }
public get description() { return this.#internal.revived.description; }
public get state() { return this.#internal.revived.state; }
public get location() { return this.#internal.revived.location; }
public get runnable() { return this.#internal.revived.runnable ?? true; }
public get debuggable() { return this.#internal.revived.debuggable ?? false; }
@@ -653,8 +721,6 @@ class TestItemFromMirror implements vscode.RequiredTestItem {
return this.#collection.getAllAsTestItem(this.#internal.children);
}
get [MirroredItemId]() { return this.#internal.id; }
constructor(internal: MirroredCollectionTestItem, collection: MirroredTestCollection) {
this.#internal = internal;
this.#collection = collection;
@@ -665,14 +731,13 @@ class TestItemFromMirror implements vscode.RequiredTestItem {
id: this.id,
label: this.label,
description: this.description,
state: this.state,
location: this.location,
runnable: this.runnable,
debuggable: this.debuggable,
children: this.children.map(c => (c as TestItemFromMirror).toJSON()),
providerId: this.#internal.providerId,
testId: this.#internal.id,
testId: this.id,
};
return serialized;

View File

@@ -10,28 +10,29 @@ import { TextEditorCursorStyle } from 'vs/editor/common/config/editorOptions';
import { IRange } from 'vs/editor/common/core/range';
import { ISingleEditOperation } from 'vs/editor/common/model';
import { IResolvedTextEditorConfiguration, ITextEditorConfigurationUpdate, MainThreadTextEditorsShape } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostDocumentData } from 'vs/workbench/api/common/extHostDocumentData';
import * as TypeConverters from 'vs/workbench/api/common/extHostTypeConverters';
import { EndOfLine, Position, Range, Selection, SnippetString, TextEditorLineNumbersStyle, TextEditorRevealType } from 'vs/workbench/api/common/extHostTypes';
import type * as vscode from 'vscode';
import { ILogService } from 'vs/platform/log/common/log';
import { Lazy } from 'vs/base/common/lazy';
export class TextEditorDecorationType implements vscode.TextEditorDecorationType {
export class TextEditorDecorationType {
private static readonly _Keys = new IdGenerator('TextEditorDecorationType');
private _proxy: MainThreadTextEditorsShape;
public key: string;
readonly value: vscode.TextEditorDecorationType;
constructor(proxy: MainThreadTextEditorsShape, options: vscode.DecorationRenderOptions) {
this.key = TextEditorDecorationType._Keys.nextId();
this._proxy = proxy;
this._proxy.$registerTextEditorDecorationType(this.key, TypeConverters.DecorationRenderOptions.from(options));
const key = TextEditorDecorationType._Keys.nextId();
proxy.$registerTextEditorDecorationType(key, TypeConverters.DecorationRenderOptions.from(options));
this.value = Object.freeze({
key,
dispose() {
proxy.$removeTextEditorDecorationType(key);
}
});
}
public dispose(): void {
this._proxy.$removeTextEditorDecorationType(this.key);
}
}
export interface ITextEditOperation {
@@ -134,36 +135,63 @@ export class TextEditorEdit {
}
}
export class ExtHostTextEditorOptions implements vscode.TextEditorOptions {
export class ExtHostTextEditorOptions {
private _proxy: MainThreadTextEditorsShape;
private _id: string;
private _logService: ILogService;
private _tabSize!: number;
private _indentSize!: number;
private _insertSpaces!: boolean;
private _cursorStyle!: TextEditorCursorStyle;
private _lineNumbers!: TextEditorLineNumbersStyle;
readonly value: vscode.TextEditorOptions;
constructor(proxy: MainThreadTextEditorsShape, id: string, source: IResolvedTextEditorConfiguration, logService: ILogService) {
this._proxy = proxy;
this._id = id;
this._accept(source);
this._logService = logService;
const that = this;
this.value = {
get tabSize(): number | string {
return that._tabSize;
},
set tabSize(value: number | string) {
that._setTabSize(value);
},
get insertSpaces(): boolean | string {
return that._insertSpaces;
},
set insertSpaces(value: boolean | string) {
that._setInsertSpaces(value);
},
get cursorStyle(): TextEditorCursorStyle {
return that._cursorStyle;
},
set cursorStyle(value: TextEditorCursorStyle) {
that._setCursorStyle(value);
},
get lineNumbers(): TextEditorLineNumbersStyle {
return that._lineNumbers;
},
set lineNumbers(value: TextEditorLineNumbersStyle) {
that._setLineNumbers(value);
}
};
}
public _accept(source: IResolvedTextEditorConfiguration): void {
this._tabSize = source.tabSize;
this._indentSize = source.indentSize;
this._insertSpaces = source.insertSpaces;
this._cursorStyle = source.cursorStyle;
this._lineNumbers = TypeConverters.TextEditorLineNumbersStyle.to(source.lineNumbers);
}
public get tabSize(): number | string {
return this._tabSize;
}
// --- internal: tabSize
private _validateTabSize(value: number | string): number | 'auto' | null {
if (value === 'auto') {
@@ -183,7 +211,7 @@ export class ExtHostTextEditorOptions implements vscode.TextEditorOptions {
return null;
}
public set tabSize(value: number | string) {
private _setTabSize(value: number | string) {
const tabSize = this._validateTabSize(value);
if (tabSize === null) {
// ignore invalid call
@@ -202,50 +230,7 @@ export class ExtHostTextEditorOptions implements vscode.TextEditorOptions {
}));
}
public get indentSize(): number | string {
return this._indentSize;
}
private _validateIndentSize(value: number | string): number | 'tabSize' | null {
if (value === 'tabSize') {
return 'tabSize';
}
if (typeof value === 'number') {
const r = Math.floor(value);
return (r > 0 ? r : null);
}
if (typeof value === 'string') {
const r = parseInt(value, 10);
if (isNaN(r)) {
return null;
}
return (r > 0 ? r : null);
}
return null;
}
public set indentSize(value: number | string) {
const indentSize = this._validateIndentSize(value);
if (indentSize === null) {
// ignore invalid call
return;
}
if (typeof indentSize === 'number') {
if (this._indentSize === indentSize) {
// nothing to do
return;
}
// reflect the new indentSize value immediately
this._indentSize = indentSize;
}
this._warnOnError(this._proxy.$trySetOptions(this._id, {
indentSize: indentSize
}));
}
public get insertSpaces(): boolean | string {
return this._insertSpaces;
}
// --- internal: insert spaces
private _validateInsertSpaces(value: boolean | string): boolean | 'auto' {
if (value === 'auto') {
@@ -254,7 +239,7 @@ export class ExtHostTextEditorOptions implements vscode.TextEditorOptions {
return (value === 'false' ? false : Boolean(value));
}
public set insertSpaces(value: boolean | string) {
private _setInsertSpaces(value: boolean | string) {
const insertSpaces = this._validateInsertSpaces(value);
if (typeof insertSpaces === 'boolean') {
if (this._insertSpaces === insertSpaces) {
@@ -269,11 +254,9 @@ export class ExtHostTextEditorOptions implements vscode.TextEditorOptions {
}));
}
public get cursorStyle(): TextEditorCursorStyle {
return this._cursorStyle;
}
// --- internal: cursor style
public set cursorStyle(value: TextEditorCursorStyle) {
private _setCursorStyle(value: TextEditorCursorStyle) {
if (this._cursorStyle === value) {
// nothing to do
return;
@@ -284,11 +267,9 @@ export class ExtHostTextEditorOptions implements vscode.TextEditorOptions {
}));
}
public get lineNumbers(): TextEditorLineNumbersStyle {
return this._lineNumbers;
}
// --- internal: line number
public set lineNumbers(value: TextEditorLineNumbersStyle) {
private _setLineNumbers(value: TextEditorLineNumbersStyle) {
if (this._lineNumbers === value) {
// nothing to do
return;
@@ -368,31 +349,170 @@ export class ExtHostTextEditorOptions implements vscode.TextEditorOptions {
}
}
export class ExtHostTextEditor implements vscode.TextEditor {
private readonly _documentData: ExtHostDocumentData;
export class ExtHostTextEditor {
private _selections: Selection[];
private _options: ExtHostTextEditorOptions;
private _visibleRanges: Range[];
private _viewColumn: vscode.ViewColumn | undefined;
private _disposed: boolean = false;
private _hasDecorationsForKey: { [key: string]: boolean; };
private _hasDecorationsForKey = new Set<string>();
readonly value: vscode.TextEditor;
constructor(
readonly id: string,
private readonly _proxy: MainThreadTextEditorsShape,
private readonly _logService: ILogService,
document: ExtHostDocumentData,
document: Lazy<vscode.TextDocument>,
selections: Selection[], options: IResolvedTextEditorConfiguration,
visibleRanges: Range[], viewColumn: vscode.ViewColumn | undefined
) {
this._documentData = document;
this._selections = selections;
this._options = new ExtHostTextEditorOptions(this._proxy, this.id, options, _logService);
this._visibleRanges = visibleRanges;
this._viewColumn = viewColumn;
this._hasDecorationsForKey = Object.create(null);
const that = this;
this.value = Object.freeze({
get document(): vscode.TextDocument {
return document.getValue();
},
set document(_value) {
throw readonly('document');
},
// --- selection
get selection(): Selection {
return that._selections && that._selections[0];
},
set selection(value: Selection) {
if (!(value instanceof Selection)) {
throw illegalArgument('selection');
}
that._selections = [value];
that._trySetSelection();
},
get selections(): Selection[] {
return that._selections;
},
set selections(value: Selection[]) {
if (!Array.isArray(value) || value.some(a => !(a instanceof Selection))) {
throw illegalArgument('selections');
}
that._selections = value;
that._trySetSelection();
},
// --- visible ranges
get visibleRanges(): Range[] {
return that._visibleRanges;
},
set visibleRanges(_value: Range[]) {
throw readonly('visibleRanges');
},
// --- options
get options(): vscode.TextEditorOptions {
return that._options.value;
},
set options(value: vscode.TextEditorOptions) {
if (!that._disposed) {
that._options.assign(value);
}
},
// --- view column
get viewColumn(): vscode.ViewColumn | undefined {
return that._viewColumn;
},
set viewColumn(_value) {
throw readonly('viewColumn');
},
// --- edit
edit(callback: (edit: TextEditorEdit) => void, options: { undoStopBefore: boolean; undoStopAfter: boolean; } = { undoStopBefore: true, undoStopAfter: true }): Promise<boolean> {
if (that._disposed) {
return Promise.reject(new Error('TextEditor#edit not possible on closed editors'));
}
const edit = new TextEditorEdit(document.getValue(), options);
callback(edit);
return that._applyEdit(edit);
},
// --- snippet edit
insertSnippet(snippet: SnippetString, where?: Position | readonly Position[] | Range | readonly Range[], options: { undoStopBefore: boolean; undoStopAfter: boolean; } = { undoStopBefore: true, undoStopAfter: true }): Promise<boolean> {
if (that._disposed) {
return Promise.reject(new Error('TextEditor#insertSnippet not possible on closed editors'));
}
let ranges: IRange[];
if (!where || (Array.isArray(where) && where.length === 0)) {
ranges = that._selections.map(range => TypeConverters.Range.from(range));
} else if (where instanceof Position) {
const { lineNumber, column } = TypeConverters.Position.from(where);
ranges = [{ startLineNumber: lineNumber, startColumn: column, endLineNumber: lineNumber, endColumn: column }];
} else if (where instanceof Range) {
ranges = [TypeConverters.Range.from(where)];
} else {
ranges = [];
for (const posOrRange of where) {
if (posOrRange instanceof Range) {
ranges.push(TypeConverters.Range.from(posOrRange));
} else {
const { lineNumber, column } = TypeConverters.Position.from(posOrRange);
ranges.push({ startLineNumber: lineNumber, startColumn: column, endLineNumber: lineNumber, endColumn: column });
}
}
}
return _proxy.$tryInsertSnippet(id, snippet.value, ranges, options);
},
setDecorations(decorationType: vscode.TextEditorDecorationType, ranges: Range[] | vscode.DecorationOptions[]): void {
const willBeEmpty = (ranges.length === 0);
if (willBeEmpty && !that._hasDecorationsForKey.has(decorationType.key)) {
// avoid no-op call to the renderer
return;
}
if (willBeEmpty) {
that._hasDecorationsForKey.delete(decorationType.key);
} else {
that._hasDecorationsForKey.add(decorationType.key);
}
that._runOnProxy(() => {
if (TypeConverters.isDecorationOptionsArr(ranges)) {
return _proxy.$trySetDecorations(
id,
decorationType.key,
TypeConverters.fromRangeOrRangeWithMessage(ranges)
);
} else {
const _ranges: number[] = new Array<number>(4 * ranges.length);
for (let i = 0, len = ranges.length; i < len; i++) {
const range = ranges[i];
_ranges[4 * i] = range.start.line + 1;
_ranges[4 * i + 1] = range.start.character + 1;
_ranges[4 * i + 2] = range.end.line + 1;
_ranges[4 * i + 3] = range.end.character + 1;
}
return _proxy.$trySetDecorationsFast(
id,
decorationType.key,
_ranges
);
}
});
},
revealRange(range: Range, revealType: vscode.TextEditorRevealType): void {
that._runOnProxy(() => _proxy.$tryRevealRange(
id,
TypeConverters.Range.from(range),
(revealType || TextEditorRevealType.Default)
));
},
show(column: vscode.ViewColumn) {
_proxy.$tryShowEditor(id, TypeConverters.ViewColumn.from(column));
},
hide() {
_proxy.$tryHideEditor(id);
}
});
}
dispose() {
@@ -400,164 +520,32 @@ export class ExtHostTextEditor implements vscode.TextEditor {
this._disposed = true;
}
show(column: vscode.ViewColumn) {
this._proxy.$tryShowEditor(this.id, TypeConverters.ViewColumn.from(column));
}
hide() {
this._proxy.$tryHideEditor(this.id);
}
// ---- the document
get document(): vscode.TextDocument {
return this._documentData.document;
}
set document(value) {
throw readonly('document');
}
// ---- options
get options(): vscode.TextEditorOptions {
return this._options;
}
set options(value: vscode.TextEditorOptions) {
if (!this._disposed) {
this._options.assign(value);
}
}
// --- incoming: extension host MUST accept what the renderer says
_acceptOptions(options: IResolvedTextEditorConfiguration): void {
ok(!this._disposed);
this._options._accept(options);
}
// ---- visible ranges
get visibleRanges(): Range[] {
return this._visibleRanges;
}
set visibleRanges(value: Range[]) {
throw readonly('visibleRanges');
}
_acceptVisibleRanges(value: Range[]): void {
ok(!this._disposed);
this._visibleRanges = value;
}
// ---- view column
get viewColumn(): vscode.ViewColumn | undefined {
return this._viewColumn;
}
set viewColumn(value) {
throw readonly('viewColumn');
}
_acceptViewColumn(value: vscode.ViewColumn) {
ok(!this._disposed);
this._viewColumn = value;
}
// ---- selections
get selection(): Selection {
return this._selections && this._selections[0];
}
set selection(value: Selection) {
if (!(value instanceof Selection)) {
throw illegalArgument('selection');
}
this._selections = [value];
this._trySetSelection();
}
get selections(): Selection[] {
return this._selections;
}
set selections(value: Selection[]) {
if (!Array.isArray(value) || value.some(a => !(a instanceof Selection))) {
throw illegalArgument('selections');
}
this._selections = value;
this._trySetSelection();
}
setDecorations(decorationType: vscode.TextEditorDecorationType, ranges: Range[] | vscode.DecorationOptions[]): void {
const willBeEmpty = (ranges.length === 0);
if (willBeEmpty && !this._hasDecorationsForKey[decorationType.key]) {
// avoid no-op call to the renderer
return;
}
if (willBeEmpty) {
delete this._hasDecorationsForKey[decorationType.key];
} else {
this._hasDecorationsForKey[decorationType.key] = true;
}
this._runOnProxy(
() => {
if (TypeConverters.isDecorationOptionsArr(ranges)) {
return this._proxy.$trySetDecorations(
this.id,
decorationType.key,
TypeConverters.fromRangeOrRangeWithMessage(ranges)
);
} else {
const _ranges: number[] = new Array<number>(4 * ranges.length);
for (let i = 0, len = ranges.length; i < len; i++) {
const range = ranges[i];
_ranges[4 * i] = range.start.line + 1;
_ranges[4 * i + 1] = range.start.character + 1;
_ranges[4 * i + 2] = range.end.line + 1;
_ranges[4 * i + 3] = range.end.character + 1;
}
return this._proxy.$trySetDecorationsFast(
this.id,
decorationType.key,
_ranges
);
}
}
);
}
revealRange(range: Range, revealType: vscode.TextEditorRevealType): void {
this._runOnProxy(
() => this._proxy.$tryRevealRange(
this.id,
TypeConverters.Range.from(range),
(revealType || TextEditorRevealType.Default)
)
);
}
private _trySetSelection(): Promise<vscode.TextEditor | null | undefined> {
const selection = this._selections.map(TypeConverters.Selection.from);
return this._runOnProxy(() => this._proxy.$trySetSelections(this.id, selection));
}
_acceptSelections(selections: Selection[]): void {
ok(!this._disposed);
this._selections = selections;
}
// ---- editing
edit(callback: (edit: TextEditorEdit) => void, options: { undoStopBefore: boolean; undoStopAfter: boolean; } = { undoStopBefore: true, undoStopAfter: true }): Promise<boolean> {
if (this._disposed) {
return Promise.reject(new Error('TextEditor#edit not possible on closed editors'));
}
const edit = new TextEditorEdit(this._documentData.document, options);
callback(edit);
return this._applyEdit(edit);
private async _trySetSelection(): Promise<vscode.TextEditor | null | undefined> {
const selection = this._selections.map(TypeConverters.Selection.from);
await this._runOnProxy(() => this._proxy.$trySetSelections(this.id, selection));
return this.value;
}
private _applyEdit(editBuilder: TextEditorEdit): Promise<boolean> {
@@ -613,44 +601,12 @@ export class ExtHostTextEditor implements vscode.TextEditor {
undoStopAfter: editData.undoStopAfter
});
}
insertSnippet(snippet: SnippetString, where?: Position | readonly Position[] | Range | readonly Range[], options: { undoStopBefore: boolean; undoStopAfter: boolean; } = { undoStopBefore: true, undoStopAfter: true }): Promise<boolean> {
if (this._disposed) {
return Promise.reject(new Error('TextEditor#insertSnippet not possible on closed editors'));
}
let ranges: IRange[];
if (!where || (Array.isArray(where) && where.length === 0)) {
ranges = this._selections.map(range => TypeConverters.Range.from(range));
} else if (where instanceof Position) {
const { lineNumber, column } = TypeConverters.Position.from(where);
ranges = [{ startLineNumber: lineNumber, startColumn: column, endLineNumber: lineNumber, endColumn: column }];
} else if (where instanceof Range) {
ranges = [TypeConverters.Range.from(where)];
} else {
ranges = [];
for (const posOrRange of where) {
if (posOrRange instanceof Range) {
ranges.push(TypeConverters.Range.from(posOrRange));
} else {
const { lineNumber, column } = TypeConverters.Position.from(posOrRange);
ranges.push({ startLineNumber: lineNumber, startColumn: column, endLineNumber: lineNumber, endColumn: column });
}
}
}
return this._proxy.$tryInsertSnippet(this.id, snippet.value, ranges, options);
}
// ---- util
private _runOnProxy(callback: () => Promise<any>): Promise<ExtHostTextEditor | undefined | null> {
if (this._disposed) {
this._logService.warn('TextEditor is closed/disposed');
return Promise.resolve(undefined);
}
return callback().then(() => this, err => {
if (!(err instanceof Error && err.name === 'DISPOSED')) {
this._logService.warn(err);
@@ -659,4 +615,3 @@ export class ExtHostTextEditor implements vscode.TextEditor {
});
}
}

View File

@@ -41,12 +41,17 @@ export class ExtHostEditors implements ExtHostEditorsShape {
this._extHostDocumentsAndEditors.onDidChangeActiveTextEditor(e => this._onDidChangeActiveTextEditor.fire(e));
}
getActiveTextEditor(): ExtHostTextEditor | undefined {
getActiveTextEditor(): vscode.TextEditor | undefined {
return this._extHostDocumentsAndEditors.activeEditor();
}
getVisibleTextEditors(): vscode.TextEditor[] {
return this._extHostDocumentsAndEditors.allEditors();
getVisibleTextEditors(): vscode.TextEditor[];
getVisibleTextEditors(internal: true): ExtHostTextEditor[];
getVisibleTextEditors(internal?: true): ExtHostTextEditor[] | vscode.TextEditor[] {
const editors = this._extHostDocumentsAndEditors.allEditors();
return internal
? editors
: editors.map(editor => editor.value);
}
showTextDocument(document: vscode.TextDocument, column: vscode.ViewColumn, preserveFocus: boolean): Promise<vscode.TextEditor>;
@@ -75,7 +80,7 @@ export class ExtHostEditors implements ExtHostEditorsShape {
const editorId = await this._proxy.$tryShowTextDocument(document.uri, options);
const editor = editorId && this._extHostDocumentsAndEditors.getEditor(editorId);
if (editor) {
return editor;
return editor.value;
}
// we have no editor... having an id means that we had an editor
// on the main side and that it isn't the current editor anymore...
@@ -87,7 +92,7 @@ export class ExtHostEditors implements ExtHostEditorsShape {
}
createTextEditorDecorationType(options: vscode.DecorationRenderOptions): vscode.TextEditorDecorationType {
return new TextEditorDecorationType(this._proxy, options);
return new TextEditorDecorationType(this._proxy, options).value;
}
// --- called from main thread
@@ -114,7 +119,7 @@ export class ExtHostEditors implements ExtHostEditorsShape {
// (2) fire change events
if (data.options) {
this._onDidChangeTextEditorOptions.fire({
textEditor: textEditor,
textEditor: textEditor.value,
options: { ...data.options, lineNumbers: TypeConverters.TextEditorLineNumbersStyle.to(data.options.lineNumbers) }
});
}
@@ -122,7 +127,7 @@ export class ExtHostEditors implements ExtHostEditorsShape {
const kind = TextEditorSelectionChangeKind.fromValue(data.selections.source);
const selections = data.selections.selections.map(TypeConverters.Selection.to);
this._onDidChangeTextEditorSelection.fire({
textEditor,
textEditor: textEditor.value,
selections,
kind
});
@@ -130,7 +135,7 @@ export class ExtHostEditors implements ExtHostEditorsShape {
if (data.visibleRanges) {
const visibleRanges = arrays.coalesce(data.visibleRanges.map(TypeConverters.Range.to));
this._onDidChangeTextEditorVisibleRanges.fire({
textEditor,
textEditor: textEditor.value,
visibleRanges
});
}
@@ -143,9 +148,9 @@ export class ExtHostEditors implements ExtHostEditorsShape {
throw new Error('Unknown text editor');
}
const viewColumn = TypeConverters.ViewColumn.to(data[id]);
if (textEditor.viewColumn !== viewColumn) {
if (textEditor.value.viewColumn !== viewColumn) {
textEditor._acceptViewColumn(viewColumn);
this._onDidChangeTextEditorViewColumn.fire({ textEditor, viewColumn });
this._onDidChangeTextEditorViewColumn.fire({ textEditor: textEditor.value, viewColumn });
}
}
}

View File

@@ -84,7 +84,7 @@ export class ExtHostTreeViews implements ExtHostTreeViewsShape {
if (!options || !options.treeDataProvider) {
throw new Error('Options with treeDataProvider is mandatory');
}
const registerPromise = this._proxy.$registerTreeViewDataProvider(viewId, { showCollapseAll: !!options.showCollapseAll, canSelectMany: !!options.canSelectMany });
const treeView = this.createExtHostTreeView(viewId, options, extension);
return {
get onDidCollapseElement() { return treeView.onDidCollapseElement; },
@@ -110,7 +110,9 @@ export class ExtHostTreeViews implements ExtHostTreeViewsShape {
reveal: (element: T, options?: IRevealOptions): Promise<void> => {
return treeView.reveal(element, options);
},
dispose: () => {
dispose: async () => {
// Wait for the registration promise to finish before doing the dispose.
await registerPromise;
this.treeViews.delete(viewId);
treeView.dispose();
}
@@ -240,7 +242,6 @@ class ExtHostTreeView<T> extends Disposable {
}
}
this.dataProvider = options.treeDataProvider;
this.proxy.$registerTreeViewDataProvider(viewId, { showCollapseAll: !!options.showCollapseAll, canSelectMany: !!options.canSelectMany });
if (this.dataProvider.onDidChangeTreeData) {
this._register(this.dataProvider.onDidChangeTreeData(element => this._onDidChangeData.fire({ message: false, element })));
}

View File

@@ -6,7 +6,7 @@
import * as modes from 'vs/editor/common/modes';
import * as types from './extHostTypes';
import * as search from 'vs/workbench/contrib/search/common/search';
import { ITextEditorOptions } from 'vs/platform/editor/common/editor';
import { ITextEditorOptions, EditorOverride } from 'vs/platform/editor/common/editor';
import { IDecorationOptions, IThemeDecorationRenderOptions, IDecorationRenderOptions, IContentDecorationRenderOptions } from 'vs/editor/common/editorCommon';
import { EndOfLineSequence, TrackedRangeStickiness } from 'vs/editor/common/model';
import type * as vscode from 'vscode';
@@ -22,7 +22,7 @@ import * as extHostProtocol from 'vs/workbench/api/common/extHost.protocol';
import { MarkerSeverity, IRelatedInformation, IMarkerData, MarkerTag } from 'vs/platform/markers/common/markers';
import { ACTIVE_GROUP, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService';
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
import { isString, isNumber } from 'vs/base/common/types';
import { isString, isNumber, isDefined } from 'vs/base/common/types';
import * as marked from 'vs/base/common/marked/marked';
import { parse } from 'vs/base/common/marshalling';
import { cloneAndChange } from 'vs/base/common/objects';
@@ -31,8 +31,8 @@ import { coalesce, isNonEmptyArray } from 'vs/base/common/arrays';
import { RenderLineNumbersType } from 'vs/editor/common/config/editorOptions';
import { CommandsConverter } from 'vs/workbench/api/common/extHostCommands';
import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook';
import { CellOutputKind, IDisplayOutput, INotebookDecorationRenderOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { ITestItem, ITestState } from 'vs/workbench/contrib/testing/common/testCollection';
import * as notebooks from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { ISerializedTestResults, ITestItem, ITestState, SerializedTestResultItem } from 'vs/workbench/contrib/testing/common/testCollection';
export interface PositionLike {
line: number;
@@ -509,7 +509,7 @@ export namespace TextEdit {
}
export namespace WorkspaceEdit {
export function from(value: vscode.WorkspaceEdit, documents?: ExtHostDocumentsAndEditors, notebooks?: ExtHostNotebookController): extHostProtocol.IWorkspaceEditDto {
export function from(value: vscode.WorkspaceEdit, documents?: ExtHostDocumentsAndEditors, extHostNotebooks?: ExtHostNotebookController): extHostProtocol.IWorkspaceEditDto {
const result: extHostProtocol.IWorkspaceEditDto = {
edits: []
};
@@ -544,7 +544,61 @@ export namespace WorkspaceEdit {
resource: entry.uri,
edit: entry.edit,
notebookMetadata: entry.notebookMetadata,
notebookVersionId: notebooks?.lookupNotebookDocument(entry.uri)?.notebookDocument.version
notebookVersionId: extHostNotebooks?.lookupNotebookDocument(entry.uri)?.notebookDocument.version
});
} else if (entry._type === types.FileEditType.CellOutput) {
if (entry.newOutputs) {
result.edits.push({
_type: extHostProtocol.WorkspaceEditType.Cell,
metadata: entry.metadata,
resource: entry.uri,
edit: {
editType: notebooks.CellEditType.Output,
index: entry.index,
append: entry.append,
outputs: entry.newOutputs.map(NotebookCellOutput.from)
}
});
}
// todo@joh merge metadata and output edit?
if (entry.newMetadata) {
result.edits.push({
_type: extHostProtocol.WorkspaceEditType.Cell,
metadata: entry.metadata,
resource: entry.uri,
edit: {
editType: notebooks.CellEditType.Metadata,
index: entry.index,
metadata: entry.newMetadata
}
});
}
} else if (entry._type === types.FileEditType.CellReplace) {
result.edits.push({
_type: extHostProtocol.WorkspaceEditType.Cell,
metadata: entry.metadata,
resource: entry.uri,
notebookVersionId: extHostNotebooks?.lookupNotebookDocument(entry.uri)?.notebookDocument.version,
edit: {
editType: notebooks.CellEditType.Replace,
index: entry.index,
count: entry.count,
cells: entry.cells.map(NotebookCellData.from)
}
});
} else if (entry._type === types.FileEditType.CellOutputItem) {
result.edits.push({
_type: extHostProtocol.WorkspaceEditType.Cell,
metadata: entry.metadata,
resource: entry.uri,
edit: {
editType: notebooks.CellEditType.OutputItems,
index: entry.index,
outputId: entry.outputId,
items: entry.newOutputItems?.map(NotebookCellOutputItem.from) || [],
append: entry.append
}
});
}
}
@@ -796,6 +850,66 @@ export namespace EvaluatableExpression {
}
}
export namespace InlineValue {
export function from(inlineValue: vscode.InlineValue): modes.InlineValue {
if (inlineValue instanceof types.InlineValueText) {
return <modes.InlineValueText>{
type: 'text',
range: Range.from(inlineValue.range),
text: inlineValue.text
};
} else if (inlineValue instanceof types.InlineValueVariableLookup) {
return <modes.InlineValueVariableLookup>{
type: 'variable',
range: Range.from(inlineValue.range),
variableName: inlineValue.variableName,
caseSensitiveLookup: inlineValue.caseSensitiveLookup
};
} else if (inlineValue instanceof types.InlineValueEvaluatableExpression) {
return <modes.InlineValueExpression>{
type: 'expression',
range: Range.from(inlineValue.range),
expression: inlineValue.expression
};
} else {
throw new Error(`Unknown 'InlineValue' type`);
}
}
export function to(inlineValue: modes.InlineValue): vscode.InlineValue {
switch (inlineValue.type) {
case 'text':
return <vscode.InlineValueText>{
range: Range.to(inlineValue.range),
text: inlineValue.text
};
case 'variable':
return <vscode.InlineValueVariableLookup>{
range: Range.to(inlineValue.range),
variableName: inlineValue.variableName,
caseSensitiveLookup: inlineValue.caseSensitiveLookup
};
case 'expression':
return <vscode.InlineValueEvaluatableExpression>{
range: Range.to(inlineValue.range),
expression: inlineValue.expression
};
}
}
}
export namespace InlineValueContext {
export function from(inlineValueContext: vscode.InlineValueContext): extHostProtocol.IInlineValueContextDto {
return <extHostProtocol.IInlineValueContextDto>{
stoppedLocation: Range.from(inlineValueContext.stoppedLocation)
};
}
export function to(inlineValueContext: extHostProtocol.IInlineValueContextDto): types.InlineValueContext {
return new types.InlineValueContext(Range.to(inlineValueContext.stoppedLocation));
}
}
export namespace DocumentHighlight {
export function from(documentHighlight: vscode.DocumentHighlight): modes.DocumentHighlight {
return {
@@ -1021,6 +1135,7 @@ export namespace InlineHint {
return {
text: hint.text,
range: Range.from(hint.range),
kind: InlineHintKind.from(hint.kind ?? types.InlineHintKind.Other),
description: hint.description && MarkdownString.fromStrict(hint.description),
whitespaceBefore: hint.whitespaceBefore,
whitespaceAfter: hint.whitespaceAfter
@@ -1028,13 +1143,24 @@ export namespace InlineHint {
}
export function to(hint: modes.InlineHint): vscode.InlineHint {
return new types.InlineHint(
const res = new types.InlineHint(
hint.text,
Range.to(hint.range),
htmlContent.isMarkdownString(hint.description) ? MarkdownString.to(hint.description) : hint.description,
hint.whitespaceBefore,
hint.whitespaceAfter
InlineHintKind.to(hint.kind)
);
res.whitespaceAfter = hint.whitespaceAfter;
res.whitespaceBefore = hint.whitespaceBefore;
res.description = htmlContent.isMarkdownString(hint.description) ? MarkdownString.to(hint.description) : hint.description;
return res;
}
}
export namespace InlineHintKind {
export function from(kind: vscode.InlineHintKind): modes.InlineHintKind {
return kind;
}
export function to(kind: modes.InlineHintKind): vscode.InlineHintKind {
return kind;
}
}
@@ -1218,7 +1344,7 @@ export namespace TextEditorOpenOptions {
inactive: options.background,
preserveFocus: options.preserveFocus,
selection: typeof options.selection === 'object' ? Range.from(options.selection) : undefined,
override: typeof options.override === 'boolean' ? false : undefined
override: typeof options.override === 'boolean' ? EditorOverride.DISABLED : undefined
};
}
@@ -1268,32 +1394,120 @@ export namespace LanguageSelector {
} else if (typeof selector === 'string') {
return selector;
} else {
const filter = selector as vscode.DocumentFilter; // TODO: microsoft/TypeScript#42768
return <languageSelector.LanguageFilter>{
language: selector.language,
scheme: selector.scheme,
pattern: typeof selector.pattern === 'undefined' ? undefined : GlobPattern.from(selector.pattern),
exclusive: selector.exclusive
language: filter.language,
scheme: filter.scheme,
pattern: typeof filter.pattern === 'undefined' ? undefined : GlobPattern.from(filter.pattern),
exclusive: filter.exclusive
};
}
}
}
export namespace NotebookCellOutput {
export function from(output: types.NotebookCellOutput): IDisplayOutput {
return output.toJSON();
export namespace NotebookCellRange {
export function from(range: vscode.NotebookCellRange): notebooks.ICellRange {
return { start: range.start, end: range.end };
}
export function to(range: notebooks.ICellRange): types.NotebookCellRange {
return new types.NotebookCellRange(range.start, range.end);
}
}
export namespace NotebookCellMetadata {
export function to(data: notebooks.NotebookCellMetadata): types.NotebookCellMetadata {
return new types.NotebookCellMetadata(data.editable, data.breakpointMargin, data.runnable, data.hasExecutionOrder, data.executionOrder, data.runState, data.runStartTime, data.statusMessage, data.lastRunDuration, data.inputCollapsed, data.outputCollapsed, data.custom);
}
}
export namespace NotebookDocumentMetadata {
export function from(data: types.NotebookDocumentMetadata): notebooks.NotebookDocumentMetadata {
return data;
}
export function to(data: notebooks.NotebookDocumentMetadata): types.NotebookDocumentMetadata {
return new types.NotebookDocumentMetadata(data.editable, data.runnable, data.cellEditable, data.cellRunnable, data.cellHasExecutionOrder, data.displayOrder, data.custom, data.runState, data.trusted);
}
}
export namespace NotebookCellKind {
export function from(data: vscode.NotebookCellKind): notebooks.CellKind {
switch (data) {
case types.NotebookCellKind.Markdown:
return notebooks.CellKind.Markdown;
case types.NotebookCellKind.Code:
default:
return notebooks.CellKind.Code;
}
}
export function to(data: notebooks.CellKind): vscode.NotebookCellKind {
switch (data) {
case notebooks.CellKind.Markdown:
return types.NotebookCellKind.Markdown;
case notebooks.CellKind.Code:
default:
return types.NotebookCellKind.Code;
}
}
}
export namespace NotebookCellData {
export function from(data: vscode.NotebookCellData): notebooks.ICellDto2 {
return {
cellKind: NotebookCellKind.from(data.cellKind),
language: data.language,
source: data.source,
metadata: data.metadata,
outputs: data.outputs.map(output => ({
outputId: output.id,
metadata: output.metadata,
outputs: (output.outputs || []).map(op => ({
mime: op.mime,
value: op.value,
metadata: op.metadata
}))
}))
};
}
}
export namespace NotebookCellOutputItem {
export function from(output: types.NotebookCellOutputItem): IDisplayOutput {
export function from(item: types.NotebookCellOutputItem): notebooks.IOutputItemDto {
return {
outputKind: CellOutputKind.Rich,
data: { [output.mime]: output.value },
metadata: output.metadata && { custom: output.metadata }
mime: item.mime,
value: item.value,
metadata: item.metadata
};
}
export function to(item: notebooks.IOutputItemDto): types.NotebookCellOutputItem {
return new types.NotebookCellOutputItem(item.mime, item.value, item.metadata);
}
}
export namespace NotebookCellOutput {
export function from(output: types.NotebookCellOutput): notebooks.IOutputDto {
return {
outputId: output.id,
outputs: output.outputs.map(NotebookCellOutputItem.from),
metadata: output.metadata
};
}
export function to(output: notebooks.IOutputDto): vscode.NotebookCellOutput {
const items = output.outputs.map(NotebookCellOutputItem.to);
return new types.NotebookCellOutput(items, output.outputId, output.metadata);
}
}
export namespace NotebookExclusiveDocumentPattern {
export function from(pattern: { include: vscode.GlobPattern | undefined, exclude: vscode.GlobPattern | undefined }): { include: string | types.RelativePattern | undefined, exclude: string | types.RelativePattern | undefined };
export function from(pattern: vscode.GlobPattern): string | types.RelativePattern;
@@ -1368,7 +1582,7 @@ export namespace NotebookExclusiveDocumentPattern {
}
export namespace NotebookDecorationRenderOptions {
export function from(options: vscode.NotebookDecorationRenderOptions): INotebookDecorationRenderOptions {
export function from(options: vscode.NotebookDecorationRenderOptions): notebooks.INotebookDecorationRenderOptions {
return {
backgroundColor: <string | types.ThemeColor>options.backgroundColor,
borderColor: <string | types.ThemeColor>options.borderColor,
@@ -1380,22 +1594,22 @@ export namespace NotebookDecorationRenderOptions {
export namespace TestState {
export function from(item: vscode.TestState): ITestState {
return {
runState: item.runState,
state: item.state,
duration: item.duration,
messages: item.messages.map(message => ({
messages: item.messages?.map(message => ({
message: MarkdownString.fromStrict(message.message) || '',
severity: message.severity,
expectedOutput: message.expectedOutput,
actualOutput: message.actualOutput,
location: message.location ? location.from(message.location) : undefined,
})),
location: message.location ? location.from(message.location) as any : undefined,
})) ?? [],
};
}
export function to(item: ITestState): vscode.TestState {
return new types.TestState(
item.runState,
item.messages.map(message => ({
return {
state: item.state,
messages: item.messages.map(message => ({
message: typeof message.message === 'string' ? message.message : MarkdownString.to(message.message),
severity: message.severity,
expectedOutput: message.expectedOutput,
@@ -1405,22 +1619,20 @@ export namespace TestState {
uri: URI.revive(message.location.uri)
}),
})),
item.duration,
);
duration: item.duration,
};
}
}
export namespace TestItem {
export function from(item: vscode.TestItem, parentExtId?: string): ITestItem {
export function from(item: vscode.TestItem): ITestItem {
return {
extId: item.id ?? (parentExtId ? `${parentExtId}\0${item.label}` : item.label),
extId: item.id,
label: item.label,
location: item.location ? location.from(item.location) : undefined,
location: item.location ? location.from(item.location) as any : undefined,
debuggable: item.debuggable ?? false,
description: item.description,
runnable: item.runnable ?? true,
state: TestState.from(item.state),
};
}
@@ -1435,7 +1647,68 @@ export namespace TestItem {
debuggable: item.debuggable,
description: item.description,
runnable: item.runnable,
state: TestState.to(item.state),
};
}
}
export namespace TestResults {
export function from(id: string, results: vscode.TestResults): ISerializedTestResults {
const serialized: ISerializedTestResults = {
completedAt: results.completedAt,
id,
items: [],
};
const queue: [parent: SerializedTestResultItem | null, children: Iterable<vscode.TestItemWithResults>][] = [
[null, results.results],
];
while (queue.length) {
const [parent, children] = queue.pop()!;
for (const item of children) {
const serializedItem: SerializedTestResultItem = {
children: item.children?.map(c => c.id) ?? [],
computedState: item.result.state,
item: TestItem.from(item),
state: TestState.from(item.result),
retired: undefined,
parent: parent?.item.extId ?? null,
providerId: '',
direct: !parent,
};
serialized.items.push(serializedItem);
if (item.children) {
queue.push([serializedItem, item.children]);
}
}
}
return serialized;
}
const convertTestResultItem = (item: SerializedTestResultItem, byInternalId: Map<string, SerializedTestResultItem>): vscode.TestItemWithResults => ({
...TestItem.toShallow(item.item),
result: TestState.to(item.state),
children: item.children
.map(c => byInternalId.get(c))
.filter(isDefined)
.map(c => convertTestResultItem(c, byInternalId)),
});
export function to(serialized: ISerializedTestResults): vscode.TestResults {
const roots: SerializedTestResultItem[] = [];
const byInternalId = new Map<string, SerializedTestResultItem>();
for (const item of serialized.items) {
byInternalId.set(item.item.extId, item);
if (item.direct) {
roots.push(item);
}
}
return {
completedAt: serialized.completedAt,
results: roots.map(r => convertTestResultItem(r, byInternalId)),
};
}
}

View File

@@ -13,7 +13,7 @@ import { URI } from 'vs/base/common/uri';
import { generateUuid } from 'vs/base/common/uuid';
import { FileSystemProviderErrorCode, markAsFileSystemProviderError } from 'vs/platform/files/common/files';
import { RemoteAuthorityResolverErrorCode } from 'vs/platform/remote/common/remoteAuthorityResolver';
import { addIdToOutput, CellEditType, ICellEditOperation, IDisplayOutput, notebookDocumentMetadataDefaults } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { CellEditType, ICellEditOperation, notebookDocumentMetadataDefaults, NOTEBOOK_DISPLAY_ORDER } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import type * as vscode from 'vscode';
function es5ClassCompat(target: Function): any {
@@ -585,7 +585,10 @@ export interface IFileOperationOptions {
export const enum FileEditType {
File = 1,
Text = 2,
Cell = 3
Cell = 3,
CellOutput = 4,
CellReplace = 5,
CellOutputItem = 6
}
export interface IFileOperation {
@@ -611,13 +614,45 @@ export interface IFileCellEdit {
metadata?: vscode.WorkspaceEditEntryMetadata;
}
export interface ICellEdit {
_type: FileEditType.CellReplace;
metadata?: vscode.WorkspaceEditEntryMetadata;
uri: URI;
index: number;
count: number;
cells: vscode.NotebookCellData[];
}
export interface ICellOutputEdit {
_type: FileEditType.CellOutput;
uri: URI;
index: number;
append: boolean;
newOutputs?: NotebookCellOutput[];
newMetadata?: vscode.NotebookCellMetadata;
metadata?: vscode.WorkspaceEditEntryMetadata;
}
export interface ICellOutputItemsEdit {
_type: FileEditType.CellOutputItem;
uri: URI;
index: number;
outputId: string;
append: boolean;
newOutputItems?: NotebookCellOutputItem[];
metadata?: vscode.WorkspaceEditEntryMetadata;
}
type WorkspaceEditEntry = IFileOperation | IFileTextEdit | IFileCellEdit | ICellEdit | ICellOutputEdit | ICellOutputItemsEdit;
@es5ClassCompat
export class WorkspaceEdit implements vscode.WorkspaceEdit {
private readonly _edits = new Array<IFileOperation | IFileTextEdit | IFileCellEdit>();
private readonly _edits: WorkspaceEditEntry[] = [];
_allEntries(): ReadonlyArray<IFileTextEdit | IFileOperation | IFileCellEdit> {
_allEntries(): ReadonlyArray<WorkspaceEditEntry> {
return this._edits;
}
@@ -643,22 +678,32 @@ export class WorkspaceEdit implements vscode.WorkspaceEdit {
replaceNotebookCells(uri: URI, start: number, end: number, cells: vscode.NotebookCellData[], metadata?: vscode.WorkspaceEditEntryMetadata): void {
if (start !== end || cells.length > 0) {
this._edits.push({ _type: FileEditType.Cell, metadata, uri, edit: { editType: CellEditType.Replace, index: start, count: end - start, cells: cells.map(cell => ({ ...cell, outputs: cell.outputs.map(output => addIdToOutput(output)) })) } });
this._edits.push({ _type: FileEditType.CellReplace, uri, index: start, count: end - start, cells, metadata });
}
}
replaceNotebookCellOutput(uri: URI, index: number, outputs: (vscode.NotebookCellOutput | vscode.CellOutput)[], metadata?: vscode.WorkspaceEditEntryMetadata): void {
this._edits.push({
_type: FileEditType.Cell, metadata, uri, edit: {
editType: CellEditType.Output, index, outputs: outputs.map(output => {
if (NotebookCellOutput.isNotebookCellOutput(output)) {
return addIdToOutput(output.toJSON());
} else {
return addIdToOutput(output);
}
})
}
});
replaceNotebookCellOutput(uri: URI, index: number, outputs: vscode.NotebookCellOutput[], metadata?: vscode.WorkspaceEditEntryMetadata): void {
this._editNotebookCellOutput(uri, index, false, outputs, metadata);
}
appendNotebookCellOutput(uri: URI, index: number, outputs: vscode.NotebookCellOutput[], metadata?: vscode.WorkspaceEditEntryMetadata): void {
this._editNotebookCellOutput(uri, index, true, outputs, metadata);
}
replaceNotebookCellOutputItems(uri: URI, index: number, outputId: string, items: NotebookCellOutputItem[], metadata?: vscode.WorkspaceEditEntryMetadata): void {
this._editNotebookCellOutputItems(uri, index, outputId, false, items, metadata);
}
appendNotebookCellOutputItems(uri: URI, index: number, outputId: string, items: NotebookCellOutputItem[], metadata?: vscode.WorkspaceEditEntryMetadata): void {
this._editNotebookCellOutputItems(uri, index, outputId, true, items, metadata);
}
private _editNotebookCellOutputItems(uri: URI, index: number, id: string, append: boolean, items: vscode.NotebookCellOutputItem[], metadata: vscode.WorkspaceEditEntryMetadata | undefined): void {
this._edits.push({ _type: FileEditType.CellOutputItem, metadata, uri, index, outputId: id, append, newOutputItems: items });
}
private _editNotebookCellOutput(uri: URI, index: number, append: boolean, outputs: vscode.NotebookCellOutput[], metadata: vscode.WorkspaceEditEntryMetadata | undefined): void {
this._edits.push({ _type: FileEditType.CellOutput, metadata, uri, index, append, newOutputs: outputs, newMetadata: undefined });
}
replaceNotebookCellMetadata(uri: URI, index: number, cellMetadata: vscode.NotebookCellMetadata, metadata?: vscode.WorkspaceEditEntryMetadata): void {
@@ -1373,20 +1418,26 @@ export enum SignatureHelpTriggerKind {
ContentChange = 3,
}
export enum InlineHintKind {
Other = 0,
Type = 1,
Parameter = 2,
}
@es5ClassCompat
export class InlineHint {
text: string;
range: Range;
kind?: vscode.InlineHintKind;
description?: string | vscode.MarkdownString;
whitespaceBefore?: boolean;
whitespaceAfter?: boolean;
constructor(text: string, range: Range, description?: string | vscode.MarkdownString, whitespaceBefore?: boolean, whitespaceAfter?: boolean) {
constructor(text: string, range: Range, kind?: vscode.InlineHintKind) {
this.text = text;
this.range = range;
this.description = description;
this.whitespaceBefore = whitespaceBefore;
this.whitespaceAfter = whitespaceAfter;
this.kind = kind;
}
}
@@ -2387,6 +2438,51 @@ export class EvaluatableExpression implements vscode.EvaluatableExpression {
}
}
@es5ClassCompat
export class InlineValueText implements vscode.InlineValueText {
readonly range: Range;
readonly text: string;
constructor(range: Range, text: string) {
this.range = range;
this.text = text;
}
}
@es5ClassCompat
export class InlineValueVariableLookup implements vscode.InlineValueVariableLookup {
readonly range: Range;
readonly variableName?: string;
readonly caseSensitiveLookup: boolean;
constructor(range: Range, variableName?: string, caseSensitiveLookup: boolean = true) {
this.range = range;
this.variableName = variableName;
this.caseSensitiveLookup = caseSensitiveLookup;
}
}
@es5ClassCompat
export class InlineValueEvaluatableExpression implements vscode.InlineValueEvaluatableExpression {
readonly range: Range;
readonly expression?: string;
constructor(range: Range, expression?: string) {
this.range = range;
this.expression = expression;
}
}
@es5ClassCompat
export class InlineValueContext implements vscode.InlineValueContext {
readonly stoppedLocation: vscode.Range;
constructor(range: vscode.Range) {
this.stoppedLocation = range;
}
}
//#region file api
export enum FileChangeType {
@@ -2797,6 +2893,264 @@ export enum ColorThemeKind {
//#region Notebook
export class NotebookCellRange {
private _start: number;
private _end: number;
get start() {
return this._start;
}
get end() {
return this._end;
}
constructor(start: number, end: number) {
// todo@rebornix
// if (start < 0) {
// throw illegalArgument('start must be positive');
// }
// if (end < start) {
// throw illegalArgument('end cannot be smaller than start');
// }
this._start = start;
this._end = end;
}
}
export class NotebookCellMetadata {
constructor(
readonly editable?: boolean,
readonly breakpointMargin?: boolean,
readonly runnable?: boolean,
readonly hasExecutionOrder?: boolean,
readonly executionOrder?: number,
readonly runState?: NotebookCellRunState,
readonly runStartTime?: number,
readonly statusMessage?: string,
readonly lastRunDuration?: number,
readonly inputCollapsed?: boolean,
readonly outputCollapsed?: boolean,
readonly custom?: Record<string, any>,
) { }
with(change: {
editable?: boolean | null,
breakpointMargin?: boolean | null,
runnable?: boolean | null,
hasExecutionOrder?: boolean | null,
executionOrder?: number | null,
runState?: NotebookCellRunState | null,
runStartTime?: number | null,
statusMessage?: string | null,
lastRunDuration?: number | null,
inputCollapsed?: boolean | null,
outputCollapsed?: boolean | null,
custom?: Record<string, any> | null,
}): NotebookCellMetadata {
let { editable, breakpointMargin, runnable, hasExecutionOrder, executionOrder, runState, runStartTime, statusMessage, lastRunDuration, inputCollapsed, outputCollapsed, custom } = change;
if (editable === undefined) {
editable = this.editable;
} else if (editable === null) {
editable = undefined;
}
if (breakpointMargin === undefined) {
breakpointMargin = this.breakpointMargin;
} else if (breakpointMargin === null) {
breakpointMargin = undefined;
}
if (runnable === undefined) {
runnable = this.runnable;
} else if (runnable === null) {
runnable = undefined;
}
if (hasExecutionOrder === undefined) {
hasExecutionOrder = this.hasExecutionOrder;
} else if (hasExecutionOrder === null) {
hasExecutionOrder = undefined;
}
if (executionOrder === undefined) {
executionOrder = this.executionOrder;
} else if (executionOrder === null) {
executionOrder = undefined;
}
if (runState === undefined) {
runState = this.runState;
} else if (runState === null) {
runState = undefined;
}
if (runStartTime === undefined) {
runStartTime = this.runStartTime;
} else if (runStartTime === null) {
runStartTime = undefined;
}
if (statusMessage === undefined) {
statusMessage = this.statusMessage;
} else if (statusMessage === null) {
statusMessage = undefined;
}
if (lastRunDuration === undefined) {
lastRunDuration = this.lastRunDuration;
} else if (lastRunDuration === null) {
lastRunDuration = undefined;
}
if (inputCollapsed === undefined) {
inputCollapsed = this.inputCollapsed;
} else if (inputCollapsed === null) {
inputCollapsed = undefined;
}
if (outputCollapsed === undefined) {
outputCollapsed = this.outputCollapsed;
} else if (outputCollapsed === null) {
outputCollapsed = undefined;
}
if (custom === undefined) {
custom = this.custom;
} else if (custom === null) {
custom = undefined;
}
if (editable === this.editable &&
breakpointMargin === this.breakpointMargin &&
runnable === this.runnable &&
hasExecutionOrder === this.hasExecutionOrder &&
executionOrder === this.executionOrder &&
runState === this.runState &&
runStartTime === this.runStartTime &&
statusMessage === this.statusMessage &&
lastRunDuration === this.lastRunDuration &&
inputCollapsed === this.inputCollapsed &&
outputCollapsed === this.outputCollapsed &&
custom === this.custom
) {
return this;
}
return new NotebookCellMetadata(
editable,
breakpointMargin,
runnable,
hasExecutionOrder,
executionOrder,
runState,
runStartTime,
statusMessage,
lastRunDuration,
inputCollapsed,
outputCollapsed,
custom,
);
}
}
export class NotebookDocumentMetadata {
constructor(
readonly editable: boolean = true,
readonly runnable: boolean = true,
readonly cellEditable: boolean = true,
readonly cellRunnable: boolean = true,
readonly cellHasExecutionOrder: boolean = true,
readonly displayOrder: vscode.GlobPattern[] = NOTEBOOK_DISPLAY_ORDER,
readonly custom: { [key: string]: any; } = {},
readonly runState: NotebookRunState = NotebookRunState.Idle,
readonly trusted: boolean = true,
) { }
with(change: {
editable?: boolean | null,
runnable?: boolean | null,
cellEditable?: boolean | null,
cellRunnable?: boolean | null,
cellHasExecutionOrder?: boolean | null,
displayOrder?: vscode.GlobPattern[] | null,
custom?: { [key: string]: any; } | null,
runState?: NotebookRunState | null,
trusted?: boolean | null,
}): NotebookDocumentMetadata {
let { editable, runnable, cellEditable, cellRunnable, cellHasExecutionOrder, displayOrder, custom, runState, trusted } = change;
if (editable === undefined) {
editable = this.editable;
} else if (editable === null) {
editable = undefined;
}
if (runnable === undefined) {
runnable = this.runnable;
} else if (runnable === null) {
runnable = undefined;
}
if (cellEditable === undefined) {
cellEditable = this.cellEditable;
} else if (cellEditable === null) {
cellEditable = undefined;
}
if (cellRunnable === undefined) {
cellRunnable = this.cellRunnable;
} else if (cellRunnable === null) {
cellRunnable = undefined;
}
if (cellHasExecutionOrder === undefined) {
cellHasExecutionOrder = this.cellHasExecutionOrder;
} else if (cellHasExecutionOrder === null) {
cellHasExecutionOrder = undefined;
}
if (displayOrder === undefined) {
displayOrder = this.displayOrder;
} else if (displayOrder === null) {
displayOrder = undefined;
}
if (custom === undefined) {
custom = this.custom;
} else if (custom === null) {
custom = undefined;
}
if (runState === undefined) {
runState = this.runState;
} else if (runState === null) {
runState = undefined;
}
if (trusted === undefined) {
trusted = this.trusted;
} else if (trusted === null) {
trusted = undefined;
}
if (editable === this.editable &&
runnable === this.runnable &&
cellEditable === this.cellEditable &&
cellRunnable === this.cellRunnable &&
cellHasExecutionOrder === this.cellHasExecutionOrder &&
displayOrder === this.displayOrder &&
custom === this.custom &&
runState === this.runState &&
trusted === this.trusted
) {
return this;
}
return new NotebookDocumentMetadata(
editable,
runnable,
cellEditable,
cellRunnable,
cellHasExecutionOrder,
displayOrder,
custom,
runState,
trusted
);
}
}
export class NotebookCellOutputItem {
static isNotebookCellOutputItem(obj: unknown): obj is vscode.NotebookCellOutputItem {
@@ -2806,52 +3160,37 @@ export class NotebookCellOutputItem {
constructor(
readonly mime: string,
readonly value: unknown, // JSON'able
readonly metadata?: Record<string, string | number | boolean>
readonly metadata?: Record<string, any>
) { }
}
export class NotebookCellOutput {
static isNotebookCellOutput(obj: unknown): obj is vscode.NotebookCellOutput {
return obj instanceof NotebookCellOutput;
}
readonly outputs: NotebookCellOutputItem[];
readonly id: string;
readonly metadata?: Record<string, any>;
constructor(
readonly outputs: NotebookCellOutputItem[],
readonly metadata?: Record<string, string | number | boolean>
) { }
toJSON(): IDisplayOutput {
let data: { [key: string]: unknown; } = {};
let custom: { [key: string]: unknown; } = {};
let hasMetadata = false;
for (let item of this.outputs) {
data[item.mime] = item.value;
if (item.metadata) {
custom[item.mime] = item.metadata;
hasMetadata = true;
}
outputs: NotebookCellOutputItem[],
idOrMetadata?: string | Record<string, any>,
metadata?: Record<string, any>
) {
this.outputs = outputs;
if (typeof idOrMetadata === 'string') {
this.id = idOrMetadata;
this.metadata = metadata;
} else {
this.id = generateUuid();
this.metadata = idOrMetadata ?? metadata;
}
return {
outputKind: CellOutputKind.Rich,
data,
metadata: hasMetadata ? { custom } : undefined
};
}
}
export enum CellKind {
export enum NotebookCellKind {
Markdown = 1,
Code = 2
}
export enum CellOutputKind {
Text = 1,
Error = 2,
Rich = 3
}
export enum NotebookCellRunState {
Running = 1,
Idle = 2,
@@ -2954,31 +3293,6 @@ export enum TestMessageSeverity {
Hint = 3
}
@es5ClassCompat
export class TestState {
#runState: TestRunState;
#duration?: number;
#messages: ReadonlyArray<Readonly<vscode.TestMessage>>;
public get runState() {
return this.#runState;
}
public get duration() {
return this.#duration;
}
public get messages() {
return this.#messages;
}
constructor(runState: TestRunState, messages: vscode.TestMessage[] = [], duration?: number) {
this.#runState = runState;
this.#messages = Object.freeze(messages.map(m => Object.freeze(m)));
this.#duration = duration;
}
}
export type RequiredTestItem = vscode.RequiredTestItem;
export type TestItem = vscode.TestItem;
@@ -2991,3 +3305,9 @@ export enum ExternalUriOpenerPriority {
Default = 2,
Preferred = 3,
}
export enum WorkspaceTrustState {
Untrusted = 0,
Trusted = 1,
Unknown = 2
}

View File

@@ -20,11 +20,12 @@ import { FileSystemProviderCapabilities } from 'vs/platform/files/common/files';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { ILogService } from 'vs/platform/log/common/log';
import { Severity } from 'vs/platform/notification/common/notification';
import { WorkspaceTrustStateChangeEvent } from 'vs/platform/workspace/common/workspaceTrust';
import { Workspace, WorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { IExtHostFileSystemInfo } from 'vs/workbench/api/common/extHostFileSystemInfo';
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
import { Range, RelativePattern } from 'vs/workbench/api/common/extHostTypes';
import { Range, RelativePattern, WorkspaceTrustState } from 'vs/workbench/api/common/extHostTypes';
import { ITextQueryBuilderOptions } from 'vs/workbench/contrib/search/common/queryBuilder';
import { IRawFileMatch2, resultIsMatch } from 'vs/workbench/services/search/common/search';
import * as vscode from 'vscode';
@@ -168,6 +169,9 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape, IExtHostWorkspac
private readonly _onDidChangeWorkspace = new Emitter<vscode.WorkspaceFoldersChangeEvent>();
readonly onDidChangeWorkspace: Event<vscode.WorkspaceFoldersChangeEvent> = this._onDidChangeWorkspace.event;
private readonly _onDidChangeWorkspaceTrustState = new Emitter<vscode.WorkspaceTrustStateChangeEvent>();
readonly onDidChangeWorkspaceTrustState: Event<vscode.WorkspaceTrustStateChangeEvent> = this._onDidChangeWorkspaceTrustState.event;
private readonly _logService: ILogService;
private readonly _requestIdProvider: Counter;
private readonly _barrier: Barrier;
@@ -181,6 +185,8 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape, IExtHostWorkspac
private readonly _activeSearchCallbacks: ((match: IRawFileMatch2) => any)[] = [];
private _workspaceTrustState: WorkspaceTrustState = WorkspaceTrustState.Unknown;
constructor(
@IExtHostRpcService extHostRpc: IExtHostRpcService,
@IExtHostInitDataService initData: IExtHostInitDataService,
@@ -198,7 +204,8 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape, IExtHostWorkspac
this._confirmedWorkspace = data ? new ExtHostWorkspaceImpl(data.id, data.name, [], data.configuration ? URI.revive(data.configuration) : null, !!data.isUntitled, uri => ignorePathCasing(uri, extHostFileSystemInfo)) : undefined;
}
$initializeWorkspace(data: IWorkspaceData | null): void {
$initializeWorkspace(data: IWorkspaceData | null, trustState: WorkspaceTrustState): void {
this._workspaceTrustState = trustState;
this.$acceptWorkspaceData(data);
this._barrier.open();
}
@@ -549,6 +556,21 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape, IExtHostWorkspac
resolveProxy(url: string): Promise<string | undefined> {
return this._proxy.$resolveProxy(url);
}
// --- trust ---
get trustState(): WorkspaceTrustState {
return this._workspaceTrustState;
}
requireWorkspaceTrust(modal?: boolean): Promise<WorkspaceTrustState> {
return this._proxy.$requireWorkspaceTrust(modal);
}
$onDidChangeWorkspaceTrustState(state: WorkspaceTrustStateChangeEvent): void {
this._workspaceTrustState = state.currentTrustState;
this._onDidChangeWorkspaceTrustState.fire(Object.freeze(state));
}
}
export const IExtHostWorkspace = createDecorator<IExtHostWorkspace>('IExtHostWorkspace');

View File

@@ -43,6 +43,11 @@ const apiMenus: IAPIMenu[] = [
id: MenuId.EditorTitle,
description: localize('menus.editorTitle', "The editor title menu")
},
{
key: 'editor/title/run',
id: MenuId.EditorTitleRun,
description: localize('menus.editorTitleRun', "Run submenu inside the editor title menu")
},
{
key: 'editor/context',
id: MenuId.EditorContext,
@@ -161,6 +166,12 @@ const apiMenus: IAPIMenu[] = [
description: localize('notebook.cell.title', "The contributed notebook cell title menu"),
proposed: true
},
{
key: 'testing/item/context',
id: MenuId.TestItem,
description: localize('testing.item.title', "The contributed test item menu"),
proposed: true
},
{
key: 'extension/context',
id: MenuId.ExtensionContext,
@@ -176,6 +187,16 @@ const apiMenus: IAPIMenu[] = [
id: MenuId.TimelineItemContext,
description: localize('view.timelineContext', "The Timeline view item context menu")
},
{
key: 'ports/item/context',
id: MenuId.TunnelContext,
description: localize('view.tunnelContext', "The Ports view item context menu")
},
{
key: 'ports/item/origin/inline',
id: MenuId.TunnelOriginInline,
description: localize('view.tunnelOriginInline', "The Ports view item origin inline menu")
}
];
namespace schema {
@@ -337,7 +358,7 @@ namespace schema {
type: 'string'
},
icon: {
description: localize('vscode.extension.contributes.submenu.icon', '(Optional) Icon which is used to represent the submenu in the UI. Either a file path, an object with file paths for dark and light themes, or a theme icon references, like `\\$(zap)`'),
description: localize({ key: 'vscode.extension.contributes.submenu.icon', comment: ['do not translate or change `\\$(zap)`, \\ in front of $ is important.'] }, '(Optional) Icon which is used to represent the submenu in the UI. Either a file path, an object with file paths for dark and light themes, or a theme icon references, like `\\$(zap)`'),
anyOf: [{
type: 'string'
},
@@ -465,7 +486,7 @@ namespace schema {
type: 'string'
},
icon: {
description: localize('vscode.extension.contributes.commandType.icon', '(Optional) Icon which is used to represent the command in the UI. Either a file path, an object with file paths for dark and light themes, or a theme icon references, like `\\$(zap)`'),
description: localize({ key: 'vscode.extension.contributes.commandType.icon', comment: ['do not translate or change `\\$(zap)`, \\ in front of $ is important.'] }, '(Optional) Icon which is used to represent the command in the UI. Either a file path, an object with file paths for dark and light themes, or a theme icon references, like `\\$(zap)`'),
anyOf: [{
type: 'string'
},

View File

@@ -163,8 +163,10 @@ export class CLIServerBase {
}
private async openExternal(data: OpenExternalCommandPipeArgs, res: http.ServerResponse) {
for (const uri of data.uris) {
await this._commands.executeCommand('_remoteCLI.openExternal', URI.parse(uri), { allowTunneling: true });
for (const uriString of data.uris) {
const uri = URI.parse(uriString);
const urioOpen = uri.scheme === 'file' ? uri : uriString; // workaround for #112577
await this._commands.executeCommand('_remoteCLI.openExternal', urioOpen);
}
res.writeHead(200);
res.end();

View File

@@ -25,7 +25,6 @@ import { IDisposable } from 'vs/base/common/lifecycle';
import { AbstractVariableResolverService } from 'vs/workbench/services/configurationResolver/common/variableResolver';
import { createCancelablePromise, firstParallel } from 'vs/base/common/async';
export class ExtHostDebugService extends ExtHostDebugServiceBase {
readonly _serviceBrand: undefined;
@@ -68,7 +67,7 @@ export class ExtHostDebugService extends ExtHostDebugServiceBase {
return new SignService();
}
public async $runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments): Promise<number | undefined> {
public async $runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments, sessionId: string): Promise<number | undefined> {
if (args.kind === 'integrated') {
@@ -116,13 +115,21 @@ export class ExtHostDebugService extends ExtHostDebugServiceBase {
const command = prepareCommand(shell, args.args, cwdForPrepareCommand, args.env);
terminal.sendText(command, true);
// Mark terminal as unused when its session ends, see #112055
const sessionListener = this.onDidTerminateDebugSession(s => {
if (s.id === sessionId) {
this._integratedTerminalInstances.free(terminal!);
sessionListener.dispose();
}
});
return shellProcessId;
} else if (args.kind === 'external') {
return runInExternalTerminal(args, await this._configurationService.getConfigProvider());
}
return super.$runInTerminal(args);
return super.$runInTerminal(args, sessionId);
}
protected createVariableResolver(folders: vscode.WorkspaceFolder[], editorService: ExtHostDocumentsAndEditors, configurationService: ExtHostConfigProvider): AbstractVariableResolverService {
@@ -139,17 +146,15 @@ class DebugTerminalCollection {
private _terminalInstances = new Map<vscode.Terminal, { lastUsedAt: number, config: string }>();
public async checkout(config: string) {
const entries = [...this._terminalInstances.keys()];
const promises = entries.map((terminal) => createCancelablePromise(async ct => {
const pid = await terminal.processId;
if (await hasChildProcesses(pid)) {
const entries = [...this._terminalInstances.entries()];
const promises = entries.map(([terminal, termInfo]) => createCancelablePromise(async ct => {
if (termInfo.lastUsedAt !== -1 && await hasChildProcesses(await terminal.processId)) {
return null;
}
// important: date check and map operations must be synchronous
const now = Date.now();
const termInfo = this._terminalInstances.get(terminal);
if (!termInfo || termInfo.lastUsedAt + DebugTerminalCollection.minUseDelay > now || ct.isCancellationRequested) {
if (termInfo.lastUsedAt + DebugTerminalCollection.minUseDelay > now || ct.isCancellationRequested) {
return null;
}
@@ -168,6 +173,13 @@ class DebugTerminalCollection {
this._terminalInstances.set(terminal, { lastUsedAt: Date.now(), config: termConfig });
}
public free(terminal: vscode.Terminal) {
const info = this._terminalInstances.get(terminal);
if (info) {
info.lastUsedAt = -1;
}
}
public onTerminalClosed(terminal: vscode.Terminal) {
this._terminalInstances.delete(terminal);
}

View File

@@ -11,11 +11,11 @@ import { ExtensionActivationTimesBuilder } from 'vs/workbench/api/common/extHost
import { connectProxyResolver } from 'vs/workbench/services/extensions/node/proxyResolver';
import { AbstractExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService';
import { ExtHostDownloadService } from 'vs/workbench/api/node/extHostDownloadService';
import { CLIServer } from 'vs/workbench/api/node/extHostCLIServer';
import { URI } from 'vs/base/common/uri';
import { Schemas } from 'vs/base/common/network';
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { ExtensionRuntime } from 'vs/workbench/api/common/extHostTypes';
import { CLIServer } from 'vs/workbench/api/node/extHostCLIServer';
class NodeModuleRequireInterceptor extends RequireInterceptor {
@@ -23,7 +23,7 @@ class NodeModuleRequireInterceptor extends RequireInterceptor {
const that = this;
const node_module = <any>require.__$__nodeRequire('module');
const original = node_module._load;
node_module._load = function load(request: string, parent: { filename: string; }, isMain: any) {
node_module._load = function load(request: string, parent: { filename: string; }, isMain: boolean) {
for (let alternativeModuleName of that._alternatives) {
let alternative = alternativeModuleName(request);
if (alternative) {

View File

@@ -3,21 +3,20 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ILogService, DelegatedLogService, LogLevel } from 'vs/platform/log/common/log';
import { ILogService, LogService, LogLevel } from 'vs/platform/log/common/log';
import { ExtHostLogServiceShape } from 'vs/workbench/api/common/extHost.protocol';
import { ExtensionHostLogFileName } from 'vs/workbench/services/extensions/common/extensions';
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
import { Schemas } from 'vs/base/common/network';
import { SpdLogService } from 'vs/platform/log/node/spdlogService';
import { dirname } from 'vs/base/common/resources';
import { SpdLogLogger } from 'vs/platform/log/node/spdlogLog';
export class ExtHostLogService extends DelegatedLogService implements ILogService, ExtHostLogServiceShape {
export class ExtHostLogService extends LogService implements ILogService, ExtHostLogServiceShape {
constructor(
@IExtHostInitDataService initData: IExtHostInitDataService,
) {
if (initData.logFile.scheme !== Schemas.file) { throw new Error('Only file-logging supported'); }
super(new SpdLogService(ExtensionHostLogFileName, dirname(initData.logFile).fsPath, initData.logLevel));
super(new SpdLogLogger(ExtensionHostLogFileName, initData.logFile.fsPath, true, initData.logLevel));
}
$setLevel(level: LogLevel): void {

View File

@@ -7,14 +7,36 @@ import { MainThreadOutputServiceShape } from '../common/extHost.protocol';
import type * as vscode from 'vscode';
import { URI } from 'vs/base/common/uri';
import { join } from 'vs/base/common/path';
import { OutputAppender } from 'vs/workbench/services/output/node/outputAppender';
import { toLocalISOString } from 'vs/base/common/date';
import { dirExists, mkdirp } from 'vs/base/node/pfs';
import { SymlinkSupport } from 'vs/base/node/pfs';
import { promises } from 'fs';
import { AbstractExtHostOutputChannel, ExtHostPushOutputChannel, ExtHostOutputService, LazyOutputChannel } from 'vs/workbench/api/common/extHostOutput';
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
import { MutableDisposable } from 'vs/base/common/lifecycle';
import { ILogService } from 'vs/platform/log/common/log';
import { createRotatingLogger } from 'vs/platform/log/node/spdlogLog';
import { RotatingLogger } from 'spdlog';
import { ByteSize } from 'vs/platform/files/common/files';
class OutputAppender {
private appender: RotatingLogger;
constructor(name: string, readonly file: string) {
this.appender = createRotatingLogger(name, file, 30 * ByteSize.MB, 1);
this.appender.clearFormatters();
}
append(content: string): void {
this.appender.critical(content);
}
flush(): void {
this.appender.flush();
}
}
export class ExtHostOutputChannelBackedByFile extends AbstractExtHostOutputChannel {
@@ -85,9 +107,9 @@ export class ExtHostOutputService2 extends ExtHostOutputService {
private async _doCreateOutChannel(name: string): Promise<AbstractExtHostOutputChannel> {
try {
const outputDirPath = join(this._logsLocation.fsPath, `output_logging_${toLocalISOString(new Date()).replace(/-|:|\.\d+Z$/g, '')}`);
const exists = await dirExists(outputDirPath);
const exists = await SymlinkSupport.existsDirectory(outputDirPath);
if (!exists) {
await mkdirp(outputDirPath);
await promises.mkdir(outputDirPath, { recursive: true });
}
const fileName = `${this._namePool++}-${name.replace(/[\\/:\*\?"<>\|]/g, '')}`;
const file = URI.file(join(outputDirPath, `${fileName}.log`));

View File

@@ -11,8 +11,7 @@ import * as terminalEnvironment from 'vs/workbench/contrib/terminal/common/termi
import { IShellLaunchConfigDto, IShellDefinitionDto, IShellAndArgsDto } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostConfiguration, ExtHostConfigProvider, IExtHostConfiguration } from 'vs/workbench/api/common/extHostConfiguration';
import { ILogService } from 'vs/platform/log/common/log';
import { IShellLaunchConfig, ITerminalEnvironment, ITerminalLaunchError } from 'vs/workbench/contrib/terminal/common/terminal';
import { TerminalProcess } from 'vs/workbench/contrib/terminal/node/terminalProcess';
import { TerminalProcess } from 'vs/platform/terminal/node/terminalProcess';
import { ExtHostWorkspace, IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { ExtHostVariableResolverService } from 'vs/workbench/api/common/extHostDebugService';
@@ -26,6 +25,7 @@ import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitData
import { withNullAsUndefined } from 'vs/base/common/types';
import { getSystemShell, getSystemShellSync } from 'vs/base/node/shell';
import { generateUuid } from 'vs/base/common/uuid';
import { IShellLaunchConfig, ITerminalEnvironment, ITerminalLaunchError } from 'vs/platform/terminal/common/terminal';
export class ExtHostTerminalService extends BaseExtHostTerminalService {
@@ -60,7 +60,7 @@ export class ExtHostTerminalService extends BaseExtHostTerminalService {
const terminal = new ExtHostTerminal(this._proxy, generateUuid(), { name, shellPath, shellArgs }, name);
this._terminals.push(terminal);
terminal.create(shellPath, shellArgs);
return terminal;
return terminal.value;
}
public createTerminalFromOptions(options: vscode.TerminalOptions, isFeatureTerminal?: boolean): vscode.Terminal {
@@ -74,8 +74,10 @@ export class ExtHostTerminalService extends BaseExtHostTerminalService {
/*options.waitOnExit*/ undefined,
withNullAsUndefined(options.strictEnv),
withNullAsUndefined(options.hideFromUser),
withNullAsUndefined(isFeatureTerminal));
return terminal;
withNullAsUndefined(isFeatureTerminal),
true
);
return terminal.value;
}
public getDefaultShell(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string {
@@ -201,10 +203,11 @@ export class ExtHostTerminalService extends BaseExtHostTerminalService {
const envFromConfig = this._apiInspectConfigToPlain(configProvider.getConfiguration('terminal.integrated').inspect<ITerminalEnvironment>(`env.${platformKey}`));
const baseEnv = terminalConfig.get<boolean>('inheritEnv', true) ? process.env as platform.IProcessEnvironment : await this._getNonInheritedEnv();
const variableResolver = terminalEnvironment.createVariableResolver(lastActiveWorkspace, this._variableResolver);
const env = terminalEnvironment.createTerminalEnvironment(
shellLaunchConfig,
envFromConfig,
terminalEnvironment.createVariableResolver(lastActiveWorkspace, this._variableResolver),
variableResolver,
isWorkspaceShellAllowed,
this._extHostInitDataService.version,
terminalConfig.get<'auto' | 'off' | 'on'>('detectLocale', 'auto'),
@@ -212,9 +215,9 @@ export class ExtHostTerminalService extends BaseExtHostTerminalService {
);
// Apply extension environment variable collections to the environment
if (!shellLaunchConfig.strictEnv) {
if (!shellLaunchConfig.strictEnv && !shellLaunchConfig.hideFromUser) {
const mergedCollection = new MergedEnvironmentVariableCollection(this._environmentVariableCollections);
mergedCollection.applyToProcessEnvironment(env);
mergedCollection.applyToProcessEnvironment(env, variableResolver);
}
this._proxy.$sendResolvedLaunchConfig(id, shellLaunchConfig);

View File

@@ -18,7 +18,6 @@ import { IExtHostTunnelService, TunnelDto } from 'vs/workbench/api/common/extHos
import { Event, Emitter } from 'vs/base/common/event';
import { TunnelOptions, TunnelCreationOptions } from 'vs/platform/remote/common/tunnel';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { promisify } from 'util';
import { MovingAverage } from 'vs/base/common/numbers';
import { CandidatePort } from 'vs/workbench/services/remote/common/remoteExplorerService';
import { ILogService } from 'vs/platform/log/common/log';
@@ -148,7 +147,7 @@ export class ExtHostTunnelService extends Disposable implements IExtHostTunnelSe
super();
this._proxy = extHostRpc.getProxy(MainContext.MainThreadTunnelService);
if (isLinux && initData.remote.isRemote && initData.remote.authority) {
this._proxy.$setCandidateFinder();
this._proxy.$setRemoteTunnelService(process.pid);
}
}
@@ -197,6 +196,9 @@ export class ExtHostTunnelService extends Disposable implements IExtHostTunnelSe
async setTunnelExtensionFunctions(provider: vscode.RemoteAuthorityResolver | undefined): Promise<IDisposable> {
if (provider) {
if (provider.candidatePortSource !== undefined) {
await this._proxy.$setCandidatePortSource(provider.candidatePortSource);
}
if (provider.showCandidatePort) {
this._showCandidatePort = provider.showCandidatePort;
await this._proxy.$setCandidateFilter();
@@ -267,8 +269,8 @@ export class ExtHostTunnelService extends Disposable implements IExtHostTunnelSe
let tcp: string = '';
let tcp6: string = '';
try {
tcp = await pfs.readFile('/proc/net/tcp', 'utf8');
tcp6 = await pfs.readFile('/proc/net/tcp6', 'utf8');
tcp = await fs.promises.readFile('/proc/net/tcp', 'utf8');
tcp6 = await fs.promises.readFile('/proc/net/tcp6', 'utf8');
} catch (e) {
// File reading error. No additional handling needed.
}
@@ -286,10 +288,10 @@ export class ExtHostTunnelService extends Disposable implements IExtHostTunnelSe
try {
const pid: number = Number(childName);
const childUri = resources.joinPath(URI.file('/proc'), childName);
const childStat = await pfs.stat(childUri.fsPath);
const childStat = await fs.promises.stat(childUri.fsPath);
if (childStat.isDirectory() && !isNaN(pid)) {
const cwd = await promisify(fs.readlink)(resources.joinPath(childUri, 'cwd').fsPath);
const cmd = await pfs.readFile(resources.joinPath(childUri, 'cmdline').fsPath, 'utf8');
const cwd = await fs.promises.readlink(resources.joinPath(childUri, 'cwd').fsPath);
const cmd = await fs.promises.readFile(resources.joinPath(childUri, 'cmdline').fsPath, 'utf8');
processes.push({ pid, cwd, cmd });
}
} catch (e) {

View File

@@ -3,13 +3,13 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ILogService, LogLevel, AbstractLogService } from 'vs/platform/log/common/log';
import { ILogService, LogLevel, AbstractLogger } from 'vs/platform/log/common/log';
import { ExtHostLogServiceShape, MainThreadLogShape, MainContext } from 'vs/workbench/api/common/extHost.protocol';
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
import { UriComponents } from 'vs/base/common/uri';
export class ExtHostLogService extends AbstractLogService implements ILogService, ExtHostLogServiceShape {
export class ExtHostLogService extends AbstractLogger implements ILogService, ExtHostLogServiceShape {
declare readonly _serviceBrand: undefined;

View File

@@ -5,7 +5,7 @@
import 'vs/css!./media/actions';
import * as nls from 'vs/nls';
import { localize } from 'vs/nls';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { domEvent } from 'vs/base/browser/event';
import { Color } from 'vs/base/common/color';
@@ -34,7 +34,7 @@ class InspectContextKeysAction extends Action2 {
constructor() {
super({
id: 'workbench.action.inspectContextKeys',
title: { value: nls.localize('inspect context keys', "Inspect Context Keys"), original: 'Inspect Context Keys' },
title: { value: localize('inspect context keys', "Inspect Context Keys"), original: 'Inspect Context Keys' },
category: CATEGORIES.Developer,
f1: true
});
@@ -96,7 +96,7 @@ class ToggleScreencastModeAction extends Action2 {
constructor() {
super({
id: 'workbench.action.toggleScreencastMode',
title: { value: nls.localize('toggle screencast mode', "Toggle Screencast Mode"), original: 'Toggle Screencast Mode' },
title: { value: localize('toggle screencast mode', "Toggle Screencast Mode"), original: 'Toggle Screencast Mode' },
category: CATEGORIES.Developer,
f1: true
});
@@ -241,7 +241,7 @@ class LogStorageAction extends Action2 {
constructor() {
super({
id: 'workbench.action.logStorage',
title: { value: nls.localize({ key: 'logStorage', comment: ['A developer only action to log the contents of the storage for the current window.'] }, "Log Storage Database Contents"), original: 'Log Storage Database Contents' },
title: { value: localize({ key: 'logStorage', comment: ['A developer only action to log the contents of the storage for the current window.'] }, "Log Storage Database Contents"), original: 'Log Storage Database Contents' },
category: CATEGORIES.Developer,
f1: true
});
@@ -257,7 +257,7 @@ class LogWorkingCopiesAction extends Action2 {
constructor() {
super({
id: 'workbench.action.logWorkingCopies',
title: { value: nls.localize({ key: 'logWorkingCopies', comment: ['A developer only action to log the working copies that exist.'] }, "Log Working Copies"), original: 'Log Working Copies' },
title: { value: localize({ key: 'logWorkingCopies', comment: ['A developer only action to log the working copies that exist.'] }, "Log Working Copies"), original: 'Log Working Copies' },
category: CATEGORIES.Developer,
f1: true
});
@@ -291,7 +291,7 @@ const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationE
configurationRegistry.registerConfiguration({
id: 'screencastMode',
order: 9,
title: nls.localize('screencastModeConfigurationTitle', "Screencast Mode"),
title: localize('screencastModeConfigurationTitle', "Screencast Mode"),
type: 'object',
properties: {
'screencastMode.verticalOffset': {
@@ -299,18 +299,18 @@ configurationRegistry.registerConfiguration({
default: 20,
minimum: 0,
maximum: 90,
description: nls.localize('screencastMode.location.verticalPosition', "Controls the vertical offset of the screencast mode overlay from the bottom as a percentage of the workbench height.")
description: localize('screencastMode.location.verticalPosition', "Controls the vertical offset of the screencast mode overlay from the bottom as a percentage of the workbench height.")
},
'screencastMode.fontSize': {
type: 'number',
default: 56,
minimum: 20,
maximum: 100,
description: nls.localize('screencastMode.fontSize', "Controls the font size (in pixels) of the screencast mode keyboard.")
description: localize('screencastMode.fontSize', "Controls the font size (in pixels) of the screencast mode keyboard.")
},
'screencastMode.onlyKeyboardShortcuts': {
type: 'boolean',
description: nls.localize('screencastMode.onlyKeyboardShortcuts', "Only show keyboard shortcuts in screencast mode."),
description: localize('screencastMode.onlyKeyboardShortcuts', "Only show keyboard shortcuts in screencast mode."),
default: false
},
'screencastMode.keyboardOverlayTimeout': {
@@ -318,20 +318,20 @@ configurationRegistry.registerConfiguration({
default: 800,
minimum: 500,
maximum: 5000,
description: nls.localize('screencastMode.keyboardOverlayTimeout', "Controls how long (in milliseconds) the keyboard overlay is shown in screencast mode.")
description: localize('screencastMode.keyboardOverlayTimeout', "Controls how long (in milliseconds) the keyboard overlay is shown in screencast mode.")
},
'screencastMode.mouseIndicatorColor': {
type: 'string',
format: 'color-hex',
default: '#FF0000',
description: nls.localize('screencastMode.mouseIndicatorColor', "Controls the color in hex (#RGB, #RGBA, #RRGGBB or #RRGGBBAA) of the mouse indicator in screencast mode.")
description: localize('screencastMode.mouseIndicatorColor', "Controls the color in hex (#RGB, #RGBA, #RRGGBB or #RRGGBBAA) of the mouse indicator in screencast mode.")
},
'screencastMode.mouseIndicatorSize': {
type: 'number',
default: 20,
minimum: 20,
maximum: 100,
description: nls.localize('screencastMode.mouseIndicatorSize', "Controls the size (in pixels) of the mouse indicator in screencast mode.")
description: localize('screencastMode.mouseIndicatorSize', "Controls the size (in pixels) of the mouse indicator in screencast mode.")
},
}
});

View File

@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import { localize } from 'vs/nls';
import product from 'vs/platform/product/common/product';
import { isMacintosh, isLinux, language } from 'vs/base/common/platform';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
@@ -24,7 +24,7 @@ class KeybindingsReferenceAction extends Action2 {
constructor() {
super({
id: KeybindingsReferenceAction.ID,
title: { value: nls.localize('keybindingsReference', "Keyboard Shortcuts Reference"), original: 'Keyboard Shortcuts Reference' },
title: { value: localize('keybindingsReference', "Keyboard Shortcuts Reference"), original: 'Keyboard Shortcuts Reference' },
category: CATEGORIES.Help,
f1: true,
keybinding: {
@@ -54,7 +54,7 @@ class OpenDocumentationUrlAction extends Action2 {
constructor() {
super({
id: OpenDocumentationUrlAction.ID,
title: { value: nls.localize('openDocumentationUrl', "Documentation"), original: 'Documentation' },
title: { value: localize('openDocumentationUrl', "Documentation"), original: 'Documentation' },
category: CATEGORIES.Help,
f1: true
});
@@ -78,7 +78,7 @@ class OpenIntroductoryVideosUrlAction extends Action2 {
constructor() {
super({
id: OpenIntroductoryVideosUrlAction.ID,
title: { value: nls.localize('openIntroductoryVideosUrl', "Introductory Videos"), original: 'Introductory Videos' },
title: { value: localize('openIntroductoryVideosUrl', "Introductory Videos"), original: 'Introductory Videos' },
category: CATEGORIES.Help,
f1: true
});
@@ -102,7 +102,7 @@ class OpenTipsAndTricksUrlAction extends Action2 {
constructor() {
super({
id: OpenTipsAndTricksUrlAction.ID,
title: { value: nls.localize('openTipsAndTricksUrl', "Tips and Tricks"), original: 'Tips and Tricks' },
title: { value: localize('openTipsAndTricksUrl', "Tips and Tricks"), original: 'Tips and Tricks' },
category: CATEGORIES.Help,
f1: true
});
@@ -126,7 +126,7 @@ class OpenNewsletterSignupUrlAction extends Action2 {
constructor() {
super({
id: OpenNewsletterSignupUrlAction.ID,
title: { value: nls.localize('newsletterSignup', "Signup for the VS Code Newsletter"), original: 'Signup for the VS Code Newsletter' },
title: { value: localize('newsletterSignup', "Signup for the VS Code Newsletter"), original: 'Signup for the VS Code Newsletter' },
category: CATEGORIES.Help,
f1: true
});
@@ -151,7 +151,7 @@ class OpenTwitterUrlAction extends Action2 {
constructor() {
super({
id: OpenTwitterUrlAction.ID,
title: { value: nls.localize('openTwitterUrl', "Join Us on Twitter"), original: 'Join Us on Twitter' },
title: { value: localize('openTwitterUrl', "Join Us on Twitter"), original: 'Join Us on Twitter' },
category: CATEGORIES.Help,
f1: true
});
@@ -175,7 +175,7 @@ class OpenRequestFeatureUrlAction extends Action2 {
constructor() {
super({
id: OpenRequestFeatureUrlAction.ID,
title: { value: nls.localize('openUserVoiceUrl', "Search Feature Requests"), original: 'Search Feature Requests' },
title: { value: localize('openUserVoiceUrl', "Search Feature Requests"), original: 'Search Feature Requests' },
category: CATEGORIES.Help,
f1: true
});
@@ -199,7 +199,7 @@ class OpenLicenseUrlAction extends Action2 {
constructor() {
super({
id: OpenLicenseUrlAction.ID,
title: { value: nls.localize('openLicenseUrl', "View License"), original: 'View License' },
title: { value: localize('openLicenseUrl', "View License"), original: 'View License' },
category: CATEGORIES.Help,
f1: true
});
@@ -228,7 +228,7 @@ class OpenPrivacyStatementUrlAction extends Action2 {
constructor() {
super({
id: OpenPrivacyStatementUrlAction.ID,
title: { value: nls.localize('openPrivacyStatement', "Privacy Statement"), original: 'Privacy Statement' },
title: { value: localize('openPrivacyStatement', "Privacy Statement"), original: 'Privacy Statement' },
category: CATEGORIES.Help,
f1: true
});
@@ -296,7 +296,7 @@ if (OpenDocumentationUrlAction.AVAILABLE) {
group: '1_welcome',
command: {
id: OpenDocumentationUrlAction.ID,
title: nls.localize({ key: 'miDocumentation', comment: ['&& denotes a mnemonic'] }, "&&Documentation")
title: localize({ key: 'miDocumentation', comment: ['&& denotes a mnemonic'] }, "&&Documentation")
},
order: 3
});
@@ -308,7 +308,7 @@ if (KeybindingsReferenceAction.AVAILABLE) {
group: '2_reference',
command: {
id: KeybindingsReferenceAction.ID,
title: nls.localize({ key: 'miKeyboardShortcuts', comment: ['&& denotes a mnemonic'] }, "&&Keyboard Shortcuts Reference")
title: localize({ key: 'miKeyboardShortcuts', comment: ['&& denotes a mnemonic'] }, "&&Keyboard Shortcuts Reference")
},
order: 1
});
@@ -319,7 +319,7 @@ if (OpenIntroductoryVideosUrlAction.AVAILABLE) {
group: '2_reference',
command: {
id: OpenIntroductoryVideosUrlAction.ID,
title: nls.localize({ key: 'miIntroductoryVideos', comment: ['&& denotes a mnemonic'] }, "Introductory &&Videos")
title: localize({ key: 'miIntroductoryVideos', comment: ['&& denotes a mnemonic'] }, "Introductory &&Videos")
},
order: 2
});
@@ -330,7 +330,7 @@ if (OpenTipsAndTricksUrlAction.AVAILABLE) {
group: '2_reference',
command: {
id: OpenTipsAndTricksUrlAction.ID,
title: nls.localize({ key: 'miTipsAndTricks', comment: ['&& denotes a mnemonic'] }, "Tips and Tri&&cks")
title: localize({ key: 'miTipsAndTricks', comment: ['&& denotes a mnemonic'] }, "Tips and Tri&&cks")
},
order: 3
});
@@ -342,7 +342,7 @@ if (OpenTwitterUrlAction.AVAILABLE) {
group: '3_feedback',
command: {
id: OpenTwitterUrlAction.ID,
title: nls.localize({ key: 'miTwitter', comment: ['&& denotes a mnemonic'] }, "&&Join Us on Twitter")
title: localize({ key: 'miTwitter', comment: ['&& denotes a mnemonic'] }, "&&Join Us on Twitter")
},
order: 1
});
@@ -353,7 +353,7 @@ if (OpenRequestFeatureUrlAction.AVAILABLE) {
group: '3_feedback',
command: {
id: OpenRequestFeatureUrlAction.ID,
title: nls.localize({ key: 'miUserVoice', comment: ['&& denotes a mnemonic'] }, "&&Search Feature Requests")
title: localize({ key: 'miUserVoice', comment: ['&& denotes a mnemonic'] }, "&&Search Feature Requests")
},
order: 2
});
@@ -365,7 +365,7 @@ if (OpenLicenseUrlAction.AVAILABLE) {
group: '4_legal',
command: {
id: OpenLicenseUrlAction.ID,
title: nls.localize({ key: 'miLicense', comment: ['&& denotes a mnemonic'] }, "View &&License")
title: localize({ key: 'miLicense', comment: ['&& denotes a mnemonic'] }, "View &&License")
},
order: 1
});
@@ -376,7 +376,7 @@ if (OpenPrivacyStatementUrlAction.AVAILABE) {
group: '4_legal',
command: {
id: OpenPrivacyStatementUrlAction.ID,
title: nls.localize({ key: 'miPrivacyStatement', comment: ['&& denotes a mnemonic'] }, "Privac&&y Statement")
title: localize({ key: 'miPrivacyStatement', comment: ['&& denotes a mnemonic'] }, "Privac&&y Statement")
},
order: 2
});

View File

@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import { localize } from 'vs/nls';
import { Registry } from 'vs/platform/registry/common/platform';
import { Action } from 'vs/base/common/actions';
import { SyncActionDescriptor, MenuId, MenuRegistry, registerAction2, Action2 } from 'vs/platform/actions/common/actions';
@@ -33,7 +33,7 @@ class CloseSidebarAction extends Action2 {
constructor() {
super({
id: 'workbench.action.closeSidebar',
title: { value: nls.localize('closeSidebar', "Close Side Bar"), original: 'Close Side Bar' },
title: { value: localize('closeSidebar', "Close Side Bar"), original: 'Close Side Bar' },
category: CATEGORIES.View,
f1: true
});
@@ -51,7 +51,7 @@ registerAction2(CloseSidebarAction);
export class ToggleActivityBarVisibilityAction extends Action2 {
static readonly ID = 'workbench.action.toggleActivityBarVisibility';
static readonly LABEL = nls.localize('toggleActivityBar', "Toggle Activity Bar Visibility");
static readonly LABEL = localize('toggleActivityBar', "Toggle Activity Bar Visibility");
private static readonly activityBarVisibleKey = 'workbench.activityBar.visible';
@@ -81,7 +81,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
group: '2_workbench_layout',
command: {
id: ToggleActivityBarVisibilityAction.ID,
title: nls.localize({ key: 'miShowActivityBar', comment: ['&& denotes a mnemonic'] }, "Show &&Activity Bar"),
title: localize({ key: 'miShowActivityBar', comment: ['&& denotes a mnemonic'] }, "Show &&Activity Bar"),
toggled: ContextKeyExpr.equals('config.workbench.activityBar.visible', true)
},
order: 4
@@ -96,7 +96,7 @@ class ToggleCenteredLayout extends Action2 {
constructor() {
super({
id: ToggleCenteredLayout.ID,
title: { value: nls.localize('toggleCenteredLayout', "Toggle Centered Layout"), original: 'Toggle Centered Layout' },
title: { value: localize('toggleCenteredLayout', "Toggle Centered Layout"), original: 'Toggle Centered Layout' },
category: CATEGORIES.View,
f1: true
});
@@ -115,7 +115,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
group: '1_toggle_view',
command: {
id: ToggleCenteredLayout.ID,
title: nls.localize({ key: 'miToggleCenteredLayout', comment: ['&& denotes a mnemonic'] }, "&&Centered Layout"),
title: localize({ key: 'miToggleCenteredLayout', comment: ['&& denotes a mnemonic'] }, "&&Centered Layout"),
toggled: IsCenteredLayoutContext
},
order: 3
@@ -126,7 +126,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
export class ToggleSidebarPositionAction extends Action {
static readonly ID = 'workbench.action.toggleSidebarPosition';
static readonly LABEL = nls.localize('toggleSidebarPosition', "Toggle Side Bar Position");
static readonly LABEL = localize('toggleSidebarPosition', "Toggle Side Bar Position");
private static readonly sidebarPositionConfigurationKey = 'workbench.sideBar.location';
@@ -147,7 +147,7 @@ export class ToggleSidebarPositionAction extends Action {
}
static getLabel(layoutService: IWorkbenchLayoutService): string {
return layoutService.getSideBarPosition() === Position.LEFT ? nls.localize('moveSidebarRight', "Move Side Bar Right") : nls.localize('moveSidebarLeft', "Move Side Bar Left");
return layoutService.getSideBarPosition() === Position.LEFT ? localize('moveSidebarRight', "Move Side Bar Right") : localize('moveSidebarLeft', "Move Side Bar Left");
}
}
@@ -155,7 +155,7 @@ registerAction2(class extends Action2 {
constructor() {
super({
id: ToggleSidebarPositionAction.ID,
title: { value: nls.localize('toggleSidebarPosition', "Toggle Side Bar Position"), original: 'Toggle Side Bar Position' },
title: { value: localize('toggleSidebarPosition', "Toggle Side Bar Position"), original: 'Toggle Side Bar Position' },
category: CATEGORIES.View,
f1: true
});
@@ -170,7 +170,7 @@ MenuRegistry.appendMenuItems([{
group: '3_workbench_layout_move',
command: {
id: ToggleSidebarPositionAction.ID,
title: nls.localize('move sidebar right', "Move Side Bar Right")
title: localize('move sidebar right', "Move Side Bar Right")
},
when: ContextKeyExpr.and(ContextKeyExpr.notEquals('config.workbench.sideBar.location', 'right'), ContextKeyExpr.equals('viewContainerLocation', ViewContainerLocationToString(ViewContainerLocation.Sidebar))),
order: 1
@@ -181,7 +181,7 @@ MenuRegistry.appendMenuItems([{
group: '3_workbench_layout_move',
command: {
id: ToggleSidebarPositionAction.ID,
title: nls.localize('move sidebar right', "Move Side Bar Right")
title: localize('move sidebar right', "Move Side Bar Right")
},
when: ContextKeyExpr.and(ContextKeyExpr.notEquals('config.workbench.sideBar.location', 'right'), ContextKeyExpr.equals('viewLocation', ViewContainerLocationToString(ViewContainerLocation.Sidebar))),
order: 1
@@ -192,7 +192,7 @@ MenuRegistry.appendMenuItems([{
group: '3_workbench_layout_move',
command: {
id: ToggleSidebarPositionAction.ID,
title: nls.localize('move sidebar left', "Move Side Bar Left")
title: localize('move sidebar left', "Move Side Bar Left")
},
when: ContextKeyExpr.and(ContextKeyExpr.equals('config.workbench.sideBar.location', 'right'), ContextKeyExpr.equals('viewContainerLocation', ViewContainerLocationToString(ViewContainerLocation.Sidebar))),
order: 1
@@ -203,7 +203,7 @@ MenuRegistry.appendMenuItems([{
group: '3_workbench_layout_move',
command: {
id: ToggleSidebarPositionAction.ID,
title: nls.localize('move sidebar left', "Move Side Bar Left")
title: localize('move sidebar left', "Move Side Bar Left")
},
when: ContextKeyExpr.and(ContextKeyExpr.equals('config.workbench.sideBar.location', 'right'), ContextKeyExpr.equals('viewLocation', ViewContainerLocationToString(ViewContainerLocation.Sidebar))),
order: 1
@@ -214,7 +214,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
group: '3_workbench_layout_move',
command: {
id: ToggleSidebarPositionAction.ID,
title: nls.localize({ key: 'miMoveSidebarRight', comment: ['&& denotes a mnemonic'] }, "&&Move Side Bar Right")
title: localize({ key: 'miMoveSidebarRight', comment: ['&& denotes a mnemonic'] }, "&&Move Side Bar Right")
},
when: ContextKeyExpr.notEquals('config.workbench.sideBar.location', 'right'),
order: 2
@@ -224,7 +224,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
group: '3_workbench_layout_move',
command: {
id: ToggleSidebarPositionAction.ID,
title: nls.localize({ key: 'miMoveSidebarLeft', comment: ['&& denotes a mnemonic'] }, "&&Move Side Bar Left")
title: localize({ key: 'miMoveSidebarLeft', comment: ['&& denotes a mnemonic'] }, "&&Move Side Bar Left")
},
when: ContextKeyExpr.equals('config.workbench.sideBar.location', 'right'),
order: 2
@@ -234,7 +234,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
export class ToggleEditorVisibilityAction extends Action {
static readonly ID = 'workbench.action.toggleEditorVisibility';
static readonly LABEL = nls.localize('toggleEditor', "Toggle Editor Area Visibility");
static readonly LABEL = localize('toggleEditor', "Toggle Editor Area Visibility");
constructor(
id: string,
@@ -255,7 +255,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
group: '2_workbench_layout',
command: {
id: ToggleEditorVisibilityAction.ID,
title: nls.localize({ key: 'miShowEditorArea', comment: ['&& denotes a mnemonic'] }, "Show &&Editor Area"),
title: localize({ key: 'miShowEditorArea', comment: ['&& denotes a mnemonic'] }, "Show &&Editor Area"),
toggled: EditorAreaVisibleContext
},
order: 5
@@ -263,7 +263,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
group: '2_appearance',
title: nls.localize({ key: 'miAppearance', comment: ['&& denotes a mnemonic'] }, "&&Appearance"),
title: localize({ key: 'miAppearance', comment: ['&& denotes a mnemonic'] }, "&&Appearance"),
submenu: MenuId.MenubarAppearanceMenu,
order: 1
});
@@ -273,7 +273,7 @@ registerAction2(class extends Action2 {
constructor() {
super({
id: TOGGLE_SIDEBAR_VISIBILITY_ACTION_ID,
title: { value: nls.localize('toggleSidebar', "Toggle Side Bar Visibility"), original: 'Toggle Side Bar Visibility' },
title: { value: localize('toggleSidebar', "Toggle Side Bar Visibility"), original: 'Toggle Side Bar Visibility' },
category: CATEGORIES.View,
f1: true,
keybinding: {
@@ -293,7 +293,7 @@ MenuRegistry.appendMenuItems([{
group: '3_workbench_layout_move',
command: {
id: TOGGLE_SIDEBAR_VISIBILITY_ACTION_ID,
title: nls.localize('compositePart.hideSideBarLabel', "Hide Side Bar"),
title: localize('compositePart.hideSideBarLabel', "Hide Side Bar"),
},
when: ContextKeyExpr.and(SideBarVisibleContext, ContextKeyExpr.equals('viewContainerLocation', ViewContainerLocationToString(ViewContainerLocation.Sidebar))),
order: 2
@@ -304,7 +304,7 @@ MenuRegistry.appendMenuItems([{
group: '3_workbench_layout_move',
command: {
id: TOGGLE_SIDEBAR_VISIBILITY_ACTION_ID,
title: nls.localize('compositePart.hideSideBarLabel', "Hide Side Bar"),
title: localize('compositePart.hideSideBarLabel', "Hide Side Bar"),
},
when: ContextKeyExpr.and(SideBarVisibleContext, ContextKeyExpr.equals('viewLocation', ViewContainerLocationToString(ViewContainerLocation.Sidebar))),
order: 2
@@ -315,7 +315,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
group: '2_workbench_layout',
command: {
id: TOGGLE_SIDEBAR_VISIBILITY_ACTION_ID,
title: nls.localize({ key: 'miShowSidebar', comment: ['&& denotes a mnemonic'] }, "Show &&Side Bar"),
title: localize({ key: 'miShowSidebar', comment: ['&& denotes a mnemonic'] }, "Show &&Side Bar"),
toggled: SideBarVisibleContext
},
order: 1
@@ -326,7 +326,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
export class ToggleStatusbarVisibilityAction extends Action {
static readonly ID = 'workbench.action.toggleStatusbarVisibility';
static readonly LABEL = nls.localize('toggleStatusbar', "Toggle Status Bar Visibility");
static readonly LABEL = localize('toggleStatusbar', "Toggle Status Bar Visibility");
private static readonly statusbarVisibleKey = 'workbench.statusBar.visible';
@@ -353,7 +353,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
group: '2_workbench_layout',
command: {
id: ToggleStatusbarVisibilityAction.ID,
title: nls.localize({ key: 'miShowStatusbar', comment: ['&& denotes a mnemonic'] }, "Show S&&tatus Bar"),
title: localize({ key: 'miShowStatusbar', comment: ['&& denotes a mnemonic'] }, "Show S&&tatus Bar"),
toggled: ContextKeyExpr.equals('config.workbench.statusBar.visible', true)
},
order: 3
@@ -364,7 +364,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
class ToggleTabsVisibilityAction extends Action {
static readonly ID = 'workbench.action.toggleTabsVisibility';
static readonly LABEL = nls.localize('toggleTabs', "Toggle Tab Visibility");
static readonly LABEL = localize('toggleTabs', "Toggle Tab Visibility");
private static readonly tabsVisibleKey = 'workbench.editor.showTabs';
@@ -395,7 +395,7 @@ registry.registerWorkbenchAction(SyncActionDescriptor.from(ToggleTabsVisibilityA
class ToggleZenMode extends Action {
static readonly ID = 'workbench.action.toggleZenMode';
static readonly LABEL = nls.localize('toggleZenMode', "Toggle Zen Mode");
static readonly LABEL = localize('toggleZenMode', "Toggle Zen Mode");
constructor(
id: string,
@@ -416,7 +416,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
group: '1_toggle_view',
command: {
id: ToggleZenMode.ID,
title: nls.localize('miToggleZenMode', "Zen Mode"),
title: localize('miToggleZenMode', "Zen Mode"),
toggled: InEditorZenModeContext
},
order: 2
@@ -438,7 +438,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
export class ToggleMenuBarAction extends Action {
static readonly ID = 'workbench.action.toggleMenuBar';
static readonly LABEL = nls.localize('toggleMenuBar', "Toggle Menu Bar");
static readonly LABEL = localize('toggleMenuBar', "Toggle Menu Bar");
constructor(
id: string,
@@ -461,8 +461,8 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
group: '2_workbench_layout',
command: {
id: ToggleMenuBarAction.ID,
title: nls.localize({ key: 'miShowMenuBar', comment: ['&& denotes a mnemonic'] }, "Show Menu &&Bar"),
toggled: ContextKeyExpr.and(IsMacNativeContext.toNegated(), ContextKeyExpr.notEquals('config.window.menuBarVisibility', 'hidden'), ContextKeyExpr.notEquals('config.window.menuBarVisibility', 'toggle'))
title: localize({ key: 'miShowMenuBar', comment: ['&& denotes a mnemonic'] }, "Show Menu &&Bar"),
toggled: ContextKeyExpr.and(IsMacNativeContext.toNegated(), ContextKeyExpr.notEquals('config.window.menuBarVisibility', 'hidden'), ContextKeyExpr.notEquals('config.window.menuBarVisibility', 'toggle'), ContextKeyExpr.notEquals('config.window.menuBarVisibility', 'compact'))
},
when: IsMacNativeContext.toNegated(),
order: 0
@@ -472,7 +472,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
export class ResetViewLocationsAction extends Action {
static readonly ID = 'workbench.action.resetViewLocations';
static readonly LABEL = nls.localize('resetViewLocations', "Reset View Locations");
static readonly LABEL = localize('resetViewLocations', "Reset View Locations");
constructor(
id: string,
@@ -489,40 +489,10 @@ export class ResetViewLocationsAction extends Action {
registry.registerWorkbenchAction(SyncActionDescriptor.from(ResetViewLocationsAction), 'View: Reset View Locations', CATEGORIES.View.value);
// --- Toggle View with Command
export class ToggleViewAction extends Action {
constructor(
id: string,
label: string,
private readonly viewId: string,
@IViewsService protected viewsService: IViewsService,
@IViewDescriptorService protected viewDescriptorService: IViewDescriptorService,
@IContextKeyService protected contextKeyService: IContextKeyService,
@IWorkbenchLayoutService private layoutService: IWorkbenchLayoutService,
) {
super(id, label);
}
async run(): Promise<void> {
const focusedViewId = FocusedViewContext.getValue(this.contextKeyService);
if (focusedViewId === this.viewId) {
if (this.viewDescriptorService.getViewLocationById(this.viewId) === ViewContainerLocation.Sidebar) {
this.layoutService.setSideBarHidden(true);
} else {
this.layoutService.setPanelHidden(true);
}
} else {
this.viewsService.openView(this.viewId, true);
}
}
}
// --- Move View with Command
export class MoveViewAction extends Action {
static readonly ID = 'workbench.action.moveView';
static readonly LABEL = nls.localize('moveView', "Move View");
static readonly LABEL = localize('moveView', "Move View");
constructor(
id: string,
@@ -551,7 +521,7 @@ export class MoveViewAction extends Action {
if (!hasAddedView) {
results.push({
type: 'separator',
label: nls.localize('sidebarContainer', "Side Bar / {0}", containerModel.title)
label: localize('sidebarContainer', "Side Bar / {0}", containerModel.title)
});
hasAddedView = true;
}
@@ -575,7 +545,7 @@ export class MoveViewAction extends Action {
if (!hasAddedView) {
results.push({
type: 'separator',
label: nls.localize('panelContainer', "Panel / {0}", containerModel.title)
label: localize('panelContainer', "Panel / {0}", containerModel.title)
});
hasAddedView = true;
}
@@ -593,7 +563,7 @@ export class MoveViewAction extends Action {
private async getView(viewId?: string): Promise<string> {
const quickPick = this.quickInputService.createQuickPick();
quickPick.placeholder = nls.localize('moveFocusedView.selectView', "Select a View to Move");
quickPick.placeholder = localize('moveFocusedView.selectView', "Select a View to Move");
quickPick.items = this.getViewItems();
quickPick.selectedItems = quickPick.items.filter(item => (item as IQuickPickItem).id === viewId) as IQuickPickItem[];
@@ -638,7 +608,7 @@ registry.registerWorkbenchAction(SyncActionDescriptor.from(MoveViewAction), 'Vie
// --- Move Focused View with Command
export class MoveFocusedViewAction extends Action {
static readonly ID = 'workbench.action.moveFocusedView';
static readonly LABEL = nls.localize('moveFocusedView', "Move Focused View");
static readonly LABEL = localize('moveFocusedView', "Move Focused View");
constructor(
id: string,
@@ -658,19 +628,19 @@ export class MoveFocusedViewAction extends Action {
const focusedViewId = viewId || FocusedViewContext.getValue(this.contextKeyService);
if (focusedViewId === undefined || focusedViewId.trim() === '') {
this.notificationService.error(nls.localize('moveFocusedView.error.noFocusedView', "There is no view currently focused."));
this.notificationService.error(localize('moveFocusedView.error.noFocusedView', "There is no view currently focused."));
return;
}
const viewDescriptor = this.viewDescriptorService.getViewDescriptorById(focusedViewId);
if (!viewDescriptor || !viewDescriptor.canMoveView) {
this.notificationService.error(nls.localize('moveFocusedView.error.nonMovableView', "The currently focused view is not movable."));
this.notificationService.error(localize('moveFocusedView.error.nonMovableView', "The currently focused view is not movable."));
return;
}
const quickPick = this.quickInputService.createQuickPick();
quickPick.placeholder = nls.localize('moveFocusedView.selectDestination', "Select a Destination for the View");
quickPick.title = nls.localize({ key: 'moveFocusedView.title', comment: ['{0} indicates the title of the view the user has selected to move.'] }, "View: Move {0}", viewDescriptor.name);
quickPick.placeholder = localize('moveFocusedView.selectDestination', "Select a Destination for the View");
quickPick.title = localize({ key: 'moveFocusedView.title', comment: ['{0} indicates the title of the view the user has selected to move.'] }, "View: Move {0}", viewDescriptor.name);
const items: Array<IQuickPickItem | IQuickPickSeparator> = [];
const currentContainer = this.viewDescriptorService.getViewContainerByViewId(focusedViewId)!;
@@ -680,20 +650,20 @@ export class MoveFocusedViewAction extends Action {
if (!(isViewSolo && currentLocation === ViewContainerLocation.Panel)) {
items.push({
id: '_.panel.newcontainer',
label: nls.localize({ key: 'moveFocusedView.newContainerInPanel', comment: ['Creates a new top-level tab in the panel.'] }, "New Panel Entry"),
label: localize({ key: 'moveFocusedView.newContainerInPanel', comment: ['Creates a new top-level tab in the panel.'] }, "New Panel Entry"),
});
}
if (!(isViewSolo && currentLocation === ViewContainerLocation.Sidebar)) {
items.push({
id: '_.sidebar.newcontainer',
label: nls.localize('moveFocusedView.newContainerInSidebar', "New Side Bar Entry")
label: localize('moveFocusedView.newContainerInSidebar', "New Side Bar Entry")
});
}
items.push({
type: 'separator',
label: nls.localize('sidebar', "Side Bar")
label: localize('sidebar', "Side Bar")
});
const pinnedViewlets = this.activityBarService.getVisibleViewContainerIds();
@@ -708,13 +678,13 @@ export class MoveFocusedViewAction extends Action {
.map(viewletId => {
return {
id: viewletId,
label: this.viewDescriptorService.getViewContainerById(viewletId)!.name
label: this.viewDescriptorService.getViewContainerModel(this.viewDescriptorService.getViewContainerById(viewletId)!)!.title
};
}));
items.push({
type: 'separator',
label: nls.localize('panel', "Panel")
label: localize('panel', "Panel")
});
const pinnedPanels = this.panelService.getPinnedPanels();
@@ -729,7 +699,7 @@ export class MoveFocusedViewAction extends Action {
.map(panel => {
return {
id: panel.id,
label: this.viewDescriptorService.getViewContainerById(panel.id)!.name
label: this.viewDescriptorService.getViewContainerModel(this.viewDescriptorService.getViewContainerById(panel.id)!)!.title
};
}));
@@ -761,7 +731,7 @@ registry.registerWorkbenchAction(SyncActionDescriptor.from(MoveFocusedViewAction
// --- Reset View Location with Command
export class ResetFocusedViewLocationAction extends Action {
static readonly ID = 'workbench.action.resetFocusedViewLocation';
static readonly LABEL = nls.localize('resetFocusedViewLocation', "Reset Focused View Location");
static readonly LABEL = localize('resetFocusedViewLocation', "Reset Focused View Location");
constructor(
id: string,
@@ -783,7 +753,7 @@ export class ResetFocusedViewLocationAction extends Action {
}
if (!viewDescriptor) {
this.notificationService.error(nls.localize('resetFocusedView.error.noFocusedView', "There is no view currently focused."));
this.notificationService.error(localize('resetFocusedView.error.noFocusedView', "There is no view currently focused."));
return;
}
@@ -837,7 +807,7 @@ export class IncreaseViewSizeAction extends BaseResizeViewAction {
constructor() {
super({
id: 'workbench.action.increaseViewSize',
title: { value: nls.localize('increaseViewSize', "Increase Current View Size"), original: 'Increase Current View Size' },
title: { value: localize('increaseViewSize', "Increase Current View Size"), original: 'Increase Current View Size' },
f1: true
});
}
@@ -852,7 +822,7 @@ export class IncreaseViewWidthAction extends BaseResizeViewAction {
constructor() {
super({
id: 'workbench.action.increaseViewWidth',
title: { value: nls.localize('increaseEditorWidth', "Increase Editor Width"), original: 'Increase Editor Width' },
title: { value: localize('increaseEditorWidth', "Increase Editor Width"), original: 'Increase Editor Width' },
f1: true
});
}
@@ -867,7 +837,7 @@ export class IncreaseViewHeightAction extends BaseResizeViewAction {
constructor() {
super({
id: 'workbench.action.increaseViewHeight',
title: { value: nls.localize('increaseEditorHeight', "Increase Editor Height"), original: 'Increase Editor Height' },
title: { value: localize('increaseEditorHeight', "Increase Editor Height"), original: 'Increase Editor Height' },
f1: true
});
}
@@ -881,7 +851,7 @@ export class DecreaseViewSizeAction extends BaseResizeViewAction {
constructor() {
super({
id: 'workbench.action.decreaseViewSize',
title: { value: nls.localize('decreaseViewSize', "Decrease Current View Size"), original: 'Decrease Current View Size' },
title: { value: localize('decreaseViewSize', "Decrease Current View Size"), original: 'Decrease Current View Size' },
f1: true
});
}
@@ -895,7 +865,7 @@ export class DecreaseViewWidthAction extends BaseResizeViewAction {
constructor() {
super({
id: 'workbench.action.decreaseViewWidth',
title: { value: nls.localize('decreaseEditorWidth', "Decrease Editor Width"), original: 'Decrease Editor Width' },
title: { value: localize('decreaseEditorWidth', "Decrease Editor Width"), original: 'Decrease Editor Width' },
f1: true
});
}
@@ -911,7 +881,7 @@ export class DecreaseViewHeightAction extends BaseResizeViewAction {
constructor() {
super({
id: 'workbench.action.decreaseViewHeight',
title: { value: nls.localize('decreaseEditorHeight', "Decrease Editor Height"), original: 'Decrease Editor Height' },
title: { value: localize('decreaseEditorHeight', "Decrease Editor Height"), original: 'Decrease Editor Height' },
f1: true
});
}

View File

@@ -7,7 +7,7 @@ import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { List } from 'vs/base/browser/ui/list/listWidget';
import { WorkbenchListFocusContextKey, IListService, WorkbenchListSupportsMultiSelectContextKey, ListWidget, WorkbenchListHasSelectionOrFocus, getSelectionKeyboardEvent } from 'vs/platform/list/browser/listService';
import { WorkbenchListFocusContextKey, IListService, WorkbenchListSupportsMultiSelectContextKey, ListWidget, WorkbenchListHasSelectionOrFocus, getSelectionKeyboardEvent, WorkbenchListWidget } from 'vs/platform/list/browser/listService';
import { PagedList } from 'vs/base/browser/ui/list/listPaging';
import { range } from 'vs/base/common/arrays';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
@@ -16,6 +16,7 @@ import { AsyncDataTree } from 'vs/base/browser/ui/tree/asyncDataTree';
import { DataTree } from 'vs/base/browser/ui/tree/dataTree';
import { ITreeNode } from 'vs/base/browser/ui/tree/tree';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { Table } from 'vs/base/browser/ui/table/tableWidget';
function ensureDOMFocus(widget: ListWidget | undefined): void {
// it can happen that one of the commands is executed while
@@ -32,7 +33,7 @@ function focusDown(accessor: ServicesAccessor, arg2?: number, loop: boolean = fa
const count = typeof arg2 === 'number' ? arg2 : 1;
// List
if (focused instanceof List || focused instanceof PagedList) {
if (focused instanceof List || focused instanceof PagedList || focused instanceof Table) {
const list = focused;
list.focusNext(count);
@@ -71,10 +72,10 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
handler: (accessor, arg2) => focusDown(accessor, arg2)
});
function expandMultiSelection(focused: List<unknown> | PagedList<unknown> | ObjectTree<unknown, unknown> | DataTree<unknown, unknown, unknown> | AsyncDataTree<unknown, unknown, unknown>, previousFocus: unknown): void {
function expandMultiSelection(focused: WorkbenchListWidget, previousFocus: unknown): void {
// List
if (focused instanceof List || focused instanceof PagedList) {
if (focused instanceof List || focused instanceof PagedList || focused instanceof Table) {
const list = focused;
const focus = list.getFocus() ? list.getFocus()[0] : undefined;
@@ -118,7 +119,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
const focused = accessor.get(IListService).lastFocusedList;
// List / Tree
if (focused instanceof List || focused instanceof PagedList || focused instanceof ObjectTree || focused instanceof DataTree || focused instanceof AsyncDataTree) {
if (focused instanceof List || focused instanceof PagedList || focused instanceof Table || focused instanceof ObjectTree || focused instanceof DataTree || focused instanceof AsyncDataTree) {
const list = focused;
// Focus down first
@@ -136,7 +137,7 @@ function focusUp(accessor: ServicesAccessor, arg2?: number, loop: boolean = fals
const count = typeof arg2 === 'number' ? arg2 : 1;
// List
if (focused instanceof List || focused instanceof PagedList) {
if (focused instanceof List || focused instanceof PagedList || focused instanceof Table) {
const list = focused;
list.focusPrevious(count);
@@ -184,7 +185,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
const focused = accessor.get(IListService).lastFocusedList;
// List / Tree
if (focused instanceof List || focused instanceof PagedList || focused instanceof ObjectTree || focused instanceof DataTree || focused instanceof AsyncDataTree) {
if (focused instanceof List || focused instanceof PagedList || focused instanceof Table || focused instanceof ObjectTree || focused instanceof DataTree || focused instanceof AsyncDataTree) {
const list = focused;
// Focus up first
@@ -210,7 +211,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
const focused = accessor.get(IListService).lastFocusedList;
// Tree only
if (focused && !(focused instanceof List || focused instanceof PagedList)) {
if (focused && !(focused instanceof List || focused instanceof PagedList || focused instanceof Table)) {
if (focused instanceof ObjectTree || focused instanceof DataTree || focused instanceof AsyncDataTree) {
const tree = focused;
const focusedElements = tree.getFocus();
@@ -245,10 +246,10 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.UpArrow]
},
handler: (accessor) => {
const focusedTree = accessor.get(IListService).lastFocusedList;
const focused = accessor.get(IListService).lastFocusedList;
if (focusedTree && !(focusedTree instanceof List || focusedTree instanceof PagedList)) {
focusedTree.collapseAll();
if (focused && !(focused instanceof List || focused instanceof PagedList || focused instanceof Table)) {
focused.collapseAll();
}
}
});
@@ -261,7 +262,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
handler: (accessor) => {
const focused = accessor.get(IListService).lastFocusedList;
if (!focused || focused instanceof List || focused instanceof PagedList) {
if (!focused || focused instanceof List || focused instanceof PagedList || focused instanceof Table) {
return;
}
@@ -291,7 +292,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
const focused = accessor.get(IListService).lastFocusedList;
// Tree only
if (focused && !(focused instanceof List || focused instanceof PagedList)) {
if (focused && !(focused instanceof List || focused instanceof PagedList || focused instanceof Table)) {
if (focused instanceof ObjectTree || focused instanceof DataTree) {
// TODO@Joao: instead of doing this here, just delegate to a tree method
const tree = focused;
@@ -355,7 +356,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
const focused = accessor.get(IListService).lastFocusedList;
// List
if (focused instanceof List || focused instanceof PagedList) {
if (focused instanceof List || focused instanceof PagedList || focused instanceof Table) {
focused.focusPreviousPage();
}
@@ -379,7 +380,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
const focused = accessor.get(IListService).lastFocusedList;
// List
if (focused instanceof List || focused instanceof PagedList) {
if (focused instanceof List || focused instanceof PagedList || focused instanceof Table) {
focused.focusNextPage();
}
@@ -414,7 +415,7 @@ function listFocusFirst(accessor: ServicesAccessor, options?: { fromFocused: boo
const focused = accessor.get(IListService).lastFocusedList;
// List
if (focused instanceof List || focused instanceof PagedList) {
if (focused instanceof List || focused instanceof PagedList || focused instanceof Table) {
const list = focused;
list.setFocus([0]);
@@ -458,7 +459,7 @@ function listFocusLast(accessor: ServicesAccessor, options?: { fromFocused: bool
const focused = accessor.get(IListService).lastFocusedList;
// List
if (focused instanceof List || focused instanceof PagedList) {
if (focused instanceof List || focused instanceof PagedList || focused instanceof Table) {
const list = focused;
list.setFocus([list.length - 1]);
@@ -487,7 +488,7 @@ function focusElement(accessor: ServicesAccessor, retainCurrentFocus: boolean):
const focused = accessor.get(IListService).lastFocusedList;
const fakeKeyboardEvent = getSelectionKeyboardEvent('keydown', retainCurrentFocus);
// List
if (focused instanceof List || focused instanceof PagedList) {
if (focused instanceof List || focused instanceof PagedList || focused instanceof Table) {
const list = focused;
list.setSelection(list.getFocus(), fakeKeyboardEvent);
}
@@ -546,7 +547,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
const focused = accessor.get(IListService).lastFocusedList;
// List
if (focused instanceof List || focused instanceof PagedList) {
if (focused instanceof List || focused instanceof PagedList || focused instanceof Table) {
const list = focused;
const fakeKeyboardEvent = new KeyboardEvent('keydown');
list.setSelection(range(list.length), fakeKeyboardEvent);
@@ -666,7 +667,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
const focused = accessor.get(IListService).lastFocusedList;
// List
if (focused instanceof List || focused instanceof PagedList) {
if (focused instanceof List || focused instanceof PagedList || focused instanceof Table) {
const list = focused;
list.setSelection([]);
@@ -690,7 +691,7 @@ CommandsRegistry.registerCommand({
const focused = accessor.get(IListService).lastFocusedList;
// List
if (focused instanceof List || focused instanceof PagedList) {
if (focused instanceof List || focused instanceof PagedList || focused instanceof Table) {
const list = focused;
list.toggleKeyboardNavigation();
}
@@ -709,7 +710,7 @@ CommandsRegistry.registerCommand({
const focused = accessor.get(IListService).lastFocusedList;
// List
if (focused instanceof List || focused instanceof PagedList) {
if (focused instanceof List || focused instanceof PagedList || focused instanceof Table) {
// TODO@joao
}

View File

@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import { localize } from 'vs/nls';
import { Registry } from 'vs/platform/registry/common/platform';
import { Action } from 'vs/base/common/actions';
import { IEditorGroupsService, GroupDirection, GroupLocation, IFindGroupScope } from 'vs/workbench/services/editor/common/editorGroupsService';
@@ -137,7 +137,7 @@ abstract class BaseNavigationAction extends Action {
class NavigateLeftAction extends BaseNavigationAction {
static readonly ID = 'workbench.action.navigateLeft';
static readonly LABEL = nls.localize('navigateLeft', "Navigate to the View on the Left");
static readonly LABEL = localize('navigateLeft', "Navigate to the View on the Left");
constructor(
id: string,
@@ -154,7 +154,7 @@ class NavigateLeftAction extends BaseNavigationAction {
class NavigateRightAction extends BaseNavigationAction {
static readonly ID = 'workbench.action.navigateRight';
static readonly LABEL = nls.localize('navigateRight', "Navigate to the View on the Right");
static readonly LABEL = localize('navigateRight', "Navigate to the View on the Right");
constructor(
id: string,
@@ -171,7 +171,7 @@ class NavigateRightAction extends BaseNavigationAction {
class NavigateUpAction extends BaseNavigationAction {
static readonly ID = 'workbench.action.navigateUp';
static readonly LABEL = nls.localize('navigateUp', "Navigate to the View Above");
static readonly LABEL = localize('navigateUp', "Navigate to the View Above");
constructor(
id: string,
@@ -188,7 +188,7 @@ class NavigateUpAction extends BaseNavigationAction {
class NavigateDownAction extends BaseNavigationAction {
static readonly ID = 'workbench.action.navigateDown';
static readonly LABEL = nls.localize('navigateDown', "Navigate to the View Below");
static readonly LABEL = localize('navigateDown', "Navigate to the View Below");
constructor(
id: string,
@@ -214,7 +214,9 @@ function findVisibleNeighbour(layoutService: IWorkbenchLayoutService, part: Part
}
function focusNextOrPreviousPart(layoutService: IWorkbenchLayoutService, editorService: IEditorService, next: boolean): void {
const editorFocused = editorService.activeEditorPane?.hasFocus();
// Need to ask if the active editor has focus since the layoutService is not aware of some custom editor focus behavior(notebooks)
// Also need to ask the layoutService for the case if no editor is opened
const editorFocused = editorService.activeEditorPane?.hasFocus() || layoutService.hasFocus(Parts.EDITOR_PART);
const currentlyFocusedPart = editorFocused ? Parts.EDITOR_PART : layoutService.hasFocus(Parts.ACTIVITYBAR_PART) ? Parts.ACTIVITYBAR_PART :
layoutService.hasFocus(Parts.STATUSBAR_PART) ? Parts.STATUSBAR_PART : layoutService.hasFocus(Parts.SIDEBAR_PART) ? Parts.SIDEBAR_PART : layoutService.hasFocus(Parts.PANEL_PART) ? Parts.PANEL_PART : undefined;
let partToFocus = Parts.EDITOR_PART;
@@ -227,7 +229,7 @@ function focusNextOrPreviousPart(layoutService: IWorkbenchLayoutService, editorS
export class FocusNextPart extends Action {
static readonly ID = 'workbench.action.focusNextPart';
static readonly LABEL = nls.localize('focusNextPart', "Focus Next Part");
static readonly LABEL = localize('focusNextPart', "Focus Next Part");
constructor(
id: string,
@@ -245,7 +247,7 @@ export class FocusNextPart extends Action {
export class FocusPreviousPart extends Action {
static readonly ID = 'workbench.action.focusPreviousPart';
static readonly LABEL = nls.localize('focusPreviousPart', "Focus Previous Part");
static readonly LABEL = localize('focusPreviousPart', "Focus Previous Part");
constructor(
id: string,

View File

@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import { localize } from 'vs/nls';
import { Action } from 'vs/base/common/actions';
import { IWindowOpenable } from 'vs/platform/windows/common/windows';
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
@@ -46,18 +46,18 @@ abstract class BaseOpenRecentAction extends Action {
private readonly removeFromRecentlyOpened: IQuickInputButton = {
iconClass: Codicon.removeClose.classNames,
tooltip: nls.localize('remove', "Remove from Recently Opened")
tooltip: localize('remove', "Remove from Recently Opened")
};
private readonly dirtyRecentlyOpenedFolder: IQuickInputButton = {
iconClass: 'dirty-workspace ' + Codicon.closeDirty.classNames,
tooltip: nls.localize('dirtyRecentlyOpenedFolder', "Folder With Unsaved Files"),
tooltip: localize('dirtyRecentlyOpenedFolder', "Folder With Unsaved Files"),
alwaysVisible: true
};
private readonly dirtyRecentlyOpenedWorkspace: IQuickInputButton = {
...this.dirtyRecentlyOpenedFolder,
tooltip: nls.localize('dirtyRecentlyOpenedWorkspace', "Workspace With Unsaved Files"),
tooltip: localize('dirtyRecentlyOpenedWorkspace', "Workspace With Unsaved Files"),
};
constructor(
@@ -133,14 +133,14 @@ abstract class BaseOpenRecentAction extends Action {
let keyMods: IKeyMods | undefined;
const workspaceSeparator: IQuickPickSeparator = { type: 'separator', label: hasWorkspaces ? nls.localize('workspacesAndFolders', "folders & workspaces") : nls.localize('folders', "folders") };
const fileSeparator: IQuickPickSeparator = { type: 'separator', label: nls.localize('files', "files") };
const workspaceSeparator: IQuickPickSeparator = { type: 'separator', label: hasWorkspaces ? localize('workspacesAndFolders', "folders & workspaces") : localize('folders', "folders") };
const fileSeparator: IQuickPickSeparator = { type: 'separator', label: localize('files', "files") };
const picks = [workspaceSeparator, ...workspacePicks, fileSeparator, ...filePicks];
const pick = await this.quickInputService.pick(picks, {
contextKey: inRecentFilesPickerContextKey,
activeItem: [...workspacePicks, ...filePicks][autoFocusSecondEntry ? 1 : 0],
placeHolder: isMacintosh ? nls.localize('openRecentPlaceholderMac', "Select to open (hold Cmd-key to force new window or Alt-key for same window)") : nls.localize('openRecentPlaceholder', "Select to open (hold Ctrl-key to force new window or Alt-key for same window)"),
placeHolder: isMacintosh ? localize('openRecentPlaceholderMac', "Select to open (hold Cmd-key to force new window or Alt-key for same window)") : localize('openRecentPlaceholder', "Select to open (hold Ctrl-key to force new window or Alt-key for same window)"),
matchOnDescription: true,
onKeyMods: mods => keyMods = mods,
quickNavigate: this.isQuickNavigate() ? { keybindings: this.keybindingService.lookupKeybindings(this.id) } : undefined,
@@ -157,9 +157,9 @@ abstract class BaseOpenRecentAction extends Action {
const isDirtyWorkspace = context.button === this.dirtyRecentlyOpenedWorkspace;
const result = await this.dialogService.confirm({
type: 'question',
title: isDirtyWorkspace ? nls.localize('dirtyWorkspace', "Workspace with Unsaved Files") : nls.localize('dirtyFolder', "Folder with Unsaved Files"),
message: isDirtyWorkspace ? nls.localize('dirtyWorkspaceConfirm', "Do you want to open the workspace to review the unsaved files?") : nls.localize('dirtyFolderConfirm', "Do you want to open the folder to review the unsaved files?"),
detail: isDirtyWorkspace ? nls.localize('dirtyWorkspaceConfirmDetail', "Workspaces with unsaved files cannot be removed until all unsaved files have been saved or reverted.") : nls.localize('dirtyFolderConfirmDetail', "Folders with unsaved files cannot be removed until all unsaved files have been saved or reverted.")
title: isDirtyWorkspace ? localize('dirtyWorkspace', "Workspace with Unsaved Files") : localize('dirtyFolder', "Folder with Unsaved Files"),
message: isDirtyWorkspace ? localize('dirtyWorkspaceConfirm', "Do you want to open the workspace to review the unsaved files?") : localize('dirtyFolderConfirm', "Do you want to open the folder to review the unsaved files?"),
detail: isDirtyWorkspace ? localize('dirtyWorkspaceConfirmDetail', "Workspaces with unsaved files cannot be removed until all unsaved files have been saved or reverted.") : localize('dirtyFolderConfirmDetail', "Folders with unsaved files cannot be removed until all unsaved files have been saved or reverted.")
});
if (result.confirmed) {
@@ -212,7 +212,7 @@ abstract class BaseOpenRecentAction extends Action {
return {
iconClasses,
label: name,
ariaLabel: isDirty ? isWorkspace ? nls.localize('recentDirtyWorkspaceAriaLabel', "{0}, workspace with unsaved changes", name) : nls.localize('recentDirtyFolderAriaLabel', "{0}, folder with unsaved changes", name) : name,
ariaLabel: isDirty ? isWorkspace ? localize('recentDirtyWorkspaceAriaLabel', "{0}, workspace with unsaved changes", name) : localize('recentDirtyFolderAriaLabel', "{0}, folder with unsaved changes", name) : name,
description: parentPath,
buttons: isDirty ? [isWorkspace ? this.dirtyRecentlyOpenedWorkspace : this.dirtyRecentlyOpenedFolder] : [this.removeFromRecentlyOpened],
openable,
@@ -224,7 +224,7 @@ abstract class BaseOpenRecentAction extends Action {
export class OpenRecentAction extends BaseOpenRecentAction {
static readonly ID = 'workbench.action.openRecent';
static readonly LABEL = nls.localize('openRecent', "Open Recent...");
static readonly LABEL = localize('openRecent', "Open Recent...");
constructor(
id: string,
@@ -250,7 +250,7 @@ export class OpenRecentAction extends BaseOpenRecentAction {
class QuickPickRecentAction extends BaseOpenRecentAction {
static readonly ID = 'workbench.action.quickOpenRecent';
static readonly LABEL = nls.localize('quickOpenRecent', "Quick Open Recent...");
static readonly LABEL = localize('quickOpenRecent', "Quick Open Recent...");
constructor(
id: string,
@@ -276,7 +276,7 @@ class QuickPickRecentAction extends BaseOpenRecentAction {
class ToggleFullScreenAction extends Action {
static readonly ID = 'workbench.action.toggleFullScreen';
static readonly LABEL = nls.localize('toggleFullScreen', "Toggle Full Screen");
static readonly LABEL = localize('toggleFullScreen', "Toggle Full Screen");
constructor(
id: string,
@@ -294,7 +294,7 @@ class ToggleFullScreenAction extends Action {
export class ReloadWindowAction extends Action {
static readonly ID = 'workbench.action.reloadWindow';
static readonly LABEL = nls.localize('reloadWindow', "Reload Window");
static readonly LABEL = localize('reloadWindow', "Reload Window");
constructor(
id: string,
@@ -314,7 +314,7 @@ export class ReloadWindowAction extends Action {
class ShowAboutDialogAction extends Action {
static readonly ID = 'workbench.action.showAboutDialog';
static readonly LABEL = nls.localize('about', "About");
static readonly LABEL = localize('about', "About");
constructor(
id: string,
@@ -332,7 +332,7 @@ class ShowAboutDialogAction extends Action {
export class NewWindowAction extends Action {
static readonly ID = 'workbench.action.newWindow';
static readonly LABEL = nls.localize('newWindow', "New Window");
static readonly LABEL = localize('newWindow', "New Window");
constructor(
id: string,
@@ -352,7 +352,7 @@ class BlurAction extends Action2 {
constructor() {
super({
id: 'workbench.action.blur',
title: nls.localize('blur', "Remove keyboard focus from focused element")
title: localize('blur', "Remove keyboard focus from focused element")
});
}
@@ -369,7 +369,7 @@ const registry = Registry.as<IWorkbenchActionRegistry>(Extensions.WorkbenchActio
// --- Actions Registration
const fileCategory = nls.localize('file', "File");
const fileCategory = localize('file', "File");
registry.registerWorkbenchAction(SyncActionDescriptor.from(NewWindowAction, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_N }), 'New Window');
registry.registerWorkbenchAction(SyncActionDescriptor.from(QuickPickRecentAction), 'File: Quick Open Recent...', fileCategory);
registry.registerWorkbenchAction(SyncActionDescriptor.from(OpenRecentAction, { primary: KeyMod.CtrlCmd | KeyCode.KEY_R, mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_R } }), 'File: Open Recent...', fileCategory);
@@ -426,7 +426,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, {
group: 'z_ConfirmClose',
command: {
id: 'workbench.action.toggleConfirmBeforeClose',
title: nls.localize('miConfirmClose', "Confirm Before Close"),
title: localize('miConfirmClose', "Confirm Before Close"),
toggled: ContextKeyExpr.notEquals('config.window.confirmBeforeClose', 'never')
},
order: 1,
@@ -437,13 +437,13 @@ MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, {
group: '1_new',
command: {
id: NewWindowAction.ID,
title: nls.localize({ key: 'miNewWindow', comment: ['&& denotes a mnemonic'] }, "New &&Window")
title: localize({ key: 'miNewWindow', comment: ['&& denotes a mnemonic'] }, "New &&Window")
},
order: 2
});
MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, {
title: nls.localize({ key: 'miOpenRecent', comment: ['&& denotes a mnemonic'] }, "Open &&Recent"),
title: localize({ key: 'miOpenRecent', comment: ['&& denotes a mnemonic'] }, "Open &&Recent"),
submenu: MenuId.MenubarRecentMenu,
group: '2_open',
order: 4
@@ -453,7 +453,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarRecentMenu, {
group: 'y_more',
command: {
id: OpenRecentAction.ID,
title: nls.localize({ key: 'miMore', comment: ['&& denotes a mnemonic'] }, "&&More...")
title: localize({ key: 'miMore', comment: ['&& denotes a mnemonic'] }, "&&More...")
},
order: 1
});
@@ -462,7 +462,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
group: '1_toggle_view',
command: {
id: ToggleFullScreenAction.ID,
title: nls.localize({ key: 'miToggleFullScreen', comment: ['&& denotes a mnemonic'] }, "&&Full Screen"),
title: localize({ key: 'miToggleFullScreen', comment: ['&& denotes a mnemonic'] }, "&&Full Screen"),
toggled: IsFullscreenContext
},
order: 1
@@ -472,7 +472,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, {
group: 'z_about',
command: {
id: ShowAboutDialogAction.ID,
title: nls.localize({ key: 'miAbout', comment: ['&& denotes a mnemonic'] }, "&&About")
title: localize({ key: 'miAbout', comment: ['&& denotes a mnemonic'] }, "&&About")
},
order: 1,
when: IsMacNativeContext.toNegated()

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { Action } from 'vs/base/common/actions';
import * as nls from 'vs/nls';
import { localize } from 'vs/nls';
import { ITelemetryData } from 'vs/platform/telemetry/common/telemetry';
import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { IWorkspaceEditingService } from 'vs/workbench/services/workspaces/common/workspaceEditing';
@@ -12,9 +12,9 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic
import { ICommandService, CommandsRegistry } from 'vs/platform/commands/common/commands';
import { ADD_ROOT_FOLDER_COMMAND_ID, ADD_ROOT_FOLDER_LABEL, PICK_WORKSPACE_FOLDER_COMMAND_ID } from 'vs/workbench/browser/actions/workspaceCommands';
import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs';
import { MenuRegistry, MenuId, SyncActionDescriptor } from 'vs/platform/actions/common/actions';
import { MenuRegistry, MenuId, SyncActionDescriptor, Action2, registerAction2 } from 'vs/platform/actions/common/actions';
import { EmptyWorkspaceSupportContext, WorkbenchStateContext, WorkspaceFolderCountContext } from 'vs/workbench/browser/contextkeys';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { Registry } from 'vs/platform/registry/common/platform';
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions';
import { INotificationService } from 'vs/platform/notification/common/notification';
@@ -23,11 +23,12 @@ import { KeyChord, KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { IWorkspacesService, hasWorkspaceFileExtension } from 'vs/platform/workspaces/common/workspaces';
import { WORKSPACE_TRUST_ENABLED } from 'vs/workbench/services/workspaces/common/workspaceTrust';
export class OpenFileAction extends Action {
static readonly ID = 'workbench.action.files.openFile';
static readonly LABEL = nls.localize('openFile', "Open File...");
static readonly LABEL = localize('openFile', "Open File...");
constructor(
id: string,
@@ -45,7 +46,7 @@ export class OpenFileAction extends Action {
export class OpenFolderAction extends Action {
static readonly ID = 'workbench.action.files.openFolder';
static readonly LABEL = nls.localize('openFolder', "Open Folder...");
static readonly LABEL = localize('openFolder', "Open Folder...");
constructor(
id: string,
@@ -63,7 +64,7 @@ export class OpenFolderAction extends Action {
export class OpenFileFolderAction extends Action {
static readonly ID = 'workbench.action.files.openFileFolder';
static readonly LABEL = nls.localize('openFileFolder', "Open...");
static readonly LABEL = localize('openFileFolder', "Open...");
constructor(
id: string,
@@ -81,7 +82,7 @@ export class OpenFileFolderAction extends Action {
export class OpenWorkspaceAction extends Action {
static readonly ID = 'workbench.action.openWorkspace';
static readonly LABEL = nls.localize('openWorkspaceAction', "Open Workspace...");
static readonly LABEL = localize('openWorkspaceAction', "Open Workspace...");
constructor(
id: string,
@@ -99,7 +100,7 @@ export class OpenWorkspaceAction extends Action {
export class CloseWorkspaceAction extends Action {
static readonly ID = 'workbench.action.closeFolder';
static readonly LABEL = nls.localize('closeWorkspace', "Close Workspace");
static readonly LABEL = localize('closeWorkspace', "Close Workspace");
constructor(
id: string,
@@ -114,7 +115,7 @@ export class CloseWorkspaceAction extends Action {
async run(): Promise<void> {
if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) {
this.notificationService.info(nls.localize('noWorkspaceOrFolderOpened', "There is currently no workspace or folder opened in this instance to close."));
this.notificationService.info(localize('noWorkspaceOrFolderOpened', "There is currently no workspace or folder opened in this instance to close."));
return;
}
@@ -125,7 +126,7 @@ export class CloseWorkspaceAction extends Action {
export class OpenWorkspaceConfigFileAction extends Action {
static readonly ID = 'workbench.action.openWorkspaceConfigFile';
static readonly LABEL = nls.localize('openWorkspaceConfigFile', "Open Workspace Configuration File");
static readonly LABEL = localize('openWorkspaceConfigFile', "Open Workspace Configuration File");
constructor(
id: string,
@@ -167,7 +168,7 @@ export class AddRootFolderAction extends Action {
export class GlobalRemoveRootFolderAction extends Action {
static readonly ID = 'workbench.action.removeRootFolder';
static readonly LABEL = nls.localize('globalRemoveFolderFromWorkspace', "Remove Folder from Workspace...");
static readonly LABEL = localize('globalRemoveFolderFromWorkspace', "Remove Folder from Workspace...");
constructor(
id: string,
@@ -195,7 +196,7 @@ export class GlobalRemoveRootFolderAction extends Action {
export class SaveWorkspaceAsAction extends Action {
static readonly ID = 'workbench.action.saveWorkspaceAs';
static readonly LABEL = nls.localize('saveWorkspaceAsAction', "Save Workspace As...");
static readonly LABEL = localize('saveWorkspaceAsAction', "Save Workspace As...");
constructor(
id: string,
@@ -225,7 +226,7 @@ export class SaveWorkspaceAsAction extends Action {
export class DuplicateWorkspaceInNewWindowAction extends Action {
static readonly ID = 'workbench.action.duplicateWorkspaceInNewWindow';
static readonly LABEL = nls.localize('duplicateWorkspaceInNewWindow', "Duplicate As Workspace in New Window");
static readonly LABEL = localize('duplicateWorkspaceInNewWindow', "Duplicate As Workspace in New Window");
constructor(
id: string,
@@ -250,10 +251,29 @@ export class DuplicateWorkspaceInNewWindowAction extends Action {
}
}
class WorkspaceTrustManageAction extends Action2 {
constructor() {
super({
id: 'workbench.action.manageTrust',
title: { value: localize('manageTrustAction', "Manage Workspace Trust"), original: 'Manage Workspace Trust' },
precondition: ContextKeyExpr.equals(`config.${WORKSPACE_TRUST_ENABLED}`, true),
category: localize('workspacesCategory', "Workspaces"),
f1: true
});
}
async run(accessor: ServicesAccessor) {
const commandService = accessor.get(ICommandService);
await commandService.executeCommand('workbench.trust.manage');
}
}
registerAction2(WorkspaceTrustManageAction);
// --- Actions Registration
const registry = Registry.as<IWorkbenchActionRegistry>(Extensions.WorkbenchActions);
const workspacesCategory = nls.localize('workspaces', "Workspaces");
const workspacesCategory = localize('workspaces', "Workspaces");
registry.registerWorkbenchAction(SyncActionDescriptor.from(AddRootFolderAction), 'Workspaces: Add Folder to Workspace...', workspacesCategory);
registry.registerWorkbenchAction(SyncActionDescriptor.from(GlobalRemoveRootFolderAction), 'Workspaces: Remove Folder from Workspace...', workspacesCategory);
@@ -271,7 +291,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, {
group: '3_workspace',
command: {
id: ADD_ROOT_FOLDER_COMMAND_ID,
title: nls.localize({ key: 'miAddFolderToWorkspace', comment: ['&& denotes a mnemonic'] }, "A&&dd Folder to Workspace...")
title: localize({ key: 'miAddFolderToWorkspace', comment: ['&& denotes a mnemonic'] }, "A&&dd Folder to Workspace...")
},
order: 1
});
@@ -280,7 +300,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, {
group: '3_workspace',
command: {
id: SaveWorkspaceAsAction.ID,
title: nls.localize('miSaveWorkspaceAs', "Save Workspace As...")
title: localize('miSaveWorkspaceAs', "Save Workspace As...")
},
order: 2,
when: EmptyWorkspaceSupportContext
@@ -298,7 +318,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, {
group: '6_close',
command: {
id: CloseWorkspaceAction.ID,
title: nls.localize({ key: 'miCloseFolder', comment: ['&& denotes a mnemonic'] }, "Close &&Folder"),
title: localize({ key: 'miCloseFolder', comment: ['&& denotes a mnemonic'] }, "Close &&Folder"),
precondition: WorkspaceFolderCountContext.notEqualsTo('0')
},
order: 3,
@@ -309,7 +329,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, {
group: '6_close',
command: {
id: CloseWorkspaceAction.ID,
title: nls.localize({ key: 'miCloseWorkspace', comment: ['&& denotes a mnemonic'] }, "Close &&Workspace")
title: localize({ key: 'miCloseWorkspace', comment: ['&& denotes a mnemonic'] }, "Close &&Workspace")
},
order: 3,
when: ContextKeyExpr.and(WorkbenchStateContext.isEqualTo('workspace'), EmptyWorkspaceSupportContext)

View File

@@ -3,10 +3,10 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import { localize } from 'vs/nls';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { IWorkspaceEditingService } from 'vs/workbench/services/workspaces/common/workspaceEditing';
import * as resources from 'vs/base/common/resources';
import { dirname, removeTrailingPathSeparator } from 'vs/base/common/resources';
import { CancellationToken } from 'vs/base/common/cancellation';
import { mnemonicButtonLabel } from 'vs/base/common/labels';
import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands';
@@ -24,7 +24,7 @@ import { IOpenWindowOptions, IWindowOpenable } from 'vs/platform/windows/common/
import { hasWorkspaceFileExtension } from 'vs/platform/workspaces/common/workspaces';
export const ADD_ROOT_FOLDER_COMMAND_ID = 'addRootFolder';
export const ADD_ROOT_FOLDER_LABEL = nls.localize('addFolderToWorkspace', "Add Folder to Workspace...");
export const ADD_ROOT_FOLDER_LABEL = localize('addFolderToWorkspace', "Add Folder to Workspace...");
export const PICK_WORKSPACE_FOLDER_COMMAND_ID = '_workbench.pickWorkspaceFolder';
@@ -61,8 +61,8 @@ CommandsRegistry.registerCommand({
const workspaceEditingService = accessor.get(IWorkspaceEditingService);
const dialogsService = accessor.get(IFileDialogService);
const folders = await dialogsService.showOpenDialog({
openLabel: mnemonicButtonLabel(nls.localize({ key: 'add', comment: ['&& denotes a mnemonic'] }, "&&Add")),
title: nls.localize('addFolderToWorkspaceTitle', "Add Folder to Workspace"),
openLabel: mnemonicButtonLabel(localize({ key: 'add', comment: ['&& denotes a mnemonic'] }, "&&Add")),
title: localize('addFolderToWorkspaceTitle', "Add Folder to Workspace"),
canSelectFolders: true,
canSelectMany: true,
defaultUri: await dialogsService.defaultFolderPath()
@@ -72,7 +72,7 @@ CommandsRegistry.registerCommand({
return;
}
await workspaceEditingService.addFolders(folders.map(folder => ({ uri: resources.removeTrailingPathSeparator(folder) })));
await workspaceEditingService.addFolders(folders.map(folder => ({ uri: removeTrailingPathSeparator(folder) })));
}
});
@@ -91,7 +91,7 @@ CommandsRegistry.registerCommand(PICK_WORKSPACE_FOLDER_COMMAND_ID, async functio
const folderPicks: IQuickPickItem[] = folders.map(folder => {
return {
label: folder.name,
description: labelService.getUriLabel(resources.dirname(folder.uri), { relative: true }),
description: labelService.getUriLabel(dirname(folder.uri), { relative: true }),
folder,
iconClasses: getIconClasses(modelService, modeService, folder.uri, FileKind.ROOT_FOLDER)
};
@@ -104,7 +104,7 @@ CommandsRegistry.registerCommand(PICK_WORKSPACE_FOLDER_COMMAND_ID, async functio
}
if (!options.placeHolder) {
options.placeHolder = nls.localize('workspaceFolderPickerPlaceholder', "Select workspace folder");
options.placeHolder = localize('workspaceFolderPickerPlaceholder', "Select workspace folder");
}
if (typeof options.matchOnDescription !== 'boolean') {
@@ -159,7 +159,7 @@ CommandsRegistry.registerCommand({
description: 'Open a folder or workspace in the current window or new window depending on the newWindow argument. Note that opening in the same window will shutdown the current extension host process and start a new one on the given folder/workspace unless the newWindow parameter is set to true.',
args: [
{ name: 'uri', description: '(optional) Uri of the folder or workspace file to open. If not provided, a native dialog will ask the user for the folder', constraint: (value: any) => value === undefined || value instanceof URI },
{ name: 'options', description: '(optional) Options. Object with the following properties: `forceNewWindow `: Whether to open the folder/workspace in a new window or the same. Defaults to opening in the same window. `noRecentEntry`: Wheter the opened URI will appear in the \'Open Recent\' list. Defaults to true. Note, for backward compatibility, options can also be of type boolean, representing the `forceNewWindow` setting.', constraint: (value: any) => value === undefined || typeof value === 'object' || typeof value === 'boolean' }
{ name: 'options', description: '(optional) Options. Object with the following properties: `forceNewWindow `: Whether to open the folder/workspace in a new window or the same. Defaults to opening in the same window. `noRecentEntry`: Whether the opened URI will appear in the \'Open Recent\' list. Defaults to true. Note, for backward compatibility, options can also be of type boolean, representing the `forceNewWindow` setting.', constraint: (value: any) => value === undefined || typeof value === 'object' || typeof value === 'boolean' }
]
}
});

View File

@@ -47,7 +47,7 @@ export class RangeHighlightDecorations extends Disposable {
}
removeHighlightRange() {
if (this.editor && this.editor.getModel() && this.rangeHighlightDecorationId) {
if (this.editor?.getModel() && this.rangeHighlightDecorationId) {
this.editor.deltaDecorations([this.rangeHighlightDecorationId], []);
this._onHighlightRemoved.fire();
}
@@ -76,7 +76,7 @@ export class RangeHighlightDecorations extends Disposable {
private getEditor(resourceRange: IRangeHighlightDecoration): ICodeEditor | undefined {
const activeEditor = this.editorService.activeEditor;
const resource = activeEditor && activeEditor.resource;
const resource = activeEditor?.resource;
if (resource && isEqual(resource, resourceRange.resource)) {
return this.editorService.activeTextEditorControl as ICodeEditor;
}
@@ -124,7 +124,7 @@ export class RangeHighlightDecorations extends Disposable {
dispose() {
super.dispose();
if (this.editor && this.editor.getModel()) {
if (this.editor?.getModel()) {
this.removeHighlightRange();
this.editor = null;
}

View File

@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IAction, IActionRunner, ActionRunner, IActionViewItem } from 'vs/base/common/actions';
import { IAction, IActionRunner, ActionRunner } from 'vs/base/common/actions';
import { Component } from 'vs/workbench/common/component';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IComposite, ICompositeControl } from 'vs/workbench/common/composite';
@@ -14,6 +14,7 @@ import { trackFocus, Dimension } from 'vs/base/browser/dom';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { Disposable } from 'vs/base/common/lifecycle';
import { assertIsDefined } from 'vs/base/common/types';
import { IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
/**
* Composites are layed out in the sidebar and panel part of the workbench. At a time only one composite

View File

@@ -3,6 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { localize } from 'vs/nls';
import { Event } from 'vs/base/common/event';
import { Disposable } from 'vs/base/common/lifecycle';
import { IContextKeyService, IContextKey, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
@@ -22,18 +23,18 @@ import { getRemoteName } from 'vs/platform/remote/common/remoteHosts';
import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService';
import { isNative } from 'vs/base/common/platform';
export const WorkbenchStateContext = new RawContextKey<string>('workbenchState', undefined);
export const WorkspaceFolderCountContext = new RawContextKey<number>('workspaceFolderCount', 0);
export const EmptyWorkspaceSupportContext = new RawContextKey<boolean>('emptyWorkspaceSupport', true);
export const WorkbenchStateContext = new RawContextKey<string>('workbenchState', undefined, { type: 'string', description: localize('workbenchState', "The kind of workspace opened in the window, either 'empty' (no workspace), 'folder' (single folder) or 'workspace' (multi-root workspace)") });
export const WorkspaceFolderCountContext = new RawContextKey<number>('workspaceFolderCount', 0, localize('workspaceFolderCount', "The number of root folders in the workspace"));
export const EmptyWorkspaceSupportContext = new RawContextKey<boolean>('emptyWorkspaceSupport', true, true);
export const DirtyWorkingCopiesContext = new RawContextKey<boolean>('dirtyWorkingCopies', false);
export const DirtyWorkingCopiesContext = new RawContextKey<boolean>('dirtyWorkingCopies', false, localize('dirtyWorkingCopies', "Wether there are any dirty working copies"));
export const RemoteNameContext = new RawContextKey<string>('remoteName', '');
export const RemoteNameContext = new RawContextKey<string>('remoteName', '', localize('remoteName', "The name of the remote the window is connected to or an empty string if not connected to any remote"));
export const IsFullscreenContext = new RawContextKey<boolean>('isFullscreen', false);
export const IsFullscreenContext = new RawContextKey<boolean>('isFullscreen', false, localize('isFullscreen', "Whether the window is in fullscreen mode"));
// Support for FileSystemAccess web APIs (https://wicg.github.io/file-system-access)
export const HasWebFileSystemAccess = new RawContextKey<boolean>('hasWebFileSystemAccess', false);
export const HasWebFileSystemAccess = new RawContextKey<boolean>('hasWebFileSystemAccess', false, true);
export class WorkbenchContextKeysHandler extends Disposable {
private inputFocusedContext: IContextKey<boolean>;
@@ -167,7 +168,7 @@ export class WorkbenchContextKeysHandler extends Disposable {
this._register(this.editorGroupService.onDidAddGroup(() => this.updateEditorContextKeys()));
this._register(this.editorGroupService.onDidRemoveGroup(() => this.updateEditorContextKeys()));
this._register(this.editorGroupService.onDidGroupIndexChange(() => this.updateEditorContextKeys()));
this._register(this.editorGroupService.onDidChangeGroupIndex(() => this.updateEditorContextKeys()));
this._register(addDisposableListener(window, EventType.FOCUS_IN, () => this.updateInputContextKeys(), true));
@@ -180,15 +181,15 @@ export class WorkbenchContextKeysHandler extends Disposable {
}
}));
this._register(this.layoutService.onZenModeChange(enabled => this.inZenModeContext.set(enabled)));
this._register(this.layoutService.onFullscreenChange(fullscreen => this.isFullscreenContext.set(fullscreen)));
this._register(this.layoutService.onCenteredLayoutChange(centered => this.isCenteredLayoutContext.set(centered)));
this._register(this.layoutService.onPanelPositionChange(position => this.panelPositionContext.set(position)));
this._register(this.layoutService.onDidChangeZenMode(enabled => this.inZenModeContext.set(enabled)));
this._register(this.layoutService.onDidChangeFullscreen(fullscreen => this.isFullscreenContext.set(fullscreen)));
this._register(this.layoutService.onDidChangeCenteredLayout(centered => this.isCenteredLayoutContext.set(centered)));
this._register(this.layoutService.onDidChangePanelPosition(position => this.panelPositionContext.set(position)));
this._register(this.viewletService.onDidViewletClose(() => this.updateSideBarContextKeys()));
this._register(this.viewletService.onDidViewletOpen(() => this.updateSideBarContextKeys()));
this._register(this.layoutService.onPartVisibilityChange(() => {
this._register(this.layoutService.onDidChangePartVisibility(() => {
this.editorAreaVisibleContext.set(this.layoutService.isVisible(Parts.EDITOR_PART));
this.panelVisibleContext.set(this.layoutService.isVisible(Parts.PANEL_PART));
this.panelMaximizedContext.set(this.layoutService.isPanelMaximized());

View File

@@ -582,7 +582,7 @@ export class CompositeDragAndDropObserver extends Disposable {
const id = e.dragAndDropData.getData().id;
const type = e.dragAndDropData.getData().type;
const data = this.readDragData(type);
if (data && data.getData().id === id) {
if (data?.getData().id === id) {
this.transferData.clearData(type === 'view' ? DraggedViewIdentifier.prototype : DraggedCompositeIdentifier.prototype);
}
}));

View File

@@ -3,6 +3,8 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { localize } from 'vs/nls';
import { Event } from 'vs/base/common/event';
import { EditorInput } from 'vs/workbench/common/editor';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { Registry } from 'vs/platform/registry/common/platform';
@@ -10,9 +12,27 @@ import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane';
import { IConstructorSignature0, IInstantiationService, BrandedService } from 'vs/platform/instantiation/common/instantiation';
import { insert } from 'vs/base/common/arrays';
import { IDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { IJSONSchema } from 'vs/base/common/jsonSchema';
import { workbenchConfigurationNodeBase } from 'vs/workbench/common/configuration';
import { Extensions as ConfigurationExtensions, IConfigurationNode, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';
export const Extensions = {
Editors: 'workbench.contributions.editors',
Associations: 'workbench.editors.associations'
};
//#region Editors Registry
export interface IEditorDescriptor {
/**
* The unique identifier of the editor
*/
getId(): string;
/**
* The display name of the editor
*/
getName(): string;
instantiate(instantiationService: IInstantiationService): EditorPane;
@@ -174,8 +194,137 @@ class EditorRegistry implements IEditorRegistry {
}
}
export const Extensions = {
Editors: 'workbench.contributions.editors'
Registry.add(Extensions.Editors, new EditorRegistry());
//#endregion
//#region Editor Associations
export const editorsAssociationsSettingId = 'workbench.editorAssociations';
export const DEFAULT_EDITOR_ASSOCIATION: IEditorType = {
id: 'default',
displayName: localize('promptOpenWith.defaultEditor.displayName', "Text Editor"),
providerDisplayName: localize('builtinProviderDisplayName', "Built-in")
};
Registry.add(Extensions.Editors, new EditorRegistry());
export type EditorAssociation = {
readonly viewType: string;
readonly filenamePattern?: string;
};
export type EditorsAssociations = readonly EditorAssociation[];
const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);
const editorTypeSchemaAddition: IJSONSchema = {
type: 'string',
enum: []
};
const editorAssociationsConfigurationNode: IConfigurationNode = {
...workbenchConfigurationNodeBase,
properties: {
'workbench.editorAssociations': {
type: 'array',
markdownDescription: localize('editor.editorAssociations', "Configure which editor to use for specific file types."),
items: {
type: 'object',
defaultSnippets: [{
body: {
'viewType': '$1',
'filenamePattern': '$2'
}
}],
properties: {
'viewType': {
anyOf: [
{
type: 'string',
description: localize('editor.editorAssociations.viewType', "The unique id of the editor to use."),
},
editorTypeSchemaAddition
]
},
'filenamePattern': {
type: 'string',
description: localize('editor.editorAssociations.filenamePattern', "Glob pattern specifying which files the editor should be used for."),
}
}
}
}
}
};
export interface IEditorType {
readonly id: string;
readonly displayName: string;
readonly providerDisplayName: string;
}
export interface IEditorTypesHandler {
readonly onDidChangeEditorTypes: Event<void>;
getEditorTypes(): IEditorType[];
}
export interface IEditorAssociationsRegistry {
/**
* Register handlers for editor types
*/
registerEditorTypesHandler(id: string, handler: IEditorTypesHandler): IDisposable;
}
class EditorAssociationsRegistry implements IEditorAssociationsRegistry {
private readonly editorTypesHandlers = new Map<string, IEditorTypesHandler>();
registerEditorTypesHandler(id: string, handler: IEditorTypesHandler): IDisposable {
if (this.editorTypesHandlers.has(id)) {
throw new Error(`An editor type handler with ${id} was already registered.`);
}
this.editorTypesHandlers.set(id, handler);
this.updateEditorAssociationsSchema();
const editorTypeChangeEvent = handler.onDidChangeEditorTypes(() => {
this.updateEditorAssociationsSchema();
});
return {
dispose: () => {
editorTypeChangeEvent.dispose();
this.editorTypesHandlers.delete(id);
this.updateEditorAssociationsSchema();
}
};
}
private updateEditorAssociationsSchema() {
const enumValues: string[] = [];
const enumDescriptions: string[] = [];
const editorTypes: IEditorType[] = [DEFAULT_EDITOR_ASSOCIATION];
for (const [, handler] of this.editorTypesHandlers) {
editorTypes.push(...handler.getEditorTypes());
}
for (const { id, providerDisplayName } of editorTypes) {
enumValues.push(id);
enumDescriptions.push(localize('editorAssociations.viewType.sourceDescription', "Source: {0}", providerDisplayName));
}
editorTypeSchemaAddition.enum = enumValues;
editorTypeSchemaAddition.enumDescriptions = enumDescriptions;
configurationRegistry.notifyConfigurationSchemaUpdated(editorAssociationsConfigurationNode);
}
}
Registry.add(Extensions.Associations, new EditorAssociationsRegistry());
configurationRegistry.registerConfiguration(editorAssociationsConfigurationNode);
//#endregion

View File

@@ -22,6 +22,7 @@ import { getIconClasses, detectModeId } from 'vs/editor/common/services/getIconC
import { Disposable, dispose, IDisposable, DisposableStore } from 'vs/base/common/lifecycle';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { withNullAsUndefined } from 'vs/base/common/types';
import { normalizeDriveLetter } from 'vs/base/common/labels';
export interface IResourceLabelProps {
resource?: URI | { primary?: URI, secondary?: URI };
@@ -368,10 +369,10 @@ class ResourceLabelWidget extends IconLabel {
}
setFile(resource: URI, options?: IFileLabelOptions): void {
const hideLabel = options && options.hideLabel;
const hideLabel = options?.hideLabel;
let name: string | undefined;
if (!hideLabel) {
if (options && options.fileKind === FileKind.ROOT_FOLDER) {
if (options?.fileKind === FileKind.ROOT_FOLDER) {
const workspaceFolder = this.contextService.getWorkspaceFolder(resource);
if (workspaceFolder) {
name = workspaceFolder.name;
@@ -379,7 +380,7 @@ class ResourceLabelWidget extends IconLabel {
}
if (!name) {
name = basenameOrAuthority(resource);
name = normalizeDriveLetter(basenameOrAuthority(resource));
}
}
@@ -545,11 +546,11 @@ class ResourceLabelWidget extends IconLabel {
iconLabelOptions.extraClasses = this.computedIconClasses.slice(0);
}
if (this.options && this.options.extraClasses) {
if (this.options?.extraClasses) {
iconLabelOptions.extraClasses.push(...this.options.extraClasses);
}
if (this.options && this.options.fileDecorations && resource) {
if (this.options?.fileDecorations && resource) {
const deco = this.decorationsService.getDecoration(
resource,
this.options.fileKind !== FileKind.FILE

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import { Emitter } from 'vs/base/common/event';
import { Event, Emitter } from 'vs/base/common/event';
import { EventType, addDisposableListener, getClientArea, Dimension, position, size, IDimension, isAncestorUsingFlowTo } from 'vs/base/browser/dom';
import { onDidChangeFullscreen, isFullscreen } from 'vs/base/browser/browser';
import { IBackupFileService } from 'vs/workbench/services/backup/common/backup';
@@ -47,6 +47,7 @@ import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
import { mark } from 'vs/base/common/performance';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { ILogService } from 'vs/platform/log/common/log';
import { Promises } from 'vs/base/common/async';
export enum Settings {
ACTIVITYBAR_VISIBLE = 'workbench.activityBar.visible',
@@ -98,26 +99,29 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
//#region Events
private readonly _onZenModeChange = this._register(new Emitter<boolean>());
readonly onZenModeChange = this._onZenModeChange.event;
private readonly _onDidChangeZenMode = this._register(new Emitter<boolean>());
readonly onDidChangeZenMode = this._onDidChangeZenMode.event;
private readonly _onFullscreenChange = this._register(new Emitter<boolean>());
readonly onFullscreenChange = this._onFullscreenChange.event;
private readonly _onDidChangeFullscreen = this._register(new Emitter<boolean>());
readonly onDidChangeFullscreen = this._onDidChangeFullscreen.event;
private readonly _onCenteredLayoutChange = this._register(new Emitter<boolean>());
readonly onCenteredLayoutChange = this._onCenteredLayoutChange.event;
private readonly _onDidChangeCenteredLayout = this._register(new Emitter<boolean>());
readonly onDidChangeCenteredLayout = this._onDidChangeCenteredLayout.event;
private readonly _onMaximizeChange = this._register(new Emitter<boolean>());
readonly onMaximizeChange = this._onMaximizeChange.event;
private readonly _onDidChangeWindowMaximized = this._register(new Emitter<boolean>());
readonly onDidChangeWindowMaximized = this._onDidChangeWindowMaximized.event;
private readonly _onPanelPositionChange = this._register(new Emitter<string>());
readonly onPanelPositionChange = this._onPanelPositionChange.event;
private readonly _onDidChangePanelPosition = this._register(new Emitter<string>());
readonly onDidChangePanelPosition = this._onDidChangePanelPosition.event;
private readonly _onPartVisibilityChange = this._register(new Emitter<void>());
readonly onPartVisibilityChange = this._onPartVisibilityChange.event;
private readonly _onDidChangePartVisibility = this._register(new Emitter<void>());
readonly onDidChangePartVisibility = this._onDidChangePartVisibility.event;
private readonly _onLayout = this._register(new Emitter<IDimension>());
readonly onLayout = this._onLayout.event;
private readonly _onDidChangeNotificationsVisibility = this._register(new Emitter<boolean>());
readonly onDidChangeNotificationsVisibility = this._onDidChangeNotificationsVisibility.event;
private readonly _onDidLayout = this._register(new Emitter<IDimension>());
readonly onDidLayout = this._onDidLayout.event;
//#endregion
@@ -179,7 +183,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
windowBorder: false,
menuBar: {
visibility: 'default' as MenuBarVisibility,
visibility: 'classic' as MenuBarVisibility,
toggled: false
},
@@ -320,8 +324,13 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
if (visible !== this.state.menuBar.toggled) {
this.state.menuBar.toggled = visible;
if (this.state.fullscreen && (this.state.menuBar.visibility === 'toggle' || this.state.menuBar.visibility === 'default')) {
// Propagate to grid
// The menu bar toggles the title bar in web because it does not need to be shown for window controls only
if (isWeb && this.state.menuBar.visibility === 'toggle') {
this.workbenchGrid.setViewVisible(this.titleBarPartView, this.isVisible(Parts.TITLEBAR_PART));
}
// The menu bar toggles the title bar in full screen for toggle and classic settings
else if (this.state.fullscreen && (this.state.menuBar.visibility === 'toggle' || this.state.menuBar.visibility === 'classic')) {
this.workbenchGrid.setViewVisible(this.titleBarPartView, this.isVisible(Parts.TITLEBAR_PART));
}
@@ -359,7 +368,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
this.layout(); // handle title bar when fullscreen changes
}
this._onFullscreenChange.fire(this.state.fullscreen);
this._onDidChangeFullscreen.fire(this.state.fullscreen);
}
private onWindowFocusChanged(hasFocus: boolean): void {
@@ -567,7 +576,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
return;
}
if (!storageService.isNew(StorageScope.WORKSPACE)) {
if (!defaultLayout.force && !storageService.isNew(StorageScope.WORKSPACE)) {
return;
}
@@ -623,24 +632,17 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
}
private _openedDefaultEditors: boolean = false;
get openedDefaultEditors() {
return this._openedDefaultEditors;
}
get openedDefaultEditors() { return this._openedDefaultEditors; }
private getInitialFilesToOpen(): { filesToOpenOrCreate?: IPath[], filesToDiff?: IPath[]; } | undefined {
const defaultLayout = this.environmentService.options?.defaultLayout;
if (defaultLayout?.editors?.length && this.storageService.isNew(StorageScope.WORKSPACE)) {
if (defaultLayout?.editors?.length && (defaultLayout.force || this.storageService.isNew(StorageScope.WORKSPACE))) {
this._openedDefaultEditors = true;
return {
filesToOpenOrCreate: defaultLayout.editors
.map<IPath>(f => {
// Support the old path+scheme api until embedders can migrate
if ('path' in f && 'scheme' in f) {
return { fileUri: URI.file((f as any).path).with({ scheme: (f as any).scheme }) };
}
return { fileUri: URI.revive(f.uri), openOnlyIfExists: f.openOnlyIfExists, overrideId: f.openWith };
})
filesToOpenOrCreate: defaultLayout.editors.map<IPath>(file => {
return { fileUri: URI.revive(file.uri), openOnlyIfExists: file.openOnlyIfExists, editorOverrideId: file.openWith };
})
};
}
@@ -718,7 +720,6 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
if (defaultViews.length) {
await this.extensionService.whenInstalledExtensionsRegistered();
let i = defaultViews.length;
while (i) {
i--;
@@ -794,7 +795,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
}
// Await restore to be done
await Promise.all(restorePromises);
await Promises.settled(restorePromises);
}
private updatePanelPosition() {
@@ -817,6 +818,10 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
return part;
}
registerNotifications(delegate: { onDidChangeNotificationsVisibility: Event<boolean> }): void {
this._register(delegate.onDidChangeNotificationsVisibility(visible => this._onDidChangeNotificationsVisibility.fire(visible)));
}
isRestored(): boolean {
return this.lifecycleService.phase >= LifecyclePhase.Restored;
}
@@ -883,19 +888,35 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
isVisible(part: Parts): boolean {
switch (part) {
case Parts.TITLEBAR_PART:
// Using the native title bar, don't ever show the custom one
if (getTitleBarStyle(this.configurationService) === 'native') {
return false;
} else if (!this.state.fullscreen && !isWeb) {
return true;
} else if (isMacintosh && isNative) {
return false;
} else if (this.state.menuBar.visibility === 'visible') {
return true;
} else if (this.state.menuBar.visibility === 'toggle' || this.state.menuBar.visibility === 'default') {
return this.state.menuBar.toggled;
}
return false;
// macOS desktop does not need a title bar when full screen
if (isMacintosh && isNative) {
return !this.state.fullscreen;
}
// non-fullscreen native must show the title bar
if (isNative && !this.state.fullscreen) {
return true;
}
// remaining behavior is based on menubar visibility
switch (this.state.menuBar.visibility) {
case 'classic':
return !this.state.fullscreen || this.state.menuBar.toggled;
case 'compact':
case 'hidden':
return false;
case 'toggle':
return this.state.menuBar.toggled;
case 'visible':
return true;
default:
return isWeb ? false : !this.state.fullscreen || this.state.menuBar.toggled;
}
case Parts.SIDEBAR_PART:
return !this.state.sideBar.hidden;
case Parts.PANEL_PART:
@@ -967,15 +988,16 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
}
editorControlSet.clear();
} else {
this.editorService.visibleTextEditorControls.forEach(editorControl => {
for (const editorControl of this.editorService.visibleTextEditorControls) {
if (!editorControlSet.has(editorControl)) {
editorControlSet.add(editorControl);
this.state.zenMode.transitionDisposables.add(editorControl.onDidDispose(() => {
editorControlSet.delete(editorControl);
}));
}
setEditorLineNumbers(editorControl);
});
}
}
};
@@ -1075,7 +1097,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
}
// Event
this._onZenModeChange.fire(this.state.zenMode.active);
this._onDidChangeZenMode.fire(this.state.zenMode.active);
// State
if (this.state.zenMode.active) {
@@ -1145,7 +1167,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
this.workbenchGrid = workbenchGrid;
this.workbenchGrid.edgeSnapping = this.state.fullscreen;
[titleBar, editorPart, activityBar, panelPart, sideBar, statusBar].forEach((part: Part) => {
for (const part of [titleBar, editorPart, activityBar, panelPart, sideBar, statusBar]) {
this._register(part.onDidVisibilityChange((visible) => {
if (part === sideBar) {
this.setSideBarHidden(!visible, true);
@@ -1154,9 +1176,9 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
} else if (part === editorPart) {
this.setEditorHidden(!visible, true);
}
this._onPartVisibilityChange.fire();
this._onDidChangePartVisibility.fire();
}));
});
}
this._register(this.storageService.onWillSaveState(() => {
const grid = this.workbenchGrid as SerializableGrid<ISerializableView>;
@@ -1196,7 +1218,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
this.workbenchGrid.layout(this._dimension.width, this._dimension.height);
// Emit as event
this._onLayout.fire(this._dimension);
this._onDidLayout.fire(this._dimension);
}
}
@@ -1234,7 +1256,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
}
}
this._onCenteredLayoutChange.fire(this.state.editor.centered);
this._onDidChangeCenteredLayout.fire(this.state.editor.centered);
}
resizePart(part: Parts, sizeChangeWidth: number, sizeChangeHeight: number): void {
@@ -1530,10 +1552,6 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
}
isPanelMaximized(): boolean {
if (!this.workbenchGrid) {
return false;
}
return this.state.editor.hidden;
}
@@ -1559,16 +1577,14 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
toggleMenuBar(): void {
let currentVisibilityValue = getMenuBarVisibility(this.configurationService);
if (typeof currentVisibilityValue !== 'string') {
currentVisibilityValue = 'default';
currentVisibilityValue = 'classic';
}
let newVisibilityValue: string;
if (currentVisibilityValue === 'visible' || currentVisibilityValue === 'default') {
newVisibilityValue = 'toggle';
} else if (currentVisibilityValue === 'compact') {
newVisibilityValue = 'hidden';
if (currentVisibilityValue === 'visible' || currentVisibilityValue === 'classic') {
newVisibilityValue = 'compact';
} else {
newVisibilityValue = (isWeb && currentVisibilityValue === 'hidden') ? 'compact' : 'default';
newVisibilityValue = 'classic';
}
this.configurationService.updateValue(Storage.MENU_VISIBILITY, newVisibilityValue);
@@ -1627,7 +1643,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
// Reset sidebar to original size before shifting the panel
this.workbenchGrid.resizeView(this.sideBarPartView, sideBarSize);
this._onPanelPositionChange.fire(newPositionValue);
this._onDidChangePanelPosition.fire(newPositionValue);
}
isWindowMaximized() {
@@ -1642,7 +1658,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
this.state.maximized = maximized;
this.updateWindowBorder();
this._onMaximizeChange.fire(maximized);
this._onDidChangeWindowMaximized.fire(maximized);
}
getVisibleNeighborPart(part: Parts, direction: Direction): Parts | undefined {

View File

@@ -13,15 +13,18 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { Composite } from 'vs/workbench/browser/composite';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { ViewPaneContainer } from './parts/views/viewPaneContainer';
import { ViewPaneContainer, ViewsSubMenu } from './parts/views/viewPaneContainer';
import { IPaneComposite } from 'vs/workbench/common/panecomposite';
import { IAction, IActionViewItem, Separator } from 'vs/base/common/actions';
import { IAction, Separator } from 'vs/base/common/actions';
import { SubmenuItemAction } from 'vs/platform/actions/common/actions';
import { IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
export class PaneComposite extends Composite implements IPaneComposite {
export abstract class PaneComposite extends Composite implements IPaneComposite {
private viewPaneContainer?: ViewPaneContainer;
constructor(
id: string,
protected readonly viewPaneContainer: ViewPaneContainer,
@ITelemetryService telemetryService: ITelemetryService,
@IStorageService protected storageService: IStorageService,
@IInstantiationService protected instantiationService: IInstantiationService,
@@ -31,78 +34,94 @@ export class PaneComposite extends Composite implements IPaneComposite {
@IWorkspaceContextService protected contextService: IWorkspaceContextService
) {
super(id, telemetryService, themeService, storageService);
this._register(this.viewPaneContainer.onTitleAreaUpdate(() => this.updateTitleArea()));
}
create(parent: HTMLElement): void {
this.viewPaneContainer = this._register(this.createViewPaneContainer(parent));
this._register(this.viewPaneContainer.onTitleAreaUpdate(() => this.updateTitleArea()));
this.viewPaneContainer.create(parent);
}
setVisible(visible: boolean): void {
super.setVisible(visible);
this.viewPaneContainer.setVisible(visible);
this.viewPaneContainer?.setVisible(visible);
}
layout(dimension: Dimension): void {
this.viewPaneContainer.layout(dimension);
this.viewPaneContainer?.layout(dimension);
}
getOptimalWidth(): number {
return this.viewPaneContainer.getOptimalWidth();
return this.viewPaneContainer?.getOptimalWidth() ?? 0;
}
openView<T extends IView>(id: string, focus?: boolean): T | undefined {
return this.viewPaneContainer.openView(id, focus) as T;
return this.viewPaneContainer?.openView(id, focus) as T;
}
getViewPaneContainer(): ViewPaneContainer {
getViewPaneContainer(): ViewPaneContainer | undefined {
return this.viewPaneContainer;
}
getActionsContext(): unknown {
return this.getViewPaneContainer().getActionsContext();
return this.getViewPaneContainer()?.getActionsContext();
}
getContextMenuActions(): ReadonlyArray<IAction> {
const result = [];
result.push(...this.viewPaneContainer.getContextMenuActions2());
const otherActions = this.viewPaneContainer.getContextMenuActions();
if (otherActions.length) {
result.push(new Separator());
result.push(...otherActions);
}
return result;
return this.viewPaneContainer?.menuActions?.getContextMenuActions() ?? [];
}
getActions(): ReadonlyArray<IAction> {
const result = [];
result.push(...this.viewPaneContainer.getActions2());
result.push(...this.viewPaneContainer.getActions());
if (this.viewPaneContainer?.menuActions) {
result.push(...this.viewPaneContainer.menuActions.getPrimaryActions());
if (this.viewPaneContainer.isViewMergedWithContainer()) {
result.push(...this.viewPaneContainer.panes[0].menuActions.getPrimaryActions());
}
}
return result;
}
getSecondaryActions(): ReadonlyArray<IAction> {
const menuActions = this.viewPaneContainer.getSecondaryActions2();
const viewPaneContainerActions = this.viewPaneContainer.getSecondaryActions();
if (menuActions.length && viewPaneContainerActions.length) {
if (!this.viewPaneContainer?.menuActions) {
return [];
}
const viewPaneActions = this.viewPaneContainer.isViewMergedWithContainer() ? this.viewPaneContainer.panes[0].menuActions.getSecondaryActions() : [];
let menuActions = this.viewPaneContainer.menuActions.getSecondaryActions();
const viewsSubmenuActionIndex = menuActions.findIndex(action => action instanceof SubmenuItemAction && action.item.submenu === ViewsSubMenu);
if (viewsSubmenuActionIndex !== -1) {
const viewsSubmenuAction = <SubmenuItemAction>menuActions[viewsSubmenuActionIndex];
if (viewsSubmenuAction.actions.some(({ enabled }) => enabled)) {
if (menuActions.length === 1 && viewPaneActions.length === 0) {
menuActions = viewsSubmenuAction.actions.slice();
} else if (viewsSubmenuActionIndex !== 0) {
menuActions = [viewsSubmenuAction, ...menuActions.slice(0, viewsSubmenuActionIndex), ...menuActions.slice(viewsSubmenuActionIndex + 1)];
}
} else {
// Remove views submenu if none of the actions are enabled
menuActions.splice(viewsSubmenuActionIndex, 1);
}
}
if (menuActions.length && viewPaneActions.length) {
return [
...menuActions,
new Separator(),
...viewPaneContainerActions
...viewPaneActions
];
}
return menuActions.length ? menuActions : viewPaneContainerActions;
return menuActions.length ? menuActions : viewPaneActions;
}
getActionViewItem(action: IAction): IActionViewItem | undefined {
return this.viewPaneContainer.getActionViewItem(action);
return this.viewPaneContainer?.getActionViewItem(action);
}
getTitle(): string {
return this.viewPaneContainer.getTitle();
return this.viewPaneContainer?.getTitle() ?? '';
}
saveState(): void {
@@ -110,6 +129,8 @@ export class PaneComposite extends Composite implements IPaneComposite {
}
focus(): void {
this.viewPaneContainer.focus();
this.viewPaneContainer?.focus();
}
protected abstract createViewPaneContainer(parent: HTMLElement): ViewPaneContainer;
}

View File

@@ -17,7 +17,6 @@ import { IStorageService } from 'vs/platform/storage/common/storage';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneContainer';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
export abstract class Panel extends PaneComposite implements IPanel {
@@ -25,7 +24,6 @@ export abstract class Panel extends PaneComposite implements IPanel {
private readonly panelActions: CompositeMenuActions;
constructor(id: string,
viewPaneContainer: ViewPaneContainer,
@ITelemetryService telemetryService: ITelemetryService,
@IStorageService storageService: IStorageService,
@IInstantiationService instantiationService: IInstantiationService,
@@ -34,7 +32,7 @@ export abstract class Panel extends PaneComposite implements IPanel {
@IExtensionService extensionService: IExtensionService,
@IWorkspaceContextService contextService: IWorkspaceContextService,
) {
super(id, viewPaneContainer, telemetryService, storageService, instantiationService, themeService, contextMenuService, extensionService, contextService);
super(id, telemetryService, storageService, instantiationService, themeService, contextMenuService, extensionService, contextService);
this.panelActions = this._register(this.instantiationService.createInstance(CompositeMenuActions, MenuId.PanelTitle, undefined, undefined));
this._register(this.panelActions.onDidChange(() => this.updateTitleArea()));
}

View File

@@ -159,7 +159,7 @@ class PartLayout {
// Title Size: Width (Fill), Height (Variable)
let titleSize: Dimension;
if (this.options && this.options.hasTitle) {
if (this.options.hasTitle) {
titleSize = new Dimension(width, Math.min(height, PartLayout.TITLE_HEIGHT));
} else {
titleSize = Dimension.None;

View File

@@ -19,7 +19,7 @@ import { IColorTheme, IThemeService, registerThemingParticipant } from 'vs/platf
import { ActivityAction, ActivityActionViewItem, ICompositeBar, ICompositeBarColors, ToggleCompositePinnedAction } from 'vs/workbench/browser/parts/compositeBarActions';
import { CATEGORIES } from 'vs/workbench/common/actions';
import { IActivity } from 'vs/workbench/common/activity';
import { ACTIVITY_BAR_FOREGROUND, ACTIVITY_BAR_ACTIVE_BORDER, ACTIVITY_BAR_ACTIVE_FOCUS_BORDER, ACTIVITY_BAR_ACTIVE_BACKGROUND, ACTIVITY_BAR_BACKGROUND } from 'vs/workbench/common/theme';
import { ACTIVITY_BAR_FOREGROUND, ACTIVITY_BAR_ACTIVE_BORDER, ACTIVITY_BAR_ACTIVE_FOCUS_BORDER, ACTIVITY_BAR_ACTIVE_BACKGROUND } from 'vs/workbench/common/theme';
import { IActivityBarService } from 'vs/workbench/services/activityBar/browser/activityBarService';
import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
@@ -118,7 +118,7 @@ class MenuActivityActionViewItem extends ActivityActionViewItem {
@IConfigurationService protected readonly configurationService: IConfigurationService,
@IWorkbenchEnvironmentService protected readonly environmentService: IWorkbenchEnvironmentService
) {
super(action, { draggable: false, colors, icon: true }, themeService);
super(action, { draggable: false, colors, icon: true, hasPopup: true }, themeService);
}
render(container: HTMLElement): void {
@@ -182,54 +182,6 @@ class MenuActivityActionViewItem extends ActivityActionViewItem {
}
}
export class HomeActivityActionViewItem extends MenuActivityActionViewItem {
static readonly HOME_BAR_VISIBILITY_PREFERENCE = 'workbench.activity.showHomeIndicator';
constructor(
private readonly goHomeHref: string,
action: ActivityAction,
contextMenuActionsProvider: () => IAction[],
colors: (theme: IColorTheme) => ICompositeBarColors,
@IThemeService themeService: IThemeService,
@IMenuService menuService: IMenuService,
@IContextMenuService contextMenuService: IContextMenuService,
@IContextKeyService contextKeyService: IContextKeyService,
@IConfigurationService configurationService: IConfigurationService,
@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService,
@IStorageService private readonly storageService: IStorageService
) {
super(MenuId.MenubarHomeMenu, action, contextMenuActionsProvider, colors, themeService, menuService, contextMenuService, contextKeyService, configurationService, environmentService);
}
protected async resolveMainMenuActions(homeMenu: IMenu, disposables: DisposableStore): Promise<IAction[]> {
const actions = [];
// Go Home
actions.push(toAction({ id: 'goHome', label: localize('goHome', "Go Home"), run: () => window.location.href = this.goHomeHref }));
// Contributed
const contributedActions = await super.resolveMainMenuActions(homeMenu, disposables);
if (contributedActions.length) {
actions.push(disposables.add(new Separator()));
actions.push(...contributedActions);
}
return actions;
}
protected async resolveContextMenuActions(disposables: DisposableStore): Promise<IAction[]> {
const actions = await super.resolveContextMenuActions(disposables);
actions.unshift(...[
toAction({ id: 'hideHomeButton', label: localize('hideHomeButton', "Hide Home Button"), run: () => this.storageService.store(HomeActivityActionViewItem.HOME_BAR_VISIBILITY_PREFERENCE, false, StorageScope.GLOBAL, StorageTarget.USER) }),
new Separator()
]);
return actions;
}
}
export class AccountsActivityActionViewItem extends MenuActivityActionViewItem {
static readonly ACCOUNTS_VISIBILITY_PREFERENCE_KEY = 'workbench.activity.showAccounts';
@@ -288,7 +240,7 @@ export class AccountsActivityActionViewItem extends MenuActivityActionViewItem {
}));
const signOutAction = disposables.add(new Action('signOut', localize('signOut', "Sign Out"), '', true, () => {
return this.authenticationService.signOutOfAccount(sessionInfo.providerId, accountName);
return this.authenticationService.removeAccountSessions(sessionInfo.providerId, accountName, sessionInfo.sessions[accountName]);
}));
const providerSubMenuActions = [manageExtensionsAction];
@@ -307,6 +259,11 @@ export class AccountsActivityActionViewItem extends MenuActivityActionViewItem {
}
});
if (providers.length && !menus.length) {
const noAccountsAvailableAction = disposables.add(new Action('noAccountsAvailable', localize('noAccounts', "You are not signed in to any accounts"), undefined, false));
menus.push(noAccountsAvailableAction);
}
if (menus.length && otherCommands.length) {
menus.push(disposables.add(new Separator()));
}
@@ -422,15 +379,6 @@ registerAction2(
);
registerThemingParticipant((theme, collector) => {
const activityBarBackgroundColor = theme.getColor(ACTIVITY_BAR_BACKGROUND);
if (activityBarBackgroundColor) {
collector.addRule(`
.monaco-workbench .activitybar > .content > .home-bar > .home-bar-icon-badge {
background-color: ${activityBarBackgroundColor};
}
`);
}
const activityBarForegroundColor = theme.getColor(ACTIVITY_BAR_FOREGROUND);
if (activityBarForegroundColor) {
collector.addRule(`
@@ -439,7 +387,6 @@ registerThemingParticipant((theme, collector) => {
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item:hover .action-label:not(.codicon) {
background-color: ${activityBarForegroundColor} !important;
}
.monaco-workbench .activitybar > .content .home-bar > .monaco-action-bar .action-item .action-label.codicon,
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.active .action-label.codicon,
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item:focus .action-label.codicon,
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item:hover .action-label.codicon {

View File

@@ -8,7 +8,7 @@ import { localize } from 'vs/nls';
import { ActionsOrientation, ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { GLOBAL_ACTIVITY_ID, IActivity, ACCOUNTS_ACTIVITY_ID } from 'vs/workbench/common/activity';
import { Part } from 'vs/workbench/browser/part';
import { GlobalActivityActionViewItem, ViewContainerActivityAction, PlaceHolderToggleCompositePinnedAction, PlaceHolderViewContainerActivityAction, AccountsActivityActionViewItem, HomeActivityActionViewItem } from 'vs/workbench/browser/parts/activitybar/activitybarActions';
import { GlobalActivityActionViewItem, ViewContainerActivityAction, PlaceHolderToggleCompositePinnedAction, PlaceHolderViewContainerActivityAction, AccountsActivityActionViewItem } from 'vs/workbench/browser/parts/activitybar/activitybarActions';
import { IBadge, NumberBadge } from 'vs/workbench/services/activity/common/activity';
import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService';
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
@@ -23,8 +23,8 @@ import { IStorageService, StorageScope, IStorageValueChangeEvent, StorageTarget
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { URI, UriComponents } from 'vs/base/common/uri';
import { ToggleCompositePinnedAction, ICompositeBarColors, ActivityAction, ICompositeActivity } from 'vs/workbench/browser/parts/compositeBarActions';
import { IViewDescriptorService, ViewContainer, IViewContainerModel, ViewContainerLocation, IViewsService } from 'vs/workbench/common/views';
import { IContextKeyService, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { IViewDescriptorService, ViewContainer, IViewContainerModel, ViewContainerLocation, IViewsService, getEnabledViewContainerContextKey } from 'vs/workbench/common/views';
import { IContextKeyService, ContextKeyExpr, IContextKey } from 'vs/platform/contextkey/common/contextkey';
import { assertIsDefined, isString } from 'vs/base/common/types';
import { IActivityBarService } from 'vs/workbench/services/activityBar/browser/activityBarService';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
@@ -32,9 +32,9 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/
import { CustomMenubarControl } from 'vs/workbench/browser/parts/titlebar/menubarControl';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { getMenuBarVisibility } from 'vs/platform/windows/common/windows';
import { isNative, isWeb } from 'vs/base/common/platform';
import { isNative } from 'vs/base/common/platform';
import { Before2D } from 'vs/workbench/browser/dnd';
import { Codicon, iconRegistry } from 'vs/base/common/codicons';
import { Codicon } from 'vs/base/common/codicons';
import { IAction, Separator, toAction } from 'vs/base/common/actions';
import { Event } from 'vs/base/common/event';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
@@ -94,9 +94,6 @@ export class ActivitybarPart extends Part implements IActivityBarService {
private content: HTMLElement | undefined;
private homeBar: ActionBar | undefined;
private homeBarContainer: HTMLElement | undefined;
private menuBar: CustomMenubarControl | undefined;
private menuBarContainer: HTMLElement | undefined;
@@ -120,6 +117,8 @@ export class ActivitybarPart extends Part implements IActivityBarService {
private readonly location = ViewContainerLocation.Sidebar;
private hasExtensionsRegistered: boolean = false;
private readonly enabledViewContainersContextKeys: Map<string, IContextKey<boolean>> = new Map<string, IContextKey<boolean>>();
constructor(
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,
@@ -163,25 +162,11 @@ export class ActivitybarPart extends Part implements IActivityBarService {
getCompositePinnedAction: compositeId => this.getCompositeActions(compositeId).pinnedAction,
getOnCompositeClickAction: compositeId => toAction({ id: compositeId, label: '', run: async () => this.viewsService.isViewContainerVisible(compositeId) ? this.viewsService.closeViewContainer(compositeId) : this.viewsService.openViewContainer(compositeId) }),
fillExtraContextMenuActions: actions => {
// Home
const topActions: IAction[] = [];
if (this.homeBarContainer) {
topActions.push({
id: 'toggleHomeBarAction',
label: localize('homeButton', "Home Button"),
class: undefined,
tooltip: localize('homeButton', "Home Button"),
checked: this.homeBarVisibilityPreference,
enabled: true,
run: async () => this.homeBarVisibilityPreference = !this.homeBarVisibilityPreference,
dispose: () => { }
});
}
// Menu
const menuBarVisibility = getMenuBarVisibility(this.configurationService);
if (menuBarVisibility === 'compact' || (menuBarVisibility === 'hidden' && isWeb)) {
if (menuBarVisibility === 'compact' || menuBarVisibility === 'hidden' || menuBarVisibility === 'toggle') {
topActions.push({
id: 'toggleMenuVisibility',
label: localize('menu', "Menu"),
@@ -189,7 +174,7 @@ export class ActivitybarPart extends Part implements IActivityBarService {
tooltip: localize('menu', "Menu"),
checked: menuBarVisibility === 'compact',
enabled: true,
run: async () => this.layoutService.toggleMenuBar(),
run: async () => this.configurationService.updateValue('window.menuBarVisibility', menuBarVisibility === 'compact' ? 'toggle' : 'compact'),
dispose: () => { }
});
}
@@ -309,12 +294,6 @@ export class ActivitybarPart extends Part implements IActivityBarService {
}
}
private onDidChangeHomeBarVisibility(): void {
if (this.homeBarContainer) {
this.homeBarContainer.style.display = this.homeBarVisibilityPreference ? '' : 'none';
}
}
private onDidRegisterExtensions(): void {
this.hasExtensionsRegistered = true;
@@ -340,7 +319,7 @@ export class ActivitybarPart extends Part implements IActivityBarService {
if (viewContainer) {
// Update the composite bar by adding
this.compositeBar.addComposite(viewContainer);
this.addComposite(viewContainer);
this.compositeBar.activateComposite(viewContainer.id);
if (this.shouldBeHidden(viewContainer)) {
@@ -459,11 +438,7 @@ export class ActivitybarPart extends Part implements IActivityBarService {
this.menuBarContainer.classList.add('menubar');
const content = assertIsDefined(this.content);
if (this.homeBarContainer) {
content.insertBefore(this.menuBarContainer, this.homeBarContainer.nextSibling);
} else {
content.prepend(this.menuBarContainer);
}
content.prepend(this.menuBarContainer);
// Menubar: install a custom menu bar depending on configuration
this.menuBar = this._register(this.instantiationService.createInstance(CustomMenubarControl));
@@ -479,19 +454,6 @@ export class ActivitybarPart extends Part implements IActivityBarService {
this.content.classList.add('content');
parent.appendChild(this.content);
// Home action bar
const homeIndicator = this.environmentService.options?.homeIndicator;
// TODO @sbatten remove the fake setting and associated code
if (homeIndicator && this.configurationService.getValue<boolean>('window.showHomeIndicator')) {
let codicon = iconRegistry.get(homeIndicator.icon);
if (!codicon) {
codicon = Codicon.code;
}
this.createHomeBar(homeIndicator.href, codicon);
this.onDidChangeHomeBarVisibility();
}
// Install menubar if compact
if (getMenuBarVisibility(this.configurationService) === 'compact') {
this.installMenubar();
@@ -515,20 +477,6 @@ export class ActivitybarPart extends Part implements IActivityBarService {
private registerKeyboardNavigationListeners(): void {
this.keyboardNavigationDisposables.clear();
// Down arrow on home indicator
if (this.homeBarContainer) {
this.keyboardNavigationDisposables.add(addDisposableListener(this.homeBarContainer, EventType.KEY_DOWN, e => {
const kbEvent = new StandardKeyboardEvent(e);
if (kbEvent.equals(KeyCode.DownArrow) || kbEvent.equals(KeyCode.RightArrow)) {
if (this.menuBar) {
this.menuBar.toggleFocus();
} else if (this.compositeBar) {
this.compositeBar.focus();
}
}
}));
}
// Up/Down arrow on compact menu
if (this.menuBarContainer) {
this.keyboardNavigationDisposables.add(addDisposableListener(this.menuBarContainer, EventType.KEY_DOWN, e => {
@@ -537,10 +485,6 @@ export class ActivitybarPart extends Part implements IActivityBarService {
if (this.compositeBar) {
this.compositeBar.focus();
}
} else if (kbEvent.equals(KeyCode.UpArrow) || kbEvent.equals(KeyCode.LeftArrow)) {
if (this.homeBar) {
this.homeBar.focus();
}
}
}));
}
@@ -556,8 +500,6 @@ export class ActivitybarPart extends Part implements IActivityBarService {
} else if (kbEvent.equals(KeyCode.UpArrow) || kbEvent.equals(KeyCode.LeftArrow)) {
if (this.menuBar) {
this.menuBar.toggleFocus();
} else if (this.homeBar) {
this.homeBar.focus();
}
}
}));
@@ -576,35 +518,6 @@ export class ActivitybarPart extends Part implements IActivityBarService {
}
}
private createHomeBar(href: string, icon: Codicon): void {
this.homeBarContainer = document.createElement('div');
this.homeBarContainer.setAttribute('aria-label', localize('homeIndicator', "Home"));
this.homeBarContainer.setAttribute('role', 'toolbar');
this.homeBarContainer.classList.add('home-bar');
this.homeBar = this._register(new ActionBar(this.homeBarContainer, {
actionViewItemProvider: action => this.instantiationService.createInstance(HomeActivityActionViewItem, href, action as ActivityAction, () => this.compositeBar.getContextMenuActions(), (theme: IColorTheme) => this.getActivitybarItemColors(theme)),
orientation: ActionsOrientation.VERTICAL,
ariaLabel: localize('home', "Home"),
animated: false,
preventLoopNavigation: true,
ignoreOrientationForPreviousAndNextKey: true
}));
const homeBarIconBadge = document.createElement('div');
homeBarIconBadge.classList.add('home-bar-icon-badge');
this.homeBarContainer.appendChild(homeBarIconBadge);
this.homeBar.push(this._register(new ActivityAction({
id: 'workbench.actions.home',
name: localize('home', "Home"),
cssClass: icon.classNames
})));
const content = assertIsDefined(this.content);
content.appendChild(this.homeBarContainer);
}
private createGlobalActivityActionBar(container: HTMLElement): void {
this.globalActivityActionBar = this._register(new ActionBar(container, {
actionViewItemProvider: action => {
@@ -621,8 +534,7 @@ export class ActivitybarPart extends Part implements IActivityBarService {
orientation: ActionsOrientation.VERTICAL,
ariaLabel: localize('manage', "Manage"),
animated: false,
preventLoopNavigation: true,
ignoreOrientationForPreviousAndNextKey: true
preventLoopNavigation: true
}));
this.globalActivityAction = this._register(new ActivityAction({
@@ -669,8 +581,8 @@ export class ActivitybarPart extends Part implements IActivityBarService {
if (viewContainer) {
const viewContainerModel = this.viewDescriptorService.getViewContainerModel(viewContainer);
compositeActions = {
activityAction: this.instantiationService.createInstance(ViewContainerActivityAction, this.toActivity(viewContainer, viewContainerModel)),
pinnedAction: new ToggleCompositePinnedAction(viewContainer, this.compositeBar)
activityAction: this.instantiationService.createInstance(ViewContainerActivityAction, this.toActivity(viewContainerModel)),
pinnedAction: new ToggleCompositePinnedAction(this.toActivity(viewContainerModel), this.compositeBar)
};
} else {
const cachedComposite = this.cachedViewContainers.filter(c => c.id === compositeId)[0];
@@ -688,7 +600,7 @@ export class ActivitybarPart extends Part implements IActivityBarService {
private onDidRegisterViewContainers(viewContainers: ReadonlyArray<ViewContainer>): void {
for (const viewContainer of viewContainers) {
this.compositeBar.addComposite(viewContainer);
this.addComposite(viewContainer);
// Pin it by default if it is new
const cachedViewContainer = this.cachedViewContainers.filter(({ id }) => id === viewContainer.id)[0];
@@ -725,7 +637,7 @@ export class ActivitybarPart extends Part implements IActivityBarService {
}
private updateActivity(viewContainer: ViewContainer, viewContainerModel: IViewContainerModel): void {
const activity: IActivity = this.toActivity(viewContainer, viewContainerModel);
const activity: IActivity = this.toActivity(viewContainerModel);
const { activityAction, pinnedAction } = this.getCompositeActions(viewContainer.id);
activityAction.updateActivity(activity);
@@ -736,8 +648,8 @@ export class ActivitybarPart extends Part implements IActivityBarService {
this.saveCachedViewContainers();
}
private toActivity({ id, focusCommand }: ViewContainer, { icon, title: name }: IViewContainerModel): IActivity {
return ActivitybarPart.toActivity(id, name, icon, focusCommand?.id || id);
private toActivity(viewContainerModel: IViewContainerModel): IActivity {
return ActivitybarPart.toActivity(viewContainerModel.viewContainer.id, viewContainerModel.title, viewContainerModel.icon, viewContainerModel.keybindingId);
}
private static toActivity(id: string, name: string, icon: URI | ThemeIcon | undefined, keybindingId: string | undefined): IActivity {
@@ -764,10 +676,17 @@ export class ActivitybarPart extends Part implements IActivityBarService {
}
private showOrHideViewContainer(viewContainer: ViewContainer): void {
let contextKey = this.enabledViewContainersContextKeys.get(viewContainer.id);
if (!contextKey) {
contextKey = this.contextKeyService.createKey(getEnabledViewContainerContextKey(viewContainer.id), false);
this.enabledViewContainersContextKeys.set(viewContainer.id, contextKey);
}
if (this.shouldBeHidden(viewContainer)) {
contextKey.set(false);
this.hideComposite(viewContainer.id);
} else {
this.compositeBar.addComposite(viewContainer);
contextKey.set(true);
this.addComposite(viewContainer);
}
}
@@ -802,6 +721,10 @@ export class ActivitybarPart extends Part implements IActivityBarService {
return true;
}
private addComposite(viewContainer: ViewContainer): void {
this.compositeBar.addComposite({ id: viewContainer.id, name: viewContainer.title, order: viewContainer.order, requestedIndex: viewContainer.requestedIndex });
}
private hideComposite(compositeId: string): void {
this.compositeBar.hideComposite(compositeId);
@@ -877,9 +800,6 @@ export class ActivitybarPart extends Part implements IActivityBarService {
// Layout composite bar
let availableHeight = contentAreaSize.height;
if (this.homeBarContainer) {
availableHeight -= this.homeBarContainer.clientHeight;
}
if (this.menuBarContainer) {
availableHeight -= this.menuBarContainer.clientHeight;
}
@@ -927,10 +847,6 @@ export class ActivitybarPart extends Part implements IActivityBarService {
this.compositeBar.setCompositeBarItems(newCompositeItems);
}
if (e.key === HomeActivityActionViewItem.HOME_BAR_VISIBILITY_PREFERENCE && e.scope === StorageScope.GLOBAL) {
this.onDidChangeHomeBarVisibility();
}
if (e.key === AccountsActivityActionViewItem.ACCOUNTS_VISIBILITY_PREFERENCE_KEY && e.scope === StorageScope.GLOBAL) {
this.toggleAccountsActivity();
}
@@ -1067,14 +983,6 @@ export class ActivitybarPart extends Part implements IActivityBarService {
this.storageService.store(ActivitybarPart.PLACEHOLDER_VIEW_CONTAINERS, value, StorageScope.GLOBAL, StorageTarget.MACHINE);
}
private get homeBarVisibilityPreference(): boolean {
return this.storageService.getBoolean(HomeActivityActionViewItem.HOME_BAR_VISIBILITY_PREFERENCE, StorageScope.GLOBAL, true);
}
private set homeBarVisibilityPreference(value: boolean) {
this.storageService.store(HomeActivityActionViewItem.HOME_BAR_VISIBILITY_PREFERENCE, value, StorageScope.GLOBAL, StorageTarget.USER);
}
private get accountsVisibilityPreference(): boolean {
return this.storageService.getBoolean(AccountsActivityActionViewItem.ACCOUNTS_VISIBILITY_PREFERENCE_KEY, StorageScope.GLOBAL, true);
}

View File

@@ -156,6 +156,19 @@
text-align: center;
}
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .badge .codicon.badge-content {
font-size: 12px;
font-weight: unset;
padding: 0 2px;
}
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .badge .codicon.badge-content::before {
text-align: center;
vertical-align: baseline;
}
/* Right aligned */
.monaco-workbench .activitybar.right > .content :not(.monaco-menu) > .monaco-action-bar .action-label:not(.codicon) {

View File

@@ -45,30 +45,6 @@
background-color: inherit;
}
/** Home Bar */
.monaco-workbench .activitybar > .content > .home-bar {
position: relative;
width: 100%;
height: 48px;
}
.monaco-workbench .activitybar > .content > .home-bar > .home-bar-icon-badge {
position: absolute;
right: 10px;
bottom: 9px;
width: 14px;
height: 14px;
z-index: 1; /* on top of home indicator */
background-image: url('../../../media/code-icon.svg');
background-repeat: no-repeat;
background-position: center center;
background-size: 14px;
pointer-events: none;
border-top: 2px solid transparent;
border-left: 2px solid transparent;
}
/** Viewlet Switcher */
.monaco-workbench .activitybar > .content .monaco-action-bar {

View File

@@ -3,10 +3,10 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import { localize } from 'vs/nls';
import { IAction, toAction } from 'vs/base/common/actions';
import { illegalArgument } from 'vs/base/common/errors';
import * as arrays from 'vs/base/common/arrays';
import { equals } from 'vs/base/common/arrays';
import { IDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { IBadge } from 'vs/workbench/services/activity/common/activity';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
@@ -224,10 +224,9 @@ export class CompositeBar extends Widget implements ICompositeBar {
);
},
orientation: this.options.orientation,
ariaLabel: nls.localize('activityBarAriaLabel', "Active View Switcher"),
ariaLabel: localize('activityBarAriaLabel', "Active View Switcher"),
animated: false,
preventLoopNavigation: this.options.preventLoopNavigation,
ignoreOrientationForPreviousAndNextKey: true,
triggerKeys: { keyDown: true }
}));
@@ -539,7 +538,7 @@ export class CompositeBar extends Widget implements ICompositeBar {
compositesToShow.length ? compositesToShow.splice(compositesToShow.length - 2, 1) : compositesToShow.pop();
}
const visibleCompositesChange = !arrays.equals(compositesToShow, this.visibleComposites);
const visibleCompositesChange = !equals(compositesToShow, this.visibleComposites);
// Pull out overflow action if there is a composite change so that we can add it to the end later
if (this.compositeOverflowAction && visibleCompositesChange) {

View File

@@ -3,13 +3,13 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import { localize } from 'vs/nls';
import { Action, IAction, Separator } from 'vs/base/common/actions';
import * as dom from 'vs/base/browser/dom';
import { $, addDisposableListener, append, clearNode, EventHelper, EventType, getDomNodePagePosition, hide, show } from 'vs/base/browser/dom';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { dispose, toDisposable, MutableDisposable } from 'vs/base/common/lifecycle';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IThemeService, IColorTheme } from 'vs/platform/theme/common/themeService';
import { IThemeService, IColorTheme, ThemeIcon } from 'vs/platform/theme/common/themeService';
import { TextBadge, NumberBadge, IBadge, IconBadge, ProgressBadge } from 'vs/workbench/services/activity/common/activity';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { contrastBorder } from 'vs/platform/theme/common/colorRegistry';
@@ -19,8 +19,8 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { Emitter, Event } from 'vs/base/common/event';
import { CompositeDragAndDropObserver, ICompositeDragAndDrop, Before2D, toggleDropEffect } from 'vs/workbench/browser/dnd';
import { Color } from 'vs/base/common/color';
import { Codicon } from 'vs/base/common/codicons';
import { IBaseActionViewItemOptions, BaseActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems';
import { Codicon } from 'vs/base/common/codicons';
export interface ICompositeActivity {
badge: IBadge;
@@ -125,6 +125,7 @@ export interface ICompositeBarColors {
export interface IActivityActionViewItemOptions extends IBaseActionViewItemOptions {
icon?: boolean;
colors: (theme: IColorTheme) => ICompositeBarColors;
hasPopup?: boolean;
}
export class ActivityActionViewItem extends BaseActionViewItem {
@@ -199,16 +200,19 @@ export class ActivityActionViewItem extends BaseActionViewItem {
this.container = container;
// Make the container tab-able for keyboard navigation
this.container.tabIndex = 0;
this.container.setAttribute('role', 'tab');
if (this.options.hasPopup) {
this.container.setAttribute('role', 'button');
this.container.setAttribute('aria-haspopup', 'true');
} else {
this.container.setAttribute('role', 'tab');
}
// Try hard to prevent keyboard only focus feedback when using mouse
this._register(dom.addDisposableListener(this.container, dom.EventType.MOUSE_DOWN, () => {
this._register(addDisposableListener(this.container, EventType.MOUSE_DOWN, () => {
this.container.classList.add('clicked');
}));
this._register(dom.addDisposableListener(this.container, dom.EventType.MOUSE_UP, () => {
this._register(addDisposableListener(this.container, EventType.MOUSE_UP, () => {
if (this.mouseUpTimeout) {
clearTimeout(this.mouseUpTimeout);
}
@@ -219,19 +223,19 @@ export class ActivityActionViewItem extends BaseActionViewItem {
}));
// Label
this.label = dom.append(container, dom.$('a'));
this.label = append(container, $('a'));
// Badge
this.badge = dom.append(container, dom.$('.badge'));
this.badgeContent = dom.append(this.badge, dom.$('.badge-content'));
this.badge = append(container, $('.badge'));
this.badgeContent = append(this.badge, $('.badge-content'));
// Activity bar active border + background
const isActivityBarItem = this.options.icon;
if (isActivityBarItem) {
dom.append(container, dom.$('.active-item-indicator'));
append(container, $('.active-item-indicator'));
}
dom.hide(this.badge);
hide(this.badge);
this.updateActivity();
this.updateStyles();
@@ -259,8 +263,8 @@ export class ActivityActionViewItem extends BaseActionViewItem {
this.badgeDisposable.clear();
dom.clearNode(this.badgeContent);
dom.hide(this.badge);
clearNode(this.badgeContent);
hide(this.badge);
if (badge) {
@@ -278,24 +282,26 @@ export class ActivityActionViewItem extends BaseActionViewItem {
}
}
this.badgeContent.textContent = number;
dom.show(this.badge);
show(this.badge);
}
}
// Text
else if (badge instanceof TextBadge) {
this.badgeContent.textContent = badge.text;
dom.show(this.badge);
show(this.badge);
}
// Text
// Icon
else if (badge instanceof IconBadge) {
dom.show(this.badge);
const clazzList = ThemeIcon.asClassNameArray(badge.icon);
this.badgeContent.classList.add(...clazzList);
show(this.badge);
}
// Progress
else if (badge instanceof ProgressBadge) {
dom.show(this.badge);
show(this.badge);
}
if (clazz) {
@@ -308,7 +314,7 @@ export class ActivityActionViewItem extends BaseActionViewItem {
let title: string;
if (badge?.getDescription()) {
if (this.activity.name) {
title = nls.localize('badgeTitle', "{0} - {1}", this.activity.name, badge.getDescription());
title = localize('badgeTitle', "{0} - {1}", this.activity.name, badge.getDescription());
} else {
title = badge.getDescription();
}
@@ -363,7 +369,7 @@ export class CompositeOverflowActivityAction extends ActivityAction {
) {
super({
id: 'additionalComposites.action',
name: nls.localize('additionalViews', "Additional Views"),
name: localize('additionalViews', "Additional Views"),
cssClass: Codicon.more.classNames
});
}
@@ -386,7 +392,7 @@ export class CompositeOverflowActivityActionViewItem extends ActivityActionViewI
@IContextMenuService private readonly contextMenuService: IContextMenuService,
@IThemeService themeService: IThemeService
) {
super(action, { icon: true, colors }, themeService);
super(action, { icon: true, colors, hasPopup: true }, themeService);
}
showMenu(): void {
@@ -418,7 +424,7 @@ export class CompositeOverflowActivityActionViewItem extends ActivityActionViewI
}
if (suffix) {
action.label = nls.localize('numberBadge', "{0} ({1})", composite.name, suffix);
action.label = localize('numberBadge', "{0} ({1})", composite.name, suffix);
} else {
action.label = composite.name || '';
}
@@ -441,7 +447,7 @@ class ManageExtensionAction extends Action {
constructor(
@ICommandService private readonly commandService: ICommandService
) {
super('activitybar.manage.extension', nls.localize('manageExtension', "Manage Extension"));
super('activitybar.manage.extension', localize('manageExtension', "Manage Extension"));
}
run(id: string): Promise<void> {
@@ -507,7 +513,7 @@ export class CompositeActionViewItem extends ActivityActionViewItem {
}
const keybinding = this.compositeActivityAction.activity.keybindingId ? this.keybindingService.lookupKeybinding(this.compositeActivityAction.activity.keybindingId) : null;
return keybinding ? nls.localize('titleKeybinding', "{0} ({1})", name, keybinding.getLabel()) : name;
return keybinding ? localize('titleKeybinding', "{0} ({1})", name, keybinding.getLabel()) : name;
}
render(container: HTMLElement): void {
@@ -516,8 +522,8 @@ export class CompositeActionViewItem extends ActivityActionViewItem {
this.updateChecked();
this.updateEnabled();
this._register(dom.addDisposableListener(this.container, dom.EventType.CONTEXT_MENU, e => {
dom.EventHelper.stop(e, true);
this._register(addDisposableListener(this.container, EventType.CONTEXT_MENU, e => {
EventHelper.stop(e, true);
this.showContextMenu(container);
}));
@@ -540,7 +546,7 @@ export class CompositeActionViewItem extends ActivityActionViewItem {
},
onDrop: e => {
dom.EventHelper.stop(e.eventData, true);
EventHelper.stop(e.eventData, true);
this.dndHandler.drop(e.dragAndDropData, this.activity.id, e.eventData, insertDropBefore);
insertDropBefore = this.updateFromDragging(container, false, e.eventData);
},
@@ -620,10 +626,10 @@ export class CompositeActionViewItem extends ActivityActionViewItem {
const isPinned = this.compositeBar.isPinned(this.activity.id);
if (isPinned) {
this.toggleCompositePinnedAction.label = nls.localize('hide', "Hide '{0}'", this.getActivtyName(true));
this.toggleCompositePinnedAction.label = localize('hide', "Hide '{0}'", this.getActivtyName(true));
this.toggleCompositePinnedAction.checked = false;
} else {
this.toggleCompositePinnedAction.label = nls.localize('keep', "Keep '{0}'", this.getActivtyName(true));
this.toggleCompositePinnedAction.label = localize('keep', "Keep '{0}'", this.getActivtyName(true));
}
const otherActions = this.contextMenuActionsProvider();
@@ -632,7 +638,7 @@ export class CompositeActionViewItem extends ActivityActionViewItem {
actions.push(...otherActions);
}
const elementPosition = dom.getDomNodePagePosition(container);
const elementPosition = getDomNodePagePosition(container);
const anchor = {
x: Math.floor(elementPosition.left + (elementPosition.width / 2)),
y: elementPosition.top + elementPosition.height
@@ -645,10 +651,6 @@ export class CompositeActionViewItem extends ActivityActionViewItem {
});
}
focus(): void {
this.container.focus();
}
protected updateChecked(): void {
if (this.getAction().checked) {
this.container.classList.add('checked');
@@ -688,7 +690,7 @@ export class ToggleCompositePinnedAction extends Action {
private activity: IActivity | undefined,
private compositeBar: ICompositeBar
) {
super('show.toggleCompositePinned', activity ? activity.name : nls.localize('toggle', "Toggle View Pinned"));
super('show.toggleCompositePinned', activity ? activity.name : localize('toggle', "Toggle View Pinned"));
this.checked = !!this.activity && this.compositeBar.isPinned(this.activity.id);
}

View File

@@ -4,15 +4,15 @@
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./media/compositepart';
import * as nls from 'vs/nls';
import { localize } from 'vs/nls';
import { defaultGenerator } from 'vs/base/common/idGenerator';
import { IDisposable, dispose, DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle';
import { Emitter } from 'vs/base/common/event';
import * as errors from 'vs/base/common/errors';
import { isPromiseCanceledError } from 'vs/base/common/errors';
import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar';
import { ActionsOrientation, prepareActions } from 'vs/base/browser/ui/actionbar/actionbar';
import { ActionsOrientation, IActionViewItem, prepareActions } from 'vs/base/browser/ui/actionbar/actionbar';
import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar';
import { IAction, WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification, IActionViewItem } from 'vs/base/common/actions';
import { IAction, WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification } from 'vs/base/common/actions';
import { Part, IPartOptions } from 'vs/workbench/browser/part';
import { Composite, CompositeRegistry } from 'vs/workbench/browser/composite';
import { IComposite } from 'vs/workbench/common/composite';
@@ -96,7 +96,7 @@ export abstract class CompositePart<T extends Composite> extends Part {
protected openComposite(id: string, focus?: boolean): Composite | undefined {
// Check if composite already visible and just focus in that case
if (this.activeComposite && this.activeComposite.getId() === id) {
if (this.activeComposite?.getId() === id) {
if (focus) {
this.activeComposite.focus();
}
@@ -137,7 +137,7 @@ export abstract class CompositePart<T extends Composite> extends Part {
}
// Check if composite already visible and just focus in that case
if (this.activeComposite && this.activeComposite.getId() === composite.getId()) {
if (this.activeComposite?.getId() === composite.getId()) {
if (focus) {
composite.focus();
}
@@ -258,7 +258,7 @@ export abstract class CompositePart<T extends Composite> extends Part {
this.telemetryActionsListener.value = toolBar.actionRunner.onDidRun(e => {
// Check for Error
if (e.error && !errors.isPromiseCanceledError(e.error)) {
if (e.error && !isPromiseCanceledError(e.error)) {
this.notificationService.error(e.error);
}
@@ -290,7 +290,7 @@ export abstract class CompositePart<T extends Composite> extends Part {
}
// Active Composite
if (this.activeComposite && this.activeComposite.getId() === compositeId) {
if (this.activeComposite?.getId() === compositeId) {
// Actions
const actionsBinding = this.collectCompositeActions(this.activeComposite);
this.mapActionsBindingToComposite.set(this.activeComposite.getId(), actionsBinding);
@@ -318,7 +318,7 @@ export abstract class CompositePart<T extends Composite> extends Part {
this.titleLabel.updateTitle(compositeId, compositeTitle, withNullAsUndefined(keybinding?.getLabel()));
const toolBar = assertIsDefined(this.toolBar);
toolBar.setAriaLabel(nls.localize('ariaCompositeToolbarLabel', "{0} actions", compositeTitle));
toolBar.setAriaLabel(localize('ariaCompositeToolbarLabel', "{0} actions", compositeTitle));
}
private collectCompositeActions(composite?: Composite): () => void {
@@ -394,7 +394,7 @@ export abstract class CompositePart<T extends Composite> extends Part {
orientation: ActionsOrientation.HORIZONTAL,
getKeyBinding: action => this.keybindingService.lookupKeybinding(action.id),
anchorAlignmentProvider: () => this.getTitleAreaDropDownAnchorAlignment(),
toggleMenuTitle: nls.localize('viewsAndMoreActions', "Views and More Actions...")
toggleMenuTitle: localize('viewsAndMoreActions', "Views and More Actions...")
}));
this.collectCompositeActions()();
@@ -413,7 +413,7 @@ export abstract class CompositePart<T extends Composite> extends Part {
// The title label is shared for all composites in the base CompositePart
if (!this.activeComposite || this.activeComposite.getId() === id) {
titleLabel.innerText = title;
titleLabel.title = keybinding ? nls.localize('titleTooltip', "{0} ({1})", title, keybinding) : title;
titleLabel.title = keybinding ? localize('titleTooltip', "{0} ({1})", title, keybinding) : title;
}
},
@@ -484,7 +484,7 @@ export abstract class CompositePart<T extends Composite> extends Part {
}
protected removeComposite(compositeId: string): boolean {
if (this.activeComposite && this.activeComposite.getId() === compositeId) {
if (this.activeComposite?.getId() === compositeId) {
return false; // do not remove active composite
}

View File

@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import { localize } from 'vs/nls';
import { IDialogOptions, IConfirmation, IConfirmationResult, DialogType, IShowResult, IInputResult, ICheckbox, IInput, IDialogHandler } from 'vs/platform/dialogs/common/dialogs';
import { ILayoutService } from 'vs/platform/layout/browser/layoutService';
import { ILogService } from 'vs/platform/log/common/log';
@@ -46,13 +46,13 @@ export class BrowserDialogHandler implements IDialogHandler {
if (confirmation.primaryButton) {
buttons.push(confirmation.primaryButton);
} else {
buttons.push(nls.localize({ key: 'yesButton', comment: ['&& denotes a mnemonic'] }, "&&Yes"));
buttons.push(localize({ key: 'yesButton', comment: ['&& denotes a mnemonic'] }, "&&Yes"));
}
if (confirmation.secondaryButton) {
buttons.push(confirmation.secondaryButton);
} else if (typeof confirmation.secondaryButton === 'undefined') {
buttons.push(nls.localize('cancelButton', "Cancel"));
buttons.push(localize('cancelButton', "Cancel"));
}
const result = await this.doShow(confirmation.type, confirmation.message, buttons, confirmation.detail, 1, confirmation.checkbox);
@@ -87,7 +87,7 @@ export class BrowserDialogHandler implements IDialogHandler {
type,
keyEventProcessor: (event: StandardKeyboardEvent) => {
const resolved = this.keybindingService.softDispatch(event, this.layoutService.container);
if (resolved && resolved.commandId) {
if (resolved?.commandId) {
if (BrowserDialogHandler.ALLOWABLE_COMMANDS.indexOf(resolved.commandId) === -1) {
EventHelper.stop(event, true);
}
@@ -121,8 +121,13 @@ export class BrowserDialogHandler implements IDialogHandler {
async about(): Promise<void> {
const detailString = (useAgo: boolean): string => {
<<<<<<< HEAD
return nls.localize('aboutDetail',
"code-server: v{4}\n VS Code: v{0}\nCommit: {1}\nDate: {2}\nBrowser: {3}",
=======
return localize('aboutDetail',
"Version: {0}\nCommit: {1}\nDate: {2}\nBrowser: {3}",
>>>>>>> e8cd17a97d8c58fffcbac05394b3ee2b3c72d384
this.productService.version || 'Unknown',
this.productService.commit || 'Unknown',
this.productService.date ? `${this.productService.date}${useAgo ? ' (' + fromNow(new Date(this.productService.date), true) + ')' : ''}` : 'Unknown',
@@ -135,7 +140,7 @@ export class BrowserDialogHandler implements IDialogHandler {
const detailToCopy = detailString(false);
const { choice } = await this.show(Severity.Info, this.productService.nameLong, [nls.localize('copy', "Copy"), nls.localize('ok', "OK")], { detail, cancelId: 1 });
const { choice } = await this.show(Severity.Info, this.productService.nameLong, [localize('copy', "Copy"), localize('ok', "OK")], { detail, cancelId: 1 });
if (choice === 0) {
this.clipboardService.writeText(detailToCopy);

View File

@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import { localize } from 'vs/nls';
import { BINARY_DIFF_EDITOR_ID } from 'vs/workbench/common/editor';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IThemeService } from 'vs/platform/theme/common/themeService';
@@ -33,7 +33,7 @@ export class BinaryResourceDiffEditor extends SideBySideEditor {
const secondary = this.secondaryEditorPane;
if (primary instanceof BaseBinaryResourceEditor && secondary instanceof BaseBinaryResourceEditor) {
return nls.localize('metadataDiff', "{0} ↔ {1}", secondary.getMetadata(), primary.getMetadata());
return localize('metadataDiff', "{0} ↔ {1}", secondary.getMetadata(), primary.getMetadata());
}
return undefined;

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./media/binaryeditor';
import * as nls from 'vs/nls';
import { localize } from 'vs/nls';
import { Emitter } from 'vs/base/common/event';
import { EditorInput, EditorOptions, IEditorOpenContext } from 'vs/workbench/common/editor';
import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane';
@@ -32,8 +32,8 @@ export interface IOpenCallbacks {
*/
export abstract class BaseBinaryResourceEditor extends EditorPane {
private readonly _onMetadataChanged = this._register(new Emitter<void>());
readonly onMetadataChanged = this._onMetadataChanged.event;
private readonly _onDidChangeMetadata = this._register(new Emitter<void>());
readonly onDidChangeMetadata = this._onDidChangeMetadata.event;
private readonly _onDidOpenInPlace = this._register(new Emitter<void>());
readonly onDidOpenInPlace = this._onDidOpenInPlace.event;
@@ -58,7 +58,7 @@ export abstract class BaseBinaryResourceEditor extends EditorPane {
}
getTitle(): string {
return this.input ? this.input.getName() : nls.localize('binaryEditor', "Binary Viewer");
return this.input ? this.input.getName() : localize('binaryEditor', "Binary Viewer");
}
protected createEditor(parent: HTMLElement): void {
@@ -111,7 +111,7 @@ export abstract class BaseBinaryResourceEditor extends EditorPane {
private handleMetadataChanged(meta: string | undefined): void {
this.metadata = meta;
this._onMetadataChanged.fire();
this._onDidChangeMetadata.fire();
}
getMetadata(): string | undefined {
@@ -139,7 +139,7 @@ export abstract class BaseBinaryResourceEditor extends EditorPane {
const [binaryContainer, scrollbar] = assertAllDefined(this.binaryContainer, this.scrollbar);
size(binaryContainer, dimension.width, dimension.height);
scrollbar.scanDomNode();
if (this.resourceViewerContext && this.resourceViewerContext.layout) {
if (typeof this.resourceViewerContext?.layout === 'function') {
this.resourceViewerContext.layout(dimension);
}
}
@@ -217,7 +217,7 @@ class FileTooLargeFileView {
clearNode(container);
const label = document.createElement('span');
label.textContent = nls.localize('nativeFileTooLargeError', "The file is not displayed in the editor because it is too large ({0}).", size);
label.textContent = localize('nativeFileTooLargeError', "The file is not displayed in the editor because it is too large ({0}).", size);
container.appendChild(label);
scrollbar.scanDomNode();
@@ -240,12 +240,12 @@ class FileSeemsBinaryFileView {
const disposables = new DisposableStore();
const label = document.createElement('p');
label.textContent = nls.localize('nativeBinaryError', "The file is not displayed in the editor because it is either binary or uses an unsupported text encoding.");
label.textContent = localize('nativeBinaryError', "The file is not displayed in the editor because it is either binary or uses an unsupported text encoding.");
container.appendChild(label);
const link = append(label, $('a.embedded-link'));
link.setAttribute('role', 'button');
link.textContent = nls.localize('openAsText', "Do you want to open it anyway?");
link.textContent = localize('openAsText', "Do you want to open it anyway?");
disposables.add(addDisposableListener(link, EventType.CLICK, () => delegate.openInternalClb(descriptor.resource)));

View File

@@ -251,12 +251,13 @@ export class BreadcrumbsControl {
// honor diff editors and such
const uri = EditorResourceAccessor.getCanonicalUri(this._editorGroup.activeEditor, { supportSideBySide: SideBySideEditor.PRIMARY });
const wasHidden = this.isHidden();
if (!uri || !this._fileService.canHandleResource(uri)) {
// cleanup and return when there is no input or when
// we cannot handle this input
this._ckBreadcrumbsPossible.set(false);
if (!this.isHidden()) {
if (!wasHidden) {
this.hide();
return true;
} else {
@@ -315,7 +316,7 @@ export class BreadcrumbsControl {
}
});
return true;
return wasHidden !== this.isHidden();
}
private _onFocusEvent(event: IBreadcrumbsItemEvent): void {

View File

@@ -427,15 +427,9 @@ export class BreadcrumbsFilePicker extends BreadcrumbsPicker {
}
async _revealElement(element: IFileStat | IWorkspaceFolder, options: IEditorOptions, sideBySide: boolean): Promise<boolean> {
let resource: URI | undefined;
if (isWorkspaceFolder(element)) {
resource = element.uri;
} else if (!element.isDirectory) {
resource = element.resource;
}
if (resource) {
if (!isWorkspaceFolder(element) && element.isFile) {
this._onWillPickElement.fire();
await this._editorService.openEditor({ resource, options }, sideBySide ? SIDE_GROUP : undefined);
await this._editorService.openEditor({ resource: element.resource, options }, sideBySide ? SIDE_GROUP : undefined);
return true;
}
return false;

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { Registry } from 'vs/platform/registry/common/platform';
import * as nls from 'vs/nls';
import { localize } from 'vs/nls';
import { URI, UriComponents } from 'vs/base/common/uri';
import { IEditorRegistry, EditorDescriptor, Extensions as EditorExtensions } from 'vs/workbench/browser/editor';
import { EditorInput, IEditorInputFactory, SideBySideEditorInput, IEditorInputFactoryRegistry, Extensions as EditorInputExtensions, TextCompareEditorActiveContext, ActiveEditorPinnedContext, EditorGroupEditorsCountContext, ActiveEditorStickyContext, ActiveEditorAvailableEditorIdsContext, MultipleEditorGroupsContext, ActiveEditorDirtyContext } from 'vs/workbench/common/editor';
@@ -15,6 +15,7 @@ import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/u
import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { TextDiffEditor } from 'vs/workbench/browser/parts/editor/textDiffEditor';
import { UntitledHintContribution } from 'vs/workbench/browser/parts/editor/untitledHint';
import { BinaryResourceDiffEditor } from 'vs/workbench/browser/parts/editor/binaryDiffEditor';
import { ChangeEncodingAction, ChangeEOLAction, ChangeModeAction, EditorStatus } from 'vs/workbench/browser/parts/editor/editorStatus';
import { IWorkbenchActionRegistry, Extensions as ActionExtensions, CATEGORIES } from 'vs/workbench/common/actions';
@@ -35,7 +36,12 @@ import {
NewEditorGroupAboveAction, NewEditorGroupBelowAction, SplitEditorOrthogonalAction, CloseEditorInAllGroupsAction, NavigateToLastEditLocationAction, ToggleGroupSizesAction, ShowAllEditorsByMostRecentlyUsedAction,
QuickAccessPreviousRecentlyUsedEditorAction, OpenPreviousRecentlyUsedEditorInGroupAction, OpenNextRecentlyUsedEditorInGroupAction, QuickAccessLeastRecentlyUsedEditorAction, QuickAccessLeastRecentlyUsedEditorInGroupAction, ReopenResourcesAction, ToggleEditorTypeAction, DuplicateGroupDownAction, DuplicateGroupLeftAction, DuplicateGroupRightAction, DuplicateGroupUpAction
} from 'vs/workbench/browser/parts/editor/editorActions';
import * as editorCommands from 'vs/workbench/browser/parts/editor/editorCommands';
import {
CLOSE_EDITORS_AND_GROUP_COMMAND_ID, CLOSE_EDITORS_IN_GROUP_COMMAND_ID, CLOSE_EDITORS_TO_THE_RIGHT_COMMAND_ID, CLOSE_EDITOR_COMMAND_ID, CLOSE_EDITOR_GROUP_COMMAND_ID,
CLOSE_OTHER_EDITORS_IN_GROUP_COMMAND_ID, CLOSE_PINNED_EDITOR_COMMAND_ID, CLOSE_SAVED_EDITORS_COMMAND_ID, GOTO_NEXT_CHANGE, GOTO_PREVIOUS_CHANGE, KEEP_EDITOR_COMMAND_ID,
PIN_EDITOR_COMMAND_ID, SHOW_EDITORS_IN_GROUP, SPLIT_EDITOR_DOWN, SPLIT_EDITOR_LEFT, SPLIT_EDITOR_RIGHT, SPLIT_EDITOR_UP, TOGGLE_DIFF_IGNORE_TRIM_WHITESPACE,
TOGGLE_DIFF_SIDE_BY_SIDE, TOGGLE_KEEP_EDITORS_COMMAND_ID, UNPIN_EDITOR_COMMAND_ID, setup
} from 'vs/workbench/browser/parts/editor/editorCommands';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { inQuickPickContext, getQuickNavigateHandler } from 'vs/workbench/browser/quickaccess';
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
@@ -63,7 +69,7 @@ Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerEditor(
EditorDescriptor.create(
TextResourceEditor,
TextResourceEditor.ID,
nls.localize('textEditor', "Text Editor"),
localize('textEditor', "Text Editor"),
),
[
new SyncDescriptor(UntitledTextEditorInput),
@@ -76,7 +82,7 @@ Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerEditor(
EditorDescriptor.create(
TextDiffEditor,
TextDiffEditor.ID,
nls.localize('textDiffEditor', "Text Diff Editor")
localize('textDiffEditor', "Text Diff Editor")
),
[
new SyncDescriptor(DiffEditorInput)
@@ -88,7 +94,7 @@ Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerEditor(
EditorDescriptor.create(
BinaryResourceDiffEditor,
BinaryResourceDiffEditor.ID,
nls.localize('binaryDiffEditor', "Binary Diff Editor")
localize('binaryDiffEditor', "Binary Diff Editor")
),
[
new SyncDescriptor(DiffEditorInput)
@@ -99,7 +105,7 @@ Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerEditor(
EditorDescriptor.create(
SideBySideEditor,
SideBySideEditor.ID,
nls.localize('sideBySideEditor', "Side by Side Editor")
localize('sideBySideEditor', "Side by Side Editor")
),
[
new SyncDescriptor(SideBySideEditorInput)
@@ -276,6 +282,9 @@ Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).regi
// Register Editor Auto Save
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(EditorAutoSave, LifecyclePhase.Ready);
// Register Untitled Hint
registerEditorContribution(UntitledHintContribution.ID, UntitledHintContribution);
// Register Status Actions
const registry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions);
registry.registerWorkbenchAction(SyncActionDescriptor.from(ChangeModeAction, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_M) }), 'Change Language Mode');
@@ -291,24 +300,24 @@ quickAccessRegistry.registerQuickAccessProvider({
ctor: ActiveGroupEditorsByMostRecentlyUsedQuickAccess,
prefix: ActiveGroupEditorsByMostRecentlyUsedQuickAccess.PREFIX,
contextKey: editorPickerContextKey,
placeholder: nls.localize('editorQuickAccessPlaceholder', "Type the name of an editor to open it."),
helpEntries: [{ description: nls.localize('activeGroupEditorsByMostRecentlyUsedQuickAccess', "Show Editors in Active Group by Most Recently Used"), needsEditor: false }]
placeholder: localize('editorQuickAccessPlaceholder', "Type the name of an editor to open it."),
helpEntries: [{ description: localize('activeGroupEditorsByMostRecentlyUsedQuickAccess', "Show Editors in Active Group by Most Recently Used"), needsEditor: false }]
});
quickAccessRegistry.registerQuickAccessProvider({
ctor: AllEditorsByAppearanceQuickAccess,
prefix: AllEditorsByAppearanceQuickAccess.PREFIX,
contextKey: editorPickerContextKey,
placeholder: nls.localize('editorQuickAccessPlaceholder', "Type the name of an editor to open it."),
helpEntries: [{ description: nls.localize('allEditorsByAppearanceQuickAccess', "Show All Opened Editors By Appearance"), needsEditor: false }]
placeholder: localize('editorQuickAccessPlaceholder', "Type the name of an editor to open it."),
helpEntries: [{ description: localize('allEditorsByAppearanceQuickAccess', "Show All Opened Editors By Appearance"), needsEditor: false }]
});
quickAccessRegistry.registerQuickAccessProvider({
ctor: AllEditorsByMostRecentlyUsedQuickAccess,
prefix: AllEditorsByMostRecentlyUsedQuickAccess.PREFIX,
contextKey: editorPickerContextKey,
placeholder: nls.localize('editorQuickAccessPlaceholder', "Type the name of an editor to open it."),
helpEntries: [{ description: nls.localize('allEditorsByMostRecentlyUsedQuickAccess', "Show All Opened Editors By Most Recently Used"), needsEditor: false }]
placeholder: localize('editorQuickAccessPlaceholder', "Type the name of an editor to open it."),
helpEntries: [{ description: localize('allEditorsByMostRecentlyUsedQuickAccess', "Show All Opened Editors By Most Recently Used"), needsEditor: false }]
});
// Register Editor Actions
@@ -326,7 +335,7 @@ registry.registerWorkbenchAction(SyncActionDescriptor.from(ReopenClosedEditorAct
registry.registerWorkbenchAction(SyncActionDescriptor.from(ShowAllEditorsByAppearanceAction, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_P), mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.Tab } }), 'View: Show All Editors By Appearance', CATEGORIES.View.value);
registry.registerWorkbenchAction(SyncActionDescriptor.from(ShowAllEditorsByMostRecentlyUsedAction), 'View: Show All Editors By Most Recently Used', CATEGORIES.View.value);
registry.registerWorkbenchAction(SyncActionDescriptor.from(ShowEditorsInActiveGroupByMostRecentlyUsedAction), 'View: Show Editors in Active Group By Most Recently Used', CATEGORIES.View.value);
registry.registerWorkbenchAction(SyncActionDescriptor.from(ClearRecentFilesAction), 'File: Clear Recently Opened', nls.localize('file', "File"));
registry.registerWorkbenchAction(SyncActionDescriptor.from(ClearRecentFilesAction), 'File: Clear Recently Opened', localize('file', "File"));
registry.registerWorkbenchAction(SyncActionDescriptor.from(CloseAllEditorsAction, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_W) }), 'View: Close All Editors', CATEGORIES.View.value);
registry.registerWorkbenchAction(SyncActionDescriptor.from(CloseAllEditorGroupsAction, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_W) }), 'View: Close All Editor Groups', CATEGORIES.View.value);
registry.registerWorkbenchAction(SyncActionDescriptor.from(CloseLeftEditorsInGroupAction), 'View: Close Editors to the Left in Group', CATEGORIES.View.value);
@@ -424,7 +433,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
});
// Editor Commands
editorCommands.setup();
setup();
// Touch Bar
if (isMacintosh) {
@@ -442,33 +451,34 @@ if (isMacintosh) {
}
// Empty Editor Group Context Menu
MenuRegistry.appendMenuItem(MenuId.EmptyEditorGroupContext, { command: { id: editorCommands.SPLIT_EDITOR_UP, title: nls.localize('splitUp', "Split Up") }, group: '2_split', order: 10 });
MenuRegistry.appendMenuItem(MenuId.EmptyEditorGroupContext, { command: { id: editorCommands.SPLIT_EDITOR_DOWN, title: nls.localize('splitDown', "Split Down") }, group: '2_split', order: 20 });
MenuRegistry.appendMenuItem(MenuId.EmptyEditorGroupContext, { command: { id: editorCommands.SPLIT_EDITOR_LEFT, title: nls.localize('splitLeft', "Split Left") }, group: '2_split', order: 30 });
MenuRegistry.appendMenuItem(MenuId.EmptyEditorGroupContext, { command: { id: editorCommands.SPLIT_EDITOR_RIGHT, title: nls.localize('splitRight', "Split Right") }, group: '2_split', order: 40 });
MenuRegistry.appendMenuItem(MenuId.EmptyEditorGroupContext, { command: { id: editorCommands.CLOSE_EDITOR_GROUP_COMMAND_ID, title: nls.localize('close', "Close") }, group: '3_close', order: 10, when: ContextKeyExpr.has('multipleEditorGroups') });
MenuRegistry.appendMenuItem(MenuId.EmptyEditorGroupContext, { command: { id: SPLIT_EDITOR_UP, title: localize('splitUp', "Split Up") }, group: '2_split', order: 10 });
MenuRegistry.appendMenuItem(MenuId.EmptyEditorGroupContext, { command: { id: SPLIT_EDITOR_DOWN, title: localize('splitDown', "Split Down") }, group: '2_split', order: 20 });
MenuRegistry.appendMenuItem(MenuId.EmptyEditorGroupContext, { command: { id: SPLIT_EDITOR_LEFT, title: localize('splitLeft', "Split Left") }, group: '2_split', order: 30 });
MenuRegistry.appendMenuItem(MenuId.EmptyEditorGroupContext, { command: { id: SPLIT_EDITOR_RIGHT, title: localize('splitRight', "Split Right") }, group: '2_split', order: 40 });
MenuRegistry.appendMenuItem(MenuId.EmptyEditorGroupContext, { command: { id: CLOSE_EDITOR_GROUP_COMMAND_ID, title: localize('close', "Close") }, group: '3_close', order: 10, when: ContextKeyExpr.has('multipleEditorGroups') });
// Editor Title Context Menu
MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: editorCommands.CLOSE_EDITOR_COMMAND_ID, title: nls.localize('close', "Close") }, group: '1_close', order: 10 });
MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: editorCommands.CLOSE_OTHER_EDITORS_IN_GROUP_COMMAND_ID, title: nls.localize('closeOthers', "Close Others"), precondition: EditorGroupEditorsCountContext.notEqualsTo('1') }, group: '1_close', order: 20 });
MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: editorCommands.CLOSE_EDITORS_TO_THE_RIGHT_COMMAND_ID, title: nls.localize('closeRight', "Close to the Right"), precondition: EditorGroupEditorsCountContext.notEqualsTo('1') }, group: '1_close', order: 30, when: ContextKeyExpr.has('config.workbench.editor.showTabs') });
MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: editorCommands.CLOSE_SAVED_EDITORS_COMMAND_ID, title: nls.localize('closeAllSaved', "Close Saved") }, group: '1_close', order: 40 });
MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: editorCommands.CLOSE_EDITORS_IN_GROUP_COMMAND_ID, title: nls.localize('closeAll', "Close All") }, group: '1_close', order: 50 });
MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: CLOSE_EDITOR_COMMAND_ID, title: localize('close', "Close") }, group: '1_close', order: 10 });
MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: CLOSE_OTHER_EDITORS_IN_GROUP_COMMAND_ID, title: localize('closeOthers', "Close Others"), precondition: EditorGroupEditorsCountContext.notEqualsTo('1') }, group: '1_close', order: 20 });
MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: CLOSE_EDITORS_TO_THE_RIGHT_COMMAND_ID, title: localize('closeRight', "Close to the Right"), precondition: EditorGroupEditorsCountContext.notEqualsTo('1') }, group: '1_close', order: 30, when: ContextKeyExpr.has('config.workbench.editor.showTabs') });
MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: CLOSE_SAVED_EDITORS_COMMAND_ID, title: localize('closeAllSaved', "Close Saved") }, group: '1_close', order: 40 });
MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: CLOSE_EDITORS_IN_GROUP_COMMAND_ID, title: localize('closeAll', "Close All") }, group: '1_close', order: 50 });
MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: ReopenResourcesAction.ID, title: ReopenResourcesAction.LABEL }, group: '1_open', order: 10, when: ActiveEditorAvailableEditorIdsContext });
MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: editorCommands.KEEP_EDITOR_COMMAND_ID, title: nls.localize('keepOpen', "Keep Open"), precondition: ActiveEditorPinnedContext.toNegated() }, group: '3_preview', order: 10, when: ContextKeyExpr.has('config.workbench.editor.enablePreview') });
MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: editorCommands.PIN_EDITOR_COMMAND_ID, title: nls.localize('pin', "Pin") }, group: '3_preview', order: 20, when: ActiveEditorStickyContext.toNegated() });
MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: editorCommands.UNPIN_EDITOR_COMMAND_ID, title: nls.localize('unpin', "Unpin") }, group: '3_preview', order: 20, when: ActiveEditorStickyContext });
MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: editorCommands.SPLIT_EDITOR_UP, title: nls.localize('splitUp', "Split Up") }, group: '5_split', order: 10 });
MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: editorCommands.SPLIT_EDITOR_DOWN, title: nls.localize('splitDown', "Split Down") }, group: '5_split', order: 20 });
MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: editorCommands.SPLIT_EDITOR_LEFT, title: nls.localize('splitLeft', "Split Left") }, group: '5_split', order: 30 });
MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: editorCommands.SPLIT_EDITOR_RIGHT, title: nls.localize('splitRight', "Split Right") }, group: '5_split', order: 40 });
MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: KEEP_EDITOR_COMMAND_ID, title: localize('keepOpen', "Keep Open"), precondition: ActiveEditorPinnedContext.toNegated() }, group: '3_preview', order: 10, when: ContextKeyExpr.has('config.workbench.editor.enablePreview') });
MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: PIN_EDITOR_COMMAND_ID, title: localize('pin', "Pin") }, group: '3_preview', order: 20, when: ActiveEditorStickyContext.toNegated() });
MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: UNPIN_EDITOR_COMMAND_ID, title: localize('unpin', "Unpin") }, group: '3_preview', order: 20, when: ActiveEditorStickyContext });
MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: SPLIT_EDITOR_UP, title: localize('splitUp', "Split Up") }, group: '5_split', order: 10 });
MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: SPLIT_EDITOR_DOWN, title: localize('splitDown', "Split Down") }, group: '5_split', order: 20 });
MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: SPLIT_EDITOR_LEFT, title: localize('splitLeft', "Split Left") }, group: '5_split', order: 30 });
MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: SPLIT_EDITOR_RIGHT, title: localize('splitRight', "Split Right") }, group: '5_split', order: 40 });
// Editor Title Menu
MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: editorCommands.TOGGLE_DIFF_SIDE_BY_SIDE, title: nls.localize('toggleInlineView', "Toggle Inline View") }, group: '1_diff', order: 10, when: ContextKeyExpr.has('isInDiffEditor') });
MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: editorCommands.SHOW_EDITORS_IN_GROUP, title: nls.localize('showOpenedEditors', "Show Opened Editors") }, group: '3_open', order: 10 });
MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: editorCommands.CLOSE_EDITORS_IN_GROUP_COMMAND_ID, title: nls.localize('closeAll', "Close All") }, group: '5_close', order: 10 });
MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: editorCommands.CLOSE_SAVED_EDITORS_COMMAND_ID, title: nls.localize('closeAllSaved', "Close Saved") }, group: '5_close', order: 20 });
MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: editorCommands.TOGGLE_KEEP_EDITORS_COMMAND_ID, title: nls.localize('toggleKeepEditors', "Keep Editors Open"), toggled: ContextKeyExpr.not('config.workbench.editor.enablePreview') }, group: '7_settings', order: 10 });
MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: TOGGLE_DIFF_SIDE_BY_SIDE, title: localize('inlineView', "Inline View"), toggled: ContextKeyExpr.equals('config.diffEditor.renderSideBySide', false) }, group: '1_diff', order: 10, when: ContextKeyExpr.has('isInDiffEditor') });
MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: SHOW_EDITORS_IN_GROUP, title: localize('showOpenedEditors', "Show Opened Editors") }, group: '3_open', order: 10 });
MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: CLOSE_EDITORS_IN_GROUP_COMMAND_ID, title: localize('closeAll', "Close All") }, group: '5_close', order: 10 });
MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: CLOSE_SAVED_EDITORS_COMMAND_ID, title: localize('closeAllSaved', "Close Saved") }, group: '5_close', order: 20 });
MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: TOGGLE_KEEP_EDITORS_COMMAND_ID, title: localize('toggleKeepEditors', "Keep Editors Open"), toggled: ContextKeyExpr.not('config.workbench.editor.enablePreview') }, group: '7_settings', order: 10 });
MenuRegistry.appendMenuItem(MenuId.EditorTitle, { submenu: MenuId.EditorTitleRun, title: { value: localize('run', "Run"), original: 'Run', }, icon: Codicon.run, group: 'navigation', order: -1 });
interface IEditorToolItem { id: string; title: string; icon?: { dark?: URI; light?: URI; } | ThemeIcon; }
@@ -500,14 +510,14 @@ function appendEditorToolItem(primary: IEditorToolItem, when: ContextKeyExpressi
appendEditorToolItem(
{
id: SplitEditorAction.ID,
title: nls.localize('splitEditorRight', "Split Editor Right"),
title: localize('splitEditorRight', "Split Editor Right"),
icon: Codicon.splitHorizontal
},
ContextKeyExpr.not('splitEditorsVertically'),
100000, // towards the end
{
id: editorCommands.SPLIT_EDITOR_DOWN,
title: nls.localize('splitEditorDown', "Split Editor Down"),
id: SPLIT_EDITOR_DOWN,
title: localize('splitEditorDown', "Split Editor Down"),
icon: Codicon.splitVertical
}
);
@@ -515,14 +525,14 @@ appendEditorToolItem(
appendEditorToolItem(
{
id: SplitEditorAction.ID,
title: nls.localize('splitEditorDown', "Split Editor Down"),
title: localize('splitEditorDown', "Split Editor Down"),
icon: Codicon.splitVertical
},
ContextKeyExpr.has('splitEditorsVertically'),
100000, // towards the end
{
id: editorCommands.SPLIT_EDITOR_RIGHT,
title: nls.localize('splitEditorRight', "Split Editor Right"),
id: SPLIT_EDITOR_RIGHT,
title: localize('splitEditorRight', "Split Editor Right"),
icon: Codicon.splitHorizontal
}
);
@@ -530,15 +540,15 @@ appendEditorToolItem(
// Editor Title Menu: Close (tabs disabled, normal editor)
appendEditorToolItem(
{
id: editorCommands.CLOSE_EDITOR_COMMAND_ID,
title: nls.localize('close', "Close"),
id: CLOSE_EDITOR_COMMAND_ID,
title: localize('close', "Close"),
icon: Codicon.close
},
ContextKeyExpr.and(ContextKeyExpr.not('config.workbench.editor.showTabs'), ActiveEditorDirtyContext.toNegated(), ActiveEditorStickyContext.toNegated()),
1000000, // towards the far end
{
id: editorCommands.CLOSE_EDITORS_IN_GROUP_COMMAND_ID,
title: nls.localize('closeAll', "Close All"),
id: CLOSE_EDITORS_IN_GROUP_COMMAND_ID,
title: localize('closeAll', "Close All"),
icon: Codicon.closeAll
}
);
@@ -546,15 +556,15 @@ appendEditorToolItem(
// Editor Title Menu: Close (tabs disabled, dirty editor)
appendEditorToolItem(
{
id: editorCommands.CLOSE_EDITOR_COMMAND_ID,
title: nls.localize('close', "Close"),
id: CLOSE_EDITOR_COMMAND_ID,
title: localize('close', "Close"),
icon: Codicon.closeDirty
},
ContextKeyExpr.and(ContextKeyExpr.not('config.workbench.editor.showTabs'), ActiveEditorDirtyContext, ActiveEditorStickyContext.toNegated()),
1000000, // towards the far end
{
id: editorCommands.CLOSE_EDITORS_IN_GROUP_COMMAND_ID,
title: nls.localize('closeAll', "Close All"),
id: CLOSE_EDITORS_IN_GROUP_COMMAND_ID,
title: localize('closeAll', "Close All"),
icon: Codicon.closeAll
}
);
@@ -562,15 +572,15 @@ appendEditorToolItem(
// Editor Title Menu: Close (tabs disabled, sticky editor)
appendEditorToolItem(
{
id: editorCommands.UNPIN_EDITOR_COMMAND_ID,
title: nls.localize('unpin', "Unpin"),
id: UNPIN_EDITOR_COMMAND_ID,
title: localize('unpin', "Unpin"),
icon: Codicon.pinned
},
ContextKeyExpr.and(ContextKeyExpr.not('config.workbench.editor.showTabs'), ActiveEditorDirtyContext.toNegated(), ActiveEditorStickyContext),
1000000, // towards the far end
{
id: editorCommands.CLOSE_EDITOR_COMMAND_ID,
title: nls.localize('close', "Close"),
id: CLOSE_EDITOR_COMMAND_ID,
title: localize('close', "Close"),
icon: Codicon.close
}
);
@@ -578,29 +588,29 @@ appendEditorToolItem(
// Editor Title Menu: Close (tabs disabled, dirty & sticky editor)
appendEditorToolItem(
{
id: editorCommands.UNPIN_EDITOR_COMMAND_ID,
title: nls.localize('unpin', "Unpin"),
id: UNPIN_EDITOR_COMMAND_ID,
title: localize('unpin', "Unpin"),
icon: Codicon.pinnedDirty
},
ContextKeyExpr.and(ContextKeyExpr.not('config.workbench.editor.showTabs'), ActiveEditorDirtyContext, ActiveEditorStickyContext),
1000000, // towards the far end
{
id: editorCommands.CLOSE_EDITOR_COMMAND_ID,
title: nls.localize('close', "Close"),
id: CLOSE_EDITOR_COMMAND_ID,
title: localize('close', "Close"),
icon: Codicon.close
}
);
const previousChangeIcon = registerIcon('diff-editor-previous-change', Codicon.arrowUp, nls.localize('previousChangeIcon', 'Icon for the previous change action in the diff editor.'));
const nextChangeIcon = registerIcon('diff-editor-next-change', Codicon.arrowDown, nls.localize('nextChangeIcon', 'Icon for the next change action in the diff editor.'));
const toggleWhitespace = registerIcon('diff-editor-toggle-whitespace', Codicon.whitespace, nls.localize('toggleWhitespace', 'Icon for the toggle whitespace action in the diff editor.'));
const previousChangeIcon = registerIcon('diff-editor-previous-change', Codicon.arrowUp, localize('previousChangeIcon', 'Icon for the previous change action in the diff editor.'));
const nextChangeIcon = registerIcon('diff-editor-next-change', Codicon.arrowDown, localize('nextChangeIcon', 'Icon for the next change action in the diff editor.'));
const toggleWhitespace = registerIcon('diff-editor-toggle-whitespace', Codicon.whitespace, localize('toggleWhitespace', 'Icon for the toggle whitespace action in the diff editor.'));
// Diff Editor Title Menu: Previous Change
appendEditorToolItem(
{
id: editorCommands.GOTO_PREVIOUS_CHANGE,
title: nls.localize('navigate.prev.label', "Previous Change"),
id: GOTO_PREVIOUS_CHANGE,
title: localize('navigate.prev.label', "Previous Change"),
icon: previousChangeIcon
},
TextCompareEditorActiveContext,
@@ -610,8 +620,8 @@ appendEditorToolItem(
// Diff Editor Title Menu: Next Change
appendEditorToolItem(
{
id: editorCommands.GOTO_NEXT_CHANGE,
title: nls.localize('navigate.next.label', "Next Change"),
id: GOTO_NEXT_CHANGE,
title: localize('navigate.next.label', "Next Change"),
icon: nextChangeIcon
},
TextCompareEditorActiveContext,
@@ -621,8 +631,8 @@ appendEditorToolItem(
// Diff Editor Title Menu: Toggle Ignore Trim Whitespace (Enabled)
appendEditorToolItem(
{
id: editorCommands.TOGGLE_DIFF_IGNORE_TRIM_WHITESPACE,
title: nls.localize('ignoreTrimWhitespace.label', "Ignore Leading/Trailing Whitespace Differences"),
id: TOGGLE_DIFF_IGNORE_TRIM_WHITESPACE,
title: localize('ignoreTrimWhitespace.label', "Ignore Leading/Trailing Whitespace Differences"),
icon: toggleWhitespace
},
ContextKeyExpr.and(TextCompareEditorActiveContext, ContextKeyExpr.notEquals('config.diffEditor.ignoreTrimWhitespace', true)),
@@ -632,8 +642,8 @@ appendEditorToolItem(
// Diff Editor Title Menu: Toggle Ignore Trim Whitespace (Disabled)
appendEditorToolItem(
{
id: editorCommands.TOGGLE_DIFF_IGNORE_TRIM_WHITESPACE,
title: nls.localize('showTrimWhitespace.label', "Show Leading/Trailing Whitespace Differences"),
id: TOGGLE_DIFF_IGNORE_TRIM_WHITESPACE,
title: localize('showTrimWhitespace.label', "Show Leading/Trailing Whitespace Differences"),
icon: ThemeIcon.modify(toggleWhitespace, 'disabled')
},
ContextKeyExpr.and(TextCompareEditorActiveContext, ContextKeyExpr.notEquals('config.diffEditor.ignoreTrimWhitespace', false)),
@@ -641,23 +651,23 @@ appendEditorToolItem(
);
// Editor Commands for Command Palette
MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: editorCommands.KEEP_EDITOR_COMMAND_ID, title: { value: nls.localize('keepEditor', "Keep Editor"), original: 'Keep Editor' }, category: CATEGORIES.View }, when: ContextKeyExpr.has('config.workbench.editor.enablePreview') });
MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: editorCommands.PIN_EDITOR_COMMAND_ID, title: { value: nls.localize('pinEditor', "Pin Editor"), original: 'Pin Editor' }, category: CATEGORIES.View } });
MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: editorCommands.UNPIN_EDITOR_COMMAND_ID, title: { value: nls.localize('unpinEditor', "Unpin Editor"), original: 'Unpin Editor' }, category: CATEGORIES.View } });
MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: editorCommands.CLOSE_EDITOR_COMMAND_ID, title: { value: nls.localize('closeEditor', "Close Editor"), original: 'Close Editor' }, category: CATEGORIES.View } });
MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: editorCommands.CLOSE_PINNED_EDITOR_COMMAND_ID, title: { value: nls.localize('closePinnedEditor', "Close Pinned Editor"), original: 'Close Pinned Editor' }, category: CATEGORIES.View } });
MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: editorCommands.CLOSE_EDITORS_IN_GROUP_COMMAND_ID, title: { value: nls.localize('closeEditorsInGroup', "Close All Editors in Group"), original: 'Close All Editors in Group' }, category: CATEGORIES.View } });
MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: editorCommands.CLOSE_SAVED_EDITORS_COMMAND_ID, title: { value: nls.localize('closeSavedEditors', "Close Saved Editors in Group"), original: 'Close Saved Editors in Group' }, category: CATEGORIES.View } });
MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: editorCommands.CLOSE_OTHER_EDITORS_IN_GROUP_COMMAND_ID, title: { value: nls.localize('closeOtherEditors', "Close Other Editors in Group"), original: 'Close Other Editors in Group' }, category: CATEGORIES.View } });
MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: editorCommands.CLOSE_EDITORS_TO_THE_RIGHT_COMMAND_ID, title: { value: nls.localize('closeRightEditors', "Close Editors to the Right in Group"), original: 'Close Editors to the Right in Group' }, category: CATEGORIES.View } });
MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: editorCommands.CLOSE_EDITORS_AND_GROUP_COMMAND_ID, title: { value: nls.localize('closeEditorGroup', "Close Editor Group"), original: 'Close Editor Group' }, category: CATEGORIES.View }, when: MultipleEditorGroupsContext });
MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: KEEP_EDITOR_COMMAND_ID, title: { value: localize('keepEditor', "Keep Editor"), original: 'Keep Editor' }, category: CATEGORIES.View }, when: ContextKeyExpr.has('config.workbench.editor.enablePreview') });
MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: PIN_EDITOR_COMMAND_ID, title: { value: localize('pinEditor', "Pin Editor"), original: 'Pin Editor' }, category: CATEGORIES.View } });
MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: UNPIN_EDITOR_COMMAND_ID, title: { value: localize('unpinEditor', "Unpin Editor"), original: 'Unpin Editor' }, category: CATEGORIES.View } });
MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: CLOSE_EDITOR_COMMAND_ID, title: { value: localize('closeEditor', "Close Editor"), original: 'Close Editor' }, category: CATEGORIES.View } });
MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: CLOSE_PINNED_EDITOR_COMMAND_ID, title: { value: localize('closePinnedEditor', "Close Pinned Editor"), original: 'Close Pinned Editor' }, category: CATEGORIES.View } });
MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: CLOSE_EDITORS_IN_GROUP_COMMAND_ID, title: { value: localize('closeEditorsInGroup', "Close All Editors in Group"), original: 'Close All Editors in Group' }, category: CATEGORIES.View } });
MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: CLOSE_SAVED_EDITORS_COMMAND_ID, title: { value: localize('closeSavedEditors', "Close Saved Editors in Group"), original: 'Close Saved Editors in Group' }, category: CATEGORIES.View } });
MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: CLOSE_OTHER_EDITORS_IN_GROUP_COMMAND_ID, title: { value: localize('closeOtherEditors', "Close Other Editors in Group"), original: 'Close Other Editors in Group' }, category: CATEGORIES.View } });
MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: CLOSE_EDITORS_TO_THE_RIGHT_COMMAND_ID, title: { value: localize('closeRightEditors', "Close Editors to the Right in Group"), original: 'Close Editors to the Right in Group' }, category: CATEGORIES.View } });
MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: CLOSE_EDITORS_AND_GROUP_COMMAND_ID, title: { value: localize('closeEditorGroup', "Close Editor Group"), original: 'Close Editor Group' }, category: CATEGORIES.View }, when: MultipleEditorGroupsContext });
// File menu
MenuRegistry.appendMenuItem(MenuId.MenubarRecentMenu, {
group: '1_editor',
command: {
id: ReopenClosedEditorAction.ID,
title: nls.localize({ key: 'miReopenClosedEditor', comment: ['&& denotes a mnemonic'] }, "&&Reopen Closed Editor"),
title: localize({ key: 'miReopenClosedEditor', comment: ['&& denotes a mnemonic'] }, "&&Reopen Closed Editor"),
precondition: ContextKeyExpr.has('canReopenClosedEditor')
},
order: 1
@@ -667,7 +677,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarRecentMenu, {
group: 'z_clear',
command: {
id: ClearRecentFilesAction.ID,
title: nls.localize({ key: 'miClearRecentOpen', comment: ['&& denotes a mnemonic'] }, "&&Clear Recently Opened")
title: localize({ key: 'miClearRecentOpen', comment: ['&& denotes a mnemonic'] }, "&&Clear Recently Opened")
},
order: 1
});
@@ -675,7 +685,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarRecentMenu, {
// Layout menu
MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
group: '2_appearance',
title: nls.localize({ key: 'miEditorLayout', comment: ['&& denotes a mnemonic'] }, "Editor &&Layout"),
title: localize({ key: 'miEditorLayout', comment: ['&& denotes a mnemonic'] }, "Editor &&Layout"),
submenu: MenuId.MenubarLayoutMenu,
order: 2
});
@@ -683,8 +693,8 @@ MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
MenuRegistry.appendMenuItem(MenuId.MenubarLayoutMenu, {
group: '1_split',
command: {
id: editorCommands.SPLIT_EDITOR_UP,
title: nls.localize({ key: 'miSplitEditorUp', comment: ['&& denotes a mnemonic'] }, "Split &&Up")
id: SPLIT_EDITOR_UP,
title: localize({ key: 'miSplitEditorUp', comment: ['&& denotes a mnemonic'] }, "Split &&Up")
},
order: 1
});
@@ -692,8 +702,8 @@ MenuRegistry.appendMenuItem(MenuId.MenubarLayoutMenu, {
MenuRegistry.appendMenuItem(MenuId.MenubarLayoutMenu, {
group: '1_split',
command: {
id: editorCommands.SPLIT_EDITOR_DOWN,
title: nls.localize({ key: 'miSplitEditorDown', comment: ['&& denotes a mnemonic'] }, "Split &&Down")
id: SPLIT_EDITOR_DOWN,
title: localize({ key: 'miSplitEditorDown', comment: ['&& denotes a mnemonic'] }, "Split &&Down")
},
order: 2
});
@@ -701,8 +711,8 @@ MenuRegistry.appendMenuItem(MenuId.MenubarLayoutMenu, {
MenuRegistry.appendMenuItem(MenuId.MenubarLayoutMenu, {
group: '1_split',
command: {
id: editorCommands.SPLIT_EDITOR_LEFT,
title: nls.localize({ key: 'miSplitEditorLeft', comment: ['&& denotes a mnemonic'] }, "Split &&Left")
id: SPLIT_EDITOR_LEFT,
title: localize({ key: 'miSplitEditorLeft', comment: ['&& denotes a mnemonic'] }, "Split &&Left")
},
order: 3
});
@@ -710,8 +720,8 @@ MenuRegistry.appendMenuItem(MenuId.MenubarLayoutMenu, {
MenuRegistry.appendMenuItem(MenuId.MenubarLayoutMenu, {
group: '1_split',
command: {
id: editorCommands.SPLIT_EDITOR_RIGHT,
title: nls.localize({ key: 'miSplitEditorRight', comment: ['&& denotes a mnemonic'] }, "Split &&Right")
id: SPLIT_EDITOR_RIGHT,
title: localize({ key: 'miSplitEditorRight', comment: ['&& denotes a mnemonic'] }, "Split &&Right")
},
order: 4
});
@@ -720,7 +730,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarLayoutMenu, {
group: '2_layouts',
command: {
id: EditorLayoutSingleAction.ID,
title: nls.localize({ key: 'miSingleColumnEditorLayout', comment: ['&& denotes a mnemonic'] }, "&&Single")
title: localize({ key: 'miSingleColumnEditorLayout', comment: ['&& denotes a mnemonic'] }, "&&Single")
},
order: 1
});
@@ -729,7 +739,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarLayoutMenu, {
group: '2_layouts',
command: {
id: EditorLayoutTwoColumnsAction.ID,
title: nls.localize({ key: 'miTwoColumnsEditorLayout', comment: ['&& denotes a mnemonic'] }, "&&Two Columns")
title: localize({ key: 'miTwoColumnsEditorLayout', comment: ['&& denotes a mnemonic'] }, "&&Two Columns")
},
order: 3
});
@@ -738,7 +748,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarLayoutMenu, {
group: '2_layouts',
command: {
id: EditorLayoutThreeColumnsAction.ID,
title: nls.localize({ key: 'miThreeColumnsEditorLayout', comment: ['&& denotes a mnemonic'] }, "T&&hree Columns")
title: localize({ key: 'miThreeColumnsEditorLayout', comment: ['&& denotes a mnemonic'] }, "T&&hree Columns")
},
order: 4
});
@@ -747,7 +757,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarLayoutMenu, {
group: '2_layouts',
command: {
id: EditorLayoutTwoRowsAction.ID,
title: nls.localize({ key: 'miTwoRowsEditorLayout', comment: ['&& denotes a mnemonic'] }, "T&&wo Rows")
title: localize({ key: 'miTwoRowsEditorLayout', comment: ['&& denotes a mnemonic'] }, "T&&wo Rows")
},
order: 5
});
@@ -756,7 +766,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarLayoutMenu, {
group: '2_layouts',
command: {
id: EditorLayoutThreeRowsAction.ID,
title: nls.localize({ key: 'miThreeRowsEditorLayout', comment: ['&& denotes a mnemonic'] }, "Three &&Rows")
title: localize({ key: 'miThreeRowsEditorLayout', comment: ['&& denotes a mnemonic'] }, "Three &&Rows")
},
order: 6
});
@@ -765,7 +775,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarLayoutMenu, {
group: '2_layouts',
command: {
id: EditorLayoutTwoByTwoGridAction.ID,
title: nls.localize({ key: 'miTwoByTwoGridEditorLayout', comment: ['&& denotes a mnemonic'] }, "&&Grid (2x2)")
title: localize({ key: 'miTwoByTwoGridEditorLayout', comment: ['&& denotes a mnemonic'] }, "&&Grid (2x2)")
},
order: 7
});
@@ -774,7 +784,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarLayoutMenu, {
group: '2_layouts',
command: {
id: EditorLayoutTwoRowsRightAction.ID,
title: nls.localize({ key: 'miTwoRowsRightEditorLayout', comment: ['&& denotes a mnemonic'] }, "Two R&&ows Right")
title: localize({ key: 'miTwoRowsRightEditorLayout', comment: ['&& denotes a mnemonic'] }, "Two R&&ows Right")
},
order: 8
});
@@ -783,7 +793,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarLayoutMenu, {
group: '2_layouts',
command: {
id: EditorLayoutTwoColumnsBottomAction.ID,
title: nls.localize({ key: 'miTwoColumnsBottomEditorLayout', comment: ['&& denotes a mnemonic'] }, "Two &&Columns Bottom")
title: localize({ key: 'miTwoColumnsBottomEditorLayout', comment: ['&& denotes a mnemonic'] }, "Two &&Columns Bottom")
},
order: 9
});
@@ -795,7 +805,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, {
group: '1_history_nav',
command: {
id: 'workbench.action.navigateBack',
title: nls.localize({ key: 'miBack', comment: ['&& denotes a mnemonic'] }, "&&Back"),
title: localize({ key: 'miBack', comment: ['&& denotes a mnemonic'] }, "&&Back"),
precondition: ContextKeyExpr.has('canNavigateBack')
},
order: 1
@@ -805,7 +815,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, {
group: '1_history_nav',
command: {
id: 'workbench.action.navigateForward',
title: nls.localize({ key: 'miForward', comment: ['&& denotes a mnemonic'] }, "&&Forward"),
title: localize({ key: 'miForward', comment: ['&& denotes a mnemonic'] }, "&&Forward"),
precondition: ContextKeyExpr.has('canNavigateForward')
},
order: 2
@@ -815,7 +825,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, {
group: '1_history_nav',
command: {
id: 'workbench.action.navigateToLastEditLocation',
title: nls.localize({ key: 'miLastEditLocation', comment: ['&& denotes a mnemonic'] }, "&&Last Edit Location"),
title: localize({ key: 'miLastEditLocation', comment: ['&& denotes a mnemonic'] }, "&&Last Edit Location"),
precondition: ContextKeyExpr.has('canNavigateToLastEditLocation')
},
order: 3
@@ -826,7 +836,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarSwitchEditorMenu, {
group: '1_any',
command: {
id: 'workbench.action.nextEditor',
title: nls.localize({ key: 'miNextEditor', comment: ['&& denotes a mnemonic'] }, "&&Next Editor")
title: localize({ key: 'miNextEditor', comment: ['&& denotes a mnemonic'] }, "&&Next Editor")
},
order: 1
});
@@ -835,7 +845,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarSwitchEditorMenu, {
group: '1_any',
command: {
id: 'workbench.action.previousEditor',
title: nls.localize({ key: 'miPreviousEditor', comment: ['&& denotes a mnemonic'] }, "&&Previous Editor")
title: localize({ key: 'miPreviousEditor', comment: ['&& denotes a mnemonic'] }, "&&Previous Editor")
},
order: 2
});
@@ -844,7 +854,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarSwitchEditorMenu, {
group: '2_any_used',
command: {
id: 'workbench.action.openNextRecentlyUsedEditor',
title: nls.localize({ key: 'miNextRecentlyUsedEditor', comment: ['&& denotes a mnemonic'] }, "&&Next Used Editor")
title: localize({ key: 'miNextRecentlyUsedEditor', comment: ['&& denotes a mnemonic'] }, "&&Next Used Editor")
},
order: 1
});
@@ -853,7 +863,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarSwitchEditorMenu, {
group: '2_any_used',
command: {
id: 'workbench.action.openPreviousRecentlyUsedEditor',
title: nls.localize({ key: 'miPreviousRecentlyUsedEditor', comment: ['&& denotes a mnemonic'] }, "&&Previous Used Editor")
title: localize({ key: 'miPreviousRecentlyUsedEditor', comment: ['&& denotes a mnemonic'] }, "&&Previous Used Editor")
},
order: 2
});
@@ -862,7 +872,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarSwitchEditorMenu, {
group: '3_group',
command: {
id: 'workbench.action.nextEditorInGroup',
title: nls.localize({ key: 'miNextEditorInGroup', comment: ['&& denotes a mnemonic'] }, "&&Next Editor in Group")
title: localize({ key: 'miNextEditorInGroup', comment: ['&& denotes a mnemonic'] }, "&&Next Editor in Group")
},
order: 1
});
@@ -871,7 +881,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarSwitchEditorMenu, {
group: '3_group',
command: {
id: 'workbench.action.previousEditorInGroup',
title: nls.localize({ key: 'miPreviousEditorInGroup', comment: ['&& denotes a mnemonic'] }, "&&Previous Editor in Group")
title: localize({ key: 'miPreviousEditorInGroup', comment: ['&& denotes a mnemonic'] }, "&&Previous Editor in Group")
},
order: 2
});
@@ -880,7 +890,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarSwitchEditorMenu, {
group: '4_group_used',
command: {
id: 'workbench.action.openNextRecentlyUsedEditorInGroup',
title: nls.localize({ key: 'miNextUsedEditorInGroup', comment: ['&& denotes a mnemonic'] }, "&&Next Used Editor in Group")
title: localize({ key: 'miNextUsedEditorInGroup', comment: ['&& denotes a mnemonic'] }, "&&Next Used Editor in Group")
},
order: 1
});
@@ -889,14 +899,14 @@ MenuRegistry.appendMenuItem(MenuId.MenubarSwitchEditorMenu, {
group: '4_group_used',
command: {
id: 'workbench.action.openPreviousRecentlyUsedEditorInGroup',
title: nls.localize({ key: 'miPreviousUsedEditorInGroup', comment: ['&& denotes a mnemonic'] }, "&&Previous Used Editor in Group")
title: localize({ key: 'miPreviousUsedEditorInGroup', comment: ['&& denotes a mnemonic'] }, "&&Previous Used Editor in Group")
},
order: 2
});
MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, {
group: '2_editor_nav',
title: nls.localize({ key: 'miSwitchEditor', comment: ['&& denotes a mnemonic'] }, "Switch &&Editor"),
title: localize({ key: 'miSwitchEditor', comment: ['&& denotes a mnemonic'] }, "Switch &&Editor"),
submenu: MenuId.MenubarSwitchEditorMenu,
order: 1
});
@@ -906,7 +916,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarSwitchGroupMenu, {
group: '1_focus_index',
command: {
id: 'workbench.action.focusFirstEditorGroup',
title: nls.localize({ key: 'miFocusFirstGroup', comment: ['&& denotes a mnemonic'] }, "Group &&1")
title: localize({ key: 'miFocusFirstGroup', comment: ['&& denotes a mnemonic'] }, "Group &&1")
},
order: 1
});
@@ -915,7 +925,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarSwitchGroupMenu, {
group: '1_focus_index',
command: {
id: 'workbench.action.focusSecondEditorGroup',
title: nls.localize({ key: 'miFocusSecondGroup', comment: ['&& denotes a mnemonic'] }, "Group &&2")
title: localize({ key: 'miFocusSecondGroup', comment: ['&& denotes a mnemonic'] }, "Group &&2")
},
order: 2
});
@@ -924,7 +934,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarSwitchGroupMenu, {
group: '1_focus_index',
command: {
id: 'workbench.action.focusThirdEditorGroup',
title: nls.localize({ key: 'miFocusThirdGroup', comment: ['&& denotes a mnemonic'] }, "Group &&3"),
title: localize({ key: 'miFocusThirdGroup', comment: ['&& denotes a mnemonic'] }, "Group &&3"),
precondition: ContextKeyExpr.has('multipleEditorGroups')
},
order: 3
@@ -934,7 +944,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarSwitchGroupMenu, {
group: '1_focus_index',
command: {
id: 'workbench.action.focusFourthEditorGroup',
title: nls.localize({ key: 'miFocusFourthGroup', comment: ['&& denotes a mnemonic'] }, "Group &&4"),
title: localize({ key: 'miFocusFourthGroup', comment: ['&& denotes a mnemonic'] }, "Group &&4"),
precondition: ContextKeyExpr.has('multipleEditorGroups')
},
order: 4
@@ -944,7 +954,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarSwitchGroupMenu, {
group: '1_focus_index',
command: {
id: 'workbench.action.focusFifthEditorGroup',
title: nls.localize({ key: 'miFocusFifthGroup', comment: ['&& denotes a mnemonic'] }, "Group &&5"),
title: localize({ key: 'miFocusFifthGroup', comment: ['&& denotes a mnemonic'] }, "Group &&5"),
precondition: ContextKeyExpr.has('multipleEditorGroups')
},
order: 5
@@ -954,7 +964,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarSwitchGroupMenu, {
group: '2_next_prev',
command: {
id: 'workbench.action.focusNextGroup',
title: nls.localize({ key: 'miNextGroup', comment: ['&& denotes a mnemonic'] }, "&&Next Group"),
title: localize({ key: 'miNextGroup', comment: ['&& denotes a mnemonic'] }, "&&Next Group"),
precondition: ContextKeyExpr.has('multipleEditorGroups')
},
order: 1
@@ -964,7 +974,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarSwitchGroupMenu, {
group: '2_next_prev',
command: {
id: 'workbench.action.focusPreviousGroup',
title: nls.localize({ key: 'miPreviousGroup', comment: ['&& denotes a mnemonic'] }, "&&Previous Group"),
title: localize({ key: 'miPreviousGroup', comment: ['&& denotes a mnemonic'] }, "&&Previous Group"),
precondition: ContextKeyExpr.has('multipleEditorGroups')
},
order: 2
@@ -974,7 +984,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarSwitchGroupMenu, {
group: '3_directional',
command: {
id: 'workbench.action.focusLeftGroup',
title: nls.localize({ key: 'miFocusLeftGroup', comment: ['&& denotes a mnemonic'] }, "Group &&Left"),
title: localize({ key: 'miFocusLeftGroup', comment: ['&& denotes a mnemonic'] }, "Group &&Left"),
precondition: ContextKeyExpr.has('multipleEditorGroups')
},
order: 1
@@ -984,7 +994,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarSwitchGroupMenu, {
group: '3_directional',
command: {
id: 'workbench.action.focusRightGroup',
title: nls.localize({ key: 'miFocusRightGroup', comment: ['&& denotes a mnemonic'] }, "Group &&Right"),
title: localize({ key: 'miFocusRightGroup', comment: ['&& denotes a mnemonic'] }, "Group &&Right"),
precondition: ContextKeyExpr.has('multipleEditorGroups')
},
order: 2
@@ -994,7 +1004,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarSwitchGroupMenu, {
group: '3_directional',
command: {
id: 'workbench.action.focusAboveGroup',
title: nls.localize({ key: 'miFocusAboveGroup', comment: ['&& denotes a mnemonic'] }, "Group &&Above"),
title: localize({ key: 'miFocusAboveGroup', comment: ['&& denotes a mnemonic'] }, "Group &&Above"),
precondition: ContextKeyExpr.has('multipleEditorGroups')
},
order: 3
@@ -1004,7 +1014,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarSwitchGroupMenu, {
group: '3_directional',
command: {
id: 'workbench.action.focusBelowGroup',
title: nls.localize({ key: 'miFocusBelowGroup', comment: ['&& denotes a mnemonic'] }, "Group &&Below"),
title: localize({ key: 'miFocusBelowGroup', comment: ['&& denotes a mnemonic'] }, "Group &&Below"),
precondition: ContextKeyExpr.has('multipleEditorGroups')
},
order: 4
@@ -1012,7 +1022,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarSwitchGroupMenu, {
MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, {
group: '2_editor_nav',
title: nls.localize({ key: 'miSwitchGroup', comment: ['&& denotes a mnemonic'] }, "Switch &&Group"),
title: localize({ key: 'miSwitchGroup', comment: ['&& denotes a mnemonic'] }, "Switch &&Group"),
submenu: MenuId.MenubarSwitchGroupMenu,
order: 2
});

View File

@@ -88,7 +88,7 @@ export interface IEditorGroupsAccessor {
readonly activeGroup: IEditorGroupView;
readonly partOptions: IEditorPartOptions;
readonly onDidEditorPartOptionsChange: Event<IEditorPartOptionsChangeEvent>;
readonly onDidChangeEditorPartOptions: Event<IEditorPartOptionsChangeEvent>;
readonly onDidVisibilityChange: Event<boolean>;
@@ -109,12 +109,12 @@ export interface IEditorGroupsAccessor {
arrangeGroups(arrangement: GroupsArrangement, target?: IEditorGroupView | GroupIdentifier): void;
}
export interface IEditorGroupTitleDimensions {
export interface IEditorGroupTitleHeight {
/**
* The overall height of the editor group title control.
*/
height: number;
total: number;
/**
* The height offset to e.g. use when drawing drop overlays.
@@ -137,7 +137,7 @@ export interface IEditorGroupView extends IDisposable, ISerializableView, IEdito
readonly group: EditorGroup;
readonly whenRestored: Promise<void>;
readonly titleDimensions: IEditorGroupTitleDimensions;
readonly titleHeight: IEditorGroupTitleHeight;
readonly isEmpty: boolean;
readonly isMinimized: boolean;

View File

@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import { localize } from 'vs/nls';
import { Action } from 'vs/base/common/actions';
import { IEditorInput, IEditorIdentifier, IEditorCommandsContext, CloseDirection, SaveReason, EditorsOrder, SideBySideEditorInput } from 'vs/workbench/common/editor';
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
@@ -22,8 +22,7 @@ import { ItemActivation, IQuickInputService } from 'vs/platform/quickinput/commo
import { AllEditorsByMostRecentlyUsedQuickAccess, ActiveGroupEditorsByMostRecentlyUsedQuickAccess, AllEditorsByAppearanceQuickAccess } from 'vs/workbench/browser/parts/editor/editorQuickAccess';
import { Codicon } from 'vs/base/common/codicons';
import { IFilesConfigurationService, AutoSaveMode } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService';
import { openEditorWith, getAllAvailableEditors } from 'vs/workbench/services/editor/common/editorOpenWith';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { EditorOverride } from 'vs/platform/editor/common/editor';
export class ExecuteCommandAction extends Action {
@@ -79,7 +78,7 @@ export class BaseSplitEditorAction extends Action {
export class SplitEditorAction extends BaseSplitEditorAction {
static readonly ID = 'workbench.action.splitEditor';
static readonly LABEL = nls.localize('splitEditor', "Split Editor");
static readonly LABEL = localize('splitEditor', "Split Editor");
constructor(
id: string,
@@ -94,7 +93,7 @@ export class SplitEditorAction extends BaseSplitEditorAction {
export class SplitEditorOrthogonalAction extends BaseSplitEditorAction {
static readonly ID = 'workbench.action.splitEditorOrthogonal';
static readonly LABEL = nls.localize('splitEditorOrthogonal', "Split Editor Orthogonal");
static readonly LABEL = localize('splitEditorOrthogonal', "Split Editor Orthogonal");
constructor(
id: string,
@@ -115,7 +114,7 @@ export class SplitEditorOrthogonalAction extends BaseSplitEditorAction {
export class SplitEditorLeftAction extends ExecuteCommandAction {
static readonly ID = SPLIT_EDITOR_LEFT;
static readonly LABEL = nls.localize('splitEditorGroupLeft', "Split Editor Left");
static readonly LABEL = localize('splitEditorGroupLeft', "Split Editor Left");
constructor(
id: string,
@@ -129,7 +128,7 @@ export class SplitEditorLeftAction extends ExecuteCommandAction {
export class SplitEditorRightAction extends ExecuteCommandAction {
static readonly ID = SPLIT_EDITOR_RIGHT;
static readonly LABEL = nls.localize('splitEditorGroupRight', "Split Editor Right");
static readonly LABEL = localize('splitEditorGroupRight', "Split Editor Right");
constructor(
id: string,
@@ -143,7 +142,7 @@ export class SplitEditorRightAction extends ExecuteCommandAction {
export class SplitEditorUpAction extends ExecuteCommandAction {
static readonly ID = SPLIT_EDITOR_UP;
static readonly LABEL = nls.localize('splitEditorGroupUp', "Split Editor Up");
static readonly LABEL = localize('splitEditorGroupUp', "Split Editor Up");
constructor(
id: string,
@@ -157,7 +156,7 @@ export class SplitEditorUpAction extends ExecuteCommandAction {
export class SplitEditorDownAction extends ExecuteCommandAction {
static readonly ID = SPLIT_EDITOR_DOWN;
static readonly LABEL = nls.localize('splitEditorGroupDown', "Split Editor Down");
static readonly LABEL = localize('splitEditorGroupDown', "Split Editor Down");
constructor(
id: string,
@@ -171,7 +170,7 @@ export class SplitEditorDownAction extends ExecuteCommandAction {
export class JoinTwoGroupsAction extends Action {
static readonly ID = 'workbench.action.joinTwoGroups';
static readonly LABEL = nls.localize('joinTwoGroups', "Join Editor Group with Next Group");
static readonly LABEL = localize('joinTwoGroups', "Join Editor Group with Next Group");
constructor(
id: string,
@@ -206,7 +205,7 @@ export class JoinTwoGroupsAction extends Action {
export class JoinAllGroupsAction extends Action {
static readonly ID = 'workbench.action.joinAllGroups';
static readonly LABEL = nls.localize('joinAllGroups', "Join All Editor Groups");
static readonly LABEL = localize('joinAllGroups', "Join All Editor Groups");
constructor(
id: string,
@@ -224,7 +223,7 @@ export class JoinAllGroupsAction extends Action {
export class NavigateBetweenGroupsAction extends Action {
static readonly ID = 'workbench.action.navigateEditorGroups';
static readonly LABEL = nls.localize('navigateEditorGroups', "Navigate Between Editor Groups");
static readonly LABEL = localize('navigateEditorGroups', "Navigate Between Editor Groups");
constructor(
id: string,
@@ -243,7 +242,7 @@ export class NavigateBetweenGroupsAction extends Action {
export class FocusActiveGroupAction extends Action {
static readonly ID = 'workbench.action.focusActiveEditorGroup';
static readonly LABEL = nls.localize('focusActiveEditorGroup', "Focus Active Editor Group");
static readonly LABEL = localize('focusActiveEditorGroup', "Focus Active Editor Group");
constructor(
id: string,
@@ -280,7 +279,7 @@ export abstract class BaseFocusGroupAction extends Action {
export class FocusFirstGroupAction extends BaseFocusGroupAction {
static readonly ID = 'workbench.action.focusFirstEditorGroup';
static readonly LABEL = nls.localize('focusFirstEditorGroup', "Focus First Editor Group");
static readonly LABEL = localize('focusFirstEditorGroup', "Focus First Editor Group");
constructor(
id: string,
@@ -294,7 +293,7 @@ export class FocusFirstGroupAction extends BaseFocusGroupAction {
export class FocusLastGroupAction extends BaseFocusGroupAction {
static readonly ID = 'workbench.action.focusLastEditorGroup';
static readonly LABEL = nls.localize('focusLastEditorGroup', "Focus Last Editor Group");
static readonly LABEL = localize('focusLastEditorGroup', "Focus Last Editor Group");
constructor(
id: string,
@@ -308,7 +307,7 @@ export class FocusLastGroupAction extends BaseFocusGroupAction {
export class FocusNextGroup extends BaseFocusGroupAction {
static readonly ID = 'workbench.action.focusNextGroup';
static readonly LABEL = nls.localize('focusNextGroup', "Focus Next Editor Group");
static readonly LABEL = localize('focusNextGroup', "Focus Next Editor Group");
constructor(
id: string,
@@ -322,7 +321,7 @@ export class FocusNextGroup extends BaseFocusGroupAction {
export class FocusPreviousGroup extends BaseFocusGroupAction {
static readonly ID = 'workbench.action.focusPreviousGroup';
static readonly LABEL = nls.localize('focusPreviousGroup', "Focus Previous Editor Group");
static readonly LABEL = localize('focusPreviousGroup', "Focus Previous Editor Group");
constructor(
id: string,
@@ -336,7 +335,7 @@ export class FocusPreviousGroup extends BaseFocusGroupAction {
export class FocusLeftGroup extends BaseFocusGroupAction {
static readonly ID = 'workbench.action.focusLeftGroup';
static readonly LABEL = nls.localize('focusLeftGroup', "Focus Left Editor Group");
static readonly LABEL = localize('focusLeftGroup', "Focus Left Editor Group");
constructor(
id: string,
@@ -350,7 +349,7 @@ export class FocusLeftGroup extends BaseFocusGroupAction {
export class FocusRightGroup extends BaseFocusGroupAction {
static readonly ID = 'workbench.action.focusRightGroup';
static readonly LABEL = nls.localize('focusRightGroup', "Focus Right Editor Group");
static readonly LABEL = localize('focusRightGroup', "Focus Right Editor Group");
constructor(
id: string,
@@ -364,7 +363,7 @@ export class FocusRightGroup extends BaseFocusGroupAction {
export class FocusAboveGroup extends BaseFocusGroupAction {
static readonly ID = 'workbench.action.focusAboveGroup';
static readonly LABEL = nls.localize('focusAboveGroup', "Focus Above Editor Group");
static readonly LABEL = localize('focusAboveGroup', "Focus Above Editor Group");
constructor(
id: string,
@@ -378,7 +377,7 @@ export class FocusAboveGroup extends BaseFocusGroupAction {
export class FocusBelowGroup extends BaseFocusGroupAction {
static readonly ID = 'workbench.action.focusBelowGroup';
static readonly LABEL = nls.localize('focusBelowGroup', "Focus Below Editor Group");
static readonly LABEL = localize('focusBelowGroup', "Focus Below Editor Group");
constructor(
id: string,
@@ -392,7 +391,7 @@ export class FocusBelowGroup extends BaseFocusGroupAction {
export class CloseEditorAction extends Action {
static readonly ID = 'workbench.action.closeActiveEditor';
static readonly LABEL = nls.localize('closeEditor', "Close Editor");
static readonly LABEL = localize('closeEditor', "Close Editor");
constructor(
id: string,
@@ -410,7 +409,7 @@ export class CloseEditorAction extends Action {
export class UnpinEditorAction extends Action {
static readonly ID = 'workbench.action.unpinActiveEditor';
static readonly LABEL = nls.localize('unpinEditor', "Unpin Editor");
static readonly LABEL = localize('unpinEditor', "Unpin Editor");
constructor(
id: string,
@@ -428,7 +427,7 @@ export class UnpinEditorAction extends Action {
export class CloseOneEditorAction extends Action {
static readonly ID = 'workbench.action.closeActiveEditor';
static readonly LABEL = nls.localize('closeOneEditor', "Close");
static readonly LABEL = localize('closeOneEditor', "Close");
constructor(
id: string,
@@ -471,7 +470,7 @@ export class CloseOneEditorAction extends Action {
export class RevertAndCloseEditorAction extends Action {
static readonly ID = 'workbench.action.revertAndCloseActiveEditor';
static readonly LABEL = nls.localize('revertAndCloseActiveEditor', "Revert and Close Editor");
static readonly LABEL = localize('revertAndCloseActiveEditor', "Revert and Close Editor");
constructor(
id: string,
@@ -498,7 +497,7 @@ export class RevertAndCloseEditorAction extends Action {
await this.editorService.revert({ editor, groupId: group.id }, { soft: true });
}
group.closeEditor(editor);
return group.closeEditor(editor);
}
}
}
@@ -506,7 +505,7 @@ export class RevertAndCloseEditorAction extends Action {
export class CloseLeftEditorsInGroupAction extends Action {
static readonly ID = 'workbench.action.closeEditorsToTheLeft';
static readonly LABEL = nls.localize('closeEditorsToTheLeft', "Close Editors to the Left in Group");
static readonly LABEL = localize('closeEditorsToTheLeft', "Close Editors to the Left in Group");
constructor(
id: string,
@@ -572,7 +571,7 @@ abstract class BaseCloseAllAction extends Action {
// Otherwise ask for combined confirmation and make sure
// to bring each dirty editor to the front so that the user
// can review if the files should be changed or not.
await Promise.all(this.groupsToClose.map(async groupToClose => {
await Promise.all(this.groupsToClose.map(groupToClose => {
for (const editor of groupToClose.getEditors(EditorsOrder.MOST_RECENTLY_ACTIVE, { excludeSticky: this.excludeSticky })) {
if (editor.isDirty() && !editor.isSaving() /* ignore editors that are being saved */) {
return groupToClose.openEditor(editor);
@@ -649,7 +648,7 @@ abstract class BaseCloseAllAction extends Action {
export class CloseAllEditorsAction extends BaseCloseAllAction {
static readonly ID = 'workbench.action.closeAllEditors';
static readonly LABEL = nls.localize('closeAllEditors', "Close All Editors");
static readonly LABEL = localize('closeAllEditors', "Close All Editors");
constructor(
id: string,
@@ -675,7 +674,7 @@ export class CloseAllEditorsAction extends BaseCloseAllAction {
export class CloseAllEditorGroupsAction extends BaseCloseAllAction {
static readonly ID = 'workbench.action.closeAllGroups';
static readonly LABEL = nls.localize('closeAllGroups', "Close All Editor Groups");
static readonly LABEL = localize('closeAllGroups', "Close All Editor Groups");
constructor(
id: string,
@@ -696,14 +695,16 @@ export class CloseAllEditorGroupsAction extends BaseCloseAllAction {
protected async doCloseAll(): Promise<void> {
await Promise.all(this.groupsToClose.map(group => group.closeAllEditors()));
this.groupsToClose.forEach(group => this.editorGroupService.removeGroup(group));
for (const groupToClose of this.groupsToClose) {
this.editorGroupService.removeGroup(groupToClose);
}
}
}
export class CloseEditorsInOtherGroupsAction extends Action {
static readonly ID = 'workbench.action.closeEditorsInOtherGroups';
static readonly LABEL = nls.localize('closeEditorsInOtherGroups', "Close Editors in Other Groups");
static readonly LABEL = localize('closeEditorsInOtherGroups', "Close Editors in Other Groups");
constructor(
id: string,
@@ -728,7 +729,7 @@ export class CloseEditorsInOtherGroupsAction extends Action {
export class CloseEditorInAllGroupsAction extends Action {
static readonly ID = 'workbench.action.closeEditorInAllGroups';
static readonly LABEL = nls.localize('closeEditorInAllGroups', "Close Editor in All Groups");
static readonly LABEL = localize('closeEditorInAllGroups', "Close Editor in All Groups");
constructor(
id: string,
@@ -827,7 +828,7 @@ class BaseMoveGroupAction extends BaseMoveCopyGroupAction {
export class MoveGroupLeftAction extends BaseMoveGroupAction {
static readonly ID = 'workbench.action.moveActiveEditorGroupLeft';
static readonly LABEL = nls.localize('moveActiveGroupLeft', "Move Editor Group Left");
static readonly LABEL = localize('moveActiveGroupLeft', "Move Editor Group Left");
constructor(
id: string,
@@ -841,7 +842,7 @@ export class MoveGroupLeftAction extends BaseMoveGroupAction {
export class MoveGroupRightAction extends BaseMoveGroupAction {
static readonly ID = 'workbench.action.moveActiveEditorGroupRight';
static readonly LABEL = nls.localize('moveActiveGroupRight', "Move Editor Group Right");
static readonly LABEL = localize('moveActiveGroupRight', "Move Editor Group Right");
constructor(
id: string,
@@ -855,7 +856,7 @@ export class MoveGroupRightAction extends BaseMoveGroupAction {
export class MoveGroupUpAction extends BaseMoveGroupAction {
static readonly ID = 'workbench.action.moveActiveEditorGroupUp';
static readonly LABEL = nls.localize('moveActiveGroupUp', "Move Editor Group Up");
static readonly LABEL = localize('moveActiveGroupUp', "Move Editor Group Up");
constructor(
id: string,
@@ -869,7 +870,7 @@ export class MoveGroupUpAction extends BaseMoveGroupAction {
export class MoveGroupDownAction extends BaseMoveGroupAction {
static readonly ID = 'workbench.action.moveActiveEditorGroupDown';
static readonly LABEL = nls.localize('moveActiveGroupDown', "Move Editor Group Down");
static readonly LABEL = localize('moveActiveGroupDown', "Move Editor Group Down");
constructor(
id: string,
@@ -895,7 +896,7 @@ class BaseDuplicateGroupAction extends BaseMoveCopyGroupAction {
export class DuplicateGroupLeftAction extends BaseDuplicateGroupAction {
static readonly ID = 'workbench.action.duplicateActiveEditorGroupLeft';
static readonly LABEL = nls.localize('duplicateActiveGroupLeft', "Duplicate Editor Group Left");
static readonly LABEL = localize('duplicateActiveGroupLeft', "Duplicate Editor Group Left");
constructor(
id: string,
@@ -909,7 +910,7 @@ export class DuplicateGroupLeftAction extends BaseDuplicateGroupAction {
export class DuplicateGroupRightAction extends BaseDuplicateGroupAction {
static readonly ID = 'workbench.action.duplicateActiveEditorGroupRight';
static readonly LABEL = nls.localize('duplicateActiveGroupRight', "Duplicate Editor Group Right");
static readonly LABEL = localize('duplicateActiveGroupRight', "Duplicate Editor Group Right");
constructor(
id: string,
@@ -923,7 +924,7 @@ export class DuplicateGroupRightAction extends BaseDuplicateGroupAction {
export class DuplicateGroupUpAction extends BaseDuplicateGroupAction {
static readonly ID = 'workbench.action.duplicateActiveEditorGroupUp';
static readonly LABEL = nls.localize('duplicateActiveGroupUp', "Duplicate Editor Group Up");
static readonly LABEL = localize('duplicateActiveGroupUp', "Duplicate Editor Group Up");
constructor(
id: string,
@@ -937,7 +938,7 @@ export class DuplicateGroupUpAction extends BaseDuplicateGroupAction {
export class DuplicateGroupDownAction extends BaseDuplicateGroupAction {
static readonly ID = 'workbench.action.duplicateActiveEditorGroupDown';
static readonly LABEL = nls.localize('duplicateActiveGroupDown', "Duplicate Editor Group Down");
static readonly LABEL = localize('duplicateActiveGroupDown', "Duplicate Editor Group Down");
constructor(
id: string,
@@ -951,7 +952,7 @@ export class DuplicateGroupDownAction extends BaseDuplicateGroupAction {
export class MinimizeOtherGroupsAction extends Action {
static readonly ID = 'workbench.action.minimizeOtherEditors';
static readonly LABEL = nls.localize('minimizeOtherEditorGroups', "Maximize Editor Group");
static readonly LABEL = localize('minimizeOtherEditorGroups', "Maximize Editor Group");
constructor(id: string, label: string, @IEditorGroupsService private readonly editorGroupService: IEditorGroupsService) {
super(id, label);
@@ -965,7 +966,7 @@ export class MinimizeOtherGroupsAction extends Action {
export class ResetGroupSizesAction extends Action {
static readonly ID = 'workbench.action.evenEditorWidths';
static readonly LABEL = nls.localize('evenEditorGroups', "Reset Editor Group Sizes");
static readonly LABEL = localize('evenEditorGroups', "Reset Editor Group Sizes");
constructor(id: string, label: string, @IEditorGroupsService private readonly editorGroupService: IEditorGroupsService) {
super(id, label);
@@ -979,7 +980,7 @@ export class ResetGroupSizesAction extends Action {
export class ToggleGroupSizesAction extends Action {
static readonly ID = 'workbench.action.toggleEditorWidths';
static readonly LABEL = nls.localize('toggleEditorWidths', "Toggle Editor Group Sizes");
static readonly LABEL = localize('toggleEditorWidths', "Toggle Editor Group Sizes");
constructor(id: string, label: string, @IEditorGroupsService private readonly editorGroupService: IEditorGroupsService) {
super(id, label);
@@ -993,7 +994,7 @@ export class ToggleGroupSizesAction extends Action {
export class MaximizeGroupAction extends Action {
static readonly ID = 'workbench.action.maximizeEditor';
static readonly LABEL = nls.localize('maximizeEditor', "Maximize Editor Group and Hide Side Bar");
static readonly LABEL = localize('maximizeEditor', "Maximize Editor Group and Hide Side Bar");
constructor(
id: string,
@@ -1047,7 +1048,7 @@ export abstract class BaseNavigateEditorAction extends Action {
export class OpenNextEditor extends BaseNavigateEditorAction {
static readonly ID = 'workbench.action.nextEditor';
static readonly LABEL = nls.localize('openNextEditor', "Open Next Editor");
static readonly LABEL = localize('openNextEditor', "Open Next Editor");
constructor(
id: string,
@@ -1082,7 +1083,7 @@ export class OpenNextEditor extends BaseNavigateEditorAction {
export class OpenPreviousEditor extends BaseNavigateEditorAction {
static readonly ID = 'workbench.action.previousEditor';
static readonly LABEL = nls.localize('openPreviousEditor', "Open Previous Editor");
static readonly LABEL = localize('openPreviousEditor', "Open Previous Editor");
constructor(
id: string,
@@ -1117,7 +1118,7 @@ export class OpenPreviousEditor extends BaseNavigateEditorAction {
export class OpenNextEditorInGroup extends BaseNavigateEditorAction {
static readonly ID = 'workbench.action.nextEditorInGroup';
static readonly LABEL = nls.localize('nextEditorInGroup', "Open Next Editor in Group");
static readonly LABEL = localize('nextEditorInGroup', "Open Next Editor in Group");
constructor(
id: string,
@@ -1140,7 +1141,7 @@ export class OpenNextEditorInGroup extends BaseNavigateEditorAction {
export class OpenPreviousEditorInGroup extends BaseNavigateEditorAction {
static readonly ID = 'workbench.action.previousEditorInGroup';
static readonly LABEL = nls.localize('openPreviousEditorInGroup', "Open Previous Editor in Group");
static readonly LABEL = localize('openPreviousEditorInGroup', "Open Previous Editor in Group");
constructor(
id: string,
@@ -1163,7 +1164,7 @@ export class OpenPreviousEditorInGroup extends BaseNavigateEditorAction {
export class OpenFirstEditorInGroup extends BaseNavigateEditorAction {
static readonly ID = 'workbench.action.firstEditorInGroup';
static readonly LABEL = nls.localize('firstEditorInGroup', "Open First Editor in Group");
static readonly LABEL = localize('firstEditorInGroup', "Open First Editor in Group");
constructor(
id: string,
@@ -1185,7 +1186,7 @@ export class OpenFirstEditorInGroup extends BaseNavigateEditorAction {
export class OpenLastEditorInGroup extends BaseNavigateEditorAction {
static readonly ID = 'workbench.action.lastEditorInGroup';
static readonly LABEL = nls.localize('lastEditorInGroup', "Open Last Editor in Group");
static readonly LABEL = localize('lastEditorInGroup', "Open Last Editor in Group");
constructor(
id: string,
@@ -1207,7 +1208,7 @@ export class OpenLastEditorInGroup extends BaseNavigateEditorAction {
export class NavigateForwardAction extends Action {
static readonly ID = 'workbench.action.navigateForward';
static readonly LABEL = nls.localize('navigateNext', "Go Forward");
static readonly LABEL = localize('navigateNext', "Go Forward");
constructor(id: string, label: string, @IHistoryService private readonly historyService: IHistoryService) {
super(id, label);
@@ -1221,7 +1222,7 @@ export class NavigateForwardAction extends Action {
export class NavigateBackwardsAction extends Action {
static readonly ID = 'workbench.action.navigateBack';
static readonly LABEL = nls.localize('navigatePrevious', "Go Back");
static readonly LABEL = localize('navigatePrevious', "Go Back");
constructor(id: string, label: string, @IHistoryService private readonly historyService: IHistoryService) {
super(id, label);
@@ -1235,7 +1236,7 @@ export class NavigateBackwardsAction extends Action {
export class NavigateToLastEditLocationAction extends Action {
static readonly ID = 'workbench.action.navigateToLastEditLocation';
static readonly LABEL = nls.localize('navigateToLastEditLocation', "Go to Last Edit Location");
static readonly LABEL = localize('navigateToLastEditLocation', "Go to Last Edit Location");
constructor(id: string, label: string, @IHistoryService private readonly historyService: IHistoryService) {
super(id, label);
@@ -1249,7 +1250,7 @@ export class NavigateToLastEditLocationAction extends Action {
export class NavigateLastAction extends Action {
static readonly ID = 'workbench.action.navigateLast';
static readonly LABEL = nls.localize('navigateLast', "Go Last");
static readonly LABEL = localize('navigateLast', "Go Last");
constructor(id: string, label: string, @IHistoryService private readonly historyService: IHistoryService) {
super(id, label);
@@ -1263,7 +1264,7 @@ export class NavigateLastAction extends Action {
export class ReopenClosedEditorAction extends Action {
static readonly ID = 'workbench.action.reopenClosedEditor';
static readonly LABEL = nls.localize('reopenClosedEditor', "Reopen Closed Editor");
static readonly LABEL = localize('reopenClosedEditor', "Reopen Closed Editor");
constructor(
id: string,
@@ -1281,7 +1282,7 @@ export class ReopenClosedEditorAction extends Action {
export class ClearRecentFilesAction extends Action {
static readonly ID = 'workbench.action.clearRecentFiles';
static readonly LABEL = nls.localize('clearRecentFiles', "Clear Recently Opened");
static readonly LABEL = localize('clearRecentFiles', "Clear Recently Opened");
constructor(
id: string,
@@ -1305,7 +1306,7 @@ export class ClearRecentFilesAction extends Action {
export class ShowEditorsInActiveGroupByMostRecentlyUsedAction extends Action {
static readonly ID = 'workbench.action.showEditorsInActiveGroup';
static readonly LABEL = nls.localize('showEditorsInActiveGroup', "Show Editors in Active Group By Most Recently Used");
static readonly LABEL = localize('showEditorsInActiveGroup', "Show Editors in Active Group By Most Recently Used");
constructor(
id: string,
@@ -1323,7 +1324,7 @@ export class ShowEditorsInActiveGroupByMostRecentlyUsedAction extends Action {
export class ShowAllEditorsByAppearanceAction extends Action {
static readonly ID = 'workbench.action.showAllEditors';
static readonly LABEL = nls.localize('showAllEditors', "Show All Editors By Appearance");
static readonly LABEL = localize('showAllEditors', "Show All Editors By Appearance");
constructor(
id: string,
@@ -1341,7 +1342,7 @@ export class ShowAllEditorsByAppearanceAction extends Action {
export class ShowAllEditorsByMostRecentlyUsedAction extends Action {
static readonly ID = 'workbench.action.showAllEditorsByMostRecentlyUsed';
static readonly LABEL = nls.localize('showAllEditorsByMostRecentlyUsed', "Show All Editors By Most Recently Used");
static readonly LABEL = localize('showAllEditorsByMostRecentlyUsed', "Show All Editors By Most Recently Used");
constructor(
id: string,
@@ -1382,7 +1383,7 @@ export class BaseQuickAccessEditorAction extends Action {
export class QuickAccessPreviousRecentlyUsedEditorAction extends BaseQuickAccessEditorAction {
static readonly ID = 'workbench.action.quickOpenPreviousRecentlyUsedEditor';
static readonly LABEL = nls.localize('quickOpenPreviousRecentlyUsedEditor', "Quick Open Previous Recently Used Editor");
static readonly LABEL = localize('quickOpenPreviousRecentlyUsedEditor', "Quick Open Previous Recently Used Editor");
constructor(
id: string,
@@ -1397,7 +1398,7 @@ export class QuickAccessPreviousRecentlyUsedEditorAction extends BaseQuickAccess
export class QuickAccessLeastRecentlyUsedEditorAction extends BaseQuickAccessEditorAction {
static readonly ID = 'workbench.action.quickOpenLeastRecentlyUsedEditor';
static readonly LABEL = nls.localize('quickOpenLeastRecentlyUsedEditor', "Quick Open Least Recently Used Editor");
static readonly LABEL = localize('quickOpenLeastRecentlyUsedEditor', "Quick Open Least Recently Used Editor");
constructor(
id: string,
@@ -1412,7 +1413,7 @@ export class QuickAccessLeastRecentlyUsedEditorAction extends BaseQuickAccessEdi
export class QuickAccessPreviousRecentlyUsedEditorInGroupAction extends BaseQuickAccessEditorAction {
static readonly ID = 'workbench.action.quickOpenPreviousRecentlyUsedEditorInGroup';
static readonly LABEL = nls.localize('quickOpenPreviousRecentlyUsedEditorInGroup', "Quick Open Previous Recently Used Editor in Group");
static readonly LABEL = localize('quickOpenPreviousRecentlyUsedEditorInGroup', "Quick Open Previous Recently Used Editor in Group");
constructor(
id: string,
@@ -1427,7 +1428,7 @@ export class QuickAccessPreviousRecentlyUsedEditorInGroupAction extends BaseQuic
export class QuickAccessLeastRecentlyUsedEditorInGroupAction extends BaseQuickAccessEditorAction {
static readonly ID = 'workbench.action.quickOpenLeastRecentlyUsedEditorInGroup';
static readonly LABEL = nls.localize('quickOpenLeastRecentlyUsedEditorInGroup', "Quick Open Least Recently Used Editor in Group");
static readonly LABEL = localize('quickOpenLeastRecentlyUsedEditorInGroup', "Quick Open Least Recently Used Editor in Group");
constructor(
id: string,
@@ -1442,7 +1443,7 @@ export class QuickAccessLeastRecentlyUsedEditorInGroupAction extends BaseQuickAc
export class QuickAccessPreviousEditorFromHistoryAction extends Action {
static readonly ID = 'workbench.action.openPreviousEditorFromHistory';
static readonly LABEL = nls.localize('navigateEditorHistoryByInput', "Quick Open Previous Editor from History");
static readonly LABEL = localize('navigateEditorHistoryByInput', "Quick Open Previous Editor from History");
constructor(
id: string,
@@ -1471,7 +1472,7 @@ export class QuickAccessPreviousEditorFromHistoryAction extends Action {
export class OpenNextRecentlyUsedEditorAction extends Action {
static readonly ID = 'workbench.action.openNextRecentlyUsedEditor';
static readonly LABEL = nls.localize('openNextRecentlyUsedEditor', "Open Next Recently Used Editor");
static readonly LABEL = localize('openNextRecentlyUsedEditor', "Open Next Recently Used Editor");
constructor(
id: string,
@@ -1489,7 +1490,7 @@ export class OpenNextRecentlyUsedEditorAction extends Action {
export class OpenPreviousRecentlyUsedEditorAction extends Action {
static readonly ID = 'workbench.action.openPreviousRecentlyUsedEditor';
static readonly LABEL = nls.localize('openPreviousRecentlyUsedEditor', "Open Previous Recently Used Editor");
static readonly LABEL = localize('openPreviousRecentlyUsedEditor', "Open Previous Recently Used Editor");
constructor(
id: string,
@@ -1507,7 +1508,7 @@ export class OpenPreviousRecentlyUsedEditorAction extends Action {
export class OpenNextRecentlyUsedEditorInGroupAction extends Action {
static readonly ID = 'workbench.action.openNextRecentlyUsedEditorInGroup';
static readonly LABEL = nls.localize('openNextRecentlyUsedEditorInGroup', "Open Next Recently Used Editor In Group");
static readonly LABEL = localize('openNextRecentlyUsedEditorInGroup', "Open Next Recently Used Editor In Group");
constructor(
id: string,
@@ -1526,7 +1527,7 @@ export class OpenNextRecentlyUsedEditorInGroupAction extends Action {
export class OpenPreviousRecentlyUsedEditorInGroupAction extends Action {
static readonly ID = 'workbench.action.openPreviousRecentlyUsedEditorInGroup';
static readonly LABEL = nls.localize('openPreviousRecentlyUsedEditorInGroup', "Open Previous Recently Used Editor In Group");
static readonly LABEL = localize('openPreviousRecentlyUsedEditorInGroup', "Open Previous Recently Used Editor In Group");
constructor(
id: string,
@@ -1545,7 +1546,7 @@ export class OpenPreviousRecentlyUsedEditorInGroupAction extends Action {
export class ClearEditorHistoryAction extends Action {
static readonly ID = 'workbench.action.clearEditorHistory';
static readonly LABEL = nls.localize('clearEditorHistory', "Clear Editor History");
static readonly LABEL = localize('clearEditorHistory', "Clear Editor History");
constructor(
id: string,
@@ -1565,7 +1566,7 @@ export class ClearEditorHistoryAction extends Action {
export class MoveEditorLeftInGroupAction extends ExecuteCommandAction {
static readonly ID = 'workbench.action.moveEditorLeftInGroup';
static readonly LABEL = nls.localize('moveEditorLeft', "Move Editor Left");
static readonly LABEL = localize('moveEditorLeft', "Move Editor Left");
constructor(
id: string,
@@ -1579,7 +1580,7 @@ export class MoveEditorLeftInGroupAction extends ExecuteCommandAction {
export class MoveEditorRightInGroupAction extends ExecuteCommandAction {
static readonly ID = 'workbench.action.moveEditorRightInGroup';
static readonly LABEL = nls.localize('moveEditorRight', "Move Editor Right");
static readonly LABEL = localize('moveEditorRight', "Move Editor Right");
constructor(
id: string,
@@ -1593,7 +1594,7 @@ export class MoveEditorRightInGroupAction extends ExecuteCommandAction {
export class MoveEditorToPreviousGroupAction extends ExecuteCommandAction {
static readonly ID = 'workbench.action.moveEditorToPreviousGroup';
static readonly LABEL = nls.localize('moveEditorToPreviousGroup', "Move Editor into Previous Group");
static readonly LABEL = localize('moveEditorToPreviousGroup', "Move Editor into Previous Group");
constructor(
id: string,
@@ -1607,7 +1608,7 @@ export class MoveEditorToPreviousGroupAction extends ExecuteCommandAction {
export class MoveEditorToNextGroupAction extends ExecuteCommandAction {
static readonly ID = 'workbench.action.moveEditorToNextGroup';
static readonly LABEL = nls.localize('moveEditorToNextGroup', "Move Editor into Next Group");
static readonly LABEL = localize('moveEditorToNextGroup', "Move Editor into Next Group");
constructor(
id: string,
@@ -1621,7 +1622,7 @@ export class MoveEditorToNextGroupAction extends ExecuteCommandAction {
export class MoveEditorToAboveGroupAction extends ExecuteCommandAction {
static readonly ID = 'workbench.action.moveEditorToAboveGroup';
static readonly LABEL = nls.localize('moveEditorToAboveGroup', "Move Editor into Above Group");
static readonly LABEL = localize('moveEditorToAboveGroup', "Move Editor into Above Group");
constructor(
id: string,
@@ -1635,7 +1636,7 @@ export class MoveEditorToAboveGroupAction extends ExecuteCommandAction {
export class MoveEditorToBelowGroupAction extends ExecuteCommandAction {
static readonly ID = 'workbench.action.moveEditorToBelowGroup';
static readonly LABEL = nls.localize('moveEditorToBelowGroup', "Move Editor into Below Group");
static readonly LABEL = localize('moveEditorToBelowGroup', "Move Editor into Below Group");
constructor(
id: string,
@@ -1649,7 +1650,7 @@ export class MoveEditorToBelowGroupAction extends ExecuteCommandAction {
export class MoveEditorToLeftGroupAction extends ExecuteCommandAction {
static readonly ID = 'workbench.action.moveEditorToLeftGroup';
static readonly LABEL = nls.localize('moveEditorToLeftGroup', "Move Editor into Left Group");
static readonly LABEL = localize('moveEditorToLeftGroup', "Move Editor into Left Group");
constructor(
id: string,
@@ -1663,7 +1664,7 @@ export class MoveEditorToLeftGroupAction extends ExecuteCommandAction {
export class MoveEditorToRightGroupAction extends ExecuteCommandAction {
static readonly ID = 'workbench.action.moveEditorToRightGroup';
static readonly LABEL = nls.localize('moveEditorToRightGroup', "Move Editor into Right Group");
static readonly LABEL = localize('moveEditorToRightGroup', "Move Editor into Right Group");
constructor(
id: string,
@@ -1677,7 +1678,7 @@ export class MoveEditorToRightGroupAction extends ExecuteCommandAction {
export class MoveEditorToFirstGroupAction extends ExecuteCommandAction {
static readonly ID = 'workbench.action.moveEditorToFirstGroup';
static readonly LABEL = nls.localize('moveEditorToFirstGroup', "Move Editor into First Group");
static readonly LABEL = localize('moveEditorToFirstGroup', "Move Editor into First Group");
constructor(
id: string,
@@ -1691,7 +1692,7 @@ export class MoveEditorToFirstGroupAction extends ExecuteCommandAction {
export class MoveEditorToLastGroupAction extends ExecuteCommandAction {
static readonly ID = 'workbench.action.moveEditorToLastGroup';
static readonly LABEL = nls.localize('moveEditorToLastGroup', "Move Editor into Last Group");
static readonly LABEL = localize('moveEditorToLastGroup', "Move Editor into Last Group");
constructor(
id: string,
@@ -1705,7 +1706,7 @@ export class MoveEditorToLastGroupAction extends ExecuteCommandAction {
export class EditorLayoutSingleAction extends ExecuteCommandAction {
static readonly ID = 'workbench.action.editorLayoutSingle';
static readonly LABEL = nls.localize('editorLayoutSingle', "Single Column Editor Layout");
static readonly LABEL = localize('editorLayoutSingle', "Single Column Editor Layout");
constructor(
id: string,
@@ -1719,7 +1720,7 @@ export class EditorLayoutSingleAction extends ExecuteCommandAction {
export class EditorLayoutTwoColumnsAction extends ExecuteCommandAction {
static readonly ID = 'workbench.action.editorLayoutTwoColumns';
static readonly LABEL = nls.localize('editorLayoutTwoColumns', "Two Columns Editor Layout");
static readonly LABEL = localize('editorLayoutTwoColumns', "Two Columns Editor Layout");
constructor(
id: string,
@@ -1733,7 +1734,7 @@ export class EditorLayoutTwoColumnsAction extends ExecuteCommandAction {
export class EditorLayoutThreeColumnsAction extends ExecuteCommandAction {
static readonly ID = 'workbench.action.editorLayoutThreeColumns';
static readonly LABEL = nls.localize('editorLayoutThreeColumns', "Three Columns Editor Layout");
static readonly LABEL = localize('editorLayoutThreeColumns', "Three Columns Editor Layout");
constructor(
id: string,
@@ -1747,7 +1748,7 @@ export class EditorLayoutThreeColumnsAction extends ExecuteCommandAction {
export class EditorLayoutTwoRowsAction extends ExecuteCommandAction {
static readonly ID = 'workbench.action.editorLayoutTwoRows';
static readonly LABEL = nls.localize('editorLayoutTwoRows', "Two Rows Editor Layout");
static readonly LABEL = localize('editorLayoutTwoRows', "Two Rows Editor Layout");
constructor(
id: string,
@@ -1761,7 +1762,7 @@ export class EditorLayoutTwoRowsAction extends ExecuteCommandAction {
export class EditorLayoutThreeRowsAction extends ExecuteCommandAction {
static readonly ID = 'workbench.action.editorLayoutThreeRows';
static readonly LABEL = nls.localize('editorLayoutThreeRows', "Three Rows Editor Layout");
static readonly LABEL = localize('editorLayoutThreeRows', "Three Rows Editor Layout");
constructor(
id: string,
@@ -1775,7 +1776,7 @@ export class EditorLayoutThreeRowsAction extends ExecuteCommandAction {
export class EditorLayoutTwoByTwoGridAction extends ExecuteCommandAction {
static readonly ID = 'workbench.action.editorLayoutTwoByTwoGrid';
static readonly LABEL = nls.localize('editorLayoutTwoByTwoGrid', "Grid Editor Layout (2x2)");
static readonly LABEL = localize('editorLayoutTwoByTwoGrid', "Grid Editor Layout (2x2)");
constructor(
id: string,
@@ -1789,7 +1790,7 @@ export class EditorLayoutTwoByTwoGridAction extends ExecuteCommandAction {
export class EditorLayoutTwoColumnsBottomAction extends ExecuteCommandAction {
static readonly ID = 'workbench.action.editorLayoutTwoColumnsBottom';
static readonly LABEL = nls.localize('editorLayoutTwoColumnsBottom', "Two Columns Bottom Editor Layout");
static readonly LABEL = localize('editorLayoutTwoColumnsBottom', "Two Columns Bottom Editor Layout");
constructor(
id: string,
@@ -1803,7 +1804,7 @@ export class EditorLayoutTwoColumnsBottomAction extends ExecuteCommandAction {
export class EditorLayoutTwoRowsRightAction extends ExecuteCommandAction {
static readonly ID = 'workbench.action.editorLayoutTwoRowsRight';
static readonly LABEL = nls.localize('editorLayoutTwoRowsRight', "Two Rows Right Editor Layout");
static readonly LABEL = localize('editorLayoutTwoRowsRight', "Two Rows Right Editor Layout");
constructor(
id: string,
@@ -1833,7 +1834,7 @@ export class BaseCreateEditorGroupAction extends Action {
export class NewEditorGroupLeftAction extends BaseCreateEditorGroupAction {
static readonly ID = 'workbench.action.newGroupLeft';
static readonly LABEL = nls.localize('newEditorLeft', "New Editor Group to the Left");
static readonly LABEL = localize('newEditorLeft', "New Editor Group to the Left");
constructor(
id: string,
@@ -1847,7 +1848,7 @@ export class NewEditorGroupLeftAction extends BaseCreateEditorGroupAction {
export class NewEditorGroupRightAction extends BaseCreateEditorGroupAction {
static readonly ID = 'workbench.action.newGroupRight';
static readonly LABEL = nls.localize('newEditorRight', "New Editor Group to the Right");
static readonly LABEL = localize('newEditorRight', "New Editor Group to the Right");
constructor(
id: string,
@@ -1861,7 +1862,7 @@ export class NewEditorGroupRightAction extends BaseCreateEditorGroupAction {
export class NewEditorGroupAboveAction extends BaseCreateEditorGroupAction {
static readonly ID = 'workbench.action.newGroupAbove';
static readonly LABEL = nls.localize('newEditorAbove', "New Editor Group Above");
static readonly LABEL = localize('newEditorAbove', "New Editor Group Above");
constructor(
id: string,
@@ -1875,7 +1876,7 @@ export class NewEditorGroupAboveAction extends BaseCreateEditorGroupAction {
export class NewEditorGroupBelowAction extends BaseCreateEditorGroupAction {
static readonly ID = 'workbench.action.newGroupBelow';
static readonly LABEL = nls.localize('newEditorBelow', "New Editor Group Below");
static readonly LABEL = localize('newEditorBelow', "New Editor Group Below");
constructor(
id: string,
@@ -1889,13 +1890,12 @@ export class NewEditorGroupBelowAction extends BaseCreateEditorGroupAction {
export class ReopenResourcesAction extends Action {
static readonly ID = 'workbench.action.reopenWithEditor';
static readonly LABEL = nls.localize('workbench.action.reopenWithEditor', "Reopen Editor With...");
static readonly LABEL = localize('workbench.action.reopenWithEditor', "Reopen Editor With...");
constructor(
id: string,
label: string,
@IEditorService private readonly editorService: IEditorService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IEditorService private readonly editorService: IEditorService
) {
super(id, label);
}
@@ -1913,14 +1913,14 @@ export class ReopenResourcesAction extends Action {
const options = activeEditorPane.options;
const group = activeEditorPane.group;
await this.instantiationService.invokeFunction(openEditorWith, activeInput, undefined, options, group);
await this.editorService.openEditor(activeInput, { ...options, override: EditorOverride.PICK }, group);
}
}
export class ToggleEditorTypeAction extends Action {
static readonly ID = 'workbench.action.toggleEditorType';
static readonly LABEL = nls.localize('workbench.action.toggleEditorType', "Toggle Editor Type");
static readonly LABEL = localize('workbench.action.toggleEditorType', "Toggle Editor Type");
constructor(
id: string,
@@ -1944,7 +1944,7 @@ export class ToggleEditorTypeAction extends Action {
const options = activeEditorPane.options;
const group = activeEditorPane.group;
const overrides = getAllAvailableEditors(activeEditorResource, undefined, options, group, this.editorService);
const overrides = this.editorService.getEditorOverrides(activeEditorResource, options, group);
const firstNonActiveOverride = overrides.find(([_, entry]) => !entry.active);
if (!firstNonActiveOverride) {
return;

View File

@@ -39,7 +39,9 @@ export class EditorAutoSave extends Disposable implements IWorkbenchContribution
this.onAutoSaveConfigurationChange(filesConfigurationService.getAutoSaveConfiguration(), false);
// Fill in initial dirty working copies
this.workingCopyService.dirtyWorkingCopies.forEach(workingCopy => this.onDidRegister(workingCopy));
for (const dirtyWorkingCopy of this.workingCopyService.dirtyWorkingCopies) {
this.onDidRegister(dirtyWorkingCopy);
}
this.registerListeners();
}

View File

@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import { localize } from 'vs/nls';
import { isObject, isString, isUndefined, isNumber, withNullAsUndefined } from 'vs/base/common/types';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
@@ -25,7 +25,6 @@ import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
import { ActiveGroupEditorsByMostRecentlyUsedQuickAccess } from 'vs/workbench/browser/parts/editor/editorQuickAccess';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { ITextEditorOptions } from 'vs/platform/editor/common/editor';
import { openEditorWith } from 'vs/workbench/services/editor/common/editorOpenWith';
export const CLOSE_SAVED_EDITORS_COMMAND_ID = 'workbench.action.closeUnmodifiedEditors';
export const CLOSE_EDITORS_IN_GROUP_COMMAND_ID = 'workbench.action.closeEditorsInGroup';
@@ -103,11 +102,11 @@ function registerActiveEditorMoveCommand(): void {
primary: 0,
handler: (accessor, args) => moveActiveEditor(args, accessor),
description: {
description: nls.localize('editorCommand.activeEditorMove.description', "Move the active editor by tabs or groups"),
description: localize('editorCommand.activeEditorMove.description', "Move the active editor by tabs or groups"),
args: [
{
name: nls.localize('editorCommand.activeEditorMove.arg.name', "Active editor move argument"),
description: nls.localize('editorCommand.activeEditorMove.arg.description', "Argument Properties:\n\t* 'to': String value providing where to move.\n\t* 'by': String value providing the unit for move (by tab or by group).\n\t* 'value': Number value providing how many positions or an absolute position to move."),
name: localize('editorCommand.activeEditorMove.arg.name', "Active editor move argument"),
description: localize('editorCommand.activeEditorMove.arg.description', "Argument Properties:\n\t* 'to': String value providing where to move.\n\t* 'by': String value providing the unit for move (by tab or by group).\n\t* 'value': Number value providing how many positions or an absolute position to move."),
constraint: isActiveEditorMoveArg,
schema: {
'type': 'object',
@@ -282,13 +281,13 @@ function registerEditorGroupsLayoutCommand(): void {
export function mergeAllGroups(editorGroupService: IEditorGroupsService): void {
const target = editorGroupService.activeGroup;
editorGroupService.getGroups(GroupsOrder.MOST_RECENTLY_ACTIVE).forEach(group => {
for (const group of editorGroupService.getGroups(GroupsOrder.MOST_RECENTLY_ACTIVE)) {
if (group === target) {
return; // keep target
continue; // keep target
}
editorGroupService.mergeGroup(group, target);
});
}
}
function registerDiffEditorCommands(): void {
@@ -408,10 +407,10 @@ function registerDiffEditorCommands(): void {
command: {
id: TOGGLE_DIFF_SIDE_BY_SIDE,
title: {
value: nls.localize('toggleInlineView', "Toggle Inline View"),
value: localize('toggleInlineView', "Toggle Inline View"),
original: 'Compare: Toggle Inline View'
},
category: nls.localize('compare', "Compare")
category: localize('compare', "Compare")
},
when: ContextKeyExpr.has('textCompareEditorActive')
});
@@ -499,10 +498,8 @@ function registerOpenEditorAPICommands(): void {
group = editorGroupsService.getGroup(viewColumnToEditorGroup(editorGroupsService, columnArg)) ?? editorGroupsService.activeGroup;
}
const textOptions: ITextEditorOptions = optionsArg ? { ...optionsArg, override: false } : { override: false };
const input = editorService.createEditorInput({ resource: URI.revive(resource) });
return openEditorWith(accessor, input, id, textOptions, group);
return editorService.openEditor(input, { ...optionsArg, override: id }, group);
});
}

View File

@@ -31,8 +31,8 @@ export class EditorControl extends Disposable {
private readonly _onDidFocus = this._register(new Emitter<void>());
readonly onDidFocus = this._onDidFocus.event;
private _onDidSizeConstraintsChange = this._register(new Emitter<{ width: number; height: number; } | undefined>());
readonly onDidSizeConstraintsChange = this._onDidSizeConstraintsChange.event;
private _onDidChangeSizeConstraints = this._register(new Emitter<{ width: number; height: number; } | undefined>());
readonly onDidChangeSizeConstraints = this._onDidChangeSizeConstraints.event;
private _activeEditorPane: EditorPane | null = null;
get activeEditorPane(): IVisibleEditorPane | null { return this._activeEditorPane as IVisibleEditorPane | null; }
@@ -139,12 +139,12 @@ export class EditorControl extends Disposable {
// Listen to editor pane changes
if (editorPane) {
this.activeEditorPaneDisposables.add(editorPane.onDidSizeConstraintsChange(e => this._onDidSizeConstraintsChange.fire(e)));
this.activeEditorPaneDisposables.add(editorPane.onDidChangeSizeConstraints(e => this._onDidChangeSizeConstraints.fire(e)));
this.activeEditorPaneDisposables.add(editorPane.onDidFocus(() => this._onDidFocus.fire()));
}
// Indicate that size constraints could have changed due to new editor
this._onDidSizeConstraintsChange.fire(undefined);
this._onDidChangeSizeConstraints.fire(undefined);
}
private async doSetInput(editorPane: EditorPane, editor: EditorInput, options: EditorOptions | undefined, context: IEditorOpenContext): Promise<boolean> {

View File

@@ -26,6 +26,7 @@ import { assertIsDefined, assertAllDefined } from 'vs/base/common/types';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { localize } from 'vs/nls';
import { ByteSize } from 'vs/platform/files/common/files';
import { EditorOverride } from 'vs/platform/editor/common/editor';
interface IDropOperation {
splitDirection?: GroupDirection;
@@ -284,7 +285,7 @@ class DropOverlay extends Themable {
const options = getActiveTextEditorOptions(sourceGroup, draggedEditor.editor, EditorOptions.create({
pinned: true, // always pin dropped editor
sticky: sourceGroup.isSticky(draggedEditor.editor), // preserve sticky state
override: false, // Use `draggedEditor.editor` as is. If it is already a custom editor, it will stay so.
override: EditorOverride.DISABLED // preserve editor type
}));
const copyEditor = this.isCopyOperation(event, draggedEditor);
targetGroup.openEditor(draggedEditor.editor, options, copyEditor ? OpenEditorContext.COPY_EDITOR : OpenEditorContext.MOVE_EDITOR);
@@ -521,7 +522,7 @@ class DropOverlay extends Themable {
// With tabs and opened editors: use the area below tabs as drop target
if (!this.groupView.isEmpty && this.accessor.partOptions.showTabs) {
return this.groupView.titleDimensions.offset;
return this.groupView.titleHeight.offset;
}
// Without tabs or empty group: use entire editor area as drop target

View File

@@ -22,15 +22,15 @@ import { EditorControl } from 'vs/workbench/browser/parts/editor/editorControl';
import { IEditorProgressService } from 'vs/platform/progress/common/progress';
import { EditorProgressIndicator } from 'vs/workbench/services/progress/browser/progressIndicator';
import { localize } from 'vs/nls';
import { isPromiseCanceledError } from 'vs/base/common/errors';
import { isErrorWithActions, isPromiseCanceledError } from 'vs/base/common/errors';
import { dispose, MutableDisposable } from 'vs/base/common/lifecycle';
import { Severity, INotificationService } from 'vs/platform/notification/common/notification';
import { toErrorMessage } from 'vs/base/common/errorMessage';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { RunOnceWorker } from 'vs/base/common/async';
import { Promises, RunOnceWorker } from 'vs/base/common/async';
import { EventType as TouchEventType, GestureEvent } from 'vs/base/browser/touch';
import { TitleControl } from 'vs/workbench/browser/parts/editor/titleControl';
import { IEditorGroupsAccessor, IEditorGroupView, getActiveTextEditorOptions, IEditorOpeningEvent, EditorServiceImpl, IEditorGroupTitleDimensions } from 'vs/workbench/browser/parts/editor/editor';
import { IEditorGroupsAccessor, IEditorGroupView, getActiveTextEditorOptions, IEditorOpeningEvent, EditorServiceImpl, IEditorGroupTitleHeight } from 'vs/workbench/browser/parts/editor/editor';
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { ActionRunner, IAction, Action } from 'vs/base/common/actions';
@@ -40,7 +40,6 @@ import { IMenuService, MenuId, IMenu } from 'vs/platform/actions/common/actions'
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
import { createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { isErrorWithActions, IErrorWithActions } from 'vs/base/common/errorsWithActions';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { withNullAsUndefined, withUndefinedAsNull } from 'vs/base/common/types';
import { hash } from 'vs/base/common/hash';
@@ -200,7 +199,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
// Editor control
this.editorControl = this._register(this.scopedInstantiationService.createInstance(EditorControl, this.editorContainer, this));
this._onDidChange.input = this.editorControl.onDidSizeConstraintsChange;
this._onDidChange.input = this.editorControl.onDidChangeSizeConstraints;
// Track Focus
this.doTrackFocus();
@@ -490,7 +489,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
this._register(this._group.onDidEditorLabelChange(editor => this.onDidEditorLabelChange(editor)));
// Option Changes
this._register(this.accessor.onDidEditorPartOptionsChange(e => this.onDidEditorPartOptionsChange(e)));
this._register(this.accessor.onDidChangeEditorPartOptions(e => this.onDidChangeEditorPartOptions(e)));
// Visibility
this._register(this.accessor.onDidVisibilityChange(e => this.onDidVisibilityChange(e)));
@@ -598,16 +597,18 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
// Split between visible and hidden editors
let activeEditor: EditorInput | undefined;
const inactiveEditors: EditorInput[] = [];
editors.forEach(editor => {
for (const editor of editors) {
if (this._group.isActive(editor)) {
activeEditor = editor;
} else if (this._group.contains(editor)) {
inactiveEditors.push(editor);
}
});
}
// Close all inactive editors first to prevent UI flicker
inactiveEditors.forEach(hidden => this.doCloseEditor(hidden, false));
for (const inactiveEditor of inactiveEditors) {
this.doCloseEditor(inactiveEditor, false);
}
// Close active one last
if (activeEditor) {
@@ -615,7 +616,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
}
}
private onDidEditorPartOptionsChange(event: IEditorPartOptionsChangeEvent): void {
private onDidChangeEditorPartOptions(event: IEditorPartOptionsChangeEvent): void {
// Title container
this.updateTitleContainer();
@@ -711,8 +712,8 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
return this._group.count === 0;
}
get titleDimensions(): IEditorGroupTitleDimensions {
return this.titleAreaControl.getDimensions();
get titleHeight(): IEditorGroupTitleHeight {
return this.titleAreaControl.getHeight();
}
get isMinimized(): boolean {
@@ -1022,14 +1023,16 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
// Extract possible error actions from the error
let errorActions: ReadonlyArray<IAction> | undefined = undefined;
if (isErrorWithActions(error)) {
errorActions = (error as IErrorWithActions).actions;
errorActions = error.actions;
}
// If the context is USER, we try to show a modal dialog instead of a background notification
if (options?.context === EditorOpenContext.USER) {
const buttons: string[] = [];
if (Array.isArray(errorActions) && errorActions.length > 0) {
errorActions.forEach(action => buttons.push(action.label));
for (const errorAction of errorActions) {
buttons.push(errorAction.label);
}
} else {
buttons.push(localize('ok', 'OK'));
}
@@ -1110,7 +1113,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
// Open the other ones inactive
const startingIndex = this.getIndexOfEditor(editor) + 1;
await Promise.all(editors.map(async ({ editor, options }, index) => {
await Promises.settled(editors.map(async ({ editor, options }, index) => {
const adjustedEditorOptions = options || new EditorOptions();
adjustedEditorOptions.inactive = true;
adjustedEditorOptions.pinned = true;
@@ -1216,18 +1219,24 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
//#region closeEditor()
async closeEditor(editor: EditorInput | undefined = this.activeEditor || undefined, options?: ICloseEditorOptions): Promise<void> {
await this.doCloseEditorWithDirtyHandling(editor, options);
}
private async doCloseEditorWithDirtyHandling(editor: EditorInput | undefined = this.activeEditor || undefined, options?: ICloseEditorOptions): Promise<boolean> {
if (!editor) {
return;
return false;
}
// Check for dirty and veto
const veto = await this.handleDirtyClosing([editor]);
if (veto) {
return;
return false;
}
// Do close
this.doCloseEditor(editor, options?.preserveFocus ? false : undefined);
return true;
}
private doCloseEditor(editor: EditorInput, focusNext = (this.accessor.activeGroup === this), fromError?: boolean): void {
@@ -1347,10 +1356,12 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
this.mapEditorToPendingConfirmation.set(editor, handleDirtyClosingPromise);
}
const veto = await handleDirtyClosingPromise;
// Make sure to remove from our map of cached pending confirmations
this.mapEditorToPendingConfirmation.delete(editor);
let veto: boolean;
try {
veto = await handleDirtyClosingPromise;
} finally {
this.mapEditorToPendingConfirmation.delete(editor);
}
// Return for the first veto we got
if (veto) {
@@ -1521,13 +1532,13 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
// Close all inactive editors first
let closeActiveEditor = false;
editors.forEach(editor => {
for (const editor of editors) {
if (!this.isActive(editor)) {
this.doCloseInactiveEditor(editor);
} else {
closeActiveEditor = true;
}
});
}
// Close active editor last if contained in editors list to close
if (closeActiveEditor) {
@@ -1571,13 +1582,13 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
// Close all inactive editors first
const editorsToClose: EditorInput[] = [];
this._group.getEditors(EditorsOrder.SEQUENTIAL, options).forEach(editor => {
for (const editor of this._group.getEditors(EditorsOrder.SEQUENTIAL, options)) {
if (!this.isActive(editor)) {
this.doCloseInactiveEditor(editor);
}
editorsToClose.push(editor);
});
}
// Close active editor last (unless we skip it, e.g. because it is sticky)
if (this.activeEditor && editorsToClose.includes(this.activeEditor)) {
@@ -1599,11 +1610,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
// Extract active vs. inactive replacements
let activeReplacement: EditorReplacement | undefined;
const inactiveReplacements: EditorReplacement[] = [];
editors.forEach(({ editor, replacement, options }) => {
if (editor.isDirty() && !editor.isSaving()) {
return; // we do not handle dirty in this method, so ignore all dirty
}
for (let { editor, replacement, options } of editors) {
const index = this.getIndexOfEditor(editor);
if (index >= 0) {
const isActiveEditor = this.isActive(editor);
@@ -1625,20 +1632,22 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
inactiveReplacements.push(editorToReplace);
}
}
});
}
// Handle inactive first
inactiveReplacements.forEach(async ({ editor, replacement, options }) => {
for (const { editor, replacement, options } of inactiveReplacements) {
// Open inactive editor
await this.doOpenEditor(replacement, options);
// Close replaced inactive editor unless they match
if (!editor.matches(replacement)) {
this.doCloseInactiveEditor(editor);
this.titleAreaControl.closeEditor(editor);
const closed = await this.doCloseEditorWithDirtyHandling(editor, { preserveFocus: true });
if (!closed) {
return; // canceled
}
}
});
}
// Handle active last
if (activeReplacement) {
@@ -1648,8 +1657,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
// Close replaced active editor unless they match
if (!activeReplacement.editor.matches(activeReplacement.replacement)) {
this.doCloseInactiveEditor(activeReplacement.editor);
this.titleAreaControl.closeEditor(activeReplacement.editor);
await this.doCloseEditorWithDirtyHandling(activeReplacement.editor, { preserveFocus: true });
}
await openEditorResult;

View File

@@ -8,12 +8,12 @@ import { EditorInput, EditorOptions, IEditorPane, GroupIdentifier, IEditorMement
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { CancellationToken } from 'vs/base/common/cancellation';
import { IEditorGroup, IEditorGroupsService, GroupsOrder } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { LRUCache, Touch } from 'vs/base/common/map';
import { URI } from 'vs/base/common/uri';
import { Event } from 'vs/base/common/event';
import { isEmptyObject, isUndefinedOrNull } from 'vs/base/common/types';
import { isEmptyObject } from 'vs/base/common/types';
import { DEFAULT_EDITOR_MIN_DIMENSIONS, DEFAULT_EDITOR_MAX_DIMENSIONS } from 'vs/workbench/browser/parts/editor/editor';
import { MementoObject } from 'vs/workbench/common/memento';
import { joinPath, IExtUri, isEqual } from 'vs/base/common/resources';
@@ -51,7 +51,7 @@ export abstract class EditorPane extends Composite implements IEditorPane {
get minimumHeight() { return DEFAULT_EDITOR_MIN_DIMENSIONS.height; }
get maximumHeight() { return DEFAULT_EDITOR_MAX_DIMENSIONS.height; }
readonly onDidSizeConstraintsChange = Event.None;
readonly onDidChangeSizeConstraints = Event.None;
protected _input: EditorInput | undefined;
get input(): EditorInput | undefined { return this._input; }
@@ -166,11 +166,11 @@ export abstract class EditorPane extends Composite implements IEditorPane {
protected saveState(): void {
// Save all editor memento for this editor type
EditorPane.EDITOR_MEMENTOS.forEach(editorMemento => {
for (const [, editorMemento] of EditorPane.EDITOR_MEMENTOS) {
if (editorMemento.id === this.getId()) {
editorMemento.saveState();
}
});
}
super.saveState();
}
@@ -224,9 +224,9 @@ export class EditorMemento<T> implements IEditorMemento<T> {
}
}
loadEditorState(group: IEditorGroup, resource: URI, fallbackToOtherGroupState?: boolean): T | undefined;
loadEditorState(group: IEditorGroup, editor: EditorInput, fallbackToOtherGroupState?: boolean): T | undefined;
loadEditorState(group: IEditorGroup, resourceOrEditor: URI | EditorInput, fallbackToOtherGroupState?: boolean): T | undefined {
loadEditorState(group: IEditorGroup, resource: URI): T | undefined;
loadEditorState(group: IEditorGroup, editor: EditorInput): T | undefined;
loadEditorState(group: IEditorGroup, resourceOrEditor: URI | EditorInput): T | undefined {
const resource = this.doGetResource(resourceOrEditor);
if (!resource || !group) {
return; // we are not in a good state to load any state for a resource
@@ -236,18 +236,7 @@ export class EditorMemento<T> implements IEditorMemento<T> {
const mementoForResource = cache.get(resource.toString());
if (mementoForResource) {
let mementoForResourceAndGroup = mementoForResource[group.id];
if (!fallbackToOtherGroupState || !isUndefinedOrNull(mementoForResourceAndGroup)) {
return mementoForResourceAndGroup;
}
// Fallback to retrieve state from the most recently active editor group as instructed
for (const group of this.editorGroupService.getGroups(GroupsOrder.MOST_RECENTLY_ACTIVE)) {
mementoForResourceAndGroup = mementoForResource[group.id];
if (!isUndefinedOrNull(mementoForResourceAndGroup)) {
return mementoForResourceAndGroup;
}
}
return mementoForResource[group.id];
}
return;

View File

@@ -3,7 +3,6 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'vs/workbench/browser/parts/editor/editor.contribution';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { Part } from 'vs/workbench/browser/part';
import { Dimension, isAncestor, $, EventHelper, addDisposableGenericMouseDownListner } from 'vs/base/browser/dom';
@@ -32,6 +31,7 @@ import { MementoObject } from 'vs/workbench/common/memento';
import { assertIsDefined } from 'vs/base/common/types';
import { IBoundarySashes } from 'vs/base/browser/ui/grid/gridview';
import { CompositeDragAndDropObserver } from 'vs/workbench/browser/dnd';
import { Promises } from 'vs/base/common/async';
interface IEditorPartUIState {
serializedGrid: ISerializedGrid;
@@ -93,11 +93,11 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro
private readonly _onDidLayout = this._register(new Emitter<Dimension>());
readonly onDidLayout = this._onDidLayout.event;
private readonly _onDidActiveGroupChange = this._register(new Emitter<IEditorGroupView>());
readonly onDidActiveGroupChange = this._onDidActiveGroupChange.event;
private readonly _onDidChangeActiveGroup = this._register(new Emitter<IEditorGroupView>());
readonly onDidChangeActiveGroup = this._onDidChangeActiveGroup.event;
private readonly _onDidGroupIndexChange = this._register(new Emitter<IEditorGroupView>());
readonly onDidGroupIndexChange = this._onDidGroupIndexChange.event;
private readonly _onDidChangeGroupIndex = this._register(new Emitter<IEditorGroupView>());
readonly onDidChangeGroupIndex = this._onDidChangeGroupIndex.event;
private readonly _onDidActivateGroup = this._register(new Emitter<IEditorGroupView>());
readonly onDidActivateGroup = this._onDidActivateGroup.event;
@@ -113,11 +113,11 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro
private readonly onDidSetGridWidget = this._register(new Emitter<{ width: number; height: number; } | undefined>());
private readonly _onDidSizeConstraintsChange = this._register(new Relay<{ width: number; height: number; } | undefined>());
readonly onDidSizeConstraintsChange = Event.any(this.onDidSetGridWidget.event, this._onDidSizeConstraintsChange.event);
private readonly _onDidChangeSizeConstraints = this._register(new Relay<{ width: number; height: number; } | undefined>());
readonly onDidChangeSizeConstraints = Event.any(this.onDidSetGridWidget.event, this._onDidChangeSizeConstraints.event);
private readonly _onDidEditorPartOptionsChange = this._register(new Emitter<IEditorPartOptionsChangeEvent>());
readonly onDidEditorPartOptionsChange = this._onDidEditorPartOptionsChange.event;
private readonly _onDidChangeEditorPartOptions = this._register(new Emitter<IEditorPartOptionsChangeEvent>());
readonly onDidChangeEditorPartOptions = this._onDidChangeEditorPartOptions.event;
//#endregion
@@ -177,7 +177,7 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro
this._partOptions = newPartOptions;
this._onDidEditorPartOptionsChange.fire({ oldPartOptions, newPartOptions });
this._onDidChangeEditorPartOptions.fire({ oldPartOptions, newPartOptions });
}
//#region IEditorGroupsService
@@ -550,7 +550,7 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro
this.updateContainer();
break;
case GroupChangeKind.GROUP_INDEX:
this._onDidGroupIndexChange.fire(groupView);
this._onDidChangeGroupIndex.fire(groupView);
break;
}
}));
@@ -588,7 +588,7 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro
this.doRestoreGroup(group);
// Event
this._onDidActiveGroupChange.fire(group);
this._onDidChangeActiveGroup.fire(group);
}
private doRestoreGroup(group: IEditorGroupView): void {
@@ -944,7 +944,7 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro
}
// Signal restored
Promise.all(this.groups.map(group => group.whenRestored)).finally(() => {
Promises.settled(this.groups.map(group => group.whenRestored)).finally(() => {
if (this.whenRestoredResolve) {
this.whenRestoredResolve();
}
@@ -1046,7 +1046,7 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro
this.gridWidget.boundarySashes = boundarySashes;
this.gridWidgetView.gridWidget = gridWidget;
this._onDidSizeConstraintsChange.input = gridWidget.onDidChange;
this._onDidChangeSizeConstraints.input = gridWidget.onDidChange;
this.onDidSetGridWidget.fire(undefined);
}

View File

@@ -10,7 +10,7 @@ import { format, compare, splitLines } from 'vs/base/common/strings';
import { extname, basename, isEqual } from 'vs/base/common/resources';
import { areFunctions, withNullAsUndefined, withUndefinedAsNull } from 'vs/base/common/types';
import { URI } from 'vs/base/common/uri';
import { Action } from 'vs/base/common/actions';
import { Action, WorkbenchActionExecutedClassification, WorkbenchActionExecutedEvent } from 'vs/base/common/actions';
import { Language } from 'vs/base/common/platform';
import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
import { IFileEditorInput, EncodingMode, IEncodingSupport, EditorResourceAccessor, SideBySideEditorInput, IEditorPane, IEditorInput, SideBySideEditor, IModeSupport } from 'vs/workbench/common/editor';
@@ -52,6 +52,7 @@ import { IStatusbarEntryAccessor, IStatusbarService, StatusbarAlignment, IStatus
import { IMarker, IMarkerService, MarkerSeverity, IMarkerData } from 'vs/platform/markers/common/markers';
import { STATUS_BAR_PROMINENT_ITEM_BACKGROUND, STATUS_BAR_PROMINENT_ITEM_FOREGROUND } from 'vs/workbench/common/theme';
import { themeColorFromId } from 'vs/platform/theme/common/themeService';
import { ITelemetryData, ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
class SideBySideEditorEncodingSupport implements IEncodingSupport {
constructor(private primary: IEncodingSupport, private secondary: IEncodingSupport) { }
@@ -696,7 +697,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution {
}
binaryEditors.forEach(editor => {
this.activeEditorListeners.add(editor.onMetadataChanged(metadata => {
this.activeEditorListeners.add(editor.onDidChangeMetadata(metadata => {
this.onMetadataChange(activeEditorPane);
}));
@@ -753,7 +754,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution {
private onColumnSelectionModeChange(editorWidget: ICodeEditor | undefined): void {
const info: StateDelta = { type: 'columnSelectionMode', columnSelectionMode: false };
if (editorWidget && editorWidget.getOption(EditorOption.columnSelection)) {
if (editorWidget?.getOption(EditorOption.columnSelection)) {
info.columnSelectionMode = true;
}
@@ -1063,12 +1064,13 @@ export class ChangeModeAction extends Action {
@IPreferencesService private readonly preferencesService: IPreferencesService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@ITextFileService private readonly textFileService: ITextFileService,
@ICommandService private readonly commandService: ICommandService
@ICommandService private readonly commandService: ICommandService,
@ITelemetryService private readonly telemetryService: ITelemetryService
) {
super(actionId, actionLabel);
}
async run(): Promise<void> {
async run(event: any, data: ITelemetryData): Promise<void> {
const activeEditorPane = this.editorService.activeEditorPane as unknown as { isNotebookEditor?: boolean } | undefined;
if (activeEditorPane?.isNotebookEditor) { // TODO@rebornix TODO@jrieken debt: https://github.com/microsoft/vscode/issues/114554
// it's inside notebook editor
@@ -1198,6 +1200,10 @@ export class ChangeModeAction extends Action {
}
activeTextEditorControl.focus();
this.telemetryService.publicLog2<WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification>('workbenchActionExecuted', {
id: ChangeModeAction.ID,
from: data?.from || 'quick open'
});
}
}

View File

@@ -67,7 +67,7 @@ export class EditorsObserver extends Disposable {
private registerListeners(): void {
this._register(this.storageService.onWillSaveState(() => this.saveState()));
this._register(this.editorGroupsService.onDidAddGroup(group => this.onGroupAdded(group)));
this._register(this.editorGroupsService.onDidEditorPartOptionsChange(e => this.onDidEditorPartOptionsChange(e)));
this._register(this.editorGroupsService.onDidChangeEditorPartOptions(e => this.onDidChangeEditorPartOptions(e)));
this.editorGroupsService.whenRestored.then(() => this.loadState());
}
@@ -142,7 +142,7 @@ export class EditorsObserver extends Disposable {
Event.once(group.onWillDispose)(() => dispose(groupDisposables));
}
private onDidEditorPartOptionsChange(event: IEditorPartOptionsChangeEvent): void {
private onDidChangeEditorPartOptions(event: IEditorPartOptionsChangeEvent): void {
if (!equals(event.newPartOptions.limit, event.oldPartOptions.limit)) {
const activeGroup = this.editorGroupsService.activeGroup;
let exclude: IEditorIdentifier | undefined = undefined;

Some files were not shown because too many files have changed in this diff Show More