*  Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ <del> .codicon.codicon-symbol-array { color: var(--vscode-symbolIcon-arrayForeground); } .codicon.codicon-symbol-boolean { color: var(--vscode-symbolIcon-booleanForeground); } .codicon.codicon-symbol-class { color: var(--vscode-symbolIcon-classForeground); } .codicon.codicon-symbol-method { color: var(--vscode-symbolIcon-methodForeground); } .codicon.codicon-symbol-color { color: var(--vscode-symbolIcon-colorForeground); } .codicon.codicon-symbol-constant { color: var(--vscode-symbolIcon-constantForeground); } .codicon.codicon-symbol-constructor { color: var(--vscode-symbolIcon-constructorForeground); } .codicon.codicon-symbol-value, .codicon.codicon-symbol-enum { color: var(--vscode-symbolIcon-enumeratorForeground); } .codicon.codicon-symbol-enum-member { color: var(--vscode-symbolIcon-enumeratorMemberForeground); } .codicon.codicon-symbol-event { color: var(--vscode-symbolIcon-eventForeground); } .codicon.codicon-symbol-field { color: var(--vscode-symbolIcon-fieldForeground); } .codicon.codicon-symbol-file { color: var(--vscode-symbolIcon-fileForeground); } .codicon.codicon-symbol-folder { color: var(--vscode-symbolIcon-folderForeground); } .codicon.codicon-symbol-function { color: var(--vscode-symbolIcon-functionForeground); } .codicon.codicon-symbol-interface { color: var(--vscode-symbolIcon-interfaceForeground); } .codicon.codicon-symbol-key { color: var(--vscode-symbolIcon-keyForeground); } .codicon.codicon-symbol-keyword { color: var(--vscode-symbolIcon-keywordForeground); } .codicon.codicon-symbol-module { color: var(--vscode-symbolIcon-moduleForeground); } .codicon.codicon-symbol-namespace { color: var(--vscode-symbolIcon-namespaceForeground); } .codicon.codicon-symbol-null { color: var(--vscode-symbolIcon-nullForeground); } .codicon.codicon-symbol-number { color: var(--vscode-symbolIcon-numberForeground); } .codicon.codicon-symbol-object { color: var(--vscode-symbolIcon-objectForeground); } .codicon.codicon-symbol-operator { color: var(--vscode-symbolIcon-operatorForeground); } .codicon.codicon-symbol-package { color: var(--vscode-symbolIcon-packageForeground); } .codicon.codicon-symbol-property { color: var(--vscode-symbolIcon-propertyForeground); } .codicon.codicon-symbol-reference { color: var(--vscode-symbolIcon-referenceForeground); } .codicon.codicon-symbol-snippet { color: var(--vscode-symbolIcon-snippetForeground); } .codicon.codicon-symbol-string { color: var(--vscode-symbolIcon-stringForeground); } .codicon.codicon-symbol-struct { color: var(--vscode-symbolIcon-structForeground); } .codicon.codicon-symbol-text { color: var(--vscode-symbolIcon-textForeground); } .codicon.codicon-symbol-type-parameter { color: var(--vscode-typeParameterForeground); } .codicon.codicon-symbol-unit { color: var(--vscode-symbolIcon-unitForeground); } .codicon.codicon-symbol-variable { color: var(--vscode-symbolIcon-variableForeground); } </del> <ins> .monaco-editor .codicon.codicon-symbol-array, .monaco-workbench .codicon.codicon-symbol-array { color: var(--vscode-symbolIcon-arrayForeground); } .monaco-editor .codicon.codicon-symbol-boolean, .monaco-workbench .codicon.codicon-symbol-boolean { color: var(--vscode-symbolIcon-booleanForeground); } .monaco-editor .codicon.codicon-symbol-class, .monaco-workbench .codicon.codicon-symbol-class { color: var(--vscode-symbolIcon-classForeground); } .monaco-editor .codicon.codicon-symbol-method, .monaco-workbench .codicon.codicon-symbol-method { color: var(--vscode-symbolIcon-methodForeground); } .monaco-editor .codicon.codicon-symbol-color, .monaco-workbench .codicon.codicon-symbol-color { color: var(--vscode-symbolIcon-colorForeground); } .monaco-editor .codicon.codicon-symbol-constant, .monaco-workbench .codicon.codicon-symbol-constant { color: var(--vscode-symbolIcon-constantForeground); } .monaco-editor .codicon.codicon-symbol-constructor, .monaco-workbench .codicon.codicon-symbol-constructor { color: var(--vscode-symbolIcon-constructorForeground); } .monaco-editor .codicon.codicon-symbol-value, .monaco-workbench .codicon.codicon-symbol-value, .monaco-editor .codicon.codicon-symbol-enum, .monaco-workbench .codicon.codicon-symbol-enum { color: var(--vscode-symbolIcon-enumeratorForeground); } .monaco-editor .codicon.codicon-symbol-enum-member, .monaco-workbench .codicon.codicon-symbol-enum-member { color: var(--vscode-symbolIcon-enumeratorMemberForeground); } .monaco-editor .codicon.codicon-symbol-event, .monaco-workbench .codicon.codicon-symbol-event { color: var(--vscode-symbolIcon-eventForeground); } .monaco-editor .codicon.codicon-symbol-field, .monaco-workbench .codicon.codicon-symbol-field { color: var(--vscode-symbolIcon-fieldForeground); } .monaco-editor .codicon.codicon-symbol-file, .monaco-workbench .codicon.codicon-symbol-file { color: var(--vscode-symbolIcon-fileForeground); } .monaco-editor .codicon.codicon-symbol-folder, .monaco-workbench .codicon.codicon-symbol-folder { color: var(--vscode-symbolIcon-folderForeground); } .monaco-editor .codicon.codicon-symbol-function, .monaco-workbench .codicon.codicon-symbol-function { color: var(--vscode-symbolIcon-functionForeground); } .monaco-editor .codicon.codicon-symbol-interface, .monaco-workbench .codicon.codicon-symbol-interface { color: var(--vscode-symbolIcon-interfaceForeground); } .monaco-editor .codicon.codicon-symbol-key, .monaco-workbench .codicon.codicon-symbol-key { color: var(--vscode-symbolIcon-keyForeground); } .monaco-editor .codicon.codicon-symbol-keyword, .monaco-workbench .codicon.codicon-symbol-keyword { color: var(--vscode-symbolIcon-keywordForeground); } .monaco-editor .codicon.codicon-symbol-module, .monaco-workbench .codicon.codicon-symbol-module { color: var(--vscode-symbolIcon-moduleForeground); } .monaco-editor .codicon.codicon-symbol-namespace, .monaco-workbench .codicon.codicon-symbol-namespace { color: var(--vscode-symbolIcon-namespaceForeground); } .monaco-editor .codicon.codicon-symbol-null, .monaco-workbench .codicon.codicon-symbol-null { color: var(--vscode-symbolIcon-nullForeground); } .monaco-editor .codicon.codicon-symbol-number, .monaco-workbench .codicon.codicon-symbol-number { color: var(--vscode-symbolIcon-numberForeground); } .monaco-editor .codicon.codicon-symbol-object, .monaco-workbench .codicon.codicon-symbol-object { color: var(--vscode-symbolIcon-objectForeground); } .monaco-editor .codicon.codicon-symbol-operator, .monaco-workbench .codicon.codicon-symbol-operator { color: var(--vscode-symbolIcon-operatorForeground); } .monaco-editor .codicon.codicon-symbol-package, .monaco-workbench .codicon.codicon-symbol-package { color: var(--vscode-symbolIcon-packageForeground); } .monaco-editor .codicon.codicon-symbol-property, .monaco-workbench .codicon.codicon-symbol-property { color: var(--vscode-symbolIcon-propertyForeground); } .monaco-editor .codicon.codicon-symbol-reference, .monaco-workbench .codicon.codicon-symbol-reference { color: var(--vscode-symbolIcon-referenceForeground); } .monaco-editor .codicon.codicon-symbol-snippet, .monaco-workbench .codicon.codicon-symbol-snippet { color: var(--vscode-symbolIcon-snippetForeground); } .monaco-editor .codicon.codicon-symbol-string, .monaco-workbench .codicon.codicon-symbol-string { color: var(--vscode-symbolIcon-stringForeground); } .monaco-editor .codicon.codicon-symbol-struct, .monaco-workbench .codicon.codicon-symbol-struct { color: var(--vscode-symbolIcon-structForeground); } .monaco-editor .codicon.codicon-symbol-text, .monaco-workbench .codicon.codicon-symbol-text { color: var(--vscode-symbolIcon-textForeground); } .monaco-editor .codicon.codicon-symbol-type-parameter, .monaco-workbench .codicon.codicon-symbol-type-parameter { color: var(--vscode-typeParameterForeground); } .monaco-editor .codicon.codicon-symbol-unit, .monaco-workbench .codicon.codicon-symbol-unit { color: var(--vscode-symbolIcon-unitForeground); } .monaco-editor .codicon.codicon-symbol-variable, .monaco-workbench .codicon.codicon-symbol-variable { color: var(--vscode-symbolIcon-variableForeground); } </ins>


const viewsService = serviceAccessor.get(IViewsService); const viewContainerLocation = viewDescriptorService.getViewContainerLocation(viewContainer); switch (viewContainerLocation) { <del> case ViewContainerLocation.Sidebar: if (!viewsService.isViewContainerVisible(viewContainer.id) || !layoutService.hasFocus(Parts.SIDEBAR_PART)) { </del> <ins> case ViewContainerLocation.AuxiliaryBar: case ViewContainerLocation.Sidebar: { const part = viewContainerLocation === ViewContainerLocation.Sidebar ? Parts.SIDEBAR_PART : Parts.AUXILIARYBAR_PART; if (!viewsService.isViewContainerVisible(viewContainer.id) || !layoutService.hasFocus(part)) { </ins> await viewsService.openViewContainer(viewContainer.id, true); } else { editorGroupService.activeGroup.focus(); } break; <ins> } </ins> case ViewContainerLocation.Panel: if (!viewsService.isViewContainerVisible(viewContainer.id) || !layoutService.hasFocus(Parts.PANEL_PART)) { await viewsService.openViewContainer(viewContainer.id, true);


throw new Error(`Call not found: ${command}`); } <del> if (arg) { const uri = URI.revive(arg); </del> <ins> if (Array.isArray(arg) && arg.length > 0) { const uri = URI.revive(arg[0]); </ins> this.logService.trace('URLHandlerRouter#routeCall() with URI argument', uri.toString(true));


return value.content; } } catch (parseError) { <ins> // We may not be able to parse it, but we keep the secret in the keychain anyway just in case // it decrypts correctly in the future. </ins> this.logService.error(parseError); <del> // If we can't parse the decrypted value, then it's not a valid secret so we should try to delete it try { await this.credentialsService.deletePassword(fullKey, key); } catch (e) { this.logService.error(e); } </del> throw new Error('Unable to parse decrypted password'); } }


const embeddedSvgsNotValid = l10n.t("Embedded SVGs are not a valid image source."); const dataUrlsNotValid = l10n.t("Data URLs are not a valid image source."); const relativeUrlRequiresHttpsRepository = l10n.t("Relative image URLs require a repository with HTTPS protocol to be specified in the package.json."); <del> const relativeIconUrlRequiresHttpsRepository = l10n.t("An icon requires a repository with HTTPS protocol to be specified in this package.json."); </del> const relativeBadgeUrlRequiresHttpsRepository = l10n.t("Relative badge URLs require a repository with HTTPS protocol to be specified in this package.json."); const apiProposalNotListed = l10n.t("This proposal cannot be used because for this extension the product defines a fixed set of API proposals. You can test your extension but before publishing you MUST reach out to the VS Code team."); const implicitActivationEvent = l10n.t("This activation event cannot be explicitly listed by your extension.");


diagnostics.push(new Diagnostic(range, dataUrlsNotValid, DiagnosticSeverity.Warning)); } <del> if (!hasScheme && !info.hasHttpsRepository) { </del> <ins> if (!hasScheme && !info.hasHttpsRepository && context !== Context.ICON) { </ins> const range = new Range(document.positionAt(begin), document.positionAt(end)); const message = (() => { switch (context) { <del> case Context.ICON: return relativeIconUrlRequiresHttpsRepository; </del> case Context.BADGE: return relativeBadgeUrlRequiresHttpsRepository; default: return relativeUrlRequiresHttpsRepository; }


import { ExtHostUriOpeners } from 'vs/workbench/api/common/extHostUriOpener'; import { IExtHostSecretState } from 'vs/workbench/api/common/extHostSecretState'; import { IExtHostEditorTabs } from 'vs/workbench/api/common/extHostEditorTabs'; <del> import { IExtHostTelemetry, isNewAppInstall } from 'vs/workbench/api/common/extHostTelemetry'; </del> <ins> import { ExtHostTelemetryLogger, IExtHostTelemetry, isNewAppInstall } from 'vs/workbench/api/common/extHostTelemetry'; </ins> import { ExtHostNotebookKernels } from 'vs/workbench/api/common/extHostNotebookKernels'; import { TextSearchCompleteMessageType } from 'vs/workbench/services/search/common/searchExtTypes'; import { ExtHostNotebookRenderers } from 'vs/workbench/api/common/extHostNotebookRenderers';


get isNewAppInstall() { return isNewAppInstall(initData.telemetryInfo.firstSessionDate); }, <del> createTelemetryLogger(appender: vscode.TelemetrySender): vscode.TelemetryLogger { </del> <ins> createTelemetryLogger(sender: vscode.TelemetrySender): vscode.TelemetryLogger { </ins> checkProposedApiEnabled(extension, 'telemetryLogger'); <del> return extHostTelemetry.instantiateLogger(extension, appender); </del> <ins> ExtHostTelemetryLogger.validateSender(sender); return extHostTelemetry.instantiateLogger(extension, sender); </ins> }, openExternal(uri: URI, options?: { allowContributedOpeners?: boolean | string }) { return extHostWindow.openUri(uri, {


} export class ExtHostTelemetryLogger { <del> private _appender: vscode.TelemetrySender; </del> <ins> static validateSender(sender: vscode.TelemetrySender): void { if (typeof sender !== 'object') { throw new TypeError('TelemetrySender argument is invalid'); } if (typeof sender.sendEventData !== 'function') { throw new TypeError('TelemetrySender.sendEventData must be a function'); } if (typeof sender.sendErrorData !== 'function') { throw new TypeError('TelemetrySender.sendErrorData must be a function'); } if (typeof sender.flush !== 'undefined' && typeof sender.flush !== 'function') { throw new TypeError('TelemetrySender.flush must be a function or undefined'); } } private readonly _sender: vscode.TelemetrySender; </ins> private readonly _onDidChangeEnableStates = new Emitter<vscode.TelemetryLogger>(); <del> private _telemetryEnablements: { isUsageEnabled: boolean; isErrorsEnabled: boolean }; private _apiObject: vscode.TelemetryLogger | undefined; </del> private readonly _ignoreBuiltinCommonProperties: boolean; private readonly _additionalCommonProperties: Record<string, any> | undefined; public readonly ignoreUnhandledExtHostErrors: boolean; <ins> private _telemetryEnablements: { isUsageEnabled: boolean; isErrorsEnabled: boolean }; private _apiObject: vscode.TelemetryLogger | undefined; </ins> constructor( sender: vscode.TelemetrySender, options: vscode.TelemetryLoggerOptions | undefined,


this.ignoreUnhandledExtHostErrors = options?.ignoreUnhandledErrors ?? false; this._ignoreBuiltinCommonProperties = options?.ignoreBuiltInCommonProperties ?? false; this._additionalCommonProperties = options?.additionalCommonProperties; <del> this._appender = sender; </del> <ins> this._sender = sender; </ins> this._telemetryEnablements = { isUsageEnabled: telemetryEnablements.isUsageEnabled, isErrorsEnabled: telemetryEnablements.isErrorsEnabled }; }


} data = this.mixInCommonPropsAndCleanData(data || {}); if (!this._inLoggingOnlyMode) { <del> this._appender.sendEventData(eventName, data); </del> <ins> this._sender.sendEventData(eventName, data); </ins> } this._logger.trace(eventName, data); }


this.logEvent(eventNameOrException, data); } else { // TODO @lramos15, implement cleaning for and logging for this case <del> this._appender.sendErrorData(eventNameOrException, data); </del> <ins> this._sender.sendErrorData(eventNameOrException, data); </ins> } }


} dispose(): void { <del> if (this._appender?.flush) { this._appender.flush(); </del> <ins> if (this._sender?.flush) { this._sender.flush(); </ins> } } }


import { ITelemetryInfo, TelemetryLevel } from 'vs/platform/telemetry/common/telemetry'; import { TestTelemetryLoggerService } from 'vs/platform/telemetry/test/common/telemetryLogAppender.test'; import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService'; <del> import { ExtHostTelemetry } from 'vs/workbench/api/common/extHostTelemetry'; </del> <ins> import { ExtHostTelemetry, ExtHostTelemetryLogger } from 'vs/workbench/api/common/extHostTelemetry'; </ins> import { IEnvironment } from 'vs/workbench/services/extensions/common/extensionHostProtocol'; import { mock } from 'vs/workbench/test/common/workbenchTestServices'; import type { TelemetrySender } from 'vscode';


return logger; }; <ins> test('Validate sender instances', function () { assert.throws(() => ExtHostTelemetryLogger.validateSender(<any>null)); assert.throws(() => ExtHostTelemetryLogger.validateSender(<any>1)); assert.throws(() => ExtHostTelemetryLogger.validateSender(<any>{})); assert.throws(() => { ExtHostTelemetryLogger.validateSender(<any>{ sendErrorData: () => { }, sendEventData: true }); }); assert.throws(() => { ExtHostTelemetryLogger.validateSender(<any>{ sendErrorData: 123, sendEventData: () => { }, }); }); assert.throws(() => { ExtHostTelemetryLogger.validateSender(<any>{ sendErrorData: () => { }, sendEventData: () => { }, flush: true }); }); }); </ins> test('Ensure logger gets proper telemetry level during initialization', function () { const extensionTelemetry = createExtHostTelemetry(); let config = extensionTelemetry.getTelemetryDetails();


'no-cached-data': { type: 'boolean' }, 'prof-startup-prefix': { type: 'string' }, 'prof-v8-extensions': { type: 'boolean' }, <del> 'disable-extensions': { type: 'boolean', deprecates: ['disableExtensions'], cat: 't', description: localize('disableExtensions', "Disable all installed extensions.") }, 'disable-extension': { type: 'string[]', cat: 't', args: 'ext-id', description: localize('disableExtension', "Disable an extension.") }, </del> <ins> 'disable-extensions': { type: 'boolean', deprecates: ['disableExtensions'], cat: 't', description: localize('disableExtensions', "Disable all installed extensions. This option is not persisted and is effective only when the command opens a new window.") }, 'disable-extension': { type: 'string[]', cat: 't', args: 'ext-id', description: localize('disableExtension', "Disable the provided extension. This option is not persisted and is effective only when the command opens a new window.") }, </ins> 'sync': { type: 'string', cat: 't', description: localize('turn sync', "Turn sync on or off."), args: ['on | off'] }, 'inspect-extensions': { type: 'string', allowEmptyValue: true, deprecates: ['debugPluginHost'], args: 'port', cat: 't', description: localize('inspect-extensions', "Allow debugging and profiling of extensions. Check the developer tools for the connection URI.") },


} } <del> this.layout({ metadataHeight: metadataLayoutChange, outputTotalHeight: outputLayoutChange }); </del> <ins> if (metadataLayoutChange || outputLayoutChange) { this.layout({ metadataHeight: metadataLayoutChange, outputTotalHeight: outputLayoutChange }); } </ins> })); }


/** Don't spam warnings */ private hasWarnedMissingSettings = false; <ins> private tocTreeDisposed = false; </ins> /** Persist the search query upon reloads */ private editorMemento: IEditorMemento<ISettingsEditor2State>;


'aria-label': localize('settings', "Settings"), })), this.viewState)); <ins> this.tocTreeDisposed = false; </ins> this._register(this.tocTree.onDidFocus(() => { this._currentFocusContext = SettingsFocusContext.TableOfContents;


this._register(this.tocTree.onDidBlur(() => { this.tocRowFocused.set(false); })); <ins> this._register(this.tocTree.onDidDispose(() => { this.tocTreeDisposed = true; })); </ins> } private applyFilter(filter: string) {


this.refreshTOCTree(); this.renderResultCountMessages(); this.refreshTree(); <del> } else { </del> <ins> } else if (!this.tocTreeDisposed) { </ins> // Leaving search mode this.tocTree.collapseAll(); this.refreshTOCTree();


import * as nls from 'vs/nls'; import { ContextKeyExpr, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; <del> import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; </del> export class GhostTextController extends Disposable { public static readonly inlineSuggestionVisible = new RawContextKey<boolean>('inlineSuggestionVisible', false, nls.localize('inlineSuggestionVisible', "Whether an inline suggestion is visible")); public static readonly inlineSuggestionHasIndentation = new RawContextKey<boolean>('inlineSuggestionHasIndentation', false, nls.localize('inlineSuggestionHasIndentation', "Whether the inline suggestion starts with whitespace")); public static readonly inlineSuggestionHasIndentationLessThanTabSize = new RawContextKey<boolean>('inlineSuggestionHasIndentationLessThanTabSize', true, nls.localize('inlineSuggestionHasIndentationLessThanTabSize', "Whether the inline suggestion starts with whitespace that is less than what would be inserted by tab")); <del> /** * Enables to use Ctrl+Left to undo fully (partially) accepted inline completions (the completion is no longer visible then). */ public static readonly inlineSuggestionJustCommitted = new RawContextKey<boolean>('inlineSuggestionJustCommitted', false, nls.localize('inlineSuggestionJustCommitted', "Whether an inline suggestion just got committed")); </del> static ID = 'editor.contrib.ghostTextController';


public commitPartially(): void { this.activeModel?.commitInlineCompletionPartially(); <del> this.activeController?.value?.contextKeys.inlineSuggestionJustCommitted.set(true); </del> } public commit(): void { this.activeModel?.commitInlineCompletion(); <del> this.activeController?.value?.contextKeys.inlineSuggestionJustCommitted.set(true); </del> } public hide(): void {


public readonly inlineCompletionVisible = GhostTextController.inlineSuggestionVisible.bindTo(this.contextKeyService); public readonly inlineCompletionSuggestsIndentation = GhostTextController.inlineSuggestionHasIndentation.bindTo(this.contextKeyService); public readonly inlineCompletionSuggestsIndentationLessThanTabSize = GhostTextController.inlineSuggestionHasIndentationLessThanTabSize.bindTo(this.contextKeyService); <del> public readonly inlineSuggestionJustCommitted = GhostTextController.inlineSuggestionJustCommitted.bindTo(this.contextKeyService); </del> constructor(private readonly contextKeyService: IContextKeyService) { }


* Must be disposed as soon as the model detaches from the editor. */ export class ActiveGhostTextController extends Disposable { <del> public readonly contextKeys = new GhostTextContextKeys(this.contextKeyService); </del> <ins> private readonly contextKeys = new GhostTextContextKeys(this.contextKeyService); </ins> public readonly model = this._register(this.instantiationService.createInstance(GhostTextModel, this.editor)); public readonly widget = this._register(this.instantiationService.createInstance(GhostTextWidget, this.editor, this.model));


this._register(this.model.onDidChange(() => { this.updateContextKeys(); })); <del> this._register(this.editor.onDidChangeModelContent(() => { this.contextKeys.inlineSuggestionJustCommitted.reset(); })); this._register(this.editor.onDidChangeCursorPosition(() => { this.contextKeys.inlineSuggestionJustCommitted.reset(); })); </del> this.updateContextKeys(); }


id: 'editor.action.inlineSuggest.acceptNextWord', label: nls.localize('action.inlineSuggest.acceptNextWord', "Accept Next Word Of Inline Suggestion"), alias: 'Accept Next Word Of Inline Suggestion', <del> precondition: ContextKeyExpr.and(EditorContextKeys.writable, GhostTextController.inlineSuggestionVisible), kbOpts: { weight: 1000, primary: KeyMod.CtrlCmd | KeyCode.RightArrow, } </del> <ins> precondition: EditorContextKeys.writable </ins> }); }


} } } <del> KeybindingsRegistry.registerKeybindingRule({ id: 'undo', weight: 1000, primary: KeyMod.CtrlCmd | KeyCode.LeftArrow, when: ContextKeyExpr.and(EditorContextKeys.writable, ContextKeyExpr.or(GhostTextController.inlineSuggestionVisible, GhostTextController.inlineSuggestionJustCommitted)), }); </del>


container.classList.add(this._className); } } <ins> protected override updateTooltip(): void { // NOOP, disable tooltip } </ins> } class StatusBarViewItem extends MenuEntryActionViewItem {


this.label.classList.add('inlineSuggestionStatusBarItemLabel'); } } <ins> protected override updateTooltip(): void { // NOOP, disable tooltip } </ins> } export class CustomizedMenuWorkbenchToolBar extends WorkbenchToolBar {


let debugKeybindingLabel = ''; viewsRegistry.registerViewWelcomeContent(WelcomeView.ID, { <del> content: localize( { key: 'runAndDebugAction', comment: [ '{0} will be replaced with a keybinding', 'Please do not translate the word "command", it is part of our internal syntax which must not change', '{Locked="](command:{1})"}' ] }, "[Run and Debug{0}](command:{1})", debugKeybindingLabel, DEBUG_START_COMMAND_ID), </del> <ins> content: `[${localize('runAndDebugAction', "Run and Debug")}${debugKeybindingLabel}](command:${DEBUG_START_COMMAND_ID})`, </ins> when: CONTEXT_DEBUGGERS_AVAILABLE, group: ViewContentGroups.Debug, // Allow inserting more buttons directly after this one (by setting order to 1).


}); viewsRegistry.registerViewWelcomeContent(WelcomeView.ID, { <del> content: localize( { key: 'detectThenRunAndDebug', comment: [ 'Please do not translate the word "command", it is part of our internal syntax which must not change', '{Locked="](command:{0})"}', ] }, "[Show all automatic debug configurations](command:{0}).", SELECT_AND_START_ID), </del> <ins> content: `[${localize('detectThenRunAndDebug', "Show all automatic debug configurations")}](command:${SELECT_AND_START_ID}).`, </ins> when: CONTEXT_DEBUGGERS_AVAILABLE, group: ViewContentGroups.Debug, order: 10


export const file = 'file'; export const untitled = 'untitled'; export const git = 'git'; <ins> export const github = 'github'; </ins> /** Live share scheme */ export const vsls = 'vsls'; export const walkThroughSnippet = 'walkThroughSnippet';


*/ export const disabledSchemes = new Set([ git, <del> vsls </del> <ins> vsls, github, </ins> ]);


"license": "MIT", "description": "Dependencies shared by all extensions", "dependencies": { <del> "typescript": "4.9.4" </del> <ins> "typescript": "4.9.5" </ins> }, "scripts": { "postinstall": "node ./postinstall.mjs"


dependencies: is-number "^7.0.0" <del> typescript@4.9.4: version "4.9.4" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.4.tgz#a2a3d2756c079abda241d75f149df9d561091e78" integrity sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg== </del> <ins> typescript@4.9.5: version "4.9.5" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== </ins> vscode-grammar-updater@^1.1.0: version "1.1.0"


this.searchWidget.setReplaceAllActionState(false); this.tree.setSelection([]); <ins> this.tree.setFocus([]); </ins> return this.viewModel.search(query) .then(onComplete, onError); }


this._register(this.actionBar.actionRunner.onDidRun((e: IRunEvent) => { // check for error if (e.error && !errors.isCancellationError(e.error)) { <del> this.notificationService.error(e.error); </del> <ins> this.notificationService.warn(e.error); </ins> } // log in telemetry


`script-src 'self' 'unsafe-eval' ${this._getScriptCspHashes(data).join(' ')} 'sha256-fh3TwPMflhsEIpR8g1OYTIMVWhXTLcjQ9kh2tIpmv54=' http://${remoteAuthority};`, // the sha is the same as in src/vs/workbench/services/extensions/worker/webWorkerExtensionHostIframe.html 'child-src 'self';', `frame-src 'self' https://*.vscode-cdn.net data:;`, <del> 'worker-src 'self' data:;', </del> <ins> 'worker-src 'self' data: blob:;', </ins> 'style-src 'self' 'unsafe-inline';', 'connect-src 'self' ws: wss: https:;', 'font-src 'self' blob:;',


<ins> /*--------------------------------------------------------------------------------------------- *  Copyright (c) Microsoft Corporation. All rights reserved. *  Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // https://github.com/microsoft/vscode/blob/6cb34eb22385bc93ab25aa2e5113f59c7a2299ac/src/vs/platform/extensions/common/extensionValidator.ts export interface IParsedVersion { hasCaret: boolean; hasGreaterEquals: boolean; majorBase: number; majorMustEqual: boolean; minorBase: number; minorMustEqual: boolean; patchBase: number; patchMustEqual: boolean; preRelease: string | null; } export interface INormalizedVersion { majorBase: number; majorMustEqual: boolean; minorBase: number; minorMustEqual: boolean; patchBase: number; patchMustEqual: boolean; notBefore: number; /* milliseconds timestamp, or 0 */ isMinimum: boolean; } const VERSION_REGEXP = /^(^|>=)?((d+)|x).((d+)|x).((d+)|x)(-.*)?$/; const NOT_BEFORE_REGEXP = /^-(d{4})(d{2})(d{2})$/; export function isValidVersionStr(version: string): boolean { version = version.trim(); return (version === '*' || VERSION_REGEXP.test(version)); } export function parseVersion(version: string): IParsedVersion | null { if (!isValidVersionStr(version)) { return null; } version = version.trim(); if (version === '*') { return { hasCaret: false, hasGreaterEquals: false, majorBase: 0, majorMustEqual: false, minorBase: 0, minorMustEqual: false, patchBase: 0, patchMustEqual: false, preRelease: null }; } const m = version.match(VERSION_REGEXP); if (!m) { return null; } return { hasCaret: m[1] === '^', hasGreaterEquals: m[1] === '>=', majorBase: m[2] === 'x' ? 0 : parseInt(m[2], 10), majorMustEqual: (m[2] === 'x' ? false : true), minorBase: m[4] === 'x' ? 0 : parseInt(m[4], 10), minorMustEqual: (m[4] === 'x' ? false : true), patchBase: m[6] === 'x' ? 0 : parseInt(m[6], 10), patchMustEqual: (m[6] === 'x' ? false : true), preRelease: m[8] || null }; } export function normalizeVersion(version: IParsedVersion | null): INormalizedVersion | null { if (!version) { return null; } const majorBase = version.majorBase; const majorMustEqual = version.majorMustEqual; const minorBase = version.minorBase; let minorMustEqual = version.minorMustEqual; const patchBase = version.patchBase; let patchMustEqual = version.patchMustEqual; if (version.hasCaret) { if (majorBase === 0) { patchMustEqual = false; } else { minorMustEqual = false; patchMustEqual = false; } } let notBefore = 0; if (version.preRelease) { const match = NOT_BEFORE_REGEXP.exec(version.preRelease); if (match) { const [, year, month, day] = match; notBefore = Date.UTC(Number(year), Number(month) - 1, Number(day)); } } return { majorBase: majorBase, majorMustEqual: majorMustEqual, minorBase: minorBase, minorMustEqual: minorMustEqual, patchBase: patchBase, patchMustEqual: patchMustEqual, isMinimum: version.hasGreaterEquals, notBefore, }; } </ins>


import * as MarkdownItType from 'markdown-it'; import { languages, workspace, Disposable, TextDocument, Uri, Diagnostic, Range, DiagnosticSeverity, Position, env, l10n } from 'vscode'; <ins> import { INormalizedVersion, normalizeVersion, parseVersion } from './extensionEngineValidation'; </ins> const product = JSON.parse(fs.readFileSync(path.join(env.appRoot, 'product.json'), { encoding: 'utf-8' })); const allowedBadgeProviders: string[] = (product.extensionAllowedBadgeProviders || []).map((s: string) => s.toLowerCase());


const apiProposalNotListed = l10n.t("This proposal cannot be used because for this extension the product defines a fixed set of API proposals. You can test your extension but before publishing you MUST reach out to the VS Code team."); const implicitActivationEvent = l10n.t("This activation event cannot be explicitly listed by your extension."); const redundantImplicitActivationEvent = l10n.t("This activation event can be removed as VS Code generates these automatically from your package.json contribution declarations."); <ins> const bumpEngineForImplicitActivationEvents = l10n.t("This activation event can be removed for extensions targeting engine version ^1.75 as VS Code will generate these automatically from your package.json contribution declarations."); </ins> const starActivation = l10n.t("Using '*' activation is usually a bad idea as it impacts performance."); enum Context {


hasHttpsRepository: boolean; repository: Uri; implicitActivationEvents: Set<string> | undefined; <ins> engineVersion: INormalizedVersion | null; </ins> } export class ExtensionLinter {


if (activationEventsNode?.type === 'array' && activationEventsNode.children) { for (const activationEventNode of activationEventsNode.children) { const activationEvent = getNodeValue(activationEventNode); <ins> const isImplicitActivationSupported = info.engineVersion && info.engineVersion?.majorBase >= 1 && info.engineVersion?.minorBase >= 75; </ins> // Redundant Implicit Activation if (info.implicitActivationEvents?.has(activationEvent) && redundantImplicitActivationEventPrefixes.some((prefix) => activationEvent.startsWith(prefix))) { const start = document.positionAt(activationEventNode.offset); const end = document.positionAt(activationEventNode.offset + activationEventNode.length); <del> diagnostics.push(new Diagnostic(new Range(start, end), redundantImplicitActivationEvent, DiagnosticSeverity.Warning)); </del> <ins> const message = isImplicitActivationSupported ? redundantImplicitActivationEvent : bumpEngineForImplicitActivationEvents; diagnostics.push(new Diagnostic(new Range(start, end), message, isImplicitActivationSupported ? DiagnosticSeverity.Warning : DiagnosticSeverity.Information)); </ins> } // Reserved Implicit Activation for (const implicitActivationEventPrefix of reservedImplicitActivationEventPrefixes) { <del> if (activationEvent.startsWith(implicitActivationEventPrefix)) { </del> <ins> if (isImplicitActivationSupported && activationEvent.startsWith(implicitActivationEventPrefix)) { </ins> const start = document.positionAt(activationEventNode.offset); const end = document.positionAt(activationEventNode.offset + activationEventNode.length); diagnostics.push(new Diagnostic(new Range(start, end), implicitActivationEvent, DiagnosticSeverity.Error));


private readPackageJsonInfo(folder: Uri, tree: JsonNode | undefined) { const engine = tree && findNodeAtLocation(tree, ['engines', 'vscode']); <ins> const parsedEngineVersion = engine?.type === 'string' ? normalizeVersion(parseVersion(engine.value)) : null; </ins> const repo = tree && findNodeAtLocation(tree, ['repository', 'url']); const uri = repo && parseUri(repo.value); const activationEvents = tree && parseImplicitActivationEvents(tree);


isExtension: !!(engine && engine.type === 'string'), hasHttpsRepository: !!(repo && repo.type === 'string' && repo.value && uri && uri.scheme.toLowerCase() === 'https'), repository: uri!, <del> implicitActivationEvents: activationEvents </del> <ins> implicitActivationEvents: activationEvents, engineVersion: parsedEngineVersion </ins> }; const str = folder.toString(); const oldInfo = this.folderToPackageJsonInfo[str];


} foundAnyProviders = true; counter++; <del> provider.provideTasks(validTypes).then((taskSet: ITaskSet) => { </del> <ins> raceTimeout(provider.provideTasks(validTypes).then((taskSet: ITaskSet) => { </ins> // Check that the tasks provided are of the correct type for (const task of taskSet.tasks) { if (task.type !== this._providerTypes.get(handle)) {


} } return done(taskSet); <del> }, error); </del> <ins> }, error), 5000, () => { // onTimeout console.error('Timed out getting tasks from ', providerType); done(undefined); }); </ins> } } if (!foundAnyProviders) {


return new Map(); } await this._waitForSupportedExecutions; <del> if (this._workspaceTasksPromise) { </del> <ins> // The build task might be run before folder open. On folder open, we need to update the tasks so that // all tasks are parsed. #173384 if (runSource !== TaskRunSource.FolderOpen && this._workspaceTasksPromise) { </ins> return this._workspaceTasksPromise; } return this._updateWorkspaceTasks(runSource);


protected _taskSystemInfos: Map<string, ITaskSystemInfo[]>; protected _workspaceTasksPromise?: Promise<Map<string, IWorkspaceFolderTaskResult>>; <ins> protected readonly _whenTaskSystemReady: Promise<void>; </ins> protected _taskSystem?: ITaskSystem; protected _taskSystemListeners?: IDisposable[] = [];


@IInstantiationService private readonly _instantiationService: IInstantiationService ) { super(); <ins> this._whenTaskSystemReady = Event.toPromise(this.onDidChangeTaskSystemInfo); </ins> this._workspaceTasksPromise = undefined; this._taskSystem = undefined; this._taskSystemListeners = undefined;


this._tasksReconnected = true; return; } <del> this._getTaskSystem(); </del> this.getWorkspaceTasks().then(async () => { this._tasksReconnected = await this._reconnectTasks(); });


return new Map(); } await this._waitForSupportedExecutions; <del> // The build task might be run before folder open. On folder open, we need to update the tasks so that // all tasks are parsed. #173384 if (runSource !== TaskRunSource.FolderOpen && this._workspaceTasksPromise) { </del> <ins> await this._whenTaskSystemReady; if (this._workspaceTasksPromise) { </ins> return this._workspaceTasksPromise; } return this._updateWorkspaceTasks(runSource);


const processContext = ProcessExecutionSupportedContext.bindTo(this._contextKeyService); processContext.set(process && !isVirtual); } <ins> // update tasks so an incomplete list isn't returned when getWorkspaceTasks is called this._workspaceTasksPromise = undefined; </ins> this._onDidRegisterSupportedExecutions.fire(); }


this._tasksReconnected = true; return; } <del> this.getWorkspaceTasks().then(async () => { </del> <ins> this.getWorkspaceTasks(TaskRunSource.Reconnect).then(async () => { </ins> this._tasksReconnected = await this._reconnectTasks(); }); }


return { workspaceFolder, set: undefined, configurations: undefined, hasErrors: false }; } <del> private async _computeTasksForSingleConfig(workspaceFolder: IWorkspaceFolder | undefined, config: TaskConfig.IExternalTaskRunnerConfiguration | undefined, runSource: TaskRunSource, custom: CustomTask[], customized: IStringDictionary<ConfiguringTask>, source: TaskConfig.TaskConfigSource, isRecentTask: boolean = false): Promise<boolean> { if (!config || !workspaceFolder) { </del> <ins> private async _computeTasksForSingleConfig(workspaceFolder: IWorkspaceFolder, config: TaskConfig.IExternalTaskRunnerConfiguration | undefined, runSource: TaskRunSource, custom: CustomTask[], customized: IStringDictionary<ConfiguringTask>, source: TaskConfig.TaskConfigSource, isRecentTask: boolean = false): Promise<boolean> { if (!config) { </ins> return false; } <del> const taskSystemInfo: ITaskSystemInfo | undefined = workspaceFolder ? this._getTaskSystemInfo(workspaceFolder.uri.scheme) : undefined; </del> <ins> const taskSystemInfo: ITaskSystemInfo | undefined = this._getTaskSystemInfo(workspaceFolder.uri.scheme); </ins> const problemReporter = new ProblemReporter(this._outputChannel); if (!taskSystemInfo) { problemReporter.fatal(nls.localize('TaskSystem.workspaceFolderError', 'Workspace folder was undefined'));


return true; } <del> private async _ensureWorkspaceTasks(): Promise<void> { if (!this._workspaceTasksPromise) { await this.getWorkspaceTasks(); } else { await this._workspaceTasksPromise; } } </del> private async _runTaskCommand(filter?: string | ITaskIdentifier): Promise<void> { <del> await this._ensureWorkspaceTasks(); </del> if (!filter) { return this._doRunTaskCommand(); }


title: strings.fetching }; const promise = (async () => { <del> await this._ensureWorkspaceTasks(); </del> let taskGroupTasks: (Task | ConfiguringTask)[] = []; async function runSingleTask(task: Task | undefined, problemMatcherOptions: IProblemMatcherRunOptions | undefined, that: AbstractTaskService) {


// We only want to fire a telemetry if we haven't seen this account yet in this session. if (!this._accountsSeen.has(session.account.id)) { this._accountsSeen.add(session.account.id); <del> this._githubServer.sendAdditionalTelemetryInfo(session.accessToken); </del> <ins> this._githubServer.sendAdditionalTelemetryInfo(session); </ins> } }


export interface IGitHubServer { login(scopes: string): Promise<string>; getUserInfo(token: string): Promise<{ id: string; accountName: string }>; <del> sendAdditionalTelemetryInfo(token: string): Promise<void>; </del> <ins> sendAdditionalTelemetryInfo(session: vscode.AuthenticationSession): Promise<void>; </ins> friendlyName: string; }


const result = await fetching(serverUri.toString(), { headers: { Authorization: `token ${token}`, <del> 'User-Agent': 'Visual-Studio-Code' </del> <ins> 'User-Agent': `${vscode.env.appName} (${vscode.env.appHost})` </ins> } });


result = await fetching(this.getServerUri('/user').toString(), { headers: { Authorization: `token ${token}`, <del> 'User-Agent': 'Visual-Studio-Code' </del> <ins> 'User-Agent': `${vscode.env.appName} (${vscode.env.appHost})` </ins> } }); } catch (ex) {


} } <del> public async sendAdditionalTelemetryInfo(token: string): Promise<void> { </del> <ins> public async sendAdditionalTelemetryInfo(session: vscode.AuthenticationSession): Promise<void> { </ins> if (!vscode.env.isTelemetryEnabled) { return; }


} if (this._type === AuthProviderType.github) { <del> return await this.checkUserDetails(token); </del> <ins> return await this.checkUserDetails(session); </ins> } // GHES <del> await this.checkEnterpriseVersion(token); </del> <ins> await this.checkEnterpriseVersion(session.accessToken); </ins> } <del> private async checkUserDetails(token: string): Promise<void> { </del> <ins> private async checkUserDetails(session: vscode.AuthenticationSession): Promise<void> { </ins> let edu: string | undefined; try { const result = await fetching('https://education.github.com/api/user', { headers: { <del> Authorization: `token ${token}`, </del> <ins> Authorization: `token ${session.accessToken}`, </ins> 'faculty-check-preview': 'true', <del> 'User-Agent': 'Visual-Studio-Code' </del> <ins> 'User-Agent': `${vscode.env.appName} (${vscode.env.appHost})` </ins> } });


: json.faculty ? 'faculty' : 'none'; <ins> } else { edu = 'unknown'; </ins> } } catch (e) { <del> // No-op } let managed: string | undefined; try { const user = await this.getUserInfo(token); // Apparently, this is how you tell if a user is an EMU... managed = user.accountName.includes('_') ? 'true' : 'false'; } catch (e) { // No-op } if (edu === undefined && managed === undefined) { return; </del> <ins> edu = 'unknown'; </ins> } /* __GDPR__


} */ this._telemetryReporter.sendTelemetryEvent('session', { <del> isEdu: edu ?? 'unknown', isManaged: managed ?? 'unknown' </del> <ins> isEdu: edu, // Apparently, this is how you tell if a user is an EMU... isManaged: session.account.label.includes('_') ? 'true' : 'false' </ins> }); }


const result = await fetching(this.getServerUri('/meta').toString(), { headers: { Authorization: `token ${token}`, <del> 'User-Agent': 'Visual-Studio-Code' </del> <ins> 'User-Agent': `${vscode.env.appName} (${vscode.env.appHost})` </ins> } });


import { ExplorerViewPaneContainer } from 'vs/workbench/contrib/files/browser/explorerViewlet'; import { onUnexpectedError } from 'vs/base/common/errors'; import { category, getElementsToOperateOn, getSearchView, openSearchView } from 'vs/workbench/contrib/search/browser/searchActionsBase'; <ins> import { withNullAsUndefined } from 'vs/base/common/types'; import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; import { IHistoryService } from 'vs/workbench/services/history/common/history'; import { Schemas } from 'vs/base/common/network'; </ins> //#region Interfaces


.filter((renderableMatch): renderableMatch is URI => (renderableMatch !== null)); } <del> export function findInFilesCommand(accessor: ServicesAccessor, args: IFindInFilesArgs = {}) { </del> <ins> export async function findInFilesCommand(accessor: ServicesAccessor, _args: IFindInFilesArgs = {}) { </ins> const searchConfig = accessor.get(IConfigurationService).getValue<ISearchConfiguration>().search; <ins> const viewsService = accessor.get(IViewsService); const args: IFindInFilesArgs = {}; if (Object.keys(_args).length !== 0) { // resolve variables in the same way as in // https://github.com/microsoft/vscode/blob/8b76efe9d317d50cb5b57a7658e09ce6ebffaf36/src/vs/workbench/contrib/searchEditor/browser/searchEditorActions.ts#L152-L158 const configurationResolverService = accessor.get(IConfigurationResolverService); const historyService = accessor.get(IHistoryService); const workspaceContextService = accessor.get(IWorkspaceContextService); const activeWorkspaceRootUri = historyService.getLastActiveWorkspaceRoot(Schemas.file); const lastActiveWorkspaceRoot = activeWorkspaceRootUri ? withNullAsUndefined(workspaceContextService.getWorkspaceFolder(activeWorkspaceRootUri)) : undefined; for (const entry of Object.entries(_args)) { const name = entry[0]; const value = entry[1]; if (value !== undefined) { (args as any)[name as any] = (typeof value === 'string') ? await configurationResolverService.resolveAsync(lastActiveWorkspaceRoot, value) : value; } } } </ins> const mode = searchConfig.mode; if (mode === 'view') { <del> const viewsService = accessor.get(IViewsService); </del> openSearchView(viewsService, false).then(openedView => { if (openedView) { const searchAndReplaceWidget = openedView.searchAndReplaceWidget;


// if it's clearing all outputs, or outputs are all rendered synchronously // shrink immediately as the final output height will be zero. // if it's rerun, then the output clearing might be temporary, so we don't shrink immediately <del> this._validateFinalOutputHeight(false || (context === CellOutputUpdateContext.Other && this.viewCell.outputsViewModels.length === 0)); </del> <ins> this._validateFinalOutputHeight(context === CellOutputUpdateContext.Other && this.viewCell.outputsViewModels.length === 0); </ins> } private _generateShowMoreElement(disposables: DisposableStore): HTMLElement {


import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; import { KeyCode } from 'vs/base/common/keyCodes'; import * as lifecycle from 'vs/base/common/lifecycle'; <ins> import { clamp } from 'vs/base/common/numbers'; </ins> import { isMacintosh } from 'vs/base/common/platform'; import { ScrollbarVisibility } from 'vs/base/common/scrollable'; import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser'; import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions'; <ins> import { IDimension } from 'vs/editor/common/core/dimension'; </ins> import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';


private scrollbar!: DomScrollableElement; private debugHoverComputer: DebugHoverComputer; <ins> private expressionToRender: IExpression | undefined; private isUpdatingTree = false; </ins> constructor( private editor: ICodeEditor, @IDebugService private readonly debugService: IDebugService,


private create(): void { this.domNode = $('.debug-hover-widget'); this.complexValueContainer = dom.append(this.domNode, $('.complex-value')); <ins> this.complexValueContainer.style.visibility = 'hidden'; </ins> this.complexValueTitle = dom.append(this.complexValueContainer, $('.title')); this.treeContainer = dom.append(this.complexValueContainer, $('.debug-hover-tree')); this.treeContainer.setAttribute('role', 'tree');


this.domNode.style.border = `1px solid ${asCssVariable(editorHoverBorder)}`; this.domNode.style.color = asCssVariable(editorHoverForeground); <del> this.toDispose.push(this.tree.onDidChangeContentHeight(() => this.layoutTreeAndContainer(false))); </del> <ins> this.toDispose.push(this.tree.onDidChangeContentHeight(() => { if (!this.isUpdatingTree) { // Don't do a layout in the middle of the async setInput this.layoutTreeAndContainer(); } })); </ins> this.registerListeners(); this.editor.addContentWidget(this);


this.valueContainer.hidden = true; <del> await this.tree.setInput(expression); </del> <ins> this.expressionToRender = expression; </ins> this.complexValueTitle.textContent = expression.value; this.complexValueTitle.title = expression.value; <del> this.layoutTreeAndContainer(true); </del> <ins> this.editor.layoutContentWidget(this); </ins> this.tree.scrollTop = 0; this.tree.scrollLeft = 0; this.complexValueContainer.hidden = false;


} } <del> private layoutTreeAndContainer(initialLayout: boolean): void { </del> <ins> private layoutTreeAndContainer(): void { this.layoutTree(); this.editor.layoutContentWidget(this); } private layoutTree(): void { </ins> const scrollBarHeight = 10; const treeHeight = Math.min(Math.max(266, this.editor.getLayoutInfo().height * 0.55), this.tree.contentHeight + scrollBarHeight); <ins> // Reset to a smaller width, if it was previously rendered wide this.tree.layout(treeHeight, 400); // const titleWidth = this.complexValueTitle.clientWidth; const realTreeWidth = this.tree.getHTMLElement().offsetWidth; // const contentWidth = Math.max(titleWidth, realTreeWidth); const treeWidth = clamp(realTreeWidth, 400, 550); this.tree.layout(treeHeight, treeWidth); </ins> this.treeContainer.style.height = `${treeHeight}px`; <del> this.tree.layout(treeHeight, initialLayout ? 400 : undefined); this.editor.layoutContentWidget(this); </del> this.scrollbar.scanDomNode(); } <ins> beforeRender(): IDimension | null { // beforeRender will be called each time the hover size changes, and the content widget is layed out again. if (this.expressionToRender) { const expression = this.expressionToRender; this.expressionToRender = undefined; // Do this in beforeRender once the content widget is no longer display=none so that its elements' sizes will be measured correctly. this.isUpdatingTree = true; this.tree.setInput(expression).then(() => { this.isUpdatingTree = false; dom.scheduleAtNextAnimationFrame(() => { // Wait for scrollWidth to update after a frame this.layoutTree(); this.editor.layoutContentWidget(this); this.complexValueContainer.style.visibility = ''; }); }); } return null; } </ins> afterRender(positionPreference: ContentWidgetPositionPreference | null) { if (positionPreference) { // Remember where the editor placed you to keep position stable #109226


hide(): void { <ins> this.complexValueContainer.style.visibility = 'hidden'; </ins> if (this.showCancellationSource) { this.showCancellationSource.cancel(); this.showCancellationSource = undefined;


export async function pickRemoteSource(model: Model, options: PickRemoteSourceOptions & { branch: true }): Promise<PickRemoteSourceResult | undefined>; export async function pickRemoteSource(model: Model, options: PickRemoteSourceOptions = {}): Promise<string | PickRemoteSourceResult | undefined> { const quickpick = window.createQuickPick<(QuickPickItem & { provider?: RemoteSourceProvider; url?: string })>(); <del> quickpick.ignoreFocusOut = true; </del> quickpick.title = options.title; if (options.providerName) {


if (options.inlineClassName) { const offset = (outputLineIndex > 0 ? lineBreakData.wrappedTextIndentLength : 0); const start = offset + Math.max(injectedTextStartOffsetInInputWithInjections - lineStartOffsetInInputWithInjections, 0); <del> const end = offset + Math.min(injectedTextEndOffsetInInputWithInjections - lineStartOffsetInInputWithInjections, lineEndOffsetInInputWithInjections); </del> <ins> const end = offset + Math.min(injectedTextEndOffsetInInputWithInjections - lineStartOffsetInInputWithInjections, lineEndOffsetInInputWithInjections - lineStartOffsetInInputWithInjections); </ins> if (start !== end) { inlineDecorations.push(new SingleLineInlineDecoration(start, end, options.inlineClassName, options.inlineClassNameAffectsLetterSpacing!)); }


})), [ { inlineDecorations: [{ startOffset: 8, endOffset: 23 }] }, <del> { inlineDecorations: [{ startOffset: 4, endOffset: 42 }] }, </del> <ins> { inlineDecorations: [{ startOffset: 4, endOffset: 30 }] }, </ins> { inlineDecorations: [{ startOffset: 4, endOffset: 16 }] }, { inlineDecorations: undefined }, { inlineDecorations: undefined },


}, "brackets": [ ["<!--", "-->"], <del> ["<", ">"], </del> ["{", "}"], ["(", ")"] ],


"@vscode/l10n": "^0.0.11", "jsonc-parser": "^3.2.0", "request-light": "^0.7.0", <del> "vscode-json-languageservice": "^5.3.1", </del> <ins> "vscode-json-languageservice": "^5.3.2", </ins> "vscode-languageserver": "^8.1.0", "vscode-uri": "^3.0.7" },


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.3.1: version "5.3.1" resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-5.3.1.tgz#c36175d05f425fbd8f47dcee6f2a72096bdda36f" integrity sha512-tPRf/2LOBS6uFflFLABdj8T3ol2/QgZ0kpzZHFCs+cbxpnjBNiCo+rfh3th0dtdytq5dSnWo5iFJj99zF6jZWQ== </del> <ins> vscode-json-languageservice@^5.3.2: version "5.3.2" resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-5.3.2.tgz#11e530ba9ec541eaeb421dc274a22efdb5d580ef" integrity sha512-5td6olfoNdtyxnNA4uocq7V9jdTJt63o9mGEntQb6cbD2HiObZW2XgbSj6nRaebWwBCiYdWpFklNjm6Wz6Xy1Q== </ins> dependencies: "@vscode/l10n" "^0.0.11" jsonc-parser "^3.2.0"


} } <del> private async selectStep(id: string | undefined, delayFocus = true, forceRebuild = false) { if (id && this.editorInput.selectedStep === id && !forceRebuild) { return; } </del> <ins> private async selectStep(id: string | undefined, delayFocus = true) { if (id && this.editorInput.selectedStep === id) { return; } </ins> if (id) { let stepElement = this.container.querySelector<HTMLDivElement>(`[data-step-id="${id}"]`);


if (event.keyCode === KeyCode.UpArrow) { const toExpand = category.steps.filter((step, index) => index < currentStepIndex() && this.contextService.contextMatchesRules(step.when)); if (toExpand.length) { <del> this.selectStep(toExpand[toExpand.length - 1].id, false, false); </del> <ins> this.selectStep(toExpand[toExpand.length - 1].id, false); </ins> } } if (event.keyCode === KeyCode.DownArrow) { const toExpand = category.steps.find((step, index) => index > currentStepIndex() && this.contextService.contextMatchesRules(step.when)); if (toExpand) { <del> this.selectStep(toExpand.id, false, false); </del> <ins> this.selectStep(toExpand.id, false); </ins> } } }));


if (e.affectsSome(contextKeysToWatch)) { buildStepList(); this.registerDispatchListeners(); <del> this.selectStep(this.editorInput.selectedStep, false, true); </del> <ins> this.selectStep(this.editorInput.selectedStep, false); </ins> } }));


reset(this.stepsContent, categoryDescriptorComponent, stepListComponent, this.stepMediaComponent, categoryFooter); const toExpand = category.steps.find(step => this.contextService.contextMatchesRules(step.when) && !step.done) ?? category.steps[0]; <del> this.selectStep(selectedStep ?? toExpand.id, !selectedStep, true); </del> <ins> this.selectStep(selectedStep ?? toExpand.id, !selectedStep); </ins> this.detailsScrollbar.scanDomNode(); this.detailsPageScrollbar?.scanDomNode();


if (!this._updateCustomBuiltinExtensionsCachePromise) { this._updateCustomBuiltinExtensionsCachePromise = (async () => { this.logService.info('Updating additional builtin extensions cache'); <del> const cached = await this.getCustomBuiltinExtensionsFromCache(); </del> const webExtensions: IWebExtension[] = []; const { extensions } = await this.readCustomBuiltinExtensionsInfoFromEnv(); if (extensions.length) {


} await Promise.all([...galleryExtensionsMap.values()].map(async gallery => { try { <del> const webExtension = cached.find(e => areSameExtensions(e.identifier, gallery.identifier) && e.version === gallery.version) ?? await this.toWebExtensionFromGallery(gallery, { isPreReleaseVersion: gallery.properties.isPreReleaseVersion, preRelease: gallery.properties.isPreReleaseVersion, isBuiltin: true }); </del> <ins> const webExtension = await this.toWebExtensionFromGallery(gallery, { isPreReleaseVersion: gallery.properties.isPreReleaseVersion, preRelease: gallery.properties.isPreReleaseVersion, isBuiltin: true }); </ins> webExtensions.push(webExtension); } catch (error) { this.logService.info(`Ignoring additional builtin extension ${gallery.identifier.id} because there is an error while converting it into web extension`, getErrorMessage(error));


MonacoEditorSchemas['http://opentools.azurewebsites.net/jsconfig'] = { 'title': nls.localize('jsconfig.json.title', "JSON schema for the JavaScript configuration file"), 'type': 'object', <del> 'default': { 'compilerOptions': { 'target': 'ES5' } }, </del> <ins> 'default': { 'compilerOptions': { 'target': 'ES6' } }, </ins> 'properties': { 'compilerOptions': { 'type': 'object',


this._compilerOptions = options || ts.getDefaultCompilerOptions(); this._compilerOptions.allowNonTsExtensions = true; // because of JS* and mirror model we need this this._compilerOptions.module = ts.ModuleKind.CommonJS; // because of JS* <ins> this._compilerOptions.target = options && options.target !== undefined ? options.target : ts.ScriptTarget.Latest; // because of JS* </ins> } getCompilationSettings(): ts.CompilerOptions {


WindowsEnableConpty = 'terminal.integrated.windowsEnableConpty', WordSeparators = 'terminal.integrated.wordSeparators', EnableFileLinks = 'terminal.integrated.enableFileLinks', <ins> AllowedLinkSchemes = 'terminal.integrated.allowedLinkSchemes', </ins> UnicodeVersion = 'terminal.integrated.unicodeVersion', LocalEchoLatencyThreshold = 'terminal.integrated.localEchoLatencyThreshold', LocalEchoEnabled = 'terminal.integrated.localEchoEnabled',


windowsEnableConpty: boolean; wordSeparators: string; enableFileLinks: 'off' | 'on' | 'notRemote'; <ins> allowedLinkSchemes: string[]; </ins> unicodeVersion: '6' | '11'; localEchoLatencyThreshold: number; localEchoExcludePrograms: ReadonlyArray<string>;


], default: 'on' }, <ins> [TerminalSettingId.AllowedLinkSchemes]: { description: localize('terminal.integrated.allowedLinkSchemes', "An array of strings containing the URI schemes that the terminal is allowed to open links for. By default, only a small subset of possible schemes are allowed for security reasons."), type: 'array', items: { type: 'string' }, default: [ 'file', 'http', 'https', 'mailto', 'vscode', 'vscode-insiders', ] }, </ins> [TerminalSettingId.UnicodeVersion]: { type: 'string', enum: ['6', '11'],


import { TerminalLocalLinkDetector } from 'vs/workbench/contrib/terminalContrib/links/browser/terminalLocalLinkDetector'; import { TerminalUriLinkDetector } from 'vs/workbench/contrib/terminalContrib/links/browser/terminalUriLinkDetector'; import { TerminalWordLinkDetector } from 'vs/workbench/contrib/terminalContrib/links/browser/terminalWordLinkDetector'; <del> import { ITerminalExternalLinkProvider, TerminalLinkQuickPickEvent } from 'vs/workbench/contrib/terminal/browser/terminal'; </del> <ins> import { ITerminalConfigurationService, ITerminalExternalLinkProvider, TerminalLinkQuickPickEvent } from 'vs/workbench/contrib/terminal/browser/terminal'; </ins> import { ILinkHoverTargetOptions, TerminalHover } from 'vs/workbench/contrib/terminal/browser/widgets/terminalHoverWidget'; import { TerminalWidgetManager } from 'vs/workbench/contrib/terminal/browser/widgets/widgetManager'; import { IXtermCore } from 'vs/workbench/contrib/terminal/browser/xterm-private';


import { RunOnceScheduler } from 'vs/base/common/async'; import { ITerminalLogService } from 'vs/platform/terminal/common/terminal'; import { TerminalMultiLineLinkDetector } from 'vs/workbench/contrib/terminalContrib/links/browser/terminalMultiLineLinkDetector'; <ins> import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; </ins> export type XtermLinkMatcherHandler = (event: MouseEvent | undefined, link: string) => Promise<void>;


capabilities: ITerminalCapabilityStore, private readonly _linkResolver: ITerminalLinkResolver, @IConfigurationService private readonly _configurationService: IConfigurationService, <ins> @ITerminalConfigurationService private readonly _terminalConfigurationService: ITerminalConfigurationService, </ins> @IInstantiationService private readonly _instantiationService: IInstantiationService, <ins> @INotificationService private readonly _notificationService: INotificationService, </ins> @ITerminalLogService private readonly _logService: ITerminalLogService, @ITunnelService private readonly _tunnelService: ITunnelService ) {


activeTooltipScheduler?.dispose(); })); this._xterm.options.linkHandler = { <del> activate: (_, text) => { </del> <ins> allowNonHttpProtocols: true, activate: (event, text) => { if (!this._isLinkActivationModifierDown(event)) { return; } const colonIndex = text.indexOf(':'); if (colonIndex === -1) { throw new Error(`Could not find scheme in link "${text}"`); } const scheme = text.substring(0, colonIndex); if (this._terminalConfigurationService.config.allowedLinkSchemes.indexOf(scheme) === -1) { this._notificationService.prompt(Severity.Warning, nls.localize('scheme', 'Opening URIs can be insecure, do you want to allow opening links with the scheme {0}?', scheme), [ { label: nls.localize('allow', 'Allow {0}', scheme), run: () => { const allowedLinkSchemes = [ ...this._terminalConfigurationService.config.allowedLinkSchemes, scheme ]; this._configurationService.updateValue(`terminal.integrated.allowedLinkSchemes`, allowedLinkSchemes); } } ]); } </ins> this._openers.get(TerminalBuiltinLinkType.Url)?.open({ type: TerminalBuiltinLinkType.Url, text,


const fileService = accessor.get(IFileService); const openerService = accessor.get(IOpenerService); <del> let { range, uri } = test.item; </del> <ins> const { range, uri } = test.item; </ins> if (!uri) { return; } // If an editor has the file open, there are decorations. Try to adjust the // revealed range to those decorations (#133441). <del> range = accessor.get(ITestingDecorationsService).getDecoratedRangeForTest(uri, extId) || range; </del> <ins> const position = accessor.get(ITestingDecorationsService).getDecoratedTestPosition(uri, extId) || range?.getStartPosition(); </ins> accessor.get(ITestExplorerFilterState).reveal.value = extId; accessor.get(ITestingPeekOpener).closeAllPeeks();


return; } <del> await openerService.open(range ? uri.with({ fragment: `L${range.startLineNumber}:${range.startColumn}` }) </del> <ins> await openerService.open(position ? uri.with({ fragment: `L${position.lineNumber}:${position.column}` }) </ins> : uri ); }


} /** @inheritdoc */ <del> public getDecoratedRangeForTest(resource: URI, testId: string) { </del> <ins> public getDecoratedTestPosition(resource: URI, testId: string) { </ins> const model = this.modelService.getModel(resource); if (!model) { return undefined;


return undefined; } <del> return model.getDecorationRange(decoration.id) || undefined; </del> <ins> // decoration is collapsed, so the range is meaningless; only position matters. return model.getDecorationRange(decoration.id)?.getStartPosition(); </ins> } private invalidate() {


} } <del> const firstLineRange = (originalRange: IRange) => ({ </del> <ins> const collapseRange = (originalRange: IRange) => ({ </ins> startLineNumber: originalRange.startLineNumber, endLineNumber: originalRange.startLineNumber, <del> startColumn: 0, endColumn: Number.MAX_SAFE_INTEGER, </del> <ins> startColumn: originalRange.startColumn, endColumn: originalRange.startColumn, </ins> }); const createRunTestDecoration = (tests: readonly IncrementalTestCollectionItem[], states: readonly (TestResultItem | undefined)[], visible: boolean): IModelDeltaDecoration => {


} if (!visible) { <del> return { range: firstLineRange(range), options: { isWholeLine: true, description: 'run-test-decoration' } }; </del> <ins> return { range: collapseRange(range), options: { isWholeLine: true, description: 'run-test-decoration' } }; </ins> } let computedState = TestResultState.Unset;


} return { <del> range: firstLineRange(range), </del> <ins> range: collapseRange(range), </ins> options: { description: 'run-test-decoration', <del> isWholeLine: true, </del> <ins> showIfCollapsed: true, </ins> get hoverMessage() { if (!hoverMessage) { const building = hoverMessage = new MarkdownString('', true).appendText(hoverMessageParts.join(', ') + '.');


import { binarySearch } from 'vs/base/common/arrays'; import { Event } from 'vs/base/common/event'; import { URI } from 'vs/base/common/uri'; <del> import { Range } from 'vs/editor/common/core/range'; </del> <ins> import { Position } from 'vs/editor/common/core/position'; </ins> import { IModelDeltaDecoration } from 'vs/editor/common/model'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { ITestMessage } from 'vs/workbench/contrib/testing/common/testTypes';


* Gets the range where a test ID is displayed, in the given URI. * Returns undefined if there's no such decoration. */ <del> getDecoratedRangeForTest(resource: URI, testId: string): Range | undefined; </del> <ins> getDecoratedTestPosition(resource: URI, testId: string): Position | undefined; </ins> } export interface ITestDecoration {


append_dir GTK_PATH "$SNAP/usr/lib/$ARCH/gtk-3.0" append_dir GTK_PATH "$SNAP/usr/lib/gtk-3.0" <ins> # We don't have gtk libraries in this path but # enforcing this environment variable will disallow # gtk binaries like `gtk-query-immodules` to not search # in system default library paths. # Based on https://gitlab.gnome.org/GNOME/gtk/-/blob/main/gtk/gtkmodules.c#L104-136 export GTK_EXE_PREFIX="$SNAP/usr" </ins> # ibus and fcitx integration GTK_IM_MODULE_DIR="$SNAP_USER_COMMON/.cache/immodules"


- libgl1 - libglib2.0-0 - libgtk-3-0 <ins> - libibus-1.0-5 </ins> - libnss3 - libpango-1.0-0 - libsecret-1-0


const gtkIMModuleFile = process.env['GTK_IM_MODULE_FILE']; const gdkBackend = process.env['GDK_BACKEND']; const gioModuleDir = process.env['GIO_MODULE_DIR']; <ins> const gtkExePrefix = process.env['GTK_EXE_PREFIX']; </ins> delete process.env['GDK_PIXBUF_MODULE_FILE']; delete process.env['GDK_PIXBUF_MODULEDIR']; delete process.env['GTK_IM_MODULE_FILE']; delete process.env['GDK_BACKEND']; delete process.env['GIO_MODULE_DIR']; <ins> delete process.env['GTK_EXE_PREFIX']; </ins> shell.openExternal(url);


process.env['GTK_IM_MODULE_FILE'] = gtkIMModuleFile; process.env['GDK_BACKEND'] = gdkBackend; process.env['GIO_MODULE_DIR'] = gioModuleDir; <ins> process.env['GTK_EXE_PREFIX'] = gtkExePrefix; </ins> } moveItemToTrash(windowId: number | undefined, fullPath: string): Promise<void> {


metadata.scrollable : options.outputScrolling; } <ins> //  div.cell_container //    div.output_container //      div.output.output-stream		<-- outputElement parameter //        div.scrollable? tabindex="0" 	<-- contentParent //          div output-item-id="{guid}"	<-- content from outputItem parameter </ins> function renderStream(outputInfo: OutputItem, outputElement: HTMLElement, error: boolean, ctx: IRichRenderContext): IDisposable { const disposableStore = createDisposableStore(); const outputScrolling = scrollingEnabled(outputInfo, ctx.settings);


const scrollTop = outputScrolling ? findScrolledHeight(outputElement) : undefined; // If the previous output item for the same cell was also a stream, append this output to the previous <del> const existingContentParent = getPreviousMatchingContentGroup(outputElement); </del> <ins> const existingContentParent = getPreviousMatchingContentGroup(outputElement) || outputElement.querySelector('div'); </ins> if (existingContentParent) { const existing = existingContentParent.querySelector(`[output-item-id="${outputInfo.id}"]`) as HTMLElement | null; if (existing) {


const link = document.createElement('a'); link.textContent = '...'; link.href = `command:workbench.action.openLargeOutput?${outputId}`; <ins> link.ariaLabel = 'Open full output in text editor'; </ins> link.title = 'Open full output in text editor'; link.style.setProperty('text-decoration', 'none'); container.appendChild(link);


import { IRange, Range } from 'vs/editor/common/core/range'; import { getDefinitionsAtPosition } from 'vs/editor/contrib/gotoSymbol/browser/goToSymbol'; import { goToDefinitionWithLocation } from 'vs/editor/contrib/inlayHints/browser/inlayHintsLocations'; <del> import { Position } from 'vs/editor/common/core/position'; </del> <ins> import { IPosition, Position } from 'vs/editor/common/core/position'; </ins> import { CancellationTokenSource } from 'vs/base/common/cancellation'; import { ILanguageConfigurationService } from 'vs/editor/common/languages/languageConfigurationRegistry'; import { ILanguageFeatureDebounceService } from 'vs/editor/common/services/languageFeatureDebounce';


private _focusedStickyElementIndex: number = -1; private _enabled = false; private _focused = false; <ins> private _positionRevealed = false; private _onMouseDown = false; </ins> constructor( private readonly _editor: ICodeEditor,


const focusTracker = this._register(dom.trackFocus(this._stickyScrollWidget.getDomNode())); this._register(focusTracker.onDidBlur(_ => { const height = this._stickyScrollWidget.getDomNode().clientHeight; <del> if (height !== 0) { this._disposeFocusStickyScrollStore(); } else { // If the height is 0, then the blur has been caused by scrolling. In that case keep the focus on the sticky scroll. </del> <ins> // Suppose that the blurring is caused by scrolling, then keep the focus on the sticky scroll // This is determined by the fact that the height of the widget has become zero and there has been no position revealing if (this._positionRevealed === false && height === 0) { </ins> this._focusedStickyElementIndex = -1; this.focus(); <ins> } // In all other casees, dispose the focus on the sticky scroll else { this._disposeFocusStickyScrollStore(); </ins> } })); this._register(focusTracker.onDidFocus(_ => { this.focus(); })); this._register(this._createClickLinkGesture()); <ins> // Suppose that mouse down on the sticky scroll, then do not focus on the sticky scroll because this will be followed by the revealing of a position this._register(dom.addDisposableListener(this._stickyScrollWidget.getDomNode(), dom.EventType.MOUSE_DOWN, (e) => { this._onMouseDown = true; })); </ins> } get stickyScrollCandidateProvider(): IStickyLineCandidateProvider {


private _disposeFocusStickyScrollStore() { this._stickyScrollFocusedContextKey.set(false); <del> this._focusDisposableStore!.dispose(); </del> <ins> this._focusDisposableStore?.dispose(); </ins> this._focused = false; <ins> this._positionRevealed = false; this._onMouseDown = false; </ins> } public focus(): void { <ins> // If the mouse is down, do not focus on the sticky scroll if (this._onMouseDown) { this._onMouseDown = false; this._editor.focus(); return; } </ins> const focusState = this._stickyScrollFocusedContextKey.get(); if (focusState === true) { return;


public goToFocused(): void { const lineNumbers = this._stickyScrollWidget.lineNumbers; this._disposeFocusStickyScrollStore(); <del> this._editor.revealPosition({ lineNumber: lineNumbers[this._focusedStickyElementIndex], column: 1 }); </del> <ins> this._revealPosition({ lineNumber: lineNumbers[this._focusedStickyElementIndex], column: 1 }); } private _revealPosition(position: IPosition): void { this._positionRevealed = true; this._editor.revealPosition(position); this._editor.setSelection(Range.fromPositions(position)); this._editor.focus(); </ins> } private _createClickLinkGesture(): IDisposable {


if (this._focused) { this._disposeFocusStickyScrollStore(); } <del> this._editor.revealPosition({ lineNumber: this._stickyScrollWidget.hoverOnLine, column: 1 }); </del> <ins> this._revealPosition({ lineNumber: this._stickyScrollWidget.hoverOnLine, column: 1 }); </ins> } this._instaService.invokeFunction(goToDefinitionWithLocation, e, this._editor as IActiveCodeEditor, { uri: this._editor.getModel()!.uri, range: this._stickyRangeProjectedOnEditor! }); } else if (!e.isRightClick) { // Normal click <del> const position = { lineNumber: this._stickyScrollWidget.hoverOnLine, column: this._stickyScrollWidget.hoverOnColumn }; </del> if (this._focused) { this._disposeFocusStickyScrollStore(); } <del> this._editor.revealPosition(position); this._editor.setSelection(Range.fromPositions(position)); </del> <ins> this._revealPosition({ lineNumber: this._stickyScrollWidget.hoverOnLine, column: this._stickyScrollWidget.hoverOnColumn }); </ins> } })); return linkGestureStore;


import { AudioCue, IAudioCueService } from 'vs/platform/audioCues/browser/audioCueService'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { TerminalContextKeys } from 'vs/workbench/contrib/terminal/common/terminalContextKey'; <ins> import { withNullAsUndefined } from 'vs/base/common/types'; </ins> const enum CssClass { Active = 'active', Hide = 'hide' } <ins> interface IAccessibleBufferQuickPickItem extends IQuickPickItem { lineNumber: number; exitCode?: number; } </ins> export class AccessibleBufferWidget extends DisposableStore { private _accessibleBuffer: HTMLElement; private _bufferEditor: CodeEditorWidget;


private readonly _focusedContextKey: IContextKey<boolean>; private readonly _focusTracker: dom.IFocusTracker; private _inQuickPick = false; <del> private _prependNewLine = false; private _bufferToEditorIndex: Map<number, number> = new Map(); </del> constructor( private readonly _instance: ITerminalInstance,


if (insertion && model && lineCount > this._xterm.raw.rows) { const lineNumber = lineCount + 1; model.pushEditOperations(null, [{ <del> range: { startLineNumber: lineNumber, endLineNumber: lineNumber, startColumn: 1, endColumn: 1 }, text: this._getContent(true) </del> <ins> range: { startLineNumber: lineNumber, endLineNumber: lineNumber, startColumn: 1, endColumn: 1 }, text: this._getContent(1) </ins> }], () => []); } else { model = await this._getTextModel(this._instance.resource.with({ fragment: this._getContent() }));


this._bufferEditor.setScrollTop(this._bufferEditor.getScrollHeight()); } <del> async createQuickPick(): Promise<IQuickPick<IQuickPickItem> | undefined> { if (!this._focusedContextKey.get()) { await this.show(); } </del> <ins> async createQuickPick(): Promise<IQuickPick<IAccessibleBufferQuickPickItem> | undefined> { let currentPosition = withNullAsUndefined(this._bufferEditor.getPosition()); </ins> this._inQuickPick = true; const commands = this._instance.capabilities.get(TerminalCapability.CommandDetection)?.commands; if (!commands?.length) { return; } <del> const quickPickItems: IQuickPickItem[] = []; </del> <ins> const quickPickItems: IAccessibleBufferQuickPickItem[] = []; </ins> for (const command of commands) { <del> let line = command.marker?.line; </del> <ins> const line = command.marker?.line; </ins> if (!line || !command.command.length) { continue; } <del> line = this._bufferToEditorIndex.get(line); if (!line) { continue; } </del> quickPickItems.push( { label: localize('terminal.integrated.symbolQuickPick.labelNoExitCode', '{0}', command.command), <del> meta: JSON.stringify({ line: line + 1, exitCode: command.exitCode }) </del> <ins> lineNumber: line + 1, exitCode: command.exitCode </ins> }); } <del> const quickPick = this._quickInputService.createQuickPick<IQuickPickItem>(); </del> <ins> const quickPick = this._quickInputService.createQuickPick<IAccessibleBufferQuickPickItem>(); quickPick.canSelectMany = false; quickPick.onDidChangeActive(() => { const activeItem = quickPick.activeItems[0]; if (activeItem.exitCode) { this._audioCueService.playAudioCue(AudioCue.error, true); } this._bufferEditor.revealLine(activeItem.lineNumber, 0); }); quickPick.onDidHide(() => { if (currentPosition) { this._bufferEditor.setPosition(currentPosition); this._bufferEditor.revealLineInCenter(currentPosition.lineNumber); } quickPick.dispose(); this._inQuickPick = false; }); </ins> quickPick.onDidAccept(() => { const item = quickPick.activeItems[0]; const model = this._bufferEditor.getModel(); <del> if (!model || !item.meta) { </del> <ins> if (!model) { </ins> return; } <ins> if (!item && currentPosition) { // reset this._bufferEditor.setPosition(currentPosition); } else { this._bufferEditor.setSelection({ startLineNumber: item.lineNumber, startColumn: 1, endLineNumber: item.lineNumber, endColumn: 1 }); currentPosition = this._bufferEditor.getSelection()?.getPosition(); } </ins> quickPick.hide(); <del> const data: { line: number; exitCode: number } = JSON.parse(item.meta); this._bufferEditor.setSelection({ startLineNumber: data.line, startColumn: 1, endLineNumber: data.line, endColumn: 1 }); this._bufferEditor.revealLine(data.line); </del> this._inQuickPick = false; return; }); <del> quickPick.onDidChangeActive(() => { const data = quickPick.activeItems?.[0]?.meta; if (data && JSON.parse(data).exitCode) { this._audioCueService.playAudioCue(AudioCue.error, true); } }); </del> quickPick.items = quickPickItems.reverse(); return quickPick; } async show(): Promise<void> { await this._updateEditor(); <del> this._prependNewLine = true; </del> this._accessibleBuffer.tabIndex = -1; this._bufferEditor.layout({ width: this._xtermElement.clientWidth, height: this._xtermElement.clientHeight }); this._accessibleBuffer.classList.add(CssClass.Active);


this._bufferEditor.focus(); } <del> private async _getTextModel(resource: URI): Promise<ITextModel | null> { const existing = this._modelService.getModel(resource); if (existing && !existing.isDisposed()) { return existing; } return this._modelService.createModel(resource.fragment, null, resource, false); } private _getContent(lastBufferIndex?: boolean): string { const buffer = this._xterm?.raw.buffer.active; </del> <ins> private _getContent(startIndex?: number): string { const buffer = this._xterm.raw.buffer.active; </ins> if (!buffer) { return ''; }


const scrollback: number = this._configurationService.getValue(TerminalSettingId.Scrollback); const maxBufferSize = scrollback + this._xterm.raw.rows - 1; const end = Math.min(maxBufferSize, buffer.length - 1); <del> if (lastBufferIndex) { </del> <ins> if (startIndex) { </ins> // If the last buffer index is requested, this is as a result of // a dynamic addition. Return only the last line to prevent duplication. const line = buffer.getLine(end - 1)?.translateToString(false).replace(new RegExp(' ', 'g'), 'xA0'); <del> const result = line ? (this._prependNewLine ? 'n' : '') + line + 'n' : ''; this._prependNewLine = false; </del> <ins> const result = line ? line + 'n' : ''; </ins> return result; } <del> this._bufferToEditorIndex = new Map(); </del> const lines: string[] = []; let currentLine: string = ''; for (let i = 0; i <= end; i++) {


continue; } const isWrapped = buffer.getLine(i + 1)?.isWrapped; <del> this._bufferToEditorIndex.set(i, lines.length); </del> currentLine += line.translateToString(!isWrapped); if (currentLine && !isWrapped || i === end - 1) { lines.push(currentLine.replace(new RegExp(' ', 'g'), 'xA0'));


return lines.join('n'); } <ins> private async _getTextModel(resource: URI): Promise<ITextModel | null> { const existing = this._modelService.getModel(resource); if (existing && !existing.isDisposed()) { return existing; } return this._modelService.createModel(resource.fragment, null, resource, false); } </ins> }


<del> # Interactive Window The interactive window component enables extensions to offer REPL like experience to its users. VS Code provides the user interface and extensions provide the execution environment, code completions, execution results rendering and so on. The interactive window consists of notebook editor at the top and regular monaco editor at the bottom of the viewport. Extensions can extend the interactive window by leveraging the notebook editor API and text editor/document APIs: * Extensions register notebook controllers for the notebook document in the intearctive window through `vscode.notebooks.createNotebookController`. The notebook document has a special notebook view type `interactive`, which is contributed by the core instead of extensions. The registered notebook controller is responsible for execution. * Extensions register auto complete provider for the bottom text editor through `vscode.languages.registerCompletionItemProvider`. The resource scheme for the text editor is `interactive-input` and the language used in the editor is determined by the notebook controller contributed by extensions. Users can type in code in the text editor and after users pressing `Shift+Enter`, we will insert a new code cell into the notebook document with the content from the text editor. Then we will request execution for the newly inserted cell. The notebook controller will handle the execution just like it;s in a normal notebook editor. ## Intearactive Window registration Registering a new editor type in the workbench consists of two steps * Register an editor input factory which is responsible for resolving resources with given `glob` patterns. Here we register an `InteractiveWindowInput` for all resources with `vscode-interactive-input` scheme: `vscode-interactive-input:/**`. * Register an editor pane factory for the given editor input type. Here we register `InteractiveEditor` for our own editor input `InteractiveWindowInput`. The workbench editor service is not aware of how models are resolved in `EditorInput`, neither how `EditorPane`s are rendered. It only cares about the common states and events on `EditorInput` or `EditorPane`, i.e., display name, capabilities (editable), content change, dirty state change. It's `EditorInput`/`EditorPane`'s responsibility to provide the right info and updates to the editor service. One major difference between Interactive Editor and other editor panes is Interactive Window is never dirty so users never  see a dot on the editor title bar. ![editor registration](interactive.editor.drawio.svg) ## Interactive Window Editor Model Resolution The Interactive.open command will manually create an EditorInput specific for the Interactive Window and resolving that Input will go through the following workflow: The `NotebookEditorModelResolverService` will create a `NotebookFileWorkingCopyModelFactory` and use that to create a `WorkingCopyManager` which is then used to create a `SimpleNotebookEditorModel`. When the `SimpleNotebookEditorModel` is requested to `load`, it will ask the `WorkingCopyManager` to create a new `StoredWorkingCopy` which reads content from a resource URI with the `fileService`. That content is passed to the the `ModelFactory` which retreives a `NotebookSerializer` from the `notebookService` and constructs a `NotebookTextModel`. ![editor registration](interactive.model.resolution.drawio.svg) The `FileSystem` provider that is registered for `vscode-interactive` schema will always return an empty buffer for any read, and will drop all write requests as nothing is stored on disk for Interactive Window resources. The `notebookSerializer` that is registered for the `interactive` viewtype knows to return an empty notebook data model when it deserializes an empty buffer when the model is being resolved. Restoring the interactive window happens through the `EditorModelCache`, where the full notebook data is stored, and can be used to repopulate the `EditorInput` without needing to go through the editor model resolution flow, effectively skipping any filesystem reads. ## UI/EH editor/document syncing `EditorInput` is responsible for resolving models for the given resources but in Interactive Window it's much simpler as we are not resolving models ourselves but delegating to Notebook and TextEditor. `InteractiveEditorInput` does the coordination job. ![arch](interactive.eh.drawio.svg) </del>


<del> ## Find in Outputs * Find is no longer **synchronous** * Progress bar in Find Widget * Require all outputs to be rendered first * `window.find` * Shadow DOM nodes are skipped in non-chromium browsers * no builtin css rule for find match color * `hiliteColor` * Modifies DOM * Shadow DOM not supported, we can potentially have our own impl * Find match range serialization `document.getSelection` * `document.getSelection().getRangeAt(0).cloneRange()` not immutable, changed when document active selection changes * range will be invalid after `hiliteColor` executed * require our own serialization/deserialization * Performance * `window.find` can be slow * We currently travese the DOM tree to figure out which cell/output contain the find match belongs to, it's really costly. One idea is checking the absolute position of the find match and compare it with output container positions. * Search only rendered outputs * MutationObserver for output change * Change active selection to the beginning of the new output and then request `window.find` </del>


<del> The notebook editor is a virtualized list view rendered in two contexts (mainframe and webview/iframe). It's on top of the builtin list/tree view renderer but its experience is different from traditional list views like File Explorer and Settings Editor. This doc covers the architecture of the notebook editor and layout optimizations we experimented with. - [Architecture](#architecture) - [Notebook model resolution](#notebook-model-resolution) - [Viewport rendering](#viewport-rendering) - [Cell rendering](#cell-rendering) - [Focus Tracking](#focus-tracking) - [Optimizations](#optimizations) - [Avoid flickering on resize of cells above current viewport](#avoid-flickering-on-resize-of-cells-above-current-viewport) - [Executing code cell followed by markdown cells](#executing-code-cell-followed-by-markdown-cells) - [Re-executing code cell followed by markdown cells](#re-executing-code-cell-followed-by-markdown-cells) - [Scrolling](#scrolling) # Architecture ## Notebook model resolution The notebook model resolution consists of two main parts * Resolving the raw data (bytes) of the resource from file service. This part is backed by the `WorkingCopyService` and it will resolve the data and broadcast updates when the resource is updated on file system. * Requesting the contributed notebook serializer to serialize/deserize the raw bytes for the resource. We will find the best matched notebook serializer (by user's editor type configuration and serializer's selector definition) and convert the raw bytes from/to `NotebookTextModel`. `NotebookTextModel` is the only source of truth for the notebook document once the resource is opened in the workspace. The source text of each individual cell in the notebook is backed by a piece tree text buffer. When the notebook is opened in the editor group, we will request the `TextModelResolverService` for the monaco `TextModel` reference for each cell. The `TextModel` will use the piece tree text buffer from the cell as the backing store so whenever the `TextModel` gets updated, the cells in `NotebookTextModel` are always up to date.`` Since we are using the `TextModelResolverService` for cell's text model resolution, the `TextModel`s will have a mirror in the extension host, just like a normal resource opened in a text editor. Extensions can treat them as normal text documents. ![arch](https://user-images.githubusercontent.com/876920/141845889-abe0384e-0093-4b08-831a-04424a4b8101.png) ## Viewport rendering The viewport rendering of notebook list view is a "guess and validate" process. It will calcuate how many cells/rows it can render within the viewport first, have them all rendered, and then ask for their real dimensions, and based on the cell/row dimensions it will decide if it needs to render more cells (if there is still some room in the viewport) or remove a few. For short, the process is more or less * Render cell/row (DOM write) * Read dimensions (DOM read) The catch here is if we happen to perform any DOM read operation between DOM write while rendering a cell, it will trigger forced reflow and block the UI. To make it even worse, there are multiple components in a cell and often they are not aware of the existence of each other. When one component is updating its own DOM content, another component might be reading DOM dimensions at the same time. To prevent the unnecessary forced reflow from happening too often, we introduced the concept of `CellPart`. A `CellPart` is an abstract component in a cell and its lifecycle consists of four phases: * Creation. `CellPart` is usually created on cell template * Attach cell. When a cell is being rendered, we would attach the cell with all `CellPart`s by invoking `CellPart#renderCell`. * A subclass of `CellPart` should implement `CellPart#didRenderCell` to customize this phase * Read DOM dimensions. All DOM read operation should be performed in this phase to prepare for the layout update. `CellPart#prepareLayout` will invoked. * Update DOM positions. Once the list view finish reading DOM dimensions of all `CellPart`s, it will ask each `CellPart` to update its internal DOM nodes' positions, by invoking `CellPart#updateLayoutNow`. When we introduce new UI elements to notebook cell, we would make it a `CellPart` and ensure that we batch the DOM read and write operations in the right phases. ![render viewport](./viewport-rendering.drawio.svg) <!-- ![render in the core](https://user-images.githubusercontent.com/876920/142806570-a477d315-40f3-4e0c-8079-f2867d5f3e88.png) --> When the notebook document contains markdown cells or rich outputs, the workflow is a bit more complex and become asynchronous partially due to the fact the markdown and rich outputs are rendered in a separate webview/iframe. While the list view renders the cell/row, it will send requests to the webview for output rendering, the rendering result (like dimensions of the output elements) won't come back in current frame. Once we receive the output rendering results from the webview (say next frame), we would ask the list view to adjust the position/dimension of the cell and ones below. ![render outputs in the webview/iframe](https://user-images.githubusercontent.com/876920/142923784-4e7a297c-6ce4-4741-b306-cbfb3277699b.png) ## Cell rendering The rendering of cells in the notebook editor consists of following steps: * Update reused DOM nodes in the template and cell decorations * Set up context for the cell and toolbars * Update cell toolbar, run toolbar and insertion toolbar between cells * Render cell * Register listeners for: * Notebook layout change * Cell layout change * Cell state change: Folding, Collapse, Focus ## Focus Tracking Due to the nature of virtualization (list view) and two layers architecture, the focus tracking is more complex compared to file explorer or monaco editor. When a notebook is *focused*, the `document.activeElement` can be * Monaco editor, when users focus on a cell editor * `textarea` when users focus the text * Widgets * Webview/iframe, when users focus on markdown cell or rich outputs rendered rendered in iframe * List view container, when users focus on cell container * Focusable element inside the notebook editor * Builtin output (e.g., text output) * Find Widget * Cell statusbar * Toolbars The catch here is if the focus is on a monaco editor, instead of the list view container, when the cell is moved out of view, the list view removes the cell row from the DOM tree. The `document.activeElement` will fall back `document.body` when that happens. To ensure that the notebook editor doesn't blur, we need to move focus back to list view container when the focused cell is moved out of view. More importantly, focus the cell editor again when the cell is visible again (if the cell is still the *active* cell). Copy in Notebook depends on the focus tracking * Send `document.executeCommand('copy')` if users select text in output rendered in main frame by builtin renderer * Request webview copy if the focus is inside the webview * Copy cells if the focus is on notebook cell list * Copy text if the focus is in cell editor (monaco editor) ![diagram](https://user-images.githubusercontent.com/876920/141730905-2818043e-1a84-45d3-ad27-83bd89235ca5.png) # Optimizations Since most elements' positions are absolute and there is latency between the two frames, we have multiple optimizations to ensure smooth (we try our best) perceived user experience. The optimizations are mostly around: * Ensure the elements in current viewport are stable when other elements' dimensions update * Fewer layout messages between the main and iframe * Less flickering and forced reflow on scrolling While we continue optimizing the layout code, we need to make sure that the new optimization won't lead to regression in above three aspects. Here is a list of existing optimziations we already have and we want to make sure they still perform well when updating layout code. ## Avoid flickering on resize of cells above current viewport We always ensure that elements in current viewport are stable (their visual positions don't change) when cells above current viewport resize. Resizing a cell above viewport will then include following steps as shown in below diagram ![cell resize above viewport](./cell-resize-above-viewport.drawio.svg) 1. User scrolls to the middle of the document, with one markdown cell partially visible (blue box in the green container) and one code cell fully visible (blue box in the white container) 2. The code cell above current viewport grows by 50px. The list view will then push down every cell below it. Thus the code cell in the viewport will move down by 50px. In current tick/frame, the markdown preview elements in the webview are not updated yet thus it's still partially visible. 3. To ensure the code cell's position is stable, we would scroll the whole list view downwards by 50px. The code cell's position is now fixed but at the same time, the webview also moves up by 50px (as it's a child of the list view scrollable element). 4. Lastly we sent requests to the webview to fix the visual positions of markdown previews After the last step, both the code and markdown cells in the viewport stays where they were. However due to the fact that code cells and markdown cells are rendered in two different contexts (UI and iframe), there is always latency between step 3 and 4 so users will notice  annoying flickering of markdown cells easily. The fix is kind of "tricky". Instead of adjusting the position of the partially markdown cells, we can actually make it visually stable by adjusting the position of the webview element (step 4). That would mess up the positions of markdown cells above current viewport, but we can fix them in next frame/tick (step 5) and since they are never in the viewport, users won't notice their position flicker/shift. ## Executing code cell followed by markdown cells Code cell outputs and markdown cells are both rendered in the underlying webview. When executing a code cell, the list view will 1. Request cell output rendering in webview 2. Cell output height change 1. in the webview, we set `maxHeight: 0; overflow: hidden` on the output DOM node, then it won't overlap with the following markdown cells 2. broadcast the height change to the list view in main frame 3. List view received the height update request 1. Send acknowledge of the output height change to webview 2. Push down code cells below 3. Webview remove `maxHeight: 0` on the output DOM node Whether users would see flickering or overlap of outputs, monaco editor and markdown cells depends on the latency between 3.2 and 3.3. ## Re-executing code cell followed by markdown cells Re-executing code cell consists of two steps: 1. Remove old outputs, which will reset the output height to 0 2. Render new outputs, which will push elements below downwards The latency between 1 and 2 will cause the UI to flicker (as cells below this code cell will move upwards then downwards in a short period of time. However a lot of the time, we just tweak the code a bit and the outputs will have the same shape and very likely same rendered height, seeing the movement of cells below it is not pleasant. For example say we have code ```py print(1) ``` it will generate text output `1`. Updating the code to ```py print(2) ``` will genrate text output `2`. The re-rendering of the output is fast and we want to ensure the UI is stable in this scenario, to achieve this: 1. Clear existing output `1` 1. Remove the output DOM node, but we reserve the height of the output 2. In 200ms, we will reset the output height to `0`, unless there is a new output rendered 2. Received new output 1. Re-render the new output 2. Calcuate the height of the new output, update layout If the new output is rendered within 200ms, users won't see the UI movement. ## Scrolling Code cell outputs and markdown cells are rendered in the webview, which are async in nature. In order to have the cell outputs and markdown previews rendered when users scroll to them, we send rendering requests of cells in the next and previous viewport when it's idle. Thus scrolling is smoother. We also warm up all rendered markdown in the document, from top to bottom, when the browser is idle. We don't warm up outputs like this, since they can be more expensive to render than markdown. But outputs do get rendered when the user starts a search in outputs. </del>


private didLayout = false; private emptyViews: ISplitViewView<{ top: number; left: number }>[] | undefined; private readonly splitViewDisposables = new DisposableStore(); <del> private centeredLayoutFixedWidth = true; </del> constructor( private container: HTMLElement, private view: IView, <del> public state: CenteredViewState = { ...defaultState } </del> <ins> public state: CenteredViewState = { ...defaultState }, private centeredLayoutFixedWidth: boolean = false </ins> ) { this.container.appendChild(this.view.element); // Make sure to hide the split view overflow like sashes #52892


this.doCreateGridControl(options); // Centered layout widget <del> this.centeredLayoutWidget = this._register(new CenteredViewLayout(this.container, this.gridWidgetView, this.profileMemento[EditorPart.EDITOR_PART_CENTERED_VIEW_STORAGE_KEY])); </del> <ins> this.centeredLayoutWidget = this._register(new CenteredViewLayout(this.container, this.gridWidgetView, this.profileMemento[EditorPart.EDITOR_PART_CENTERED_VIEW_STORAGE_KEY], this._partOptions.centeredLayoutFixedWidth)); </ins> this._register(this.onDidChangeEditorPartOptions(e => this.centeredLayoutWidget.setFixedWidth(e.newPartOptions.centeredLayoutFixedWidth ?? false))); // Drag & Drop support


.pipe(util.skipDirectories()) .pipe(util.fixWin32DirectoryPermissions()) .pipe(filter(['**', '!**/.github/**'], { dot: true })) // https://github.com/microsoft/vscode/issues/116523 <del> .pipe(electron({ ...config, platform, arch: arch === 'armhf' ? 'arm' : arch, ffmpegChromium: true })) </del> <ins> .pipe(electron({ ...config, platform, arch: arch === 'armhf' ? 'arm' : arch, ffmpegChromium: false })) </ins> .pipe(filter(['**', '!LICENSE', '!LICENSES.chromium.html', '!version'], { dot: true })); if (platform === 'linux') {


}); } exports.config = { <del> version: product.electronRepository ? '22.4.4' : util.getElectronVersion(), </del> <ins> version: product.electronRepository ? '22.4.5' : util.getElectronVersion(), </ins> productAppName: product.nameLong, companyName: 'Microsoft Corporation', copyright: 'Copyright (C) 2023 Microsoft. All rights reserved',


const electronOpts = _.extend({}, exports.config, { platform: process.platform, arch: arch === 'armhf' ? 'arm' : arch, <del> ffmpegChromium: true, </del> <ins> ffmpegChromium: false, </ins> keepDefaultApp: true }); return vfs.src('package.json')