resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.8.0.tgz#4bc6bb4dbfea5b0d2d7978d6c5cef922d584fb4f" integrity sha512-dlpYPsv0C9S6v6+T/h/d/otSbdUTizMJdxvSoS34tUpMOHev6iW7Zqt5KRFqYxl4vCqpDk9Wmhb3fKL3kwX5fQ== <del> xterm@4.9.0-beta.8: version "4.9.0-beta.8" resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.9.0-beta.8.tgz#ca121934d63f88668d2d5b11d9b2fc3bde7bd805" integrity sha512-EEonYBLANDUBfEeEnHG632bZdgBaAUWst8LFr6oC6f2uLFfJGHQvVJuLaEkPtRvS+jOeoorEXZRPmso1/ANHXA== </del> <ins> xterm@4.9.0-beta.24: version "4.9.0-beta.24" resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.9.0-beta.24.tgz#48f0990c6d32ad3a9bcc4fb49531d7effdaccea5" integrity sha512-CIVxxxbBiSw1WOMkIjjivaiIC9jNgih4klfWsRGx0qiDF5nbzHuLXkPTt+yAQUu9FCyTUwECm9Pkl3gUsSaGKg== </ins> y18n@^3.2.1: version "3.2.1"


export interface PickRemoteSourceOptions { readonly providerLabel?: (provider: RemoteSourceProvider) => string; readonly urlLabel?: string; <ins> readonly providerName?: string; </ins> } export async function pickRemoteSource(model: Model, options: PickRemoteSourceOptions = {}): Promise<string | undefined> { const quickpick = window.createQuickPick<(QuickPickItem & { provider?: RemoteSourceProvider, url?: string })>(); quickpick.ignoreFocusOut = true; <del> const providers = model.getRemoteProviders() .map(provider => ({ label: (provider.icon ? `$(${provider.icon}) ` : '') + (options.providerLabel ? options.providerLabel(provider) : provider.name), alwaysShow: true, provider })); quickpick.placeholder = providers.length === 0 ? localize('provide url', "Provide repository URL") : localize('provide url or pick', "Provide repository URL or pick a repository source."); const updatePicks = (value?: string) => { if (value) { quickpick.items = [{ label: options.urlLabel ?? localize('url', "URL"), description: value, alwaysShow: true, url: value }, ...providers]; } else { quickpick.items = providers; } }; quickpick.onDidChangeValue(updatePicks); updatePicks(); const result = await getQuickPickResult(quickpick); if (result) { if (result.url) { return result.url; } else if (result.provider) { const quickpick = new RemoteSourceProviderQuickPick(result.provider); const remote = await quickpick.pick(); if (remote) { if (typeof remote.url === 'string') { return remote.url; } else if (remote.url.length > 0) { return await window.showQuickPick(remote.url, { ignoreFocusOut: true, placeHolder: localize('pick url', "Choose a URL to clone from.") }); } </del> <ins> const targetedProvider = model.getRemoteProviders().filter(provider => provider.name === options.providerName); if (targetedProvider && targetedProvider.length === 1) { return await pickProviderSource(targetedProvider[0]); } else { const providers = model.getRemoteProviders() .map(provider => ({ label: (provider.icon ? `$(${provider.icon}) ` : '') + (options.providerLabel ? options.providerLabel(provider) : provider.name), alwaysShow: true, provider })); quickpick.placeholder = providers.length === 0 ? localize('provide url', "Provide repository URL") : localize('provide url or pick', "Provide repository URL or pick a repository source."); const updatePicks = (value?: string) => { if (value) { quickpick.items = [{ label: options.urlLabel ?? localize('url', "URL"), description: value, alwaysShow: true, url: value }, ...providers]; } else { quickpick.items = providers; } }; quickpick.onDidChangeValue(updatePicks); updatePicks(); const result = await getQuickPickResult(quickpick); if (result) { if (result.url) { return result.url; } else if (result.provider) { return await pickProviderSource(result.provider); </ins> } } } return undefined; } <ins> async function pickProviderSource(provider: RemoteSourceProvider): Promise<string | undefined> { const quickpick = new RemoteSourceProviderQuickPick(provider); const remote = await quickpick.pick(); if (remote) { if (typeof remote.url === 'string') { return remote.url; } else if (remote.url.length > 0) { return await window.showQuickPick(remote.url, { ignoreFocusOut: true, placeHolder: localize('pick url', "Choose a URL to clone from.") }); } } return undefined; } </ins>


{ "view": "scm", "contents": "%view.workbench.scm.empty%", <del> "when": "config.git.enabled && git.state == initialized && workbenchState == empty", </del> <ins> "when": "config.git.enabled && workbenchState == empty", "enablement": "git.state == initialized", </ins> "group": "2_open@1" }, { "view": "scm", "contents": "%view.workbench.scm.folder%", <del> "when": "config.git.enabled && git.state == initialized && workbenchState == folder", </del> <ins> "when": "config.git.enabled && workbenchState == folder", "enablement": "git.state == initialized", </ins> "group": "5_scm@1" }, { "view": "scm", "contents": "%view.workbench.scm.workspace%", "when": "config.git.enabled && git.state == initialized && workbenchState == workspace && workspaceFolderCount != 0", <ins> "enablement": "git.state == initialized", </ins> "group": "5_scm@1" }, { "view": "scm", "contents": "%view.workbench.scm.emptyWorkspace%", <del> "when": "config.git.enabled && git.state == initialized && workbenchState == workspace && workspaceFolderCount == 0", </del> <ins> "when": "config.git.enabled && workbenchState == workspace && workspaceFolderCount == 0", "enablement": "git.state == initialized", </ins> "group": "2_open@1" }, { "view": "explorer", "contents": "%view.workbench.cloneRepository%", <del> "when": "config.git.enabled && git.state == initialized", </del> <ins> "when": "config.git.enabled", "enablement": "git.state == initialized", </ins> "group": "5_scm@1" } ]


"view.workbench.scm.folder": "The folder currently open doesn't have a git repository. You can initialize a repository which will enable source control features powered by git.n[Initialize Repository](command:git.init?%5Btrue%5D)nTo learn more about how to use git and source control in VS Code [read our docs](https://aka.ms/vscode-scm).", "view.workbench.scm.workspace": "The workspace currently open doesn't have any folders containing git repositories. You can initialize a repository on a folder which will enable source control features powered by git.n[Initialize Repository](command:git.init)nTo learn more about how to use git and source control in VS Code [read our docs](https://aka.ms/vscode-scm).", "view.workbench.scm.emptyWorkspace": "The workspace currently open doesn't have any folders containing git repositories.n[Add Folder to Workspace](command:workbench.action.addRootFolder)nTo learn more about how to use git and source control in VS Code [read our docs](https://aka.ms/vscode-scm).", <del> "view.workbench.cloneRepository": "You can also clone a repository from a URL. To learn more about how to use git and source control in VS Code [read our docs](https://aka.ms/vscode-scm).n[Clone Repository](command:git.clone)" </del> <ins> "view.workbench.cloneRepository": "You can also clone a repository from a URL. To learn more about how to use git and source control in VS Code [read our docs](https://aka.ms/vscode-scm).n[Clone Repository](command:git.clone 'Clone a repository once the git extension has activated')" </ins> }


this.bodyContainer.classList.add('welcome'); this.viewWelcomeContainer.innerText = ''; <del> let buttonIndex = 0; </del> for (const { content, preconditions } of contents) { <ins> let buttonIndex = 0; </ins> const lines = content.split('n'); for (let line of lines) {


for (const welcome of contribution.value) { const id = ViewIdentifierMap[welcome.view] ?? welcome.view; const { group, order } = parseGroupAndOrder(welcome, contribution); <ins> const enablement = ContextKeyExpr.deserialize(welcome.enablement); </ins> const disposable = viewsRegistry.registerViewWelcomeContent(id, { content: welcome.contents, when: ContextKeyExpr.deserialize(welcome.when), <ins> // supply the enablement clause for each line in case the line defines a button preconditions: welcome.contents.split('n').map((_) => enablement), </ins> group, order });


contents = 'contents', when = 'when', group = 'group', <ins> enablement = 'enablement', </ins> } export interface ViewWelcome {


readonly [ViewsWelcomeExtensionPointFields.contents]: string; readonly [ViewsWelcomeExtensionPointFields.when]: string; readonly [ViewsWelcomeExtensionPointFields.group]: string; <ins> readonly [ViewsWelcomeExtensionPointFields.enablement]: string; </ins> } export type ViewsWelcomeExtensionPoint = ViewWelcome[];


type: 'string', description: nls.localize('contributes.viewsWelcome.view.group', "Group to which this welcome content belongs."), }, <ins> [ViewsWelcomeExtensionPointFields.enablement]: { type: 'string', description: nls.localize('contributes.viewsWelcome.view.enablement', "Condition when the welcome content buttons should be enabled."), }, </ins> } } });


Package: @@NAME@@ Version: @@VERSION@@ Section: devel <del> Depends: libnss3 (>= 2:3.26), gnupg, apt, libxkbfile1, libsecret-1-0, libgtk-3-0 (>= 3.10.0), libxss1 </del> <ins> Depends: libnss3 (>= 2:3.26), gnupg, apt, libxkbfile1, libsecret-1-0, libgtk-3-0 (>= 3.10.0), libxss1, libgbm1 </ins> Priority: optional Architecture: @@ARCHITECTURE@@ Maintainer: Microsoft Corporation <vscode-linux@microsoft.com>


"libc.so.6(GLIBC_2.9)(64bit)", "libxcb.so.1()(64bit)", "libxkbfile.so.1()(64bit)", <del> "libsecret-1.so.0()(64bit)" </del> <ins> "libsecret-1.so.0()(64bit)", "libgbm.so.1()(64bit)" </ins> ], "aarch64": [ "libpthread.so.0()(aarch64)",


- libgconf-2-4 - libglib2.0-bin - libgnome-keyring0 <ins> - libgbm1 </ins> - libgtk-3-0 - libnotify4 - libnspr4


const editorService = accessor.get(IEditorService); const viewsService = accessor.get(IViewsService); const notificationService = accessor.get(INotificationService); <ins> const workingCopyFileService = accessor.get(IWorkingCopyFileService); </ins> await viewsService.openView(VIEW_ID, true);


const onSuccess = async (value: string): Promise<void> => { try { <del> const created = isFolder ? await fileService.createFolder(resources.joinPath(folder.resource, value)) : await textFileService.create(resources.joinPath(folder.resource, value)); </del> <ins> const created = isFolder ? await workingCopyFileService.createFolder(resources.joinPath(folder.resource, value)) : await textFileService.create(resources.joinPath(folder.resource, value)); </ins> await refreshIfSeparator(value, explorerService); isFolder ?


create(resource: URI, contents?: VSBuffer | VSBufferReadable | VSBufferReadableStream, options?: { overwrite?: boolean }): Promise<IFileStatWithMetadata>; /** <ins> * Will create a folder and any parent folder that needs to be created. * * Working copy owners can listen to the `onWillRunWorkingCopyFileOperation` and * `onDidRunWorkingCopyFileOperation` events to participate. * * Note: events will only be emitted for the provided resource, but not any * parent folders that are being created as part of the operation. */ createFolder(resource: URI): Promise<IFileStatWithMetadata>; /** </ins> * Will move working copies matching the provided resources and corresponding children * to the target resources using the associated file service for those resources. *


//#region File operations <del> async create(resource: URI, contents?: VSBuffer | VSBufferReadable | VSBufferReadableStream, options?: { overwrite?: boolean }): Promise<IFileStatWithMetadata> { </del> <ins> create(resource: URI, contents?: VSBuffer | VSBufferReadable | VSBufferReadableStream, options?: { overwrite?: boolean }): Promise<IFileStatWithMetadata> { return this.doCreateFileOrFolder(resource, true, contents, options); } createFolder(resource: URI, options?: { overwrite?: boolean }): Promise<IFileStatWithMetadata> { return this.doCreateFileOrFolder(resource, false); } async doCreateFileOrFolder(resource: URI, isFile: boolean, contents?: VSBuffer | VSBufferReadable | VSBufferReadableStream, options?: { overwrite?: boolean }): Promise<IFileStatWithMetadata> { </ins> // validate create operation before starting <del> const validateCreate = await this.fileService.canCreateFile(resource, options); if (validateCreate instanceof Error) { throw validateCreate; </del> <ins> if (isFile) { const validateCreate = await this.fileService.canCreateFile(resource, options); if (validateCreate instanceof Error) { throw validateCreate; } </ins> } // file operation participant


// now actually create on disk let stat: IFileStatWithMetadata; try { <del> stat = await this.fileService.createFile(resource, contents, { overwrite: options?.overwrite }); </del> <ins> if (isFile) { stat = await this.fileService.createFile(resource, contents, { overwrite: options?.overwrite }); } else { stat = await this.fileService.createFolder(resource); } </ins> } catch (error) { // error event


model1.dispose(); }); <ins> test('createFolder', async function () { let eventCounter = 0; let correlationId: number | undefined = undefined; const resource = toResource.call(this, '/path/folder'); const participant = accessor.workingCopyFileService.addFileOperationParticipant({ participate: async (files, operation) => { assert.equal(files.length, 1); const file = files[0]; assert.equal(file.target.toString(), resource.toString()); assert.equal(operation, FileOperation.CREATE); eventCounter++; } }); const listener1 = accessor.workingCopyFileService.onWillRunWorkingCopyFileOperation(e => { assert.equal(e.files.length, 1); const file = e.files[0]; assert.equal(file.target.toString(), resource.toString()); assert.equal(e.operation, FileOperation.CREATE); correlationId = e.correlationId; eventCounter++; }); const listener2 = accessor.workingCopyFileService.onDidRunWorkingCopyFileOperation(e => { assert.equal(e.files.length, 1); const file = e.files[0]; assert.equal(file.target.toString(), resource.toString()); assert.equal(e.operation, FileOperation.CREATE); assert.equal(e.correlationId, correlationId); eventCounter++; }); await accessor.workingCopyFileService.createFolder(resource); assert.equal(eventCounter, 3); participant.dispose(); listener1.dispose(); listener2.dispose(); }); </ins> async function testEventsMoveOrCopy(files: { source: URI, target: URI }[], move?: boolean): Promise<number> { let eventCounter = 0;


move(_source: URI, _target: URI, _overwrite?: boolean): Promise<IFileStatWithMetadata> { return Promise.resolve(null!); } copy(_source: URI, _target: URI, _overwrite?: boolean): Promise<IFileStatWithMetadata> { return Promise.resolve(null!); } createFile(_resource: URI, _content?: VSBuffer | VSBufferReadable, _options?: ICreateFileOptions): Promise<IFileStatWithMetadata> { return Promise.resolve(null!); } <del> createFolder(_resource: URI): Promise<IFileStatWithMetadata> { throw new Error('not implemented'); } </del> <ins> createFolder(_resource: URI): Promise<IFileStatWithMetadata> { return Promise.resolve(null!); } </ins> onDidChangeFileSystemProviderRegistrations = Event.None;


getDirty(resource: URI): IWorkingCopy[] { return []; } create(resource: URI, contents?: VSBuffer | VSBufferReadable | VSBufferReadableStream, options?: { overwrite?: boolean | undefined; } | undefined): Promise<IFileStatWithMetadata> { throw new Error('Method not implemented.'); } <ins> createFolder(resource: URI): Promise<IFileStatWithMetadata> { throw new Error('Method not implemented.'); } </ins> move(files: { source: URI; target: URI; }[], options?: { overwrite?: boolean }): Promise<IFileStatWithMetadata[]> { throw new Error('Method not implemented.'); }


* @param pattern A file glob pattern like `*.{ts,js}` that will be matched on file paths * relative to the base path. */ <del> constructor(base: WorkspaceFolder | string, pattern: string) </del> <ins> constructor(base: Uri | WorkspaceFolder | string, pattern: string) </ins> } /**


pattern: string; <del> constructor(base: vscode.WorkspaceFolder | string, pattern: string) { </del> <ins> constructor(base: URI | vscode.WorkspaceFolder | string, pattern: string) { </ins> if (typeof base !== 'string') { <del> if (!base || !URI.isUri(base.uri)) { </del> <ins> if (!base || !URI.isUri(base) && !URI.isUri(base.uri)) { </ins> throw illegalArgument('base'); } }


if (typeof base === 'string') { this.base = base; <ins> } else if (URI.isUri(base)) { this.baseFolder = base; this.base = base.fsPath; </ins> } else { this.baseFolder = base.uri; this.base = base.uri.fsPath;


import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { createAndFillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; import { getCurrentAuthenticationSessionInfo } from 'vs/workbench/services/authentication/browser/authenticationService'; <del> import { AuthenticationSession, IAuthenticationService } from 'vs/workbench/services/authentication/common/authentication'; </del> <ins> import { AuthenticationSessionAccount, IAuthenticationService } from 'vs/workbench/services/authentication/common/authentication'; </ins> import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IProductService } from 'vs/platform/product/common/productService';


import { ICredentialsService } from 'vs/platform/credentials/common/credentials'; import { IUserDataProfileService } from 'vs/workbench/services/userDataProfile/common/userDataProfile'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; <ins> import { ILogService } from 'vs/platform/log/common/log'; </ins> export class ViewContainerActivityAction extends ActivityAction {


static readonly ACCOUNTS_VISIBILITY_PREFERENCE_KEY = 'workbench.activity.showAccounts'; <ins> private readonly groupedAccounts: Map<string, (AuthenticationSessionAccount & { canSignOut: boolean })[]> = new Map(); private readonly problematicProviders: Set<string> = new Set(); private initialized = false; private sessionFromEmbedder = getCurrentAuthenticationSessionInfo(this.credentialsService, this.productService); </ins> constructor( action: ActivityAction, contextMenuActionsProvider: () => IAction[],


@IStorageService private readonly storageService: IStorageService, @IKeybindingService keybindingService: IKeybindingService, @ICredentialsService private readonly credentialsService: ICredentialsService, <ins> @ILogService private readonly logService: ILogService </ins> ) { super(MenuId.AccountsContext, action, contextMenuActionsProvider, true, colors, activityHoverOptions, themeService, hoverService, menuService, contextMenuService, contextKeyService, configurationService, environmentService, keybindingService); <ins> this.registerListeners(); this.initialize(); } private registerListeners(): void { this._register(this.authenticationService.onDidRegisterAuthenticationProvider(async (e) => { await this.addAccountsFromProvider(e.id); })); this._register(this.authenticationService.onDidUnregisterAuthenticationProvider((e) => { this.groupedAccounts.delete(e.id); this.problematicProviders.delete(e.id); })); this._register(this.authenticationService.onDidChangeSessions(async e => { const promises = []; for (const changed of e.event.changed) { promises.push(this.addOrUpdateAccount(e.providerId, changed.account)); } for (const added of e.event.added) { promises.push(this.addOrUpdateAccount(e.providerId, added.account)); } const result = await Promise.allSettled(promises); for (const r of result) { if (r.status === 'rejected') { this.logService.error(r.reason); } } for (const removed of e.event.removed) { this.removeAccount(e.providerId, removed.account); } })); } // This function exists to ensure that the accounts are added for auth providers that had already been registered // before the menu was created. private async initialize(): Promise<void> { const providerIds = this.authenticationService.getProviderIds(); const results = await Promise.allSettled(providerIds.map(providerId => this.addAccountsFromProvider(providerId))); // Log any errors that occurred while initializing. We try to be best effort here to show the most amount of accounts for (const result of results) { if (result.status === 'rejected') { this.logService.error(result.reason); } } this.initialized = true; </ins> } <ins> //#region overrides </ins> protected override async resolveMainMenuActions(accountsMenu: IMenu, disposables: DisposableStore): Promise<IAction[]> { await super.resolveMainMenuActions(accountsMenu, disposables); <del> const otherCommands = accountsMenu.getActions(); </del> const providers = this.authenticationService.getProviderIds(); <del> const allSessions = providers.map(async providerId => { try { const sessions = await this.authenticationService.getSessions(providerId); const groupedSessions: { [label: string]: AuthenticationSession[] } = {}; sessions.forEach(session => { if (groupedSessions[session.account.label]) { groupedSessions[session.account.label].push(session); } else { groupedSessions[session.account.label] = [session]; } }); </del> <ins> const otherCommands = accountsMenu.getActions(); let menus: IAction[] = []; </ins> <del> return { providerId, sessions: groupedSessions }; } catch { return { providerId }; </del> <ins> for (const providerId of providers) { if (!this.initialized) { const noAccountsAvailableAction = disposables.add(new Action('noAccountsAvailable', localize('loading', "Loading..."), undefined, false)); menus.push(noAccountsAvailableAction); break; } const providerLabel = this.authenticationService.getLabel(providerId); const accounts = this.groupedAccounts.get(providerId); if (!accounts) { if (this.problematicProviders.has(providerId)) { const providerUnavailableAction = disposables.add(new Action('providerUnavailable', localize('authProviderUnavailable', '{0} is currently unavailable', providerLabel), undefined, false)); menus.push(providerUnavailableAction); // try again in the background so that if the failure was intermittent, we can resolve it on the next showing of the menu try { await this.addAccountsFromProvider(providerId); } catch (e) { this.logService.error(e); } } continue; </ins> } <del> }); const result = await Promise.all(allSessions); let menus: IAction[] = []; const authenticationSession = await getCurrentAuthenticationSessionInfo(this.credentialsService, this.productService); result.forEach(sessionInfo => { const providerDisplayName = this.authenticationService.getLabel(sessionInfo.providerId); if (sessionInfo.sessions) { Object.keys(sessionInfo.sessions).forEach(accountName => { const manageExtensionsAction = disposables.add(new Action(`configureSessions${accountName}`, localize('manageTrustedExtensions', "Manage Trusted Extensions"), '', true, () => { return this.authenticationService.manageTrustedExtensionsForAccount(sessionInfo.providerId, accountName); })); const signOutAction = disposables.add(new Action('signOut', localize('signOut', "Sign Out"), '', true, () => { return this.authenticationService.removeAccountSessions(sessionInfo.providerId, accountName, sessionInfo.sessions[accountName]); })); </del> <ins> for (const account of accounts) { const manageExtensionsAction = disposables.add(new Action(`configureSessions${account.label}`, localize('manageTrustedExtensions', "Manage Trusted Extensions"), undefined, true, () => { return this.authenticationService.manageTrustedExtensionsForAccount(providerId, account.label); })); </ins> <del> const providerSubMenuActions = [manageExtensionsAction]; </del> <ins> const providerSubMenuActions: Action[] = [manageExtensionsAction]; </ins> <del> const hasEmbedderAccountSession = sessionInfo.sessions[accountName].some(session => session.id === (authenticationSession?.id)); if (!hasEmbedderAccountSession || authenticationSession?.canSignOut) { providerSubMenuActions.push(signOutAction); } </del> <ins> if (account.canSignOut) { const signOutAction = disposables.add(new Action('signOut', localize('signOut', "Sign Out"), undefined, true, async () => { const allSessions = await this.authenticationService.getSessions(providerId); const sessionsForAccount = allSessions.filter(s => s.account.id === account.id); return await this.authenticationService.removeAccountSessions(providerId, account.label, sessionsForAccount); })); providerSubMenuActions.push(signOutAction); } </ins> <del> const providerSubMenu = new SubmenuAction('activitybar.submenu', `${accountName} (${providerDisplayName})`, providerSubMenuActions); menus.push(providerSubMenu); }); } else { const providerUnavailableAction = disposables.add(new Action('providerUnavailable', localize('authProviderUnavailable', '{0} is currently unavailable', providerDisplayName))); menus.push(providerUnavailableAction); </del> <ins> const providerSubMenu = new SubmenuAction('activitybar.submenu', `${account.label} (${providerLabel})`, providerSubMenuActions); menus.push(providerSubMenu); </ins> } <del> }); </del> <ins> } </ins> if (providers.length && !menus.length) { const noAccountsAvailableAction = disposables.add(new Action('noAccountsAvailable', localize('noAccounts', "You are not signed in to any accounts"), undefined, false));


return actions; } <ins> //#endregion //#region groupedAccounts helpers private async addOrUpdateAccount(providerId: string, account: AuthenticationSessionAccount): Promise<void> { const accounts = this.groupedAccounts.get(providerId); const existingAccount = accounts?.find(a => a.id === account.id); if (existingAccount) { if (existingAccount.label !== account.label) { existingAccount.label = account.label; } return; } const sessionFromEmbedder = await this.sessionFromEmbedder; // If the session stored from the embedder allows sign out, then we can treat it and all others as sign out-able let canSignOut = !!sessionFromEmbedder?.canSignOut; if (!canSignOut) { if (sessionFromEmbedder?.id) { const sessions = (await this.authenticationService.getSessions(providerId)).filter(s => s.account.id === account.id); canSignOut = !sessions.some(s => s.id === sessionFromEmbedder.id); } else { // The default if we don't have a session from the embedder is to allow sign out canSignOut = true; } } if (!accounts) { this.groupedAccounts.set(providerId, [{ ...account, canSignOut }]); return; } accounts.push({ ...account, canSignOut }); } private removeAccount(providerId: string, account: AuthenticationSessionAccount): void { const accounts = this.groupedAccounts.get(providerId); if (!accounts) { return; } const index = accounts.findIndex(a => a.id === account.id); if (index === -1) { return; } accounts.splice(index, 1); if (accounts.length === 0) { this.groupedAccounts.delete(providerId); } } private async addAccountsFromProvider(providerId: string): Promise<void> { try { const sessions = await this.authenticationService.getSessions(providerId); this.problematicProviders.delete(providerId); const result = await Promise.allSettled(sessions.map(s => this.addOrUpdateAccount(providerId, s.account))); for (const r of result) { if (r.status === 'rejected') { this.logService.error(r.reason); } } } catch (e) { this.logService.error(e); this.problematicProviders.add(providerId); } } //#endregion </ins> } export interface IProfileActivity extends IActivity {


import { Event } from 'vs/base/common/event'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; <ins> export interface AuthenticationSessionAccount { label: string; id: string; } </ins> export interface AuthenticationSession { id: string; accessToken: string; <del> account: { label: string; id: string; }; </del> <ins> account: AuthenticationSessionAccount; </ins> scopes: ReadonlyArray<string>; idToken?: string; }


} private _delayedUpdateHistory() { <del> this._updateHistoryDelayer.trigger(this._updateHistory.bind(this)); </del> <ins> this._updateHistoryDelayer.trigger(this._updateHistory.bind(this)).then(undefined, onUnexpectedError); </ins> } private _updateHistory() {


import { exec } from 'child_process'; import * as resources from 'vs/base/common/resources'; import * as fs from 'fs'; <ins> import * as pfs from 'vs/base/node/pfs'; </ins> import { isLinux } from 'vs/base/common/platform'; import { IExtHostTunnelService, TunnelDto } from 'vs/workbench/api/common/extHostTunnelService'; import { asPromise } from 'vs/base/common/async'; 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'; <ins> import { promisify } from 'util'; import { MovingAverage } from 'vs/base/common/numbers'; </ins> class ExtensionTunnel implements vscode.Tunnel { private _onDispose: Emitter<void> = new Emitter();


) { super(); this._proxy = extHostRpc.getProxy(MainContext.MainThreadTunnelService); <del> if (initData.remote.isRemote && initData.remote.authority && !process.env['VSCODE_DISABLE_PROC_READING']) { </del> <ins> if (initData.remote.isRemote && initData.remote.authority) { </ins> this.registerCandidateFinder(); } }


return this._proxy.$getTunnels(); } <del> registerCandidateFinder(): void { // Every two seconds, scan to see if the candidate ports have changed; if (isLinux) { let oldPorts: { host: string, port: number, detail: string }[] | undefined = undefined; setInterval(async () => { const newPorts = await this.findCandidatePorts(); if (!oldPorts || (JSON.stringify(oldPorts) !== JSON.stringify(newPorts))) { oldPorts = newPorts; this._proxy.$onFoundNewCandidates(oldPorts.filter(async (candidate) => await this._showCandidatePort(candidate.host, candidate.port, candidate.detail))); return; } }, 2000); </del> <ins> private calculateDelay(movingAverage: number) { // Some local testing indicated that the moving average might be between 50-100 ms. return Math.max(movingAverage * 20, 2000); } async registerCandidateFinder(): Promise<void> { // Regularly scan to see if the candidate ports have changed. if (!isLinux) { return; } let movingAverage = new MovingAverage(); let oldPorts: { host: string, port: number, detail: string }[] | undefined = undefined; while (1) { const startTime = new Date().getTime(); const newPorts = await this.findCandidatePorts(); const timeTaken = new Date().getTime() - startTime; movingAverage.update(timeTaken); if (!oldPorts || (JSON.stringify(oldPorts) !== JSON.stringify(newPorts))) { oldPorts = newPorts; await this._proxy.$onFoundNewCandidates(oldPorts.filter(async (candidate) => await this._showCandidatePort(candidate.host, candidate.port, candidate.detail))); } await (new Promise<void>(resolve => setTimeout(() => resolve(), this.calculateDelay(movingAverage.value)))); </ins> } }


let tcp: string = ''; let tcp6: string = ''; try { <del> tcp = fs.readFileSync('/proc/net/tcp', 'utf8'); tcp6 = fs.readFileSync('/proc/net/tcp6', 'utf8'); </del> <ins> tcp = await pfs.readFile('/proc/net/tcp', 'utf8'); tcp6 = await pfs.readFile('/proc/net/tcp6', 'utf8'); </ins> } catch (e) { // File reading error. No additional handling needed. }


}); })); <del> const procChildren = fs.readdirSync('/proc'); const processes: { pid: number, cwd: string, cmd: string }[] = []; </del> <ins> const procChildren = await pfs.readdir('/proc'); const processes: { pid: number, cwd: string, cmd: string }[] = []; </ins> for (let childName of procChildren) { try { const pid: number = Number(childName); const childUri = resources.joinPath(URI.file('/proc'), childName); <del> const childStat = fs.statSync(childUri.fsPath); </del> <ins> const childStat = await pfs.stat(childUri.fsPath); </ins> if (childStat.isDirectory() && !isNaN(pid)) { <del> const cwd = fs.readlinkSync(resources.joinPath(childUri, 'cwd').fsPath); const cmd = fs.readFileSync(resources.joinPath(childUri, 'cmdline').fsPath, 'utf8'); </del> <ins> const cwd = await promisify(fs.readlink)(resources.joinPath(childUri, 'cwd').fsPath); const cmd = await pfs.readFile(resources.joinPath(childUri, 'cmdline').fsPath, 'utf8'); </ins> processes.push({ pid, cwd, cmd }); } } catch (e) {


// Menu registration - open editors <ins> const isFileOrUntitledResourceContextKey = ContextKeyExpr.or(ResourceContextKey.IsFileSystemResource, ResourceContextKey.Scheme.isEqualTo(Schemas.untitled)); </ins> const openToSideCommand = { id: OPEN_TO_SIDE_COMMAND_ID, title: nls.localize('openToSide', "Open to the Side")


group: 'navigation', order: 10, command: openToSideCommand, <del> when: ContextKeyExpr.or(ResourceContextKey.IsFileSystemResource, ResourceContextKey.Scheme.isEqualTo(Schemas.untitled)) </del> <ins> when: isFileOrUntitledResourceContextKey </ins> }); MenuRegistry.appendMenuItem(MenuId.OpenEditorsContext, {


group: '3_compare', order: 20, command: compareResourceCommand, <del> when: ContextKeyExpr.and(ResourceContextKey.HasResource, ResourceSelectedForCompareContext, WorkbenchListDoubleSelection.toNegated()) </del> <ins> when: ContextKeyExpr.and(ResourceContextKey.HasResource, ResourceSelectedForCompareContext, isFileOrUntitledResourceContextKey, WorkbenchListDoubleSelection.toNegated()) </ins> }); const selectForCompareCommand = {


group: '3_compare', order: 30, command: selectForCompareCommand, <del> when: ContextKeyExpr.and(ResourceContextKey.HasResource, WorkbenchListDoubleSelection.toNegated()) </del> <ins> when: ContextKeyExpr.and(ResourceContextKey.HasResource, isFileOrUntitledResourceContextKey, WorkbenchListDoubleSelection.toNegated()) </ins> }); const compareSelectedCommand = {


group: '3_compare', order: 30, command: compareSelectedCommand, <del> when: ContextKeyExpr.and(ResourceContextKey.HasResource, WorkbenchListDoubleSelection) </del> <ins> when: ContextKeyExpr.and(ResourceContextKey.HasResource, WorkbenchListDoubleSelection, isFileOrUntitledResourceContextKey) </ins> }); MenuRegistry.appendMenuItem(MenuId.OpenEditorsContext, {


if (this.accessor.partOptions.wrapTabs) { const visibleTabsWidth = tabsContainer.offsetWidth; const allTabsWidth = tabsContainer.scrollWidth; <ins> const lastTabFitsWrapped = () => { const lastTab = this.getLastTab(); if (!lastTab) { return true; // no tab always fits } return lastTab.offsetWidth <= (dimensions.available.width - editorToolbarContainer.offsetWidth); }; </ins> // If tabs wrap or should start to wrap (when width exceeds visible width) // we must trigger `updateWrapping` to set the `last-tab-margin-right` // accordingly based on the number of actions. The margin is important to // properly position the last tab apart from the actions <del> if (tabsWrapMultiLine || allTabsWidth > visibleTabsWidth) { </del> <ins> // // We already check here if the last tab would fit when wrapped given the // editor toolbar will also show right next to it. This ensures we are not // enabling wrapping only to disable it again in the code below (this fixes // flickering issue https://github.com/microsoft/vscode/issues/115050) if (tabsWrapMultiLine || (allTabsWidth > visibleTabsWidth && lastTabFitsWrapped())) { </ins> updateTabsWrapping(true); } // Tabs wrap multiline: remove wrapping under certain size constraint conditions if (tabsWrapMultiLine) { <del> const lastTab = this.getLastTab(); </del> if ( (tabsContainer.offsetHeight > dimensions.available.height) ||											// if height exceeds available height (allTabsWidth === visibleTabsWidth && tabsContainer.offsetHeight === TabsTitleControl.TAB_HEIGHT) ||	// if wrapping is not needed anymore <del> (lastTab && lastTab.offsetWidth > (dimensions.available.width - editorToolbarContainer.offsetWidth))	// if editor actions occupy too much space </del> <ins> (!lastTabFitsWrapped())																					// if last tab does not fit anymore </ins> ) { updateTabsWrapping(false); }


.monaco-workbench .pane-body.integrated-terminal .split-view-view { box-sizing: border-box; <ins> overflow: hidden; </ins> } /* border-color is set by theme key terminal.border */


if (lens.command) { const title = renderLabelWithIcons(lens.command.title.trim()); if (lens.command.id) { <del> children.push(dom.$('a', { id: String(i) }, ...title)); </del> <ins> children.push(dom.$('a', { id: String(i), title: lens.command.tooltip }, ...title)); </ins> this._commands.set(String(i), lens.command); } else { <del> children.push(dom.$('span', undefined, ...title)); </del> <ins> children.push(dom.$('span', { title: lens.command.tooltip }, ...title)); </ins> } if (i + 1 < lenses.length) { children.push(dom.$('span', undefined, 'u00a0|u00a0'));


* Submitting pull requests ## Related Projects <del> Many of the core components and extensions to Code live in their own repositories on GitHub. For example, the [node debug adapter](https://github.com/microsoft/vscode-node-debug), the [mono debug adapter](https://github.com/microsoft/vscode-mono-debug). </del> <ins> Many of the core components and extensions to Code live in their own repositories on GitHub. For example, the [node debug adapter](https://github.com/microsoft/vscode-node-debug) and the [mono debug adapter](https://github.com/microsoft/vscode-mono-debug). </ins> For a complete list, please see the [Related Projects](https://github.com/Microsoft/vscode/wiki/Related-Projects) page on our wiki.


unhideMarkdownPreview(cell: ICellViewModel): Promise<void>; hideMarkdownPreview(cell: ICellViewModel): Promise<void>; removeMarkdownPreview(cell: ICellViewModel): Promise<void>; <ins> updateMarkdownPreviewSelectionState(cell: ICellViewModel, isSelected: boolean): Promise<void>; </ins> /** * Render the output in webview layer


await this._webview?.removeMarkdownPreview(cell.id); } <ins> async updateMarkdownPreviewSelectionState(cell: ICellViewModel, isSelected: boolean): Promise<void> { if (!this._webview) { return; } await this._resolveWebview(); await this._webview?.updateMarkdownPreviewSelectionState(cell.id, isSelected); } </ins> async createInset(cell: CodeCellViewModel, output: IInsetRenderOutput, offset: number): Promise<void> { this._insetModifyQueueByOutputId.queue(output.source.model.outputId, async () => { if (!this._webview) {


top: number; } <ins> export interface IUpdateMarkdownPreviewSelectionState { readonly type: 'updateMarkdownPreviewSelectionState', readonly id: string; readonly isSelected: boolean; } </ins> export interface IInitializeMarkdownMessage { type: 'initializeMarkdownPreview'; cells: Array<{ cellId: string, content: string }>;


| IShowMarkdownMessage | IHideMarkdownMessage | IUnhideMarkdownMessage <ins> | IUpdateMarkdownPreviewSelectionState </ins> | IInitializeMarkdownMessage | IViewScrollMarkdownRequestMessage;


padding-left: ${this.options.leftMargin}px; } <ins> #container > div > div.preview.selected { background: var(--vscode-notebook-selectedCellBackground); } </ins> #container > div > div.preview img { max-width: 100%; max-height: 100%;


}); } <ins> async updateMarkdownPreviewSelectionState(cellId: any, isSelected: boolean) { if (this._disposed) { return; } this._sendMessageToWebview({ type: 'updateMarkdownPreviewSelectionState', id: cellId, isSelected }); } async updateMarkdownPreviewDecpratopms(cellId: any, isSelected: boolean) { if (this._disposed) { return; } this._sendMessageToWebview({ type: 'updateMarkdownPreviewSelectionState', id: cellId, isSelected }); } </ins> async initializeMarkdown(cells: Array<{ cellId: string, content: string }>) { await this._loaded;


} private updateForLayout(element: MarkdownCellViewModel, templateData: MarkdownCellRenderTemplate): void { <del> // templateData.focusIndicatorLeft.style.height = `${element.layoutInfo.indicatorHeight}px`; </del> templateData.focusIndicatorBottom.style.top = `${element.layoutInfo.totalHeight - BOTTOM_CELL_TOOLBAR_GAP - CELL_BOTTOM_MARGIN}px`; const focusSideHeight = element.layoutInfo.totalHeight - BOTTOM_CELL_TOOLBAR_GAP;


} })); <ins> // Update for selection if (this.useRenderer) { this._register(this.notebookEditor.onDidChangeSelection(() => { const selectedCells = this.notebookEditor.getSelectionViewModels(); const isSelected = selectedCells.length > 1 && selectedCells.some(selectedCell => selectedCell === viewCell); this.notebookEditor.updateMarkdownPreviewSelectionState(viewCell, isSelected); })); } // apply decorations </ins> this._register(viewCell.onCellDecorationsChanged((e) => { e.added.forEach(options => { if (options.className) { <del> templateData.rootContainer.classList.add(options.className); </del> <ins> if (this.useRenderer) { this.notebookEditor.deltaCellOutputContainerClassNames(this.viewCell.id, [options.className], []); } else { templateData.rootContainer.classList.add(options.className); } </ins> } }); e.removed.forEach(options => { if (options.className) { <del> templateData.rootContainer.classList.remove(options.className); </del> <ins> if (this.useRenderer) { this.notebookEditor.deltaCellOutputContainerClassNames(this.viewCell.id, [], [options.className]); } else { templateData.rootContainer.classList.remove(options.className); } </ins> } }); })); <del> // apply decorations </del> viewCell.getCellDecorations().forEach(options => { if (options.className) { <del> templateData.rootContainer.classList.add(options.className); </del> <ins> if (this.useRenderer) { this.notebookEditor.deltaCellOutputContainerClassNames(this.viewCell.id, [options.className], []); } else { templateData.rootContainer.classList.add(options.className); } </ins> } });


const data = event.data; let cellContainer = document.getElementById(data.id); if (cellContainer) { <del> cellContainer?.parentElement?.removeChild(cellContainer); </del> <ins> cellContainer.parentElement?.removeChild(cellContainer); } } break; case 'updateMarkdownPreviewSelectionState': { const data = event.data; const previewNode = document.getElementById(`${data.id}_preview`); if (previewNode) { previewNode.classList.toggle('selected', data.isSelected); </ins> } } break;


markdownCellDragEnd(cellId: string, position: { clientY: number }): void { throw new Error('Method not implemented.'); } <ins> updateMarkdownPreviewSelectionState(cell: ICellViewModel, isSelected: boolean): Promise<void> { throw new Error('Method not implemented.'); } </ins> async beginComputeContributedKernels(): Promise<INotebookKernel[]> { return []; }


protected _modifyText(text: string, wordSeparators: string): string { return (text .replace(/(p{Ll})(p{Lu})/gmu, '$1_$2') <del> .replace(/([^b_])(p{Lu})(p{Ll})/gmu, '$1_$2$3') </del> <ins> .replace(/(p{Lu}|p{N})(p{Lu})(p{Ll})/gmu, '$1_$2$3') </ins> .toLocaleLowerCase() ); }


`function helloWorld() { return someGlobalObject.printHelloWorld("en", "utf-8"); } <del> helloWorld();`.replace(/^s+/gm, '') </del> <ins> helloWorld();`.replace(/^s+/gm, ''), `'JavaScript'`, 'parseHTML4String', '_accessor: ServicesAccessor' </ins> ], {}, (editor) => { let model = editor.getModel()!; let uppercaseAction = new UpperCaseAction();


} hello_world();`.replace(/^s+/gm, '')); assertSelection(editor, new Selection(14, 1, 17, 15)); <ins> editor.setSelection(new Selection(18, 1, 18, 13)); executeAction(snakecaseAction, editor); assert.strictEqual(model.getLineContent(18), `'java_script'`); assertSelection(editor, new Selection(18, 1, 18, 14)); editor.setSelection(new Selection(19, 1, 19, 17)); executeAction(snakecaseAction, editor); assert.strictEqual(model.getLineContent(19), 'parse_html4_string'); assertSelection(editor, new Selection(19, 1, 19, 19)); editor.setSelection(new Selection(20, 1, 20, 28)); executeAction(snakecaseAction, editor); assert.strictEqual(model.getLineContent(20), '_accessor: services_accessor'); assertSelection(editor, new Selection(20, 1, 20, 29)); </ins> } );


- use the `--debug` to see an electron window with dev tools which allows for debugging - to run only a subset of tests use the `--run` or `--glob` options <ins> - use `yarn watch` to automatically compile changes </ins> For instance, `./scripts/test.sh --debug --glob **/extHost*.test.js` runs all tests from `extHost`-files and enables you to debug them.


## Run (with node) <del> yarn run mocha --run src/vs/editor/test/browser/controller/cursor.test.ts </del> <ins> yarn run mocha --ui tdd --run src/vs/editor/test/browser/controller/cursor.test.ts </ins> ## Coverage


return this._remoteTerminalChannel.setTerminalLayoutInfo(layout); } <del> public getTerminalLayoutInfo(): Promise<ITerminalsLayoutInfo | undefined> { </del> <ins> public async getTerminalLayoutInfo(): Promise<ITerminalsLayoutInfo | undefined> { await this._remoteTerminalChannel?.listProcesses(true); </ins> if (!this._remoteTerminalChannel) { throw new Error(`Cannot call getActiveInstanceId when there is no remote`); }


private async onDidClickPreviewLink(href: string) { let [hrefPath, fragment] = decodeURIComponent(href).split('#'); <del> // We perviously already resolve absolute paths. // Now make sure we handle relative file paths </del> if (hrefPath[0] !== '/') { <del> // Fix #93691, use this.resource.fsPath instead of this.resource.path hrefPath = path.join(path.dirname(this.resource.fsPath), hrefPath); </del> <ins> // We perviously already resolve absolute paths. // Now make sure we handle relative file paths const dirnameUri = vscode.Uri.parse(path.dirname(this.resource.path)); hrefPath = vscode.Uri.joinPath(dirnameUri, hrefPath).path; </ins> } else { // Handle any normalized file paths <del> hrefPath = vscode.Uri.parse(hrefPath.replace('/file', '')).fsPath; </del> <ins> hrefPath = vscode.Uri.parse(hrefPath.replace('/file', '')).path; </ins> } const config = vscode.workspace.getConfiguration('markdown', this.resource);


}); }); <del> // https://github.com/microsoft/vscode/issues/119826 suite.skip('environmentVariableCollection', () => { </del> <ins> suite('environmentVariableCollection', () => { </ins> test('should have collection variables apply to terminals immediately after setting', (done) => { // Text to match on before passing the test const expectedText = [


assert.strictEqual(count, 0); }); <ins> test('correct cell selection on undo/redo of cell creation', async function () { const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow'); await vscode.commands.executeCommand('undo'); const selectionUndo = [...vscode.window.activeNotebookEditor!.selections]; await vscode.commands.executeCommand('redo'); const selectionRedo = vscode.window.activeNotebookEditor!.selections; // On undo, the selected cell must be the upper cell, ie the first one assert.strictEqual(selectionUndo.length, 1); assert.strictEqual(selectionUndo[0].start, 0); assert.strictEqual(selectionUndo[0].end, 1); // On redo, the selected cell must be the new cell, ie the second one assert.strictEqual(selectionRedo.length, 1); assert.strictEqual(selectionRedo[0].start, 1); assert.strictEqual(selectionRedo[0].end, 2); }); </ins> test('editor editing event 2', async function () { const resource = await createRandomFile('', undefined, '.vsctestnb'); await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');


} async runWithContext(accessor: ServicesAccessor, context: INotebookActionContext): Promise<void> { <del> const newCell = context.notebookEditor.insertNotebookCell(context.cell, this.kind, this.direction, undefined, true); if (newCell) { context.notebookEditor.focusNotebookCell(newCell, 'editor'); } </del> <ins> context.notebookEditor.insertNotebookCell(context.cell, this.kind, this.direction, undefined, true); </ins> } }


createCell(index: number, source: string, language: string, type: CellKind, metadata: NotebookCellMetadata | undefined, outputs: IOutputDto[], synchronous: boolean, pushUndoStop: boolean = true, previouslyPrimary: number | null = null, previouslyFocused: ICellViewModel[] = []): CellViewModel { const beforeSelections = previouslyFocused.map(e => e.handle); <ins> const endSelections: ISelectionState = { kind: SelectionStateType.Index, focus: { start: index, end: index + 1 }, selections: [{ start: index, end: index + 1 }] }; </ins> this._notebook.applyEdits([ { editType: CellEditType.Replace,


} ] } <del> ], synchronous, { kind: SelectionStateType.Handle, primary: previouslyPrimary, selections: beforeSelections }, () => undefined, undefined); </del> <ins> ], synchronous, { kind: SelectionStateType.Handle, primary: previouslyPrimary, selections: beforeSelections }, () => endSelections, undefined); </ins> return this._viewCells[index]; }


if (useWslProfiles) { const distroOutput = await new Promise<string>((resolve, reject) => { // wsl.exe output is encoded in utf16le (ie. A -> 0x4100) <del> cp.exec('wsl.exe -l', { encoding: 'utf16le' }, (err, stdout) => { </del> <ins> cp.exec('wsl.exe -l -q', { encoding: 'utf16le' }, (err, stdout) => { </ins> if (err) { return reject('Problem occurred when getting wsl distros'); }


if (distroOutput) { const regex = new RegExp(/[r?n]/); const distroNames = distroOutput.split(regex).filter(t => t.trim().length > 0 && t !== ''); <del> // don't need the Windows Subsystem for Linux Distributions header distroNames.shift(); </del> for (let distroName of distroNames) { <del> // Remove default from distro name distroName = distroName.replace(/ (Default)$/, ''); </del> // Skip empty lines if (distroName === '') { continue;


this.textArea.setAttribute('aria-haspopup', 'false'); this.textArea.setAttribute('aria-autocomplete', 'both'); <del> if (options.get(EditorOption.domReadOnly)) { </del> <ins> if (options.get(EditorOption.domReadOnly) && options.get(EditorOption.readOnly)) { </ins> this.textArea.setAttribute('readonly', 'true'); }


this.textArea.setAttribute('aria-label', this._getAriaLabel(options)); this.textArea.setAttribute('tabindex', String(options.get(EditorOption.tabIndex))); <del> if (e.hasChanged(EditorOption.domReadOnly)) { if (options.get(EditorOption.domReadOnly)) { </del> <ins> if (e.hasChanged(EditorOption.domReadOnly) || e.hasChanged(EditorOption.readOnly)) { if (options.get(EditorOption.domReadOnly) && options.get(EditorOption.readOnly)) { </ins> this.textArea.setAttribute('readonly', 'true'); } else { this.textArea.removeAttribute('readonly');


import { ModesGlyphHoverWidget } from 'vs/editor/contrib/hover/modesGlyphHover'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { IOpenerService } from 'vs/platform/opener/common/opener'; <del> import { editorHoverBackground, editorHoverBorder, editorHoverHighlight, textCodeBlockBackground, textLinkForeground, editorHoverStatusBarBackground, editorHoverForeground } from 'vs/platform/theme/common/colorRegistry'; </del> <ins> import { editorHoverBackground, editorHoverBorder, editorHoverHighlight, textCodeBlockBackground, textLinkForeground, editorHoverStatusBarBackground, editorHoverForeground, textLinkActiveForeground } from 'vs/platform/theme/common/colorRegistry'; </ins> import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; import { GotoDefinitionAtPositionEditorContribution } from 'vs/editor/contrib/gotoSymbol/link/goToDefinitionAtPosition';


if (link) { collector.addRule(`.monaco-editor .monaco-hover a { color: ${link}; }`); } <ins> const linkHover = theme.getColor(textLinkActiveForeground); if (linkHover) { collector.addRule(`.monaco-editor .monaco-hover a:hover { color: ${linkHover}; }`); } </ins> const hoverForeground = theme.getColor(editorHoverForeground); if (hoverForeground) { collector.addRule(`.monaco-editor .monaco-hover { color: ${hoverForeground}; }`);


return result; } <ins> if (node !== this.root) { const treeNode = this.tree.getNode(node); if (treeNode.collapsed) { node.hasChildren = !!this.dataSource.hasChildren(node.element!); node.stale = true; return; } } </ins> return this.doRefreshSubTree(node, recursive, viewStateContext); }


import { AsyncDataTree } from 'vs/base/browser/ui/tree/asyncDataTree'; import { IAsyncDataSource, ITreeNode, ITreeRenderer } from 'vs/base/browser/ui/tree/tree'; import { timeout } from 'vs/base/common/async'; <ins> import { Iterable } from 'vs/base/common/iterator'; </ins> interface Element { id: string;


assert.deepStrictEqual(Array.from(container.querySelectorAll('.monaco-list-row')).map(e => e.textContent), ['a', 'b2']); }); <ins> test('issue #121567', async () => { const container = document.createElement('div'); const calls: Element[] = []; const dataSource = new class implements IAsyncDataSource<Element, Element> { hasChildren(element: Element): boolean { return !!element.children && element.children.length > 0; } async getChildren(element: Element) { calls.push(element); return element.children ?? Iterable.empty(); } }; const model = new Model({ id: 'root', children: [{ id: 'a', children: [{ id: 'aa' }] }] }); const a = model.get('a'); const tree = new AsyncDataTree<Element, Element>('test', container, new VirtualDelegate(), [new Renderer()], dataSource, { identityProvider: new IdentityProvider() }); tree.layout(200); await tree.setInput(model.root); assert.strictEqual(calls.length, 1, 'There should be a single getChildren call for the root'); assert(tree.isCollapsible(a), 'a is collapsible'); assert(tree.isCollapsed(a), 'a is collapsed'); await tree.updateChildren(a, false); assert.strictEqual(calls.length, 1, 'There should be no changes to the calls list, since a was collapsed'); assert(tree.isCollapsible(a), 'a is collapsible'); assert(tree.isCollapsed(a), 'a is collapsed'); const children = a.children; a.children = []; await tree.updateChildren(a, false); assert.strictEqual(calls.length, 1, 'There should still be no changes to the calls list, since a was collapsed'); assert(!tree.isCollapsible(a), 'a is no longer collapsible'); assert(tree.isCollapsed(a), 'a is collapsed'); a.children = children; await tree.updateChildren(a, false); assert.strictEqual(calls.length, 1, 'There should still be no changes to the calls list, since a was collapsed'); assert(tree.isCollapsible(a), 'a is collapsible again'); assert(tree.isCollapsed(a), 'a is collapsed'); await tree.expand(a); assert.strictEqual(calls.length, 2, 'Finally, there should be a getChildren call for a'); assert(tree.isCollapsible(a), 'a is still collapsible'); assert(!tree.isCollapsed(a), 'a is expanded'); }); </ins> });


import { Event } from 'vs/base/common/event'; const WAIT_TIME_TO_SHOW_SURVEY = 1000 * 60 * 60; // 1 hour <del> const MIN_WAIT_TIME_TO_SHOW_SURVEY = 1000 * 60 * 5; // 5 minutes </del> <ins> const MIN_WAIT_TIME_TO_SHOW_SURVEY = 1000 * 60 * 2; // 2 minutes </ins> const MAX_INSTALL_AGE = 1000 * 60 * 60 * 24; // 24 hours const REMIND_LATER_DELAY = 1000 * 60 * 60 * 4; // 4 hours const SKIP_SURVEY_KEY = 'ces/skipSurvey';


run: () => { sendTelemetry('accept'); this.telemetryService.getTelemetryInfo().then(info => { <del> this.openerService.open(URI.parse(`${this.productService.cesSurveyUrl}?o=${encodeURIComponent(platform)}&v=${encodeURIComponent(this.productService.version)}&m=${encodeURIComponent(info.machineId)}`)); </del> <ins> let surveyUrl = `${this.productService.cesSurveyUrl}?o=${encodeURIComponent(platform)}&v=${encodeURIComponent(this.productService.version)}&m=${encodeURIComponent(info.machineId)}`; const usedParams = this.productService.surveys ?.filter(surveyData => surveyData.surveyId && surveyData.languageId) // Counts provided by contrib/surveys/browser/languageSurveys .filter(surveyData => this.storageService.getNumber(`${surveyData.surveyId}.editedCount`, StorageScope.GLOBAL, 0) > 0) .map(surveyData => `${encodeURIComponent(surveyData.languageId)}Lang=1`) .join('&'); if (usedParams) { surveyUrl += `&${usedParams}`; } this.openerService.open(URI.parse(surveyUrl)); </ins> this.skipSurvey(); }); }


import { ContributedEditorInfo, ContributedEditorPriority, ContributionPointOptions, DEFAULT_EDITOR_ASSOCIATION, DiffEditorInputFactoryFunction, EditorAssociation, EditorAssociations, EditorInputFactoryFunction, editorsAssociationsSettingId, globMatchesResource, IEditorOverrideService, priorityToRank } from 'vs/workbench/services/editor/common/editorOverrideService'; import { IKeyMods, IQuickInputService, IQuickPickItem, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput'; import { localize } from 'vs/nls'; <del> import { Codicon } from 'vs/base/common/codicons'; </del> import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions';


export class EditorOverrideService extends Disposable implements IEditorOverrideService { readonly _serviceBrand: undefined; <ins> private static readonly configureDefaultID = 'promptOpenWith.configureDefault'; </ins> private _contributionPoints: Map<string | glob.IRelativePattern, ContributionPoints> = new Map<string | glob.IRelativePattern, ContributionPoints>(); private static readonly overrideCacheStorageID = 'editorOverrideService.cache'; private cache: Set<string> | undefined;


}); } <del> private mapContributionsToQuickPickEntry(resource: URI, group: IEditorGroup, alwaysUpdateSetting?: boolean) { </del> <ins> private mapContributionsToQuickPickEntry(resource: URI, group: IEditorGroup, showDefaultPicker?: boolean) { </ins> const currentEditor = firstOrDefault(group.findEditors(resource)); // If untitled, we want all contribution points let contributionPoints = resource.scheme === Schemas.untitled ? distinct(flatten(Array.from(this._contributionPoints.values())), (contrib) => contrib.editorInfo.id) : this.findMatchingContributions(resource);


return priorityToRank(b.editorInfo.priority) - priorityToRank(a.editorInfo.priority); } }); <del> const contribGroups: { defaults: Array<IQuickPickSeparator | IQuickPickItem>, optional: Array<IQuickPickSeparator | IQuickPickItem> } = { defaults: [ { type: 'separator', label: localize('editorOverride.picker.default', 'Defaults') } ], optional: [ { type: 'separator', label: localize('editorOverride.picker.optional', 'Optional') } ], }; </del> <ins> const quickPickEntries: Array<IQuickPickItem | IQuickPickSeparator> = []; </ins> // Get the matching contribtuions and call resolve whether they're active for the picker contributionPoints.forEach(contribPoint => { const isActive = currentEditor ? contribPoint.editorInfo.describes(currentEditor) : false; <del> const quickPickEntry = { </del> <ins> const quickPickEntry: IQuickPickItem = { </ins> id: contribPoint.editorInfo.id, label: contribPoint.editorInfo.label, description: isActive ? localize('promptOpenWith.currentlyActive', "Currently Active") : undefined, detail: contribPoint.editorInfo.detail ?? contribPoint.editorInfo.priority, <del> buttons: alwaysUpdateSetting ? [] : [{ iconClass: Codicon.gear.classNames, tooltip: localize('promptOpenWith.setDefaultTooltip', "Set as default editor for '{0}' files", extname(resource)) }], </del> }; <del> if (contribPoint.editorInfo.priority === ContributedEditorPriority.option) { contribGroups.optional.push(quickPickEntry); } else { contribGroups.defaults.push(quickPickEntry); } </del> <ins> quickPickEntries.push(quickPickEntry); </ins> }); <del> return [...contribGroups.defaults, ...contribGroups.optional]; </del> <ins> if (!showDefaultPicker) { const separator: IQuickPickSeparator = { type: 'separator' }; quickPickEntries.push(separator); const configureDefaultEntry = { id: EditorOverrideService.configureDefaultID, label: localize('promptOpenWith.configureDefault', "Configure default editor....") }; quickPickEntries.push(configureDefaultEntry); } return quickPickEntries; </ins> } <del> private async doPickEditorOverride(editor: IEditorInput, options: IEditorOptions | undefined, group: IEditorGroup, alwaysUpdateSetting?: boolean): Promise<[IEditorOptions, IEditorGroup | undefined] | undefined> { </del> <ins> private async doPickEditorOverride(editor: IEditorInput, options: IEditorOptions | undefined, group: IEditorGroup, showDefaultPicker?: boolean): Promise<[IEditorOptions, IEditorGroup | undefined] | undefined> { </ins> type EditorOverridePick = { readonly item: IQuickPickItem;


} // Text editor has the lowest priority because we <del> const editorOverridePicks = this.mapContributionsToQuickPickEntry(resource, group, alwaysUpdateSetting); </del> <ins> const editorOverridePicks = this.mapContributionsToQuickPickEntry(resource, group, showDefaultPicker); </ins> // Create editor override picker const editorOverridePicker = this.quickInputService.createQuickPick<IQuickPickItem>(); <del> const placeHolderMessage = alwaysUpdateSetting ? </del> <ins> const placeHolderMessage = showDefaultPicker ? </ins> localize('prompOpenWith.updateDefaultPlaceHolder', "Select new default editor for '{0}'", basename(resource)) : localize('promptOpenWith.placeHolder', "Select editor for '{0}'", basename(resource)); editorOverridePicker.placeholder = placeHolderMessage;


} // If asked to always update the setting then update it even if the gear isn't clicked <del> if (alwaysUpdateSetting && result?.item.id) { </del> <ins> if (showDefaultPicker && result?.item.id) { </ins> this.updateUserAssociations(`*${extname(resource)}`, result.item.id,); }


// options and group to use accordingly if (picked) { <ins> // If the user selected to configure default we trigger this picker again and tell it to show the default picker if (picked.item.id === EditorOverrideService.configureDefaultID) { return this.doPickEditorOverride(editor, options, group, true); } </ins> // Figure out target group let targetGroup: IEditorGroup | undefined; if (picked.keyMods?.alt || picked.keyMods?.ctrlCmd) {


collector.addRule(`.notebookOverlay .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row > .cell-inner-container { padding-top: ${CELL_TOP_MARGIN}px; }`); collector.addRule(`.notebookOverlay .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .markdown-cell-row > .cell-inner-container { padding-bottom: ${MARKDOWN_CELL_BOTTOM_MARGIN}px; padding-top: ${MARKDOWN_CELL_TOP_MARGIN}px; }`); collector.addRule(`.notebookOverlay .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .markdown-cell-row > .cell-inner-container.webview-backed-markdown-cell { padding: 0; }`); <del> collector.addRule(`.notebookOverlay .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .markdown-cell-row > .webview-backed-markdown-cell.markdown-cell-edit-mode .cell.code { padding-top: ${MARKDOWN_CELL_TOP_MARGIN}px; }`); </del> <ins> collector.addRule(`.notebookOverlay .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .markdown-cell-row > .webview-backed-markdown-cell.markdown-cell-edit-mode .cell.code { padding-bottom: ${MARKDOWN_CELL_BOTTOM_MARGIN}px; padding-top: ${MARKDOWN_CELL_TOP_MARGIN}px; }`); </ins> collector.addRule(`.notebookOverlay .output { margin: 0px ${CELL_RIGHT_MARGIN}px 0px ${CODE_CELL_LEFT_MARGIN + CELL_RUN_GUTTER}px; }`); collector.addRule(`.notebookOverlay .output { width: calc(100% - ${CODE_CELL_LEFT_MARGIN + CELL_RUN_GUTTER + CELL_RIGHT_MARGIN}px); }`);


readonly onDidTriggerButton: Event<QuickInputButton>; /** <del> * Items to pick from. </del> <ins> * Items to pick from. This can be read and updated by the extension. </ins> */ items: readonly T[];


fileMatch?: string[]; url?: string; schema?: any; <ins> folderUri?: string; </ins> }; export namespace SettingIds {


jsonFoldingLimit = normalizeLimit(workspace.getConfiguration(SettingIds.editorSection, { languageId: 'json' }).get(SettingIds.foldingMaximumRegions)); jsoncFoldingLimit = normalizeLimit(workspace.getConfiguration(SettingIds.editorSection, { languageId: 'jsonc' }).get(SettingIds.foldingMaximumRegions)); <ins> const schemas: JSONSchemaSettings[] = []; </ins> const settings: Settings = { http: { proxy: httpSettings.get('proxy'),


validate: { enable: configuration.get(SettingIds.enableValidation) }, format: { enable: configuration.get(SettingIds.enableFormatter) }, keepLines: { enable: configuration.get(SettingIds.enableKeepLines) }, <del> schemas: [], </del> <ins> schemas, </ins> resultLimit: resultLimit + 1, // ask for one more so we can detect if the limit has been exceeded jsonFoldingLimit: jsonFoldingLimit + 1, jsoncFoldingLimit: jsoncFoldingLimit + 1 } }; <del> const schemaSettingsById: { [schemaId: string]: JSONSchemaSettings } = Object.create(null); const collectSchemaSettings = (schemaSettings: JSONSchemaSettings[], folderUri?: Uri, isMultiRoot?: boolean) => { let fileMatchPrefix = undefined; if (folderUri && isMultiRoot) { fileMatchPrefix = folderUri.toString(); if (fileMatchPrefix[fileMatchPrefix.length - 1] === '/') { fileMatchPrefix = fileMatchPrefix.substr(0, fileMatchPrefix.length - 1); } } </del> <ins> const collectSchemaSettings = (schemaSettings: JSONSchemaSettings[], folderUri?: Uri) => { </ins> for (const setting of schemaSettings) { const url = getSchemaId(setting, folderUri); <del> if (!url) { continue; } let schemaSetting = schemaSettingsById[url]; if (!schemaSetting) { schemaSetting = schemaSettingsById[url] = { url, fileMatch: [] }; settings.json!.schemas!.push(schemaSetting); } const fileMatches = setting.fileMatch; if (Array.isArray(fileMatches)) { const resultingFileMatches = schemaSetting.fileMatch || []; schemaSetting.fileMatch = resultingFileMatches; const addMatch = (pattern: string) => { //  filter duplicates if (resultingFileMatches.indexOf(pattern) === -1) { resultingFileMatches.push(pattern); } }; for (const fileMatch of fileMatches) { if (fileMatchPrefix) { if (fileMatch[0] === '/') { addMatch(fileMatchPrefix + fileMatch); addMatch(fileMatchPrefix + '/*' + fileMatch); } else { addMatch(fileMatchPrefix + '/' + fileMatch); addMatch(fileMatchPrefix + '/*/' + fileMatch); } } else { addMatch(fileMatch); } } } if (setting.schema && !schemaSetting.schema) { schemaSetting.schema = setting.schema; </del> <ins> if (url) { const schemaSetting: JSONSchemaSettings = { url, fileMatch: setting.fileMatch, folderUri: folderUri?.toString(false), schema: setting.schema }; schemas.push(schemaSetting); </ins> } } }; <del> const folders = workspace.workspaceFolders; // merge global and folder settings. Qualify all file matches with the folder path. </del> const globalSettings = workspace.getConfiguration('json', null).get<JSONSchemaSettings[]>('schemas'); if (Array.isArray(globalSettings)) { <del> if (!folders) { collectSchemaSettings(globalSettings); } </del> <ins> collectSchemaSettings(globalSettings); </ins> } <ins> const folders = workspace.workspaceFolders; </ins> if (folders) { <del> const isMultiRoot = folders.length > 1; </del> for (const folder of folders) { <del> const folderUri = folder.uri; const schemaConfigInfo = workspace.getConfiguration('json', folderUri).inspect<JSONSchemaSettings[]>('schemas'); const folderSchemas = schemaConfigInfo!.workspaceFolderValue; if (Array.isArray(folderSchemas)) { collectSchemaSettings(folderSchemas, folderUri, isMultiRoot); </del> <ins> const schemaConfigInfo = workspace.getConfiguration('json', folder.uri).inspect<JSONSchemaSettings[]>('schemas'); if (schemaConfigInfo && Array.isArray(schemaConfigInfo.workspaceFolderValue)) { collectSchemaSettings(schemaConfigInfo.workspaceFolderValue, folder.uri); </ins> } <del> if (Array.isArray(globalSettings)) { collectSchemaSettings(globalSettings, folderUri, isMultiRoot); } </del> } } return settings;


url = schema.schema.id || `vscode://schemas/custom/${encodeURIComponent(hash(schema.schema).toString(16))}`; } } else if (folderUri && (url[0] === '.' || url[0] === '/')) { <del> url = Uri.joinPath(folderUri, url).toString(); </del> <ins> url = Uri.joinPath(folderUri, url).toString(false); </ins> } return url; }


- `schemas`: Configures association of file names to schema URL or schemas and/or associations of schema URL to schema content. - `fileMatch`: an array of file names or paths (separated by `/`). `*` can be used as a wildcard. Exclusion patterns can also be defined and start with '!'. A file matches when there is at least one matching pattern and the last matching pattern is not an exclusion pattern. - `url`: The URL of the schema, optional when also a schema is provided. <del> - `schema`: The schema content. </del> <ins> - `schema`: The schema content, optional - `folderUri`: If provided, the association is only used if the document is located in the given folder (directly or indirectly) </ins> - `resultLimit`: The max number of color decorators and outline symbols to be computed (for performance reasons) - `jsonFoldingLimit`: The max number of folding ranges to be computed for json documents (for performance reasons) - `jsoncFoldingLimit`: The max number of folding ranges to be computed for jsonc documents (for performance reasons)


* A match succeeds when there is at least one pattern matching and last matching pattern does not start with '!'. */ fileMatch: string[]; <ins> /** * If provided, the association is only used if the validated document is located in the given folder (directly or indirectly) */ folderUri?: string; </ins> /* * The schema for the given URI. * If no schema is provided, the schema will be fetched with the schema request service (if available).


}, "main": "./out/node/jsonServerMain", "dependencies": { <ins> "@vscode/l10n": "^0.0.11", </ins> "jsonc-parser": "^3.2.0", "request-light": "^0.7.0", <del> "vscode-json-languageservice": "^5.1.4", </del> <ins> "vscode-json-languageservice": "^5.2.0", </ins> "vscode-languageserver": "^8.1.0-next.6", <del> "vscode-uri": "^3.0.7", "@vscode/l10n": "^0.0.11" </del> <ins> "vscode-uri": "^3.0.7" </ins> }, "devDependencies": { "@types/mocha": "^9.1.1",


fileMatch?: string[]; url?: string; schema?: JSONSchema; <ins> folderUri?: string; </ins> }


uri = schema.schema.id || `vscode://schemas/custom/${index}`; } if (uri) { <del> languageSettings.schemas.push({ uri, fileMatch: schema.fileMatch, schema: schema.schema }); </del> <ins> languageSettings.schemas.push({ uri, fileMatch: schema.fileMatch, schema: schema.schema, folderUri: schema.folderUri }); </ins> } }); }


resolved "https://registry.yarnpkg.com/request-light/-/request-light-0.7.0.tgz#885628bb2f8040c26401ebf258ec51c4ae98ac2a" integrity sha512-lMbBMrDoxgsyO+yB3sDcrDuX85yYt7sS8BfQd11jtbW/z5ZWgLZRcEGLsLoYw7I0WSUGQBs8CC8ScIxkTX1+6Q== <del> vscode-json-languageservice@^5.1.4: version "5.1.4" resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-5.1.4.tgz#cbdb447f281dcd107705e7fe8fbfc0b71db7610d" integrity sha512-ROZ1ezYQUbq9b/07xYpHtZSyyhoUk3oTTGVAEr6bU1DKr8ELaz9fsDoHno34tKtHj/Tf3deQqfjQNGKdbRuvTw== </del> <ins> vscode-json-languageservice@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-5.2.0.tgz#884b7f108be4310e3332167c3ea60ab17f03418c" integrity sha512-q8Rdhu2HEddRxvlhVqwh0cWmKK+OtyMB2xRhtqXEQ7cjb0iZ14madb90iJe9fCHPjoj9CGBrq6QzuOp8OE6XWg== </ins> dependencies: "@vscode/l10n" "^0.0.11" jsonc-parser "^3.2.0"


} }; <del> const collectSchemaSettings = (schemaSettings: JSONSchemaSettings[], folderUri?: Uri) => { for (const setting of schemaSettings) { const url = getSchemaId(setting, folderUri); if (url) { const schemaSetting: JSONSchemaSettings = { url, fileMatch: setting.fileMatch, folderUri: folderUri?.toString(false), schema: setting.schema }; schemas.push(schemaSetting); </del> <ins> const collectSchemaSettings = (schemaSettings: JSONSchemaSettings[] | undefined, folderUri?: Uri) => { if (schemaSettings) { for (const setting of schemaSettings) { const url = getSchemaId(setting, folderUri); if (url) { const schemaSetting: JSONSchemaSettings = { url, fileMatch: setting.fileMatch, folderUri: folderUri?.toString(false), schema: setting.schema }; schemas.push(schemaSetting); } </ins> } } }; <del> const globalSettings = workspace.getConfiguration('json', null).get<JSONSchemaSettings[]>('schemas'); if (Array.isArray(globalSettings)) { collectSchemaSettings(globalSettings); </del> <ins> const schemaConfigInfo = workspace.getConfiguration('json', null).inspect<JSONSchemaSettings[]>('schemas'); if (schemaConfigInfo) { if (workspace.workspaceFile) { collectSchemaSettings(schemaConfigInfo.workspaceValue, workspace.workspaceFile); } collectSchemaSettings(schemaConfigInfo.globalValue); </ins> } const folders = workspace.workspaceFolders; if (folders) { for (const folder of folders) { const schemaConfigInfo = workspace.getConfiguration('json', folder.uri).inspect<JSONSchemaSettings[]>('schemas'); <del> if (schemaConfigInfo && Array.isArray(schemaConfigInfo.workspaceFolderValue)) { collectSchemaSettings(schemaConfigInfo.workspaceFolderValue, folder.uri); } </del> <ins> collectSchemaSettings(schemaConfigInfo?.workspaceFolderValue, folder.uri); </ins> } } return settings;


} }; <del> const collectSchemaSettings = (schemaSettings: JSONSchemaSettings[] | undefined, folderUri?: Uri) => { </del> <ins> const collectSchemaSettings = (schemaSettings: JSONSchemaSettings[] | undefined, folderUri: Uri | undefined = undefined, settingsLocation = folderUri) => { </ins> if (schemaSettings) { for (const setting of schemaSettings) { <del> const url = getSchemaId(setting, folderUri); </del> <ins> const url = getSchemaId(setting, settingsLocation); </ins> if (url) { const schemaSetting: JSONSchemaSettings = { url, fileMatch: setting.fileMatch, folderUri: folderUri?.toString(false), schema: setting.schema }; schemas.push(schemaSetting);


} }; <ins> const folders = workspace.workspaceFolders; </ins> const schemaConfigInfo = workspace.getConfiguration('json', null).inspect<JSONSchemaSettings[]>('schemas'); if (schemaConfigInfo) { <del> if (workspace.workspaceFile) { collectSchemaSettings(schemaConfigInfo.workspaceValue, workspace.workspaceFile); </del> <ins> if (schemaConfigInfo.workspaceValue && workspace.workspaceFile && folders && folders.length) { const settingsLocation = Uri.joinPath(workspace.workspaceFile, '..'); for (const folder of folders) { collectSchemaSettings(schemaConfigInfo.workspaceValue, folder.uri, settingsLocation); } </ins> } collectSchemaSettings(schemaConfigInfo.globalValue); } <del> const folders = workspace.workspaceFolders; </del> if (folders) { for (const folder of folders) { const schemaConfigInfo = workspace.getConfiguration('json', folder.uri).inspect<JSONSchemaSettings[]>('schemas');


return settings; } <del> function getSchemaId(schema: JSONSchemaSettings, folderUri?: Uri): string | undefined { </del> <ins> function getSchemaId(schema: JSONSchemaSettings, settingsLocation?: Uri): string | undefined { </ins> let url = schema.url; if (!url) { if (schema.schema) { url = schema.schema.id || `vscode://schemas/custom/${encodeURIComponent(hash(schema.schema).toString(16))}`; } <del> } else if (folderUri && (url[0] === '.' || url[0] === '/')) { url = Uri.joinPath(folderUri, url).toString(false); </del> <ins> } else if (settingsLocation && (url[0] === '.' || url[0] === '/')) { url = Uri.joinPath(settingsLocation, url).toString(false); </ins> } return url; }


if (isWeb()) { // On web, treat absolute paths as pointing to standard lib files if (filepath.startsWith('/')) { <del> return vscode.Uri.joinPath(this.context.extensionUri, 'node_modules', 'typescript', 'lib', filepath.slice(1)); </del> <ins> return vscode.Uri.joinPath(this.context.extensionUri, 'dist', 'browser', 'typescript', filepath.slice(1)); </ins> } }


import { IWorkspaceTrustManagementService, IWorkspaceTrustRequestService, workspaceTrustToString } from 'vs/platform/workspace/common/workspaceTrust'; import { Extensions as WorkbenchExtensions, IWorkbenchContribution, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; <del> import { Codicon, registerCodicon } from 'vs/base/common/codicons'; </del> <ins> import { Codicon } from 'vs/base/common/codicons'; </ins> import { ThemeColor } from 'vs/workbench/api/common/extHostTypes'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';


import { LIST_WORKSPACE_UNSUPPORTED_EXTENSIONS_COMMAND_ID } from 'vs/workbench/contrib/extensions/common/extensions'; const BANNER_RESTRICTED_MODE = 'workbench.banner.restrictedMode'; <del> const BANNER_VIRTUAL_WORKSPACE = 'workbench.banner.virtualWorkspace'; const BANNER_VIRTUAL_AND_RESTRICTED = 'workbench.banner.virtualAndRestricted'; </del> const STARTUP_PROMPT_SHOWN_KEY = 'workspace.trust.startupPrompt.shown'; const BANNER_RESTRICTED_MODE_DISMISSED_KEY = 'workbench.banner.restrictedMode.dismissed'; <del> const BANNER_VIRTUAL_WORKSPACE_DISMISSED_KEY = 'workbench.banner.virtualWorkspace.dismissed'; const infoIcon = registerCodicon('workspace-banner-warning-icon', Codicon.info); </del> /* * Trust Request via Service UX handler


break; case 'Manage': this.workspaceTrustRequestService.cancelRequest(); <del> await this.commandService.executeCommand('workbench.trust.manage'); </del> <ins> await this.commandService.executeCommand(MANAGE_TRUST_COMMAND_ID); </ins> break; case 'Cancel': this.workspaceTrustRequestService.cancelRequest();


this.statusbarService.updateEntryVisibility(this.entryId, false); } <del> private getBannerItem(isInVirtualWorkspace: boolean, restrictedMode: boolean): IBannerItem | undefined { </del> <ins> private getBannerItem(restrictedMode: boolean): IBannerItem | undefined { </ins> <del> const dismissedVirtual = this.storageService.getBoolean(BANNER_VIRTUAL_WORKSPACE_DISMISSED_KEY, StorageScope.WORKSPACE, false); </del> const dismissedRestricted = this.storageService.getBoolean(BANNER_RESTRICTED_MODE_DISMISSED_KEY, StorageScope.WORKSPACE, false); <del> // all important info has been dismissed if (dismissedVirtual && dismissedRestricted) { return undefined; } // don't show restricted mode only banner if (dismissedRestricted && !isInVirtualWorkspace) { </del> <ins> // info has been dismissed if (dismissedRestricted) { </ins> return undefined; } <del> // don't show virtual workspace only banner if (dismissedVirtual && !restrictedMode) { return undefined; } const choose = (virtual: any, restricted: any, virtualAndRestricted: any) => { return (isInVirtualWorkspace && !dismissedVirtual) && (restrictedMode && !dismissedRestricted) ? virtualAndRestricted : ((isInVirtualWorkspace && !dismissedVirtual) ? virtual : restricted); }; const id = choose(BANNER_VIRTUAL_WORKSPACE, BANNER_RESTRICTED_MODE, BANNER_VIRTUAL_AND_RESTRICTED); const icon = choose(infoIcon, shieldIcon, infoIcon); const [virtualAriaLabel, restrictedModeAriaLabel, virtualAndRestrictedModeAriaLabel] = this.getBannerItemAriaLabels(); const ariaLabel = choose(virtualAriaLabel, restrictedModeAriaLabel, virtualAndRestrictedModeAriaLabel); const [virtualMessage, restrictedModeMessage, virtualAndRestrictedModeMessage] = this.getBannerItemMessages(); const message = choose(virtualMessage, restrictedModeMessage, virtualAndRestrictedModeMessage); const actions = choose( [ { label: localize('virtualBannerLearnMore', "Learn More"), href: 'https://aka.ms/vscode-virtual-workspaces' } ], </del> <ins> const actions = </ins> [ { label: localize('restrictedModeBannerManage', "Manage"), <del> href: 'command:workbench.trust.manage' </del> <ins> href: 'command:' + MANAGE_TRUST_COMMAND_ID </ins> }, { label: localize('restrictedModeBannerLearnMore', "Learn More"), href: 'https://aka.ms/vscode-workspace-trust' } <del> ], [ { label: localize('virtualAndRestrictedModeBannerManage', "Manage Trust"), href: 'command:workbench.trust.manage' }, { label: localize('virtualBannerLearnMore', "Learn More"), href: 'https://aka.ms/vscode-virtual-workspaces' } ] ); </del> <ins> ]; </ins> return { <del> id, icon, ariaLabel, message, </del> <ins> id: BANNER_RESTRICTED_MODE, icon: shieldIcon, ariaLabel: this.getBannerItemAriaLabels(), message: this.getBannerItemMessages(), </ins> actions, onClose: () => { <del> if (isInVirtualWorkspace) { this.storageService.store(BANNER_VIRTUAL_WORKSPACE_DISMISSED_KEY, true, StorageScope.WORKSPACE, StorageTarget.MACHINE); } </del> if (restrictedMode) { this.storageService.store(BANNER_RESTRICTED_MODE_DISMISSED_KEY, true, StorageScope.WORKSPACE, StorageTarget.MACHINE); }


}; } <del> private getBannerItemAriaLabels(): [string, string, string] { </del> <ins> private getBannerItemAriaLabels(): string { </ins> switch (this.workspaceContextService.getWorkbenchState()) { case WorkbenchState.EMPTY: <del> return [ localize('virtualBannerAriaLabelWindow', "Some features are not available because the current window is backed by a virtual file system. Use navigation keys to access banner actions."), localize('restrictedModeBannerAriaLabelWindow', "Restricted Mode is intended for safe code browsing. Trust this window to enable all features. Use navigation keys to access banner actions."), localize('virtualAndRestrictedModeBannerAriaLabelWindow', "Some features are not available because the current window is backed by a virtual file system and is not trusted. You can trust this window to enable some of these features. Use navigation keys to access banner actions.") ]; </del> <ins> return localize('restrictedModeBannerAriaLabelWindow', "Restricted Mode is intended for safe code browsing. Trust this window to enable all features. Use navigation keys to access banner actions."); </ins> case WorkbenchState.FOLDER: <del> return [ localize('virtualBannerAriaLabelFolder', "Some features are not available because the current folder is backed by a virtual file system. Use navigation keys to access banner actions."), localize('restrictedModeBannerAriaLabelFolder', "Restricted Mode is intended for safe code browsing. Trust this folder to enable all features. Use navigation keys to access banner actions."), localize('virtualAndRestrictedModeBannerAriaLabelFolder', "Some features are not available because the current folder is backed by a virtual file system and is not trusted. You can trust this folder to enable some of these features. Use navigation keys to access banner actions.") ]; </del> <ins> return localize('restrictedModeBannerAriaLabelFolder', "Restricted Mode is intended for safe code browsing. Trust this folder to enable all features. Use navigation keys to access banner actions."); </ins> case WorkbenchState.WORKSPACE: <del> return [ localize('virtualBannerAriaLabelWorkspace', "Some features are not available because the current workspace is backed by a virtual file system. Use navigation keys to access banner actions."), localize('restrictedModeBannerAriaLabelWorkspace', "Restricted Mode is intended for safe code browsing. Trust this workspace to enable all features. Use navigation keys to access banner actions."), localize('virtualAndRestrictedModeBannerAriaLabelWorkspace', "Some features are not available because the current workspace is backed by a virtual file system and is not trusted. You can trust this workspace to enable some of these features. Use navigation keys to access banner actions.") ]; </del> <ins> return localize('restrictedModeBannerAriaLabelWorkspace', "Restricted Mode is intended for safe code browsing. Trust this workspace to enable all features. Use navigation keys to access banner actions."); </ins> } } <del> private getBannerItemMessages(): [string, string, string] { </del> <ins> private getBannerItemMessages(): string { </ins> switch (this.workspaceContextService.getWorkbenchState()) { case WorkbenchState.EMPTY: <del> return [ localize('virtualBannerMessageWindow', "Some features are not available because the current workspace is backed by a virtual file system."), localize('restrictedModeBannerMessageWindow', "Restricted Mode is intended for safe code browsing. Trust this window to enable all features."), localize('virtualAndRestrictedModeBannerMessageWindow', "Some features are not available because the current window is backed by a virtual file system and is not trusted. You can trust this window to enable some of these features.") ]; </del> <ins> return localize('restrictedModeBannerMessageWindow', "Restricted Mode is intended for safe code browsing. Trust this window to enable all features."); </ins> case WorkbenchState.FOLDER: <del> return [ localize('virtualBannerMessageFolder', "Some features are not available because the current folder is backed by a virtual file system."), localize('restrictedModeBannerMessageFolder', "Restricted Mode is intended for safe code browsing. Trust this folder to enable all features."), localize('virtualAndRestrictedModeBannerMessageFolder', "Some features are not available because the current folder is backed by a virtual file system and is not trusted. You can trust this folder to enable some of these features.") ]; </del> <ins> return localize('restrictedModeBannerMessageFolder', "Restricted Mode is intended for safe code browsing. Trust this folder to enable all features."); </ins> case WorkbenchState.WORKSPACE: <del> return [ localize('virtualBannerMessageWorkspace', "Some features are not available because the current workspace is backed by a virtual file system."), localize('restrictedModeBannerMessageWorkspace', "Restricted Mode is intended for safe code browsing. Trust this workspace to enable all features."), localize('virtualAndRestrictedModeBannerMessageWorkspace', "Some features are not available because the current workspace is backed by a virtual file system and is not trusted. You can trust this workspace to enable some of these features.") ]; </del> <ins> return localize('restrictedModeBannerMessageWorkspace', "Restricted Mode is intended for safe code browsing. Trust this workspace to enable all features."); </ins> } }


text: trusted ? `$(shield)` : `$(shield) ${text}`, ariaLabel: ariaLabel, tooltip: toolTip, <del> command: 'workbench.trust.manage', </del> <ins> command: MANAGE_TRUST_COMMAND_ID, </ins> backgroundColor, color };


} private updateWorkbenchIndicators(trusted: boolean): void { <del> const isInVirtualWorkspace = isVirtualWorkspace(this.workspaceContextService.getWorkspace()); </del> const isEmptyWorkspace = this.workspaceContextService.getWorkbenchState() === WorkbenchState.EMPTY; <del> const bannerItem = this.getBannerItem(isInVirtualWorkspace, !trusted); </del> <ins> const bannerItem = this.getBannerItem(!trusted); </ins> if (!isEmptyWorkspace || this.showIndicatorsInEmptyWindow) { this.updateStatusbarEntry(trusted); if (bannerItem) { <del> if (!isInVirtualWorkspace) { if (!trusted) { this.bannerService.show(bannerItem); } else { this.bannerService.hide(BANNER_RESTRICTED_MODE); } } else { </del> <ins> if (!trusted) { </ins> this.bannerService.show(bannerItem); <ins> } else { this.bannerService.hide(BANNER_RESTRICTED_MODE); </ins> } } }


[ConsolidatedRunButton]: { description: nls.localize('notebook.consolidatedRunButton.description', "Control whether extra actions are shown in a dropdown next to the run button."), type: 'boolean', <del> default: true, </del> <ins> default: false, </ins> tags: ['notebookLayout'] }, [NotebookCellEditorOptionsCustomizations]: editorOptionsCustomizationSchema


[ localize('untrustedTasks', "Tasks are disabled"), localize('untrustedDebugging', "Debugging is disabled"), <del> localize('untrustedExtensions', "[{0} extensions](command:{1}) are disabled or have limited functionality", numExtensions, LIST_WORKSPACE_UNSUPPORTED_EXTENSIONS_COMMAND_ID) </del> <ins> localize('untrustedExtensions', "[{0} extensions]({1}) are disabled or have limited functionality", numExtensions, `command:${LIST_WORKSPACE_UNSUPPORTED_EXTENSIONS_COMMAND_ID}`) </ins> ] : [ localize('untrustedTasks', "Tasks are disabled"), localize('untrustedDebugging', "Debugging is disabled"), <del> numSettings ? localize('untrustedSettings', "[{0} workspace settings](command:{1}) are not applied", numSettings, 'settings.filterUntrusted') : localize('no untrustedSettings', "Workspace settings requiring trust are not applied"), localize('untrustedExtensions', "[{0} extensions](command:{1}) are disabled or have limited functionality", numExtensions, LIST_WORKSPACE_UNSUPPORTED_EXTENSIONS_COMMAND_ID) </del> <ins> numSettings ? localize('untrustedSettings', "[{0} workspace settings]({1}) are not applied", numSettings, 'command:settings.filterUntrusted') : localize('no untrustedSettings', "Workspace settings requiring trust are not applied"), localize('untrustedExtensions', "[{0} extensions]({1}) are disabled or have limited functionality", numExtensions, `command:${LIST_WORKSPACE_UNSUPPORTED_EXTENSIONS_COMMAND_ID}`) </ins> ]; this.renderLimitationsListElement(untrustedContainer, untrustedContainerItems, xListIcon.classNamesArray);


import { disposableTimeout, Throttler } from 'vs/base/common/async'; import { CancellationTokenSource } from 'vs/base/common/cancellation'; import { Disposable, toDisposable } from 'vs/base/common/lifecycle'; <del> import { ICellVisibilityChangeEvent, NotebookVisibleCellObserver } from 'vs/workbench/contrib/notebook/browser/contrib/statusBar/notebookVisibleCellObserver'; </del> <ins> import { NotebookVisibleCellObserver } from 'vs/workbench/contrib/notebook/browser/contrib/statusBar/notebookVisibleCellObserver'; </ins> import { ICellViewModel, INotebookEditor, INotebookEditorContribution } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { registerNotebookContribution } from 'vs/workbench/contrib/notebook/browser/notebookEditorExtensions'; <del> import { NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel'; </del> <ins> import { CellViewModel, NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel'; </ins> import { INotebookCellStatusBarService } from 'vs/workbench/contrib/notebook/common/notebookCellStatusBarService'; import { INotebookCellStatusBarItemList } from 'vs/workbench/contrib/notebook/common/notebookCommon';


} private _updateEverything(): void { <del> this._visibleCells.forEach(cell => cell.dispose()); this._visibleCells.clear(); this._updateVisibleCells({ added: this._observer.visibleCells, removed: [] }); </del> <ins> const newCells = this._observer.visibleCells.filter(cell => !this._visibleCells.has(cell.handle)); const visibleCellHandles = new Set(this._observer.visibleCells.map(item => item.handle)); const currentCellHandles = Array.from(this._visibleCells.keys()); const removedCells = currentCellHandles.filter(handle => !visibleCellHandles.has(handle)); const itemsToUpdate = currentCellHandles.filter(handle => visibleCellHandles.has(handle)); this._updateVisibleCells({ added: newCells, removed: removedCells.map(handle => ({ handle })) }); itemsToUpdate.forEach(handle => this._visibleCells.get(handle)?.update()); </ins> } <del> private _updateVisibleCells(e: ICellVisibilityChangeEvent): void { </del> <ins> private _updateVisibleCells(e: { added: CellViewModel[]; removed: { handle: number }[]; }): void { </ins> const vm = this._notebookEditor.viewModel; if (!vm) { return;


this._register(this._cell.model.onDidChangeOutputs(() => this._updateSoon())); } <ins> public update(): void { this._updateSoon(); } </ins> private _updateSoon(): void { // Wait a tick to make sure that the event is fired to the EH before triggering status bar providers this._register(disposableTimeout(() => {


override dispose() { super.dispose(); <ins> this._activeToken?.dispose(true); </ins> this._notebookViewModel.deltaCellStatusBarItems(this._currentItemIds, [{ handle: this._cell.handle, items: [] }]); this._currentItemLists.forEach(itemList => itemList.dispose && itemList.dispose());


import { IEditorContribution } from 'vs/editor/common/editorCommon'; import { ITextModel } from 'vs/editor/common/model'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; <ins> import { basename } from 'vs/base/common/resources'; </ins> const ignoreUnusualLineTerminators = 'ignoreUnusualLineTerminators';


const result = await this._dialogService.confirm({ title: nls.localize('unusualLineTerminators.title', "Unusual Line Terminators"), message: nls.localize('unusualLineTerminators.message', "Detected unusual line terminators"), <del> detail: nls.localize('unusualLineTerminators.detail', "This file contains one or more unusual line terminator characters, like Line Separator (LS) or Paragraph Separator (PS).nnIt is recommended to remove them from the file. This can be configured via `editor.unusualLineTerminators`."), primaryButton: nls.localize('unusualLineTerminators.fix', "Fix this file"), secondaryButton: nls.localize('unusualLineTerminators.ignore', "Ignore problem for this file") </del> <ins> detail: nls.localize('unusualLineTerminators.detail', "The file '{0}' contains one or more unusual line terminator characters, like Line Separator (LS) or Paragraph Separator (PS).nnIt is recommended to remove them from the file. This can be configured via `editor.unusualLineTerminators`.", basename(model.uri)), primaryButton: nls.localize('unusualLineTerminators.fix', "Remove Unusual Line Terminators"), secondaryButton: nls.localize('unusualLineTerminators.ignore', "Ignore") </ins> }); if (!result.confirmed) {


import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments'; import * as extHostTypeConverter from 'vs/workbench/api/common/extHostTypeConverters'; import * as types from 'vs/workbench/api/common/extHostTypes'; <del> import { checkProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions'; </del> import type * as vscode from 'vscode'; import { ExtHostCommentsShape, IMainContext, MainContext, CommentThreadChanges, CommentChanges } from './extHost.protocol'; import { ExtHostCommands } from './extHostCommands';


private _state?: vscode.CommentThreadState; get state(): vscode.CommentThreadState { <del> checkProposedApiEnabled(this.extensionDescription, 'commentsResolvedState'); </del> return this._state!; } set state(newState: vscode.CommentThreadState) { <del> checkProposedApiEnabled(this.extensionDescription, 'commentsResolvedState'); </del> this._state = newState; this.modifications.state = newState; this._onDidUpdateCommentThread.fire();


export const allApiProposals = Object.freeze({ authSession: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.authSession.d.ts', codiconDecoration: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.codiconDecoration.d.ts', <del> commentsResolvedState: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.commentsResolvedState.d.ts', </del> contribCommentEditorActionsMenu: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribCommentEditorActionsMenu.d.ts', contribCommentPeekContext: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribCommentPeekContext.d.ts', contribCommentThreadAdditionalMenu: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribCommentThreadAdditionalMenu.d.ts',


} /** <ins> * The state of a comment thread. */ export enum CommentThreadState { Unresolved = 0, Resolved = 1 } /** </ins> * A collection of {@link Comment comments} representing a conversation at a particular range in a document. */ export interface CommentThread {


label?: string; /** <ins> * The optional state of a comment thread, which may affect how the comment is displayed. */ state?: CommentThreadState; /** </ins> * Dispose this comment thread. * * Once disposed, this comment thread will be removed from visible editors and Comment Panel when appropriate.


<del> /*--------------------------------------------------------------------------------------------- *  Copyright (c) Microsoft Corporation. All rights reserved. *  Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ declare module 'vscode' { // https://github.com/microsoft/vscode/issues/127473 /** * The state of a comment thread. */ export enum CommentThreadState { Unresolved = 0, Resolved = 1 } export interface CommentThread { /** * The optional state of a comment thread, which may affect how the comment is displayed. */ state?: CommentThreadState; } } </del>


} else { this._onDidChangeViewWelcomeState.fire(); } <del> if (!this._terminalService.activeInstance?.shellLaunchConfig.extHostTerminalId) { // showPanel is already called with !preserveFocus // when extension host terminals are created this._terminalGroupService.showPanel(true); } </del> <ins> // we don't know here whether or not it should be focused, so // defer focusing the panel to the focus() call // to prevent overriding preserveFocus for extensions this._terminalGroupService.showPanel(false); </ins> if (hadTerminals) { this._terminalGroupService.activeGroup?.setVisible(visible); }


// Only focus the terminal if the activeElement has not changed since focus() was called // TODO hack if (document.activeElement === activeElement) { <del> this._focus(); </del> <ins> this._terminalGroupService.showPanel(true); </ins> } })); return; } <del> this._focus(); } private _focus() { this._terminalService.activeInstance?.focusWhenReady(); </del> <ins> this._terminalGroupService.showPanel(true); </ins> } override shouldShowWelcome(): boolean {


globalStorageHome: URI; workspaceStorageHome: URI; useHostProxy?: boolean; <ins> skipWorkspaceStorageLock?: boolean; </ins> } export interface IStaticWorkspaceData {


return workspaceStorageURI; } <ins> if (this._environment.skipWorkspaceStorageLock) { this._logService.info(`Skipping acquiring lock for ${workspaceStorageURI.fsPath}.`); return workspaceStorageURI; } </ins> const workspaceStorageBase = workspaceStorageURI.fsPath; let attempt = 0; do {


} // Run Extension Host as fork of current process <del> this._extensionHostProcess = fork(FileAccess.asFileUri('bootstrap-fork', require).fsPath, ['--type=extensionHost'], opts); </del> <ins> this._extensionHostProcess = fork(FileAccess.asFileUri('bootstrap-fork', require).fsPath, ['--type=extensionHost', '--skipWorkspaceStorageLock'], opts); </ins> // Catch all output coming from the extension host process type Output = { data: string, format: string[] };


import { realpath } from 'vs/base/node/extpath'; import { IHostUtils } from 'vs/workbench/api/common/extHostExtensionService'; import { RunOnceScheduler } from 'vs/base/common/async'; <ins> import { boolean } from 'vs/editor/common/config/editorOptions'; </ins> import 'vs/workbench/api/common/extHost.common.services'; import 'vs/workbench/api/node/extHost.node.services'; interface ParsedExtHostArgs { uriTransformerPath?: string; <ins> skipWorkspaceStorageLock?: boolean; </ins> useHostProxy?: string; }


string: [ 'uriTransformerPath', 'useHostProxy' <ins> ], boolean: [ 'skipWorkspaceStorageLock' </ins> ] }) as ParsedExtHostArgs;


// setup things patchProcess(!!initData.environment.extensionTestsLocationURI); // to support other test frameworks like Jasmin that use process.exit (https://github.com/microsoft/vscode/issues/37708) initData.environment.useHostProxy = args.useHostProxy !== undefined ? args.useHostProxy !== 'false' : undefined; <ins> initData.environment.skipWorkspaceStorageLock = boolean(args.skipWorkspaceStorageLock, false); </ins> // host abstraction const hostUtils = new class NodeHost implements IHostUtils {


const editorInput = InteractiveEditorInput.create(accessor.get(IInstantiationService), notebookUri, inputUri); historyService.clearHistory(notebookUri); <del> await editorService.openEditor(editorInput, editorOptions, group); </del> <ins> await editorService.openEditor(editorInput, { ...editorOptions, pinned: true }, group); </ins> // Extensions must retain references to these URIs to manipulate the interactive editor return { notebookUri, inputUri }; }