From 1fbb4c3095dd2345a34888cf082370f2f874bd89 Mon Sep 17 00:00:00 2001 From: Aman Khalid Date: Thu, 14 Apr 2022 13:18:52 -0400 Subject: [PATCH 001/347] Close #134566: Added settings for terminal tab default color/icon --- src/vs/platform/terminal/common/terminal.ts | 2 ++ .../browser/terminalProfileResolverService.ts | 12 ++++++++-- .../terminal/common/terminalConfiguration.ts | 22 +++++++++++++++++++ 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/vs/platform/terminal/common/terminal.ts b/src/vs/platform/terminal/common/terminal.ts index 32247de9d60..de83dc8e4ae 100644 --- a/src/vs/platform/terminal/common/terminal.ts +++ b/src/vs/platform/terminal/common/terminal.ts @@ -39,6 +39,8 @@ export const enum TerminalSettingId { DefaultProfileMacOs = 'terminal.integrated.defaultProfile.osx', DefaultProfileWindows = 'terminal.integrated.defaultProfile.windows', UseWslProfiles = 'terminal.integrated.useWslProfiles', + TabsDefaultColor = 'terminal.integrated.tabs.defaultColor', + TabsDefaultIcon = 'terminal.integrated.tabs.defaultIcon', TabsEnabled = 'terminal.integrated.tabs.enabled', TabsEnableAnimation = 'terminal.integrated.tabs.enableAnimation', TabsHideCondition = 'terminal.integrated.tabs.hideCondition', diff --git a/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts b/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts index 0849f6676b2..1554d580f33 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts @@ -16,6 +16,7 @@ import { IShellLaunchConfig, ITerminalProfile, ITerminalProfileObject, TerminalI import { IShellLaunchConfigResolveOptions, ITerminalProfileResolverService, ITerminalProfileService } from 'vs/workbench/contrib/terminal/common/terminal'; import * as path from 'vs/base/common/path'; import { Codicon } from 'vs/base/common/codicons'; +import { getIconRegistry, IIconRegistry } from 'vs/platform/theme/common/iconRegistry'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import { debounce } from 'vs/base/common/decorators'; import { ThemeIcon } from 'vs/platform/theme/common/themeService'; @@ -51,6 +52,8 @@ export abstract class BaseTerminalProfileResolverService implements ITerminalPro private _primaryBackendOs: OperatingSystem | undefined; + private readonly _iconRegistry: IIconRegistry = getIconRegistry(); + private _defaultProfileName: string | undefined; get defaultProfileName(): string | undefined { return this._defaultProfileName; } @@ -135,7 +138,10 @@ export abstract class BaseTerminalProfileResolverService implements ITerminalPro // Verify the icon is valid, and fallback correctly to the generic terminal id if there is // an issue - shellLaunchConfig.icon = this._getCustomIcon(shellLaunchConfig.icon) || this._getCustomIcon(resolvedProfile.icon) || Codicon.terminal; + shellLaunchConfig.icon = this._getCustomIcon(shellLaunchConfig.icon) + || this._getCustomIcon(resolvedProfile.icon) + || this._iconRegistry.getIcon(this._configurationService.getValue(TerminalSettingId.TabsDefaultIcon)) + || Codicon.terminal; // Override the name if specified if (resolvedProfile.overrideName) { @@ -143,7 +149,9 @@ export abstract class BaseTerminalProfileResolverService implements ITerminalPro } // Apply the color - shellLaunchConfig.color = shellLaunchConfig.color || resolvedProfile.color; + shellLaunchConfig.color = shellLaunchConfig.color + || resolvedProfile.color + || this._configurationService.getValue(TerminalSettingId.TabsDefaultColor); // Resolve useShellEnvironment based on the setting if it's not set if (shellLaunchConfig.useShellEnvironment === undefined) { diff --git a/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts b/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts index 4020b3e6fa0..27f5698ddb8 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts @@ -9,6 +9,7 @@ import { DEFAULT_LETTER_SPACING, DEFAULT_LINE_HEIGHT, TerminalCursorStyle, DEFAU import { TerminalLocationString, TerminalSettingId } from 'vs/platform/terminal/common/terminal'; import { isMacintosh, isWindows } from 'vs/base/common/platform'; import { Registry } from 'vs/platform/registry/common/platform'; +import { Codicon } from 'vs/base/common/codicons'; const terminalDescriptors = '\n- ' + [ '`\${cwd}`: ' + localize("cwd", "the terminal's current working directory"), @@ -38,6 +39,27 @@ const terminalConfiguration: IConfigurationNode = { type: 'boolean', default: false }, + [TerminalSettingId.TabsDefaultColor]: { + description: localize('terminal.integrated.tabs.defaultColor', "Controls the terminal tab icon's default color."), + type: 'string', + enum: [ + 'terminal.ansiBlack', + 'terminal.ansiRed', + 'terminal.ansiGreen', + 'terminal.ansiYellow', + 'terminal.ansiBlue', + 'terminal.ansiMagenta', + 'terminal.ansiCyan', + 'terminal.ansiWhite' + ], + default: undefined, + }, + [TerminalSettingId.TabsDefaultIcon]: { + description: localize('terminal.integrated.tabs.defaultIcon', "Controls the terminal tab's default icon."), + type: 'string', + enum: Codicon.getAll().map(icon => icon.id), + default: undefined, + }, [TerminalSettingId.TabsEnabled]: { description: localize('terminal.integrated.tabs.enabled', 'Controls whether terminal tabs display as a list to the side of the terminal. When this is disabled a dropdown will display instead.'), type: 'boolean', From 71c15eac23c7cf2e32b3ed8222c6ac4d35c614ba Mon Sep 17 00:00:00 2001 From: Stephen Sigwart Date: Sat, 11 Jun 2022 20:57:05 -0400 Subject: [PATCH 002/347] Fix terminals in editor area not reloading - Closes #140429 - This isn't perfect because it just reopens then without setting the original location, but at least it reloads them. --- src/vs/platform/terminal/common/terminal.ts | 5 +++ .../terminal/common/terminalProcess.ts | 3 +- src/vs/platform/terminal/node/ptyService.ts | 26 ++++++++++++-- .../terminal/browser/terminalService.ts | 35 +++++++++++++++++-- .../terminal/common/remoteTerminalChannel.ts | 3 +- .../electron-sandbox/localTerminalBackend.ts | 3 +- 6 files changed, 67 insertions(+), 8 deletions(-) diff --git a/src/vs/platform/terminal/common/terminal.ts b/src/vs/platform/terminal/common/terminal.ts index 91b3244bd3f..a368b53f6c7 100644 --- a/src/vs/platform/terminal/common/terminal.ts +++ b/src/vs/platform/terminal/common/terminal.ts @@ -133,6 +133,9 @@ export interface IRawTerminalInstanceLayoutInfo { relativeSize: number; terminal: T; } +export interface IRawTerminalEditorInstanceLayoutInfo { + terminal: T; +} export type ITerminalInstanceLayoutInfoById = IRawTerminalInstanceLayoutInfo; export type ITerminalInstanceLayoutInfo = IRawTerminalInstanceLayoutInfo; @@ -143,9 +146,11 @@ export interface IRawTerminalTabLayoutInfo { } export type ITerminalTabLayoutInfoById = IRawTerminalTabLayoutInfo; +export type ITerminalEditorInstanceLayoutInfoById = IRawTerminalEditorInstanceLayoutInfo; export interface IRawTerminalsLayoutInfo { tabs: IRawTerminalTabLayoutInfo[]; + editorTerminals: IRawTerminalEditorInstanceLayoutInfo[]; } export interface IPtyHostAttachTarget { diff --git a/src/vs/platform/terminal/common/terminalProcess.ts b/src/vs/platform/terminal/common/terminalProcess.ts index dea87c461a1..d949d919061 100644 --- a/src/vs/platform/terminal/common/terminalProcess.ts +++ b/src/vs/platform/terminal/common/terminalProcess.ts @@ -5,7 +5,7 @@ import { UriComponents } from 'vs/base/common/uri'; import { ISerializableEnvironmentVariableCollection } from 'vs/platform/terminal/common/environmentVariable'; -import { IFixedTerminalDimensions, IRawTerminalTabLayoutInfo, ITerminalEnvironment, ITerminalTabLayoutInfoById, TerminalIcon, TitleEventSource } from 'vs/platform/terminal/common/terminal'; +import { IFixedTerminalDimensions, IRawTerminalTabLayoutInfo, ITerminalEnvironment, ITerminalTabLayoutInfoById, ITerminalEditorInstanceLayoutInfoById, TerminalIcon, TitleEventSource } from 'vs/platform/terminal/common/terminal'; export interface ISingleTerminalConfiguration { userValue: T | undefined; @@ -41,6 +41,7 @@ export interface IWorkspaceFolderData { export interface ISetTerminalLayoutInfoArgs { workspaceId: string; tabs: ITerminalTabLayoutInfoById[]; + editorTerminals: ITerminalEditorInstanceLayoutInfoById[]; } export interface IGetTerminalLayoutInfoArgs { diff --git a/src/vs/platform/terminal/node/ptyService.ts b/src/vs/platform/terminal/node/ptyService.ts index 397fee9a493..250c44a2838 100644 --- a/src/vs/platform/terminal/node/ptyService.ts +++ b/src/vs/platform/terminal/node/ptyService.ts @@ -12,7 +12,7 @@ import { URI } from 'vs/base/common/uri'; import { getSystemShell } from 'vs/base/node/shell'; import { ILogService } from 'vs/platform/log/common/log'; import { RequestStore } from 'vs/platform/terminal/common/requestStore'; -import { IProcessDataEvent, IProcessReadyEvent, IPtyService, IRawTerminalInstanceLayoutInfo, IReconnectConstants, IRequestResolveVariablesEvent, IShellLaunchConfig, ITerminalInstanceLayoutInfoById, ITerminalLaunchError, ITerminalsLayoutInfo, ITerminalTabLayoutInfoById, TerminalIcon, IProcessProperty, TitleEventSource, ProcessPropertyType, IProcessPropertyMap, IFixedTerminalDimensions, IPersistentTerminalProcessLaunchConfig, ICrossVersionSerializedTerminalState, ISerializedTerminalState, ITerminalProcessOptions } from 'vs/platform/terminal/common/terminal'; +import { IProcessDataEvent, IProcessReadyEvent, IPtyService, IRawTerminalInstanceLayoutInfo, IReconnectConstants, IRequestResolveVariablesEvent, IShellLaunchConfig, ITerminalInstanceLayoutInfoById, ITerminalLaunchError, ITerminalsLayoutInfo, ITerminalTabLayoutInfoById, TerminalIcon, IProcessProperty, TitleEventSource, ProcessPropertyType, IProcessPropertyMap, IFixedTerminalDimensions, IPersistentTerminalProcessLaunchConfig, ICrossVersionSerializedTerminalState, ISerializedTerminalState, ITerminalProcessOptions, ITerminalEditorInstanceLayoutInfoById, IRawTerminalEditorInstanceLayoutInfo } from 'vs/platform/terminal/common/terminal'; import { TerminalDataBufferer } from 'vs/platform/terminal/common/terminalDataBuffering'; import { escapeNonWindowsPath } from 'vs/platform/terminal/common/terminalEnvironment'; import { Terminal as XtermTerminal } from 'xterm-headless'; @@ -343,8 +343,12 @@ export class PtyService extends Disposable implements IPtyService { if (layout) { const expandedTabs = await Promise.all(layout.tabs.map(async tab => this._expandTerminalTab(tab))); const tabs = expandedTabs.filter(t => t.terminals.length > 0); + const expandedEditors = await Promise.all(layout.editorTerminals.map(async editorTerminal => this._expandTerminalEditorInstance(editorTerminal))); this._logService.trace('ptyService#returnLayoutInfo', tabs); - return { tabs }; + return { + tabs, + editorTerminals: expandedEditors + }; } return undefined; } @@ -379,6 +383,24 @@ export class PtyService extends Disposable implements IPtyService { } } + private async _expandTerminalEditorInstance(t: ITerminalEditorInstanceLayoutInfoById): Promise> { + try { + const revivedPtyId = this._revivedPtyIdMap.get(t.terminal)?.newId; + const persistentProcessId = revivedPtyId ?? t.terminal; + const persistentProcess = this._throwIfNoPty(persistentProcessId); + const processDetails = persistentProcess && await this._buildProcessDetails(t.terminal, persistentProcess, revivedPtyId !== undefined); + return { + terminal: { ...processDetails, id: persistentProcessId } ?? null + }; + } catch (e) { + this._logService.trace(`Couldn't get layout info, a terminal was probably disconnected`, e.message); + // this will be filtered out and not reconnected + return { + terminal: null + }; + } + } + private async _buildProcessDetails(id: number, persistentProcess: PersistentTerminalProcess, wasRevived: boolean = false): Promise { // If the process was just revived, don't do the orphan check as it will // take some time diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 62d52e82cc9..4bb83addb42 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -403,8 +403,18 @@ export class TerminalService implements ITerminalService { return; } const layoutInfo = await localBackend.getTerminalLayoutInfo(); - if (layoutInfo && layoutInfo.tabs.length > 0) { - await this._recreateTerminalGroups(layoutInfo); + if (layoutInfo) { + if (layoutInfo.tabs.length > 0) { + await this._recreateTerminalGroups(layoutInfo); + } + if (layoutInfo.editorTerminals && layoutInfo.editorTerminals.length > 0) { + for (const editorTerminal of layoutInfo.editorTerminals) { + await this.createTerminal({ + config: { attachPersistentProcess: editorTerminal.terminal! }, + location: TerminalLocation.Editor + }); + } + } } // now that terminals have been restored, // attach listeners to update local state when terminals are changed @@ -642,7 +652,26 @@ export class TerminalService implements ITerminalService { return; } const tabs = this._terminalGroupService.groups.map(g => g.getLayoutInfo(g === this._terminalGroupService.activeGroup)); - const state: ITerminalsLayoutInfoById = { tabs }; + + // Save terminals in editors too + const seenPersistentProcessIds: number[] = []; + for (const t of tabs) { + for (const term of t.terminals) { + seenPersistentProcessIds.push(term.terminal); + } + } + const otherInstances = this.instances.filter(instance => typeof instance.persistentProcessId === 'number' && instance.shouldPersist && seenPersistentProcessIds.indexOf(instance.persistentProcessId) === -1); + const editorTerminals = otherInstances.map((instance) => { + instance. + return { + terminal: instance.persistentProcessId || 0 + }; + }); + + const state: ITerminalsLayoutInfoById = { + tabs, + editorTerminals + }; this._primaryBackend?.setTerminalLayoutInfo(state); } diff --git a/src/vs/workbench/contrib/terminal/common/remoteTerminalChannel.ts b/src/vs/workbench/contrib/terminal/common/remoteTerminalChannel.ts index e8c7da68932..a41a5f89716 100644 --- a/src/vs/workbench/contrib/terminal/common/remoteTerminalChannel.ts +++ b/src/vs/workbench/contrib/terminal/common/remoteTerminalChannel.ts @@ -266,7 +266,8 @@ export class RemoteTerminalChannelClient implements IPtyHostController { const workspace = this._workspaceContextService.getWorkspace(); const args: ISetTerminalLayoutInfoArgs = { workspaceId: workspace.id, - tabs: layout ? layout.tabs : [] + tabs: layout ? layout.tabs : [], + editorTerminals: layout ? layout.editorTerminals : [] }; return this._channel.call('$setTerminalLayoutInfo', args); } diff --git a/src/vs/workbench/contrib/terminal/electron-sandbox/localTerminalBackend.ts b/src/vs/workbench/contrib/terminal/electron-sandbox/localTerminalBackend.ts index b2f01c3e853..e423da8a59f 100644 --- a/src/vs/workbench/contrib/terminal/electron-sandbox/localTerminalBackend.ts +++ b/src/vs/workbench/contrib/terminal/electron-sandbox/localTerminalBackend.ts @@ -199,7 +199,8 @@ class LocalTerminalBackend extends BaseTerminalBackend implements ITerminalBacke async setTerminalLayoutInfo(layoutInfo?: ITerminalsLayoutInfoById): Promise { const args: ISetTerminalLayoutInfoArgs = { workspaceId: this._getWorkspaceId(), - tabs: layoutInfo ? layoutInfo.tabs : [] + tabs: layoutInfo ? layoutInfo.tabs : [], + editorTerminals: layoutInfo ? layoutInfo.editorTerminals : [] }; await this._localPtyService.setTerminalLayoutInfo(args); // Store in the storage service as well to be used when reviving processes as normally this From f33aeb876f2acd410693ccd241b667ce4173fd09 Mon Sep 17 00:00:00 2001 From: Stephen Sigwart Date: Sat, 11 Jun 2022 21:07:33 -0400 Subject: [PATCH 003/347] Fix accidental line of code --- src/vs/workbench/contrib/terminal/browser/terminalService.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 4bb83addb42..e8b200aa2f1 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -662,8 +662,7 @@ export class TerminalService implements ITerminalService { } const otherInstances = this.instances.filter(instance => typeof instance.persistentProcessId === 'number' && instance.shouldPersist && seenPersistentProcessIds.indexOf(instance.persistentProcessId) === -1); const editorTerminals = otherInstances.map((instance) => { - instance. - return { + return { terminal: instance.persistentProcessId || 0 }; }); From dda67a9626ebc385dd2f9ff6a649d2dd6d3df299 Mon Sep 17 00:00:00 2001 From: Stephen Sigwart Date: Mon, 13 Jun 2022 23:17:05 -0400 Subject: [PATCH 004/347] Fix suggestion widget hanging. Closes #152010 --- src/vs/editor/contrib/suggest/browser/suggestWidgetDetails.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/suggest/browser/suggestWidgetDetails.ts b/src/vs/editor/contrib/suggest/browser/suggestWidgetDetails.ts index fc4a44920ed..bfea6618d0d 100644 --- a/src/vs/editor/contrib/suggest/browser/suggestWidgetDetails.ts +++ b/src/vs/editor/contrib/suggest/browser/suggestWidgetDetails.ts @@ -173,7 +173,7 @@ export class SuggestDetailsWidget { const renderedContents = this._markdownRenderer.render(documentation); this._docs.appendChild(renderedContents.element); this._renderDisposeable.add(renderedContents); - this._renderDisposeable.add(this._markdownRenderer.onDidRenderAsync(() => { + this._renderDisposeable.add(Event.debounce(this._markdownRenderer.onDidRenderAsync, () => (last: Event, event: Event) => event, 50)(() => { this.layout(this._size.width, this._type.clientHeight + this._docs.clientHeight); this._onDidChangeContents.fire(this); })); From f1008c80bbcc9a170f0686c12eaa8da9c4d91504 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Tue, 14 Jun 2022 21:54:33 -0700 Subject: [PATCH 005/347] fix imports --- src/vs/platform/terminal/common/terminalProcess.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/vs/platform/terminal/common/terminalProcess.ts b/src/vs/platform/terminal/common/terminalProcess.ts index 09ae38589cf..980c345a6bd 100644 --- a/src/vs/platform/terminal/common/terminalProcess.ts +++ b/src/vs/platform/terminal/common/terminalProcess.ts @@ -5,9 +5,7 @@ import { UriComponents } from 'vs/base/common/uri'; import { ISerializableEnvironmentVariableCollection } from 'vs/platform/terminal/common/environmentVariable'; -import { IFixedTerminalDimensions, IRawTerminalTabLayoutInfo, ITerminalEnvironment, ITerminalTabLayoutInfoById, ITerminalEditorInstanceLayoutInfoById, TerminalIcon, TitleEventSource } from 'vs/platform/terminal/common/terminal'; -import { ISerializableEnvironmentVariableCollection, ISerializableEnvironmentVariableCollections } from 'vs/platform/terminal/common/environmentVariable'; -import { IFixedTerminalDimensions, IRawTerminalTabLayoutInfo, ITerminalEnvironment, ITerminalTabLayoutInfoById, TerminalIcon, TitleEventSource } from 'vs/platform/terminal/common/terminal'; +import { IFixedTerminalDimensions, IRawTerminalTabLayoutInfo, ITerminalEditorInstanceLayoutInfoById, ITerminalEnvironment, ITerminalTabLayoutInfoById, TerminalIcon, TitleEventSource } from 'vs/platform/terminal/common/terminal'; export interface ISingleTerminalConfiguration { userValue: T | undefined; @@ -62,7 +60,7 @@ export interface IProcessDetails { icon: TerminalIcon | undefined; color: string | undefined; fixedDimensions: IFixedTerminalDimensions | undefined; - environmentVariableCollections: ISerializableEnvironmentVariableCollections | undefined; + environmentVariableCollections: ISerializableEnvironmentVariableCollection | undefined; } export type ITerminalTabLayoutInfoDto = IRawTerminalTabLayoutInfo; From a084f63f4d3e5477efbcd8851008e8d996a45681 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Wed, 15 Jun 2022 10:17:53 -0700 Subject: [PATCH 006/347] fix issues --- src/vs/platform/terminal/common/terminalProcess.ts | 4 ++-- src/vs/workbench/contrib/terminal/browser/terminalService.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/platform/terminal/common/terminalProcess.ts b/src/vs/platform/terminal/common/terminalProcess.ts index 980c345a6bd..fa7e3252db1 100644 --- a/src/vs/platform/terminal/common/terminalProcess.ts +++ b/src/vs/platform/terminal/common/terminalProcess.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { UriComponents } from 'vs/base/common/uri'; -import { ISerializableEnvironmentVariableCollection } from 'vs/platform/terminal/common/environmentVariable'; +import { ISerializableEnvironmentVariableCollection, ISerializableEnvironmentVariableCollections } from 'vs/platform/terminal/common/environmentVariable'; import { IFixedTerminalDimensions, IRawTerminalTabLayoutInfo, ITerminalEditorInstanceLayoutInfoById, ITerminalEnvironment, ITerminalTabLayoutInfoById, TerminalIcon, TitleEventSource } from 'vs/platform/terminal/common/terminal'; export interface ISingleTerminalConfiguration { @@ -60,7 +60,7 @@ export interface IProcessDetails { icon: TerminalIcon | undefined; color: string | undefined; fixedDimensions: IFixedTerminalDimensions | undefined; - environmentVariableCollections: ISerializableEnvironmentVariableCollection | undefined; + environmentVariableCollections: ISerializableEnvironmentVariableCollections | undefined; } export type ITerminalTabLayoutInfoDto = IRawTerminalTabLayoutInfo; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index f9ba263232c..02072ae283c 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -21,6 +21,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { ILogService } from 'vs/platform/log/common/log'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { ICreateContributedTerminalProfileOptions, IShellLaunchConfig, ITerminalLaunchError, ITerminalsLayoutInfo, ITerminalsLayoutInfoById, TerminalLocation, TerminalLocationString, TitleEventSource } from 'vs/platform/terminal/common/terminal'; +import { formatMessageForTerminal } from 'vs/platform/terminal/common/terminalStrings'; import { iconForeground } from 'vs/platform/theme/common/colorRegistry'; import { getIconRegistry } from 'vs/platform/theme/common/iconRegistry'; import { ColorScheme } from 'vs/platform/theme/common/theme'; @@ -38,7 +39,6 @@ import { getInstanceFromResource, getTerminalUri, parseTerminalUri } from 'vs/wo import { TerminalViewPane } from 'vs/workbench/contrib/terminal/browser/terminalView'; import { IRemoteTerminalAttachTarget, IStartExtensionTerminalRequest, ITerminalBackend, ITerminalConfigHelper, ITerminalProcessExtHostProxy, ITerminalProfileService, TERMINAL_VIEW_ID } from 'vs/workbench/contrib/terminal/common/terminal'; import { TerminalContextKeys } from 'vs/workbench/contrib/terminal/common/terminalContextKey'; -import { formatMessageForTerminal } from 'vs/platform/terminal/common/terminalStrings'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { ACTIVE_GROUP, IEditorService, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; From 399a12432e975960ed528cb89ea6a8ef87b1fd79 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 16 Jun 2022 08:40:21 -0700 Subject: [PATCH 007/347] Remove [Unsupported] annotation from title bar We now rely on Help > About and issue reporter to call out unsupported builds, the title bar is just a nuisance to users now. Fixes #151104 --- src/vs/workbench/browser/parts/titlebar/windowTitle.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/vs/workbench/browser/parts/titlebar/windowTitle.ts b/src/vs/workbench/browser/parts/titlebar/windowTitle.ts index 5f5e16ead26..9e9922b840a 100644 --- a/src/vs/workbench/browser/parts/titlebar/windowTitle.ts +++ b/src/vs/workbench/browser/parts/titlebar/windowTitle.ts @@ -27,7 +27,6 @@ import { getVirtualWorkspaceLocation } from 'vs/platform/workspace/common/virtua export class WindowTitle extends Disposable { - private static readonly NLS_UNSUPPORTED = localize('patchedWindowTitle', "[Unsupported]"); private static readonly NLS_USER_IS_ADMIN = isWindows ? localize('userIsAdmin', "[Administrator]") : localize('userIsSudo', "[Superuser]"); private static readonly NLS_EXTENSION_HOST = localize('devExtensionWindowTitlePrefix', "[Extension Development Host]"); private static readonly TITLE_DIRTY = '\u25cf '; @@ -137,11 +136,6 @@ export class WindowTitle extends Disposable { if (this.properties.isAdmin) { suffix = WindowTitle.NLS_USER_IS_ADMIN; } - if (!this.properties.isPure) { - suffix = !suffix - ? WindowTitle.NLS_UNSUPPORTED - : `${suffix} ${WindowTitle.NLS_UNSUPPORTED}`; - } return { prefix, suffix }; } From bc7344685d7213a16a1a0c43d8287d824692c4ae Mon Sep 17 00:00:00 2001 From: meganrogge Date: Fri, 17 Jun 2022 08:51:28 -0700 Subject: [PATCH 008/347] check length of editor terminals --- .../terminal/browser/terminalEditorService.ts | 2 ++ .../contrib/terminal/browser/terminalService.ts | 16 ++++++++++------ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts b/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts index aec68ee5d91..5a501adebd2 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts @@ -93,6 +93,7 @@ export class TerminalEditorService extends Disposable implements ITerminalEditor // Remove the terminal from the managed instances when the editor closes. This fires when // dragging and dropping to another editor or closing the editor via cmd/ctrl+w. this._register(this._editorService.onDidCloseEditor(e => { + console.log('closed editor'); const instance = e.editor instanceof TerminalEditorInput ? e.editor.terminalInstance : undefined; if (instance) { const instanceIndex = this.instances.findIndex(e => e === instance); @@ -100,6 +101,7 @@ export class TerminalEditorService extends Disposable implements ITerminalEditor this.instances.splice(instanceIndex, 1); } } + console.log(this.instances); })); this._register(this._editorService.onDidActiveEditorChange(() => { const instance = this._editorService.activeEditor instanceof TerminalEditorInput ? this._editorService.activeEditor : undefined; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 02072ae283c..4d1220d4375 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -407,12 +407,16 @@ export class TerminalService implements ITerminalService { if (layoutInfo.tabs.length > 0) { await this._recreateTerminalGroups(layoutInfo); } - if (layoutInfo.editorTerminals && layoutInfo.editorTerminals.length > 0) { - for (const editorTerminal of layoutInfo.editorTerminals) { - await this.createTerminal({ - config: { attachPersistentProcess: editorTerminal.terminal! }, - location: TerminalLocation.Editor - }); + if (this._terminalEditorService.instances.length === 0) { + // only do this for restart because editor terminals are already restored + // on reload + if (layoutInfo.editorTerminals && layoutInfo.editorTerminals.length > 0) { + for (const editorTerminal of layoutInfo.editorTerminals) { + await this.createTerminal({ + config: { attachPersistentProcess: editorTerminal.terminal! }, + location: TerminalLocation.Editor + }); + } } } } From 7aa326e2d7a802cb8622842309e10196ce228b53 Mon Sep 17 00:00:00 2001 From: Stephen Sigwart Date: Sat, 18 Jun 2022 15:26:59 -0400 Subject: [PATCH 009/347] Get info from terminal editor - The issue is `_onWillShutdown` is called before `TerminalInputSerializer` serializes, so I added `shutdownPersistentProcessId`. - When restoring the editor, it was using the wrong ID, so I added `getRevivedPtyNewId`. --- src/vs/platform/terminal/common/terminal.ts | 8 +--- .../terminal/common/terminalProcess.ts | 3 +- .../platform/terminal/node/ptyHostService.ts | 4 ++ src/vs/platform/terminal/node/ptyService.ts | 34 +++++---------- src/vs/server/node/remoteTerminalChannel.ts | 1 + .../terminal/browser/remoteTerminalBackend.ts | 17 ++++++++ .../contrib/terminal/browser/terminal.ts | 5 +++ .../terminal/browser/terminalEditorService.ts | 3 +- .../terminal/browser/terminalInstance.ts | 8 +++- .../browser/terminalProcessManager.ts | 2 +- .../terminal/browser/terminalService.ts | 41 ++++--------------- .../terminal/common/remoteTerminalChannel.ts | 7 +++- .../contrib/terminal/common/terminal.ts | 1 + .../electron-sandbox/localTerminalBackend.ts | 16 +++++++- 14 files changed, 78 insertions(+), 72 deletions(-) diff --git a/src/vs/platform/terminal/common/terminal.ts b/src/vs/platform/terminal/common/terminal.ts index fefc6dfe936..4bd9644b0b1 100644 --- a/src/vs/platform/terminal/common/terminal.ts +++ b/src/vs/platform/terminal/common/terminal.ts @@ -134,9 +134,6 @@ export interface IRawTerminalInstanceLayoutInfo { relativeSize: number; terminal: T; } -export interface IRawTerminalEditorInstanceLayoutInfo { - terminal: T; -} export type ITerminalInstanceLayoutInfoById = IRawTerminalInstanceLayoutInfo; export type ITerminalInstanceLayoutInfo = IRawTerminalInstanceLayoutInfo; @@ -147,11 +144,9 @@ export interface IRawTerminalTabLayoutInfo { } export type ITerminalTabLayoutInfoById = IRawTerminalTabLayoutInfo; -export type ITerminalEditorInstanceLayoutInfoById = IRawTerminalEditorInstanceLayoutInfo; export interface IRawTerminalsLayoutInfo { tabs: IRawTerminalTabLayoutInfo[]; - editorTerminals: IRawTerminalEditorInstanceLayoutInfo[]; } export interface IPtyHostAttachTarget { @@ -317,6 +312,7 @@ export interface IPtyService extends IPtyHostController { getProfiles?(workspaceId: string, profiles: unknown, defaultProfile: unknown, includeDetectedProfiles?: boolean): Promise; getEnvironment(): Promise; getWslPath(original: string): Promise; + getRevivedPtyNewId(id: number): Promise; setTerminalLayoutInfo(args: ISetTerminalLayoutInfoArgs): Promise; getTerminalLayoutInfo(args: IGetTerminalLayoutInfoArgs): Promise; reduceConnectionGraceTime(): Promise; @@ -463,7 +459,7 @@ export interface IShellLaunchConfig { /** * This is a terminal that attaches to an already running terminal. */ - attachPersistentProcess?: { id: number; pid: number; title: string; titleSource: TitleEventSource; cwd: string; icon?: TerminalIcon; color?: string; hasChildProcesses?: boolean; fixedDimensions?: IFixedTerminalDimensions; environmentVariableCollections?: ISerializableEnvironmentVariableCollections }; + attachPersistentProcess?: { id: number; findRevivedId?: boolean; pid: number; title: string; titleSource: TitleEventSource; cwd: string; icon?: TerminalIcon; color?: string; hasChildProcesses?: boolean; fixedDimensions?: IFixedTerminalDimensions; environmentVariableCollections?: ISerializableEnvironmentVariableCollections }; /** * Whether the terminal process environment should be exactly as provided in diff --git a/src/vs/platform/terminal/common/terminalProcess.ts b/src/vs/platform/terminal/common/terminalProcess.ts index fa7e3252db1..f89a48394a5 100644 --- a/src/vs/platform/terminal/common/terminalProcess.ts +++ b/src/vs/platform/terminal/common/terminalProcess.ts @@ -5,7 +5,7 @@ import { UriComponents } from 'vs/base/common/uri'; import { ISerializableEnvironmentVariableCollection, ISerializableEnvironmentVariableCollections } from 'vs/platform/terminal/common/environmentVariable'; -import { IFixedTerminalDimensions, IRawTerminalTabLayoutInfo, ITerminalEditorInstanceLayoutInfoById, ITerminalEnvironment, ITerminalTabLayoutInfoById, TerminalIcon, TitleEventSource } from 'vs/platform/terminal/common/terminal'; +import { IFixedTerminalDimensions, IRawTerminalTabLayoutInfo, ITerminalEnvironment, ITerminalTabLayoutInfoById, TerminalIcon, TitleEventSource } from 'vs/platform/terminal/common/terminal'; export interface ISingleTerminalConfiguration { userValue: T | undefined; @@ -41,7 +41,6 @@ export interface IWorkspaceFolderData { export interface ISetTerminalLayoutInfoArgs { workspaceId: string; tabs: ITerminalTabLayoutInfoById[]; - editorTerminals: ITerminalEditorInstanceLayoutInfoById[]; } export interface IGetTerminalLayoutInfoArgs { diff --git a/src/vs/platform/terminal/node/ptyHostService.ts b/src/vs/platform/terminal/node/ptyHostService.ts index b7679d75f90..2f4371ddcef 100644 --- a/src/vs/platform/terminal/node/ptyHostService.ts +++ b/src/vs/platform/terminal/node/ptyHostService.ts @@ -296,6 +296,10 @@ export class PtyHostService extends Disposable implements IPtyService { return this._proxy.getWslPath(original); } + getRevivedPtyNewId(id: number): Promise { + return this._proxy.getRevivedPtyNewId(id); + } + setTerminalLayoutInfo(args: ISetTerminalLayoutInfoArgs): Promise { return this._proxy.setTerminalLayoutInfo(args); } diff --git a/src/vs/platform/terminal/node/ptyService.ts b/src/vs/platform/terminal/node/ptyService.ts index 09341482551..659a2f7f500 100644 --- a/src/vs/platform/terminal/node/ptyService.ts +++ b/src/vs/platform/terminal/node/ptyService.ts @@ -12,7 +12,7 @@ import { URI } from 'vs/base/common/uri'; import { getSystemShell } from 'vs/base/node/shell'; import { ILogService } from 'vs/platform/log/common/log'; import { RequestStore } from 'vs/platform/terminal/common/requestStore'; -import { IProcessDataEvent, IProcessReadyEvent, IPtyService, IRawTerminalInstanceLayoutInfo, IReconnectConstants, IRequestResolveVariablesEvent, IShellLaunchConfig, ITerminalInstanceLayoutInfoById, ITerminalLaunchError, ITerminalsLayoutInfo, ITerminalTabLayoutInfoById, TerminalIcon, IProcessProperty, TitleEventSource, ProcessPropertyType, IProcessPropertyMap, IFixedTerminalDimensions, IPersistentTerminalProcessLaunchConfig, ICrossVersionSerializedTerminalState, ISerializedTerminalState, ITerminalProcessOptions, ITerminalEditorInstanceLayoutInfoById, IRawTerminalEditorInstanceLayoutInfo } from 'vs/platform/terminal/common/terminal'; +import { IProcessDataEvent, IProcessReadyEvent, IPtyService, IRawTerminalInstanceLayoutInfo, IReconnectConstants, IRequestResolveVariablesEvent, IShellLaunchConfig, ITerminalInstanceLayoutInfoById, ITerminalLaunchError, ITerminalsLayoutInfo, ITerminalTabLayoutInfoById, TerminalIcon, IProcessProperty, TitleEventSource, ProcessPropertyType, IProcessPropertyMap, IFixedTerminalDimensions, IPersistentTerminalProcessLaunchConfig, ICrossVersionSerializedTerminalState, ISerializedTerminalState, ITerminalProcessOptions } from 'vs/platform/terminal/common/terminal'; import { TerminalDataBufferer } from 'vs/platform/terminal/common/terminalDataBuffering'; import { escapeNonWindowsPath } from 'vs/platform/terminal/common/terminalEnvironment'; import { Terminal as XtermTerminal } from 'xterm-headless'; @@ -334,21 +334,27 @@ export class PtyService extends Disposable implements IPtyService { }); } + async getRevivedPtyNewId(id: number): Promise { + try { + return this._revivedPtyIdMap.get(id)?.newId; + } catch (e) { + this._logService.trace(`Couldn't find terminal ID ${id}`, e.message); + } + return undefined; + } + async setTerminalLayoutInfo(args: ISetTerminalLayoutInfoArgs): Promise { this._workspaceLayoutInfos.set(args.workspaceId, args); } async getTerminalLayoutInfo(args: IGetTerminalLayoutInfoArgs): Promise { const layout = this._workspaceLayoutInfos.get(args.workspaceId); - this._logService.trace('ptyService#getLayoutInfo', args); if (layout) { const expandedTabs = await Promise.all(layout.tabs.map(async tab => this._expandTerminalTab(tab))); const tabs = expandedTabs.filter(t => t.terminals.length > 0); - const expandedEditors = await Promise.all(layout.editorTerminals.map(async editorTerminal => this._expandTerminalEditorInstance(editorTerminal))); this._logService.trace('ptyService#returnLayoutInfo', tabs); return { - tabs, - editorTerminals: expandedEditors + tabs }; } return undefined; @@ -384,24 +390,6 @@ export class PtyService extends Disposable implements IPtyService { } } - private async _expandTerminalEditorInstance(t: ITerminalEditorInstanceLayoutInfoById): Promise> { - try { - const revivedPtyId = this._revivedPtyIdMap.get(t.terminal)?.newId; - const persistentProcessId = revivedPtyId ?? t.terminal; - const persistentProcess = this._throwIfNoPty(persistentProcessId); - const processDetails = persistentProcess && await this._buildProcessDetails(t.terminal, persistentProcess, revivedPtyId !== undefined); - return { - terminal: { ...processDetails, id: persistentProcessId } ?? null - }; - } catch (e) { - this._logService.trace(`Couldn't get layout info, a terminal was probably disconnected`, e.message); - // this will be filtered out and not reconnected - return { - terminal: null - }; - } - } - private async _buildProcessDetails(id: number, persistentProcess: PersistentTerminalProcess, wasRevived: boolean = false): Promise { // If the process was just revived, don't do the orphan check as it will // take some time diff --git a/src/vs/server/node/remoteTerminalChannel.ts b/src/vs/server/node/remoteTerminalChannel.ts index 5c14bf3006c..96241c74e8c 100644 --- a/src/vs/server/node/remoteTerminalChannel.ts +++ b/src/vs/server/node/remoteTerminalChannel.ts @@ -138,6 +138,7 @@ export class RemoteTerminalChannel extends Disposable implements IServerChannel< case '$setTerminalLayoutInfo': return this._ptyService.setTerminalLayoutInfo(args); case '$serializeTerminalState': return this._ptyService.serializeTerminalState.apply(this._ptyService, args); case '$reviveTerminalProcesses': return this._ptyService.reviveTerminalProcesses.apply(this._ptyService, args); + case '$getRevivedPtyNewId': return this._ptyService.getRevivedPtyNewId.apply(this._ptyService, args); case '$setUnicodeVersion': return this._ptyService.setUnicodeVersion.apply(this._ptyService, args); case '$reduceConnectionGraceTime': return this._reduceConnectionGraceTime(); case '$updateIcon': return this._ptyService.updateIcon.apply(this._ptyService, args); diff --git a/src/vs/workbench/contrib/terminal/browser/remoteTerminalBackend.ts b/src/vs/workbench/contrib/terminal/browser/remoteTerminalBackend.ts index dbbcea77cf9..6b304681efd 100644 --- a/src/vs/workbench/contrib/terminal/browser/remoteTerminalBackend.ts +++ b/src/vs/workbench/contrib/terminal/browser/remoteTerminalBackend.ts @@ -239,6 +239,23 @@ class RemoteTerminalBackend extends BaseTerminalBackend implements ITerminalBack return undefined; } + async attachToRevivedProcess(id: number): Promise { + if (!this._remoteTerminalChannel) { + throw new Error(`Cannot create remote terminal when there is no remote!`); + } + + try { + const newId = await this._remoteTerminalChannel.getRevivedPtyNewId(id); + if (newId === undefined) { + return undefined; + } + return await this.attachToProcess(newId); + } catch (e) { + this._logService.trace(`Couldn't attach to process ${e.message}`); + } + return undefined; + } + async listProcesses(): Promise { const terms = this._remoteTerminalChannel ? await this._remoteTerminalChannel.listProcesses() : []; return terms.map(termDto => { diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index d11e3359e8a..ecff6314eec 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -470,6 +470,11 @@ export interface ITerminalInstance { */ readonly persistentProcessId: number | undefined; + /** + * The id of a persistent process during the shutdown process + */ + shutdownPersistentProcessId: number | undefined; + /** * Whether the process should be persisted across reloads. */ diff --git a/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts b/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts index 5a501adebd2..5ed91cd6c12 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts @@ -281,7 +281,8 @@ export class TerminalEditorService extends Disposable implements ITerminalEditor const inputKey = resource.path; if ('pid' in deserializedInput) { - const instance = this._terminalInstanceService.createInstance({ attachPersistentProcess: deserializedInput }, TerminalLocation.Editor); + const newDeserializedInput = { ...deserializedInput, findRevivedId: true }; + const instance = this._terminalInstanceService.createInstance({ attachPersistentProcess: newDeserializedInput }, TerminalLocation.Editor); instance.target = TerminalLocation.Editor; const input = this._instantiationService.createInstance(TerminalEditorInput, resource, instance); this._registerInstance(inputKey, input, instance); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 7f9589e2ca3..119ef061d0a 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -150,6 +150,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { private readonly _processManager: ITerminalProcessManager; private readonly _resource: URI; + private _shutdownPersistentProcessId: number | undefined; // Enables disposal of the xterm onKey // event when the CwdDetection capability @@ -654,8 +655,11 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { return TerminalInstance._lastKnownCanvasDimensions; } - get persistentProcessId(): number | undefined { return this._processManager.persistentProcessId; } - get shouldPersist(): boolean { return this._processManager.shouldPersist && !this.shellLaunchConfig.isTransient; } + set shutdownPersistentProcessId(shutdownPersistentProcessId: number | undefined) { + this._shutdownPersistentProcessId = shutdownPersistentProcessId; + } + get persistentProcessId(): number | undefined { return this._processManager.persistentProcessId ?? this._shutdownPersistentProcessId; } + get shouldPersist(): boolean { return (this._processManager.shouldPersist || this._shutdownPersistentProcessId !== undefined) && !this.shellLaunchConfig.isTransient; } /** * Create xterm.js instance and attach data listeners. diff --git a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts index bba89cdbcee..db29d770391 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts @@ -290,7 +290,7 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce } } else { if (shellLaunchConfig.attachPersistentProcess) { - const result = await backend.attachToProcess(shellLaunchConfig.attachPersistentProcess.id); + const result = shellLaunchConfig.attachPersistentProcess.findRevivedId ? await backend.attachToRevivedProcess(shellLaunchConfig.attachPersistentProcess.id) : await backend.attachToProcess(shellLaunchConfig.attachPersistentProcess.id); if (result) { newProcess = result; } else { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 4d1220d4375..69ec76c20d0 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -403,22 +403,8 @@ export class TerminalService implements ITerminalService { return; } const layoutInfo = await localBackend.getTerminalLayoutInfo(); - if (layoutInfo) { - if (layoutInfo.tabs.length > 0) { - await this._recreateTerminalGroups(layoutInfo); - } - if (this._terminalEditorService.instances.length === 0) { - // only do this for restart because editor terminals are already restored - // on reload - if (layoutInfo.editorTerminals && layoutInfo.editorTerminals.length > 0) { - for (const editorTerminal of layoutInfo.editorTerminals) { - await this.createTerminal({ - config: { attachPersistentProcess: editorTerminal.terminal! }, - location: TerminalLocation.Editor - }); - } - } - } + if (layoutInfo && layoutInfo.tabs.length > 0) { + await this._recreateTerminalGroups(layoutInfo); } // now that terminals have been restored, // attach listeners to update local state when terminals are changed @@ -634,8 +620,13 @@ export class TerminalService implements ITerminalService { return; } + // Force dispose of all terminal instances + const shouldPersistTerminalsForEvent = this._shouldReviveProcesses(e.reason); for (const instance of this.instances) { + if (shouldPersistTerminalsForEvent) { + instance.shutdownPersistentProcessId = instance.persistentProcessId; + } instance.dispose(); } @@ -659,24 +650,8 @@ export class TerminalService implements ITerminalService { return; } const tabs = this._terminalGroupService.groups.map(g => g.getLayoutInfo(g === this._terminalGroupService.activeGroup)); - - // Save terminals in editors too - const seenPersistentProcessIds: number[] = []; - for (const t of tabs) { - for (const term of t.terminals) { - seenPersistentProcessIds.push(term.terminal); - } - } - const otherInstances = this.instances.filter(instance => typeof instance.persistentProcessId === 'number' && instance.shouldPersist && seenPersistentProcessIds.indexOf(instance.persistentProcessId) === -1); - const editorTerminals = otherInstances.map((instance) => { - return { - terminal: instance.persistentProcessId || 0 - }; - }); - const state: ITerminalsLayoutInfoById = { - tabs, - editorTerminals + tabs }; this._primaryBackend?.setTerminalLayoutInfo(state); } diff --git a/src/vs/workbench/contrib/terminal/common/remoteTerminalChannel.ts b/src/vs/workbench/contrib/terminal/common/remoteTerminalChannel.ts index a41a5f89716..1b62d1e9cb3 100644 --- a/src/vs/workbench/contrib/terminal/common/remoteTerminalChannel.ts +++ b/src/vs/workbench/contrib/terminal/common/remoteTerminalChannel.ts @@ -266,8 +266,7 @@ export class RemoteTerminalChannelClient implements IPtyHostController { const workspace = this._workspaceContextService.getWorkspace(); const args: ISetTerminalLayoutInfoArgs = { workspaceId: workspace.id, - tabs: layout ? layout.tabs : [], - editorTerminals: layout ? layout.editorTerminals : [] + tabs: layout ? layout.tabs : [] }; return this._channel.call('$setTerminalLayoutInfo', args); } @@ -300,6 +299,10 @@ export class RemoteTerminalChannelClient implements IPtyHostController { return this._channel.call('$reviveTerminalProcesses', [state, dateTimeFormatLocate]); } + getRevivedPtyNewId(id: number): Promise { + return this._channel.call('$getRevivedPtyNewId', [id]); + } + serializeTerminalState(ids: number[]): Promise { return this._channel.call('$serializeTerminalState', [ids]); } diff --git a/src/vs/workbench/contrib/terminal/common/terminal.ts b/src/vs/workbench/contrib/terminal/common/terminal.ts index 1d3a1aa85db..04b98030a41 100644 --- a/src/vs/workbench/contrib/terminal/common/terminal.ts +++ b/src/vs/workbench/contrib/terminal/common/terminal.ts @@ -116,6 +116,7 @@ export interface ITerminalBackend { onDidRequestDetach: Event<{ requestId: number; workspaceId: string; instanceId: number }>; attachToProcess(id: number): Promise; + attachToRevivedProcess(id: number): Promise; listProcesses(): Promise; getDefaultSystemShell(osOverride?: OperatingSystem): Promise; getProfiles(profiles: unknown, defaultProfile: unknown, includeDetectedProfiles?: boolean): Promise; diff --git a/src/vs/workbench/contrib/terminal/electron-sandbox/localTerminalBackend.ts b/src/vs/workbench/contrib/terminal/electron-sandbox/localTerminalBackend.ts index e423da8a59f..8b9802f0abc 100644 --- a/src/vs/workbench/contrib/terminal/electron-sandbox/localTerminalBackend.ts +++ b/src/vs/workbench/contrib/terminal/electron-sandbox/localTerminalBackend.ts @@ -168,6 +168,19 @@ class LocalTerminalBackend extends BaseTerminalBackend implements ITerminalBacke return undefined; } + async attachToRevivedProcess(id: number): Promise { + try { + const newId = await this._localPtyService.getRevivedPtyNewId(id); + if (newId === undefined) { + return undefined; + } + return await this.attachToProcess(newId); + } catch (e) { + this._logService.trace(`Couldn't attach to process ${e.message}`); + } + return undefined; + } + async listProcesses(): Promise { return this._localPtyService.listProcesses(); } @@ -199,8 +212,7 @@ class LocalTerminalBackend extends BaseTerminalBackend implements ITerminalBacke async setTerminalLayoutInfo(layoutInfo?: ITerminalsLayoutInfoById): Promise { const args: ISetTerminalLayoutInfoArgs = { workspaceId: this._getWorkspaceId(), - tabs: layoutInfo ? layoutInfo.tabs : [], - editorTerminals: layoutInfo ? layoutInfo.editorTerminals : [] + tabs: layoutInfo ? layoutInfo.tabs : [] }; await this._localPtyService.setTerminalLayoutInfo(args); // Store in the storage service as well to be used when reviving processes as normally this From 1f37af91f0533162174ce784e023af03b6c0d7ed Mon Sep 17 00:00:00 2001 From: Stephen Sigwart Date: Sat, 18 Jun 2022 15:30:19 -0400 Subject: [PATCH 010/347] Self review cleanup --- src/vs/platform/terminal/node/ptyService.ts | 5 ++--- .../contrib/terminal/browser/terminalEditorService.ts | 2 -- src/vs/workbench/contrib/terminal/browser/terminalService.ts | 4 +--- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/vs/platform/terminal/node/ptyService.ts b/src/vs/platform/terminal/node/ptyService.ts index 659a2f7f500..02494098900 100644 --- a/src/vs/platform/terminal/node/ptyService.ts +++ b/src/vs/platform/terminal/node/ptyService.ts @@ -349,13 +349,12 @@ export class PtyService extends Disposable implements IPtyService { async getTerminalLayoutInfo(args: IGetTerminalLayoutInfoArgs): Promise { const layout = this._workspaceLayoutInfos.get(args.workspaceId); + this._logService.trace('ptyService#getLayoutInfo', args); if (layout) { const expandedTabs = await Promise.all(layout.tabs.map(async tab => this._expandTerminalTab(tab))); const tabs = expandedTabs.filter(t => t.terminals.length > 0); this._logService.trace('ptyService#returnLayoutInfo', tabs); - return { - tabs - }; + return { tabs }; } return undefined; } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts b/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts index 5ed91cd6c12..74b83274dca 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalEditorService.ts @@ -93,7 +93,6 @@ export class TerminalEditorService extends Disposable implements ITerminalEditor // Remove the terminal from the managed instances when the editor closes. This fires when // dragging and dropping to another editor or closing the editor via cmd/ctrl+w. this._register(this._editorService.onDidCloseEditor(e => { - console.log('closed editor'); const instance = e.editor instanceof TerminalEditorInput ? e.editor.terminalInstance : undefined; if (instance) { const instanceIndex = this.instances.findIndex(e => e === instance); @@ -101,7 +100,6 @@ export class TerminalEditorService extends Disposable implements ITerminalEditor this.instances.splice(instanceIndex, 1); } } - console.log(this.instances); })); this._register(this._editorService.onDidActiveEditorChange(() => { const instance = this._editorService.activeEditor instanceof TerminalEditorInput ? this._editorService.activeEditor : undefined; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 69ec76c20d0..11e980b5f71 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -650,9 +650,7 @@ export class TerminalService implements ITerminalService { return; } const tabs = this._terminalGroupService.groups.map(g => g.getLayoutInfo(g === this._terminalGroupService.activeGroup)); - const state: ITerminalsLayoutInfoById = { - tabs - }; + const state: ITerminalsLayoutInfoById = { tabs }; this._primaryBackend?.setTerminalLayoutInfo(state); } From 9dcdfa421e249c14cceb2c8bcd8e9f407e738457 Mon Sep 17 00:00:00 2001 From: Stephen Sigwart Date: Mon, 20 Jun 2022 20:41:14 -0400 Subject: [PATCH 011/347] Use same ID for reload to reconnect --- .../contrib/terminal/browser/remoteTerminalBackend.ts | 5 +---- .../terminal/electron-sandbox/localTerminalBackend.ts | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/remoteTerminalBackend.ts b/src/vs/workbench/contrib/terminal/browser/remoteTerminalBackend.ts index 6b304681efd..35454bcae4e 100644 --- a/src/vs/workbench/contrib/terminal/browser/remoteTerminalBackend.ts +++ b/src/vs/workbench/contrib/terminal/browser/remoteTerminalBackend.ts @@ -245,10 +245,7 @@ class RemoteTerminalBackend extends BaseTerminalBackend implements ITerminalBack } try { - const newId = await this._remoteTerminalChannel.getRevivedPtyNewId(id); - if (newId === undefined) { - return undefined; - } + const newId = await this._remoteTerminalChannel.getRevivedPtyNewId(id) ?? id; return await this.attachToProcess(newId); } catch (e) { this._logService.trace(`Couldn't attach to process ${e.message}`); diff --git a/src/vs/workbench/contrib/terminal/electron-sandbox/localTerminalBackend.ts b/src/vs/workbench/contrib/terminal/electron-sandbox/localTerminalBackend.ts index 8b9802f0abc..d61acd4c4a4 100644 --- a/src/vs/workbench/contrib/terminal/electron-sandbox/localTerminalBackend.ts +++ b/src/vs/workbench/contrib/terminal/electron-sandbox/localTerminalBackend.ts @@ -170,10 +170,7 @@ class LocalTerminalBackend extends BaseTerminalBackend implements ITerminalBacke async attachToRevivedProcess(id: number): Promise { try { - const newId = await this._localPtyService.getRevivedPtyNewId(id); - if (newId === undefined) { - return undefined; - } + const newId = await this._localPtyService.getRevivedPtyNewId(id) ?? id; return await this.attachToProcess(newId); } catch (e) { this._logService.trace(`Couldn't attach to process ${e.message}`); From 334795d2da3849c7b6e8944e663f48ab40c23b56 Mon Sep 17 00:00:00 2001 From: Prashant Cholachagudda Date: Thu, 23 Jun 2022 16:58:30 +0530 Subject: [PATCH 012/347] Add VSCode session id to gallery extension query --- .../extensionManagement/common/extensionGalleryService.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/vs/platform/extensionManagement/common/extensionGalleryService.ts b/src/vs/platform/extensionManagement/common/extensionGalleryService.ts index 6f04a76edb6..cfea8e58f80 100644 --- a/src/vs/platform/extensionManagement/common/extensionGalleryService.ts +++ b/src/vs/platform/extensionManagement/common/extensionGalleryService.ts @@ -923,12 +923,14 @@ abstract class AbstractExtensionGalleryService implements IExtensionGalleryServi const commonHeaders = await this.commonHeadersPromise; const data = JSON.stringify(query.raw); + const { sessionId } = await this.telemetryService.getTelemetryInfo(); const headers = { ...commonHeaders, 'Content-Type': 'application/json', 'Accept': 'application/json;api-version=3.0-preview.1', 'Accept-Encoding': 'gzip', - 'Content-Length': String(data.length) + 'Content-Length': String(data.length), + 'VSCode-SessionId': sessionId }; const startTime = new Date().getTime(); From 94459e758e229b13d882cc8298ad98c67586a52f Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Sun, 26 Jun 2022 00:06:27 +0200 Subject: [PATCH 013/347] Improve extensions management in profiles - Make version property mandatory in extension profiles (like in web) - Extend extensions clean up to profiles - Add necessay changes in other services to support extension cleanup: - Introduce INativeServerExtensionManagementService - Extend profile change event to provide added and removed profiles --- .../contrib/extensionsCleaner.ts | 144 +++++++++++++++++- .../sharedProcess/sharedProcessMain.ts | 4 +- src/vs/code/node/cliProcessMain.ts | 6 +- .../abstractExtensionManagementService.ts | 52 ++++--- .../common/extensionManagement.ts | 7 +- .../common/extensionsProfileScannerService.ts | 61 +++++++- .../node/extensionManagementService.ts | 34 +++-- .../node/extensionsScannerService.test.ts | 5 +- .../userDataProfile/common/userDataProfile.ts | 6 +- .../electron-main/userDataProfile.ts | 8 +- .../electron-sandbox/userDataProfile.ts | 10 +- .../node/remoteExtensionHostAgentCli.ts | 6 +- src/vs/server/node/serverServices.ts | 10 +- .../browser/extensions.contribution.ts | 15 +- .../extensions/browser/extensionsCleaner.ts | 19 --- .../common/webExtensionManagementService.ts | 8 +- 16 files changed, 301 insertions(+), 94 deletions(-) delete mode 100644 src/vs/workbench/contrib/extensions/browser/extensionsCleaner.ts diff --git a/src/vs/code/electron-browser/sharedProcess/contrib/extensionsCleaner.ts b/src/vs/code/electron-browser/sharedProcess/contrib/extensionsCleaner.ts index a7ebe66abca..3ac907be458 100644 --- a/src/vs/code/electron-browser/sharedProcess/contrib/extensionsCleaner.ts +++ b/src/vs/code/electron-browser/sharedProcess/contrib/extensionsCleaner.ts @@ -4,26 +4,162 @@ *--------------------------------------------------------------------------------------------*/ import { Disposable } from 'vs/base/common/lifecycle'; -import { IExtensionGalleryService, IGlobalExtensionEnablementService, IServerExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { URI } from 'vs/base/common/uri'; +import { IExtensionGalleryService, IExtensionIdentifier, IGlobalExtensionEnablementService, ServerDidUninstallExtensionEvent, ServerInstallExtensionResult, UninstallOptions } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionsProfileScannerService } from 'vs/platform/extensionManagement/common/extensionsProfileScannerService'; import { ExtensionStorageService, IExtensionStorageService } from 'vs/platform/extensionManagement/common/extensionStorage'; import { migrateUnsupportedExtensions } from 'vs/platform/extensionManagement/common/unsupportedExtensionsMigration'; -import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService'; +import { INativeServerExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService'; +import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ILogService } from 'vs/platform/log/common/log'; import { IStorageService } from 'vs/platform/storage/common/storage'; +import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'; +import { DidChangeProfilesEvent, IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile'; + +const uninstalOptions: UninstallOptions = { versionOnly: true, donotIncludePack: true, donotCheckDependents: true }; export class ExtensionsCleaner extends Disposable { constructor( - @IServerExtensionManagementService extensionManagementService: ExtensionManagementService, + @INativeServerExtensionManagementService extensionManagementService: INativeServerExtensionManagementService, + @IUserDataProfilesService private readonly userDataProfilesService: IUserDataProfilesService, @IExtensionGalleryService extensionGalleryService: IExtensionGalleryService, @IExtensionStorageService extensionStorageService: IExtensionStorageService, @IGlobalExtensionEnablementService extensionEnablementService: IGlobalExtensionEnablementService, + @IInstantiationService instantiationService: IInstantiationService, @IStorageService storageService: IStorageService, @ILogService logService: ILogService, ) { super(); - extensionManagementService.removeDeprecatedExtensions(); + + extensionManagementService.removeUninstalledExtensions(this.userDataProfilesService.profiles.length > 1); migrateUnsupportedExtensions(extensionManagementService, extensionGalleryService, extensionStorageService, extensionEnablementService, logService); ExtensionStorageService.removeOutdatedExtensionVersions(extensionManagementService, storageService); + this._register(instantiationService.createInstance(ProfileExtensionsCleaner)); } + +} + +class ProfileExtensionsCleaner extends Disposable { + + private profileExtensionsLocations = new Map; + private readonly initPromise: Promise; + + constructor( + @INativeServerExtensionManagementService private readonly extensionManagementService: INativeServerExtensionManagementService, + @IUserDataProfilesService private readonly userDataProfilesService: IUserDataProfilesService, + @IExtensionsProfileScannerService private readonly extensionsProfileScannerService: IExtensionsProfileScannerService, + @IUriIdentityService private readonly uriIdentityService: IUriIdentityService, + @ILogService private readonly logService: ILogService, + ) { + super(); + + this.initPromise = this.initialize(); + this._register(this.userDataProfilesService.onDidChangeProfiles(e => this.onDidChangeProfiles(e))); + this._register(this.extensionManagementService.onDidInstallExtensions(e => this.onDidInstallExtensions(e))); + this._register(this.extensionManagementService.onDidUninstallExtension(e => this.onDidUninstallExtension(e))); + } + + private async initialize(): Promise { + if (this.userDataProfilesService.profiles.length === 1) { + return true; + } + try { + const installed = await this.extensionManagementService.getAllUserInstalled(); + await Promise.all(this.userDataProfilesService.profiles.map(profile => profile.extensionsResource ? this.populateExtensionsFromProfile(profile.extensionsResource) : Promise.resolve())); + const toUninstall = installed.filter(installedExtension => !this.profileExtensionsLocations.has(this.getKey(installedExtension.identifier, installedExtension.manifest.version))); + if (toUninstall.length) { + await Promise.all(toUninstall.map(extension => this.extensionManagementService.uninstall(extension, uninstalOptions))); + } + return true; + } catch (error) { + this.logService.error('ExtensionsCleaner: Failed to initialize'); + this.logService.error(error); + return false; + } + } + + private async onDidChangeProfiles({ added, removed }: DidChangeProfilesEvent): Promise { + if (!(await this.initPromise)) { + return; + } + await Promise.all(added.map(profile => profile.extensionsResource ? this.populateExtensionsFromProfile(profile.extensionsResource) : Promise.resolve())); + await Promise.all(removed.map(profile => profile.extensionsResource ? this.removeExtensionsFromProfile(profile.extensionsResource) : Promise.resolve())); + } + + private async onDidInstallExtensions(installedExtensions: readonly ServerInstallExtensionResult[]): Promise { + if (!(await this.initPromise)) { + return; + } + for (const { local, profileLocation } of installedExtensions) { + if (!local || !profileLocation) { + continue; + } + this.addExtensionWithKey(this.getKey(local.identifier, local.manifest.version), profileLocation); + } + } + + private async onDidUninstallExtension(e: ServerDidUninstallExtensionEvent): Promise { + if (!e.profileLocation || !e.version) { + return; + } + if (!(await this.initPromise)) { + return; + } + if (this.removeExtensionWithKey(this.getKey(e.identifier, e.version), e.profileLocation)) { + await this.uninstallExtensions([{ identifier: e.identifier, version: e.version }]); + } + } + + private async populateExtensionsFromProfile(extensionsProfileLocation: URI): Promise { + const extensions = await this.extensionsProfileScannerService.scanProfileExtensions(extensionsProfileLocation); + for (const extension of extensions) { + this.addExtensionWithKey(this.getKey(extension.identifier, extension.version), extensionsProfileLocation); + } + } + + private async removeExtensionsFromProfile(removedProfile: URI): Promise { + const profileExtensions = await this.extensionsProfileScannerService.scanProfileExtensions(removedProfile); + const extensionsToRemove = profileExtensions.filter(profileExtension => this.removeExtensionWithKey(this.getKey(profileExtension.identifier, profileExtension.version), removedProfile)); + if (extensionsToRemove.length) { + await this.uninstallExtensions(extensionsToRemove); + } + } + + private addExtensionWithKey(key: string, extensionsProfileLocation: URI): void { + let locations = this.profileExtensionsLocations.get(key); + if (!locations) { + locations = []; + this.profileExtensionsLocations.set(key, locations); + } + locations.push(extensionsProfileLocation); + } + + private removeExtensionWithKey(key: string, profileLocation: URI): boolean { + const profiles = this.profileExtensionsLocations.get(key); + if (profiles) { + const index = profiles.findIndex(profile => this.uriIdentityService.extUri.isEqual(profile, profileLocation)); + if (index > -1) { + profiles.splice(index, 1); + } + } + if (!profiles?.length) { + this.profileExtensionsLocations.delete(key); + } + return !profiles?.length; + } + + private async uninstallExtensions(extensionsToRemove: { identifier: IExtensionIdentifier; version: string }[]): Promise { + const installed = await this.extensionManagementService.getAllUserInstalled(); + const toUninstall = installed.filter(installedExtension => extensionsToRemove.some(e => this.getKey(installedExtension.identifier, installedExtension.manifest.version) === this.getKey(e.identifier, e.version))); + if (toUninstall.length) { + await Promise.all(toUninstall.map(extension => this.extensionManagementService.uninstall(extension, uninstalOptions))); + } + } + + private getKey(identifier: IExtensionIdentifier, version: string): string { + return `${ExtensionIdentifier.toKey(identifier.id)}@${version}`; + } + } diff --git a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts index 862a359dfd9..11116cc4cce 100644 --- a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts +++ b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts @@ -34,7 +34,7 @@ import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/ import { IExtensionGalleryService, IExtensionManagementService, IExtensionTipsService, IGlobalExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { ExtensionManagementChannel, ExtensionTipsChannel } from 'vs/platform/extensionManagement/common/extensionManagementIpc'; import { ExtensionTipsService } from 'vs/platform/extensionManagement/electron-sandbox/extensionTipsService'; -import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService'; +import { ExtensionManagementService, INativeServerExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService'; import { IExtensionRecommendationNotificationService } from 'vs/platform/extensionRecommendations/common/extensionRecommendations'; import { ExtensionRecommendationNotificationServiceChannelClient } from 'vs/platform/extensionRecommendations/electron-sandbox/extensionRecommendationsIpc'; import { IFileService } from 'vs/platform/files/common/files'; @@ -315,7 +315,7 @@ class SharedProcessMain extends Disposable { // Extension Management services.set(IExtensionsProfileScannerService, new SyncDescriptor(ExtensionsProfileScannerService)); services.set(IExtensionsScannerService, new SyncDescriptor(ExtensionsScannerService)); - services.set(IExtensionManagementService, new SyncDescriptor(ExtensionManagementService)); + services.set(INativeServerExtensionManagementService, new SyncDescriptor(ExtensionManagementService)); // Extension Gallery services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryService)); diff --git a/src/vs/code/node/cliProcessMain.ts b/src/vs/code/node/cliProcessMain.ts index 6ffc074614c..56ee36e7f1b 100644 --- a/src/vs/code/node/cliProcessMain.ts +++ b/src/vs/code/node/cliProcessMain.ts @@ -23,11 +23,11 @@ import { NativeParsedArgs } from 'vs/platform/environment/common/argv'; import { INativeEnvironmentService } from 'vs/platform/environment/common/environment'; import { NativeEnvironmentService } from 'vs/platform/environment/node/environmentService'; import { ExtensionGalleryServiceWithNoStorageService } from 'vs/platform/extensionManagement/common/extensionGalleryService'; -import { IExtensionGalleryService, IExtensionManagementCLIService, IExtensionManagementService, InstallOptions } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionGalleryService, IExtensionManagementCLIService, InstallOptions } from 'vs/platform/extensionManagement/common/extensionManagement'; import { ExtensionManagementCLIService } from 'vs/platform/extensionManagement/common/extensionManagementCLIService'; import { ExtensionsProfileScannerService, IExtensionsProfileScannerService } from 'vs/platform/extensionManagement/common/extensionsProfileScannerService'; import { IExtensionsScannerService } from 'vs/platform/extensionManagement/common/extensionsScannerService'; -import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService'; +import { ExtensionManagementService, INativeServerExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService'; import { ExtensionsScannerService } from 'vs/platform/extensionManagement/node/extensionsScannerService'; import { IFileService } from 'vs/platform/files/common/files'; import { FileService } from 'vs/platform/files/common/fileService'; @@ -178,7 +178,7 @@ class CliMain extends Disposable { // Extensions services.set(IExtensionsProfileScannerService, new SyncDescriptor(ExtensionsProfileScannerService)); services.set(IExtensionsScannerService, new SyncDescriptor(ExtensionsScannerService)); - services.set(IExtensionManagementService, new SyncDescriptor(ExtensionManagementService)); + services.set(INativeServerExtensionManagementService, new SyncDescriptor(ExtensionManagementService)); services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryServiceWithNoStorageService)); services.set(IExtensionManagementCLIService, new SyncDescriptor(ExtensionManagementCLIService)); diff --git a/src/vs/platform/extensionManagement/common/abstractExtensionManagementService.ts b/src/vs/platform/extensionManagement/common/abstractExtensionManagementService.ts index 99d049079ed..c31a9e3c427 100644 --- a/src/vs/platform/extensionManagement/common/abstractExtensionManagementService.ts +++ b/src/vs/platform/extensionManagement/common/abstractExtensionManagementService.ts @@ -14,7 +14,8 @@ import { URI } from 'vs/base/common/uri'; import * as nls from 'vs/nls'; import { ExtensionManagementError, IExtensionGalleryService, IExtensionIdentifier, IExtensionManagementParticipant, IGalleryExtension, IGalleryMetadata, ILocalExtension, InstallOperation, - IExtensionsControlManifest, StatisticType, isTargetPlatformCompatible, TargetPlatformToString, ExtensionManagementErrorCode, IServerExtensionManagementService, ServerInstallOptions, ServerInstallVSIXOptions, ServerUninstallOptions, Metadata, ServerInstallExtensionEvent, ServerInstallExtensionResult, ServerUninstallExtensionEvent, ServerDidUninstallExtensionEvent + IExtensionsControlManifest, StatisticType, isTargetPlatformCompatible, TargetPlatformToString, ExtensionManagementErrorCode, IServerExtensionManagementService, + ServerInstallOptions, ServerInstallVSIXOptions, ServerUninstallOptions, Metadata, ServerInstallExtensionEvent, ServerInstallExtensionResult, ServerUninstallExtensionEvent, ServerDidUninstallExtensionEvent } from 'vs/platform/extensionManagement/common/extensionManagement'; import { areSameExtensions, ExtensionKey, getGalleryExtensionTelemetryData, getLocalExtensionTelemetryData, getMaliciousExtensionsSet } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { IExtensionsProfileScannerService } from 'vs/platform/extensionManagement/common/extensionsProfileScannerService'; @@ -34,8 +35,6 @@ export interface IInstallExtensionTask { cancel(): void; } -export type UninstallExtensionTaskOptions = { readonly remove?: boolean; readonly versionOnly?: boolean }; - export interface IUninstallExtensionTask { readonly extension: ILocalExtension; run(): Promise; @@ -426,47 +425,58 @@ export abstract class AbstractExtensionManagementService extends Disposable impl } private async unininstallExtension(extension: ILocalExtension, options: ServerUninstallOptions): Promise { - if (!options.profileLocation) { - const uninstallExtensionTask = this.uninstallingExtensions.get(extension.identifier.id.toLowerCase()); - if (uninstallExtensionTask) { - this.logService.info('Extensions is already requested to uninstall', extension.identifier.id); - return uninstallExtensionTask.waitUntilTaskIsFinished(); - } + const getUninstallExtensionTaskKey = (identifier: IExtensionIdentifier) => `${identifier.id.toLowerCase()}${options.profileLocation ? `@${options.profileLocation.toString()}` : ''}`; + const uninstallExtensionTask = this.uninstallingExtensions.get(getUninstallExtensionTaskKey(extension.identifier)); + if (uninstallExtensionTask) { + this.logService.info('Extensions is already requested to uninstall', extension.identifier.id); + return uninstallExtensionTask.waitUntilTaskIsFinished(); } - const createUninstallExtensionTask = (extension: ILocalExtension, uninstallOptions: UninstallExtensionTaskOptions): IUninstallExtensionTask => { + const createUninstallExtensionTask = (extension: ILocalExtension, uninstallOptions: ServerUninstallOptions): IUninstallExtensionTask => { const uninstallExtensionTask = this.createUninstallExtensionTask(extension, uninstallOptions, options.profileLocation); - this.uninstallingExtensions.set(uninstallExtensionTask.extension.identifier.id.toLowerCase(), uninstallExtensionTask); - this.logService.info('Uninstalling extension:', extension.identifier.id); + this.uninstallingExtensions.set(getUninstallExtensionTaskKey(uninstallExtensionTask.extension.identifier), uninstallExtensionTask); + if (options.profileLocation) { + this.logService.info('Uninstalling extension from the profile:', extension.identifier.id, options.profileLocation.toString()); + } else { + this.logService.info('Uninstalling extension:', extension.identifier.id); + } this._onUninstallExtension.fire({ identifier: extension.identifier, profileLocation: options.profileLocation, applicationScoped: extension.isApplicationScoped }); return uninstallExtensionTask; }; const postUninstallExtension = (extension: ILocalExtension, error?: ExtensionManagementError): void => { if (error) { - this.logService.error('Failed to uninstall extension:', extension.identifier.id, error.message); + if (options.profileLocation) { + this.logService.error('Failed to uninstall extension from the profile:', extension.identifier.id, options.profileLocation.toString(), error.message); + } else { + this.logService.error('Failed to uninstall extension:', extension.identifier.id, error.message); + } } else { - this.logService.info('Successfully uninstalled extension:', extension.identifier.id); + if (options.profileLocation) { + this.logService.info('Successfully uninstalled extension from the profile', extension.identifier.id, options.profileLocation.toString()); + } else { + this.logService.info('Successfully uninstalled extension:', extension.identifier.id); + } } reportTelemetry(this.telemetryService, 'extensionGallery:uninstall', { extensionData: getLocalExtensionTelemetryData(extension), error }); - this._onDidUninstallExtension.fire({ identifier: extension.identifier, error: error?.code, profileLocation: options.profileLocation, applicationScoped: extension.isApplicationScoped }); + this._onDidUninstallExtension.fire({ identifier: extension.identifier, version: extension.manifest.version, error: error?.code, profileLocation: options.profileLocation, applicationScoped: extension.isApplicationScoped }); }; const allTasks: IUninstallExtensionTask[] = []; const processedTasks: IUninstallExtensionTask[] = []; try { - allTasks.push(createUninstallExtensionTask(extension, {})); + allTasks.push(createUninstallExtensionTask(extension, options)); const installed = await this.getInstalled(ExtensionType.User, options.profileLocation); if (options.donotIncludePack) { this.logService.info('Uninstalling the extension without including packed extension', extension.identifier.id); } else { const packedExtensions = this.getAllPackExtensionsToUninstall(extension, installed); for (const packedExtension of packedExtensions) { - if (this.uninstallingExtensions.has(packedExtension.identifier.id.toLowerCase())) { + if (this.uninstallingExtensions.has(getUninstallExtensionTaskKey(packedExtension.identifier))) { this.logService.info('Extensions is already requested to uninstall', packedExtension.identifier.id); } else { - allTasks.push(createUninstallExtensionTask(packedExtension, {})); + allTasks.push(createUninstallExtensionTask(packedExtension, options)); } } } @@ -511,7 +521,7 @@ export abstract class AbstractExtensionManagementService extends Disposable impl } finally { // Remove tasks from cache for (const task of allTasks) { - if (!this.uninstallingExtensions.delete(task.extension.identifier.id.toLowerCase())) { + if (!this.uninstallingExtensions.delete(getUninstallExtensionTaskKey(task.extension.identifier))) { this.logService.warn('Uninstallation task is not found in the cache', task.extension.identifier.id); } } @@ -607,7 +617,7 @@ export abstract class AbstractExtensionManagementService extends Disposable impl return new InstallExtensionInProfileTask(installTask, options.profileLocation, this.userDataProfilesService.defaultProfile.extensionsResource, this.extensionsProfileScannerService); } - private createUninstallExtensionTask(extension: ILocalExtension, options: UninstallExtensionTaskOptions, profile?: URI): IUninstallExtensionTask { + private createUninstallExtensionTask(extension: ILocalExtension, options: ServerUninstallOptions, profile?: URI): IUninstallExtensionTask { return profile && this.userDataProfilesService.defaultProfile.extensionsResource ? new UninstallExtensionFromProfileTask(extension, profile, this.userDataProfilesService, this.extensionsProfileScannerService) : this.createDefaultUninstallExtensionTask(extension, options); } @@ -623,7 +633,7 @@ export abstract class AbstractExtensionManagementService extends Disposable impl abstract updateExtensionScope(local: ILocalExtension, isMachineScoped: boolean): Promise; protected abstract createDefaultInstallExtensionTask(manifest: IExtensionManifest, extension: URI | IGalleryExtension, options: ServerInstallOptions & ServerInstallVSIXOptions): IInstallExtensionTask; - protected abstract createDefaultUninstallExtensionTask(extension: ILocalExtension, options: UninstallExtensionTaskOptions): IUninstallExtensionTask; + protected abstract createDefaultUninstallExtensionTask(extension: ILocalExtension, options: ServerUninstallOptions): IUninstallExtensionTask; } export function joinErrors(errorOrErrors: (Error | string) | (Array)): Error { diff --git a/src/vs/platform/extensionManagement/common/extensionManagement.ts b/src/vs/platform/extensionManagement/common/extensionManagement.ts index 4e376a1a4c8..3c5ec520512 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagement.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagement.ts @@ -361,8 +361,9 @@ export interface UninstallExtensionEvent { } export interface DidUninstallExtensionEvent { - identifier: IExtensionIdentifier; - error?: string; + readonly identifier: IExtensionIdentifier; + readonly version?: string; + readonly error?: string; } export enum ExtensionManagementErrorCode { @@ -403,7 +404,7 @@ export type InstallOptions = { context?: IStringDictionary; }; export type InstallVSIXOptions = Omit & { installOnlyNewlyAddedFromExtensionPack?: boolean }; -export type UninstallOptions = { donotIncludePack?: boolean; donotCheckDependents?: boolean }; +export type UninstallOptions = { readonly donotIncludePack?: boolean; readonly donotCheckDependents?: boolean; readonly versionOnly?: boolean; readonly remove?: boolean }; export interface IExtensionManagementParticipant { postInstall(local: ILocalExtension, source: URI | IGalleryExtension, options: InstallOptions | InstallVSIXOptions, token: CancellationToken): Promise; diff --git a/src/vs/platform/extensionManagement/common/extensionsProfileScannerService.ts b/src/vs/platform/extensionManagement/common/extensionsProfileScannerService.ts index 0dfadaa8c49..8acce96e6e1 100644 --- a/src/vs/platform/extensionManagement/common/extensionsProfileScannerService.ts +++ b/src/vs/platform/extensionManagement/common/extensionsProfileScannerService.ts @@ -10,19 +10,23 @@ import { ResourceMap } from 'vs/base/common/map'; import { URI, UriComponents } from 'vs/base/common/uri'; import { ILocalExtension, Metadata } from 'vs/platform/extensionManagement/common/extensionManagement'; import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; -import { IExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; +import { IExtensionIdentifier, IExtensionManifest } from 'vs/platform/extensions/common/extensions'; import { FileOperationError, FileOperationResult, IFileService } from 'vs/platform/files/common/files'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { ILogService } from 'vs/platform/log/common/log'; +import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'; +import { IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile'; interface IStoredProfileExtension { - readonly identifier: IExtensionIdentifier; - readonly location: UriComponents; - readonly metadata?: Metadata; + identifier: IExtensionIdentifier; + location: UriComponents; + version: string; + metadata?: Metadata; } export interface IScannedProfileExtension { readonly identifier: IExtensionIdentifier; + readonly version: string; readonly location: URI; readonly metadata?: Metadata; } @@ -39,13 +43,45 @@ export interface IExtensionsProfileScannerService { export class ExtensionsProfileScannerService extends Disposable implements IExtensionsProfileScannerService { readonly _serviceBrand: undefined; + private readonly migratePromise: Promise; private readonly resourcesAccessQueueMap = new ResourceMap>(); constructor( @IFileService private readonly fileService: IFileService, + @IUriIdentityService private readonly uriIdentityService: IUriIdentityService, + @IUserDataProfilesService private readonly userDataProfilesService: IUserDataProfilesService, @ILogService private readonly logService: ILogService, ) { super(); + this.migratePromise = this.migrate(); + } + + // TODO: @sandy081 remove it in a month + private async migrate(): Promise { + await Promise.all(this.userDataProfilesService.profiles.map(async e => { + if (!e.extensionsResource) { + return; + } + try { + let needsMigrating: boolean = false; + const storedWebExtensions: IStoredProfileExtension[] = JSON.parse((await this.fileService.readFile(e.extensionsResource)).value.toString()); + for (const e of storedWebExtensions) { + if (!e.location) { + continue; + } + if (!e.version) { + try { + const content = (await this.fileService.readFile(this.uriIdentityService.extUri.joinPath(URI.revive(e.location), 'package.json'))).value.toString(); + e.version = (JSON.parse(content)).version; + needsMigrating = true; + } catch (error) { /* ignore */ } + } + } + if (needsMigrating) { + await this.fileService.writeFile(e.extensionsResource, VSBuffer.fromString(JSON.stringify(storedWebExtensions))); + } + } catch (error) { /* Ignore */ } + })); } scanProfileExtensions(profileLocation: URI): Promise { @@ -56,7 +92,7 @@ export class ExtensionsProfileScannerService extends Disposable implements IExte return this.withProfileExtensions(profileLocation, profileExtensions => { // Remove the existing extension to avoid duplicates profileExtensions = profileExtensions.filter(e => extensions.some(([extension]) => !areSameExtensions(e.identifier, extension.identifier))); - profileExtensions.push(...extensions.map(([extension, metadata]) => ({ identifier: extension.identifier, location: extension.location, metadata }))); + profileExtensions.push(...extensions.map(([extension, metadata]) => ({ identifier: extension.identifier, version: extension.manifest.version, location: extension.location, metadata }))); return profileExtensions; }); } @@ -66,6 +102,7 @@ export class ExtensionsProfileScannerService extends Disposable implements IExte } private async withProfileExtensions(file: URI, updateFn?: (extensions: IScannedProfileExtension[]) => IScannedProfileExtension[]): Promise { + await this.migratePromise; return this.getResourceAccessQueue(file).queue(async () => { let extensions: IScannedProfileExtension[] = []; @@ -74,13 +111,22 @@ export class ExtensionsProfileScannerService extends Disposable implements IExte const content = await this.fileService.readFile(file); const storedWebExtensions: IStoredProfileExtension[] = JSON.parse(content.value.toString()); for (const e of storedWebExtensions) { - if (!e.location || !e.identifier) { - this.logService.info('Ignoring invalid extension while scanning', storedWebExtensions); + if (!e.identifier) { + this.logService.info('Ignoring invalid extension while scanning. Identifier does not exist.', e); + continue; + } + if (!e.location) { + this.logService.info('Ignoring invalid extension while scanning. Location does not exist.', e); + continue; + } + if (!e.version) { + this.logService.info('Ignoring invalid extension while scanning. Version does not exist.', e); continue; } extensions.push({ identifier: e.identifier, location: URI.revive(e.location), + version: e.version, metadata: e.metadata, }); } @@ -96,6 +142,7 @@ export class ExtensionsProfileScannerService extends Disposable implements IExte extensions = updateFn(extensions); const storedProfileExtensions: IStoredProfileExtension[] = extensions.map(e => ({ identifier: e.identifier, + version: e.version, location: e.location.toJSON(), metadata: e.metadata })); diff --git a/src/vs/platform/extensionManagement/node/extensionManagementService.ts b/src/vs/platform/extensionManagement/node/extensionManagementService.ts index 4c2d6a47d6b..3eadb31770b 100644 --- a/src/vs/platform/extensionManagement/node/extensionManagementService.ts +++ b/src/vs/platform/extensionManagement/node/extensionManagementService.ts @@ -22,10 +22,11 @@ import { extract, ExtractError, IFile, zip } from 'vs/base/node/zip'; import * as nls from 'vs/nls'; import { IDownloadService } from 'vs/platform/download/common/download'; import { INativeEnvironmentService } from 'vs/platform/environment/common/environment'; -import { AbstractExtensionManagementService, AbstractExtensionTask, IInstallExtensionTask, IUninstallExtensionTask, joinErrors, UninstallExtensionTaskOptions } from 'vs/platform/extensionManagement/common/abstractExtensionManagementService'; +import { AbstractExtensionManagementService, AbstractExtensionTask, IInstallExtensionTask, IUninstallExtensionTask, joinErrors } from 'vs/platform/extensionManagement/common/abstractExtensionManagementService'; import { ExtensionManagementError, ExtensionManagementErrorCode, IExtensionGalleryService, IExtensionIdentifier, IGalleryExtension, IGalleryMetadata, ILocalExtension, InstallOperation, - Metadata, ServerInstallOptions, ServerInstallVSIXOptions + IServerExtensionManagementService, + Metadata, ServerInstallOptions, ServerInstallVSIXOptions, ServerUninstallOptions } from 'vs/platform/extensionManagement/common/extensionManagement'; import { areSameExtensions, computeTargetPlatform, ExtensionKey, getGalleryExtensionId, groupByExtension } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { IExtensionsProfileScannerService } from 'vs/platform/extensionManagement/common/extensionsProfileScannerService'; @@ -38,7 +39,7 @@ import { ExtensionsWatcher } from 'vs/platform/extensionManagement/node/extensio import { ExtensionType, IExtensionManifest, isApplicationScopedExtension, TargetPlatform } from 'vs/platform/extensions/common/extensions'; import { isEngineValid } from 'vs/platform/extensions/common/extensionValidator'; import { IFileService } from 'vs/platform/files/common/files'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { IInstantiationService, refineServiceDecorator } from 'vs/platform/instantiation/common/instantiation'; import { ILogService } from 'vs/platform/log/common/log'; import { IProductService } from 'vs/platform/product/common/productService'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -51,7 +52,14 @@ interface InstallableExtension { metadata?: Metadata; } -export class ExtensionManagementService extends AbstractExtensionManagementService { +export const INativeServerExtensionManagementService = refineServiceDecorator(IServerExtensionManagementService); +export interface INativeServerExtensionManagementService extends IServerExtensionManagementService { + readonly _serviceBrand: undefined; + removeUninstalledExtensions(removeOutdated: boolean): Promise; + getAllUserInstalled(): Promise; +} + +export class ExtensionManagementService extends AbstractExtensionManagementService implements INativeServerExtensionManagementService { private readonly extensionsScanner: ExtensionsScanner; private readonly manifestCache: ExtensionsManifestCache; @@ -117,6 +125,10 @@ export class ExtensionManagementService extends AbstractExtensionManagementServi return this.extensionsScanner.scanExtensions(type ?? null, profileLocation); } + getAllUserInstalled(): Promise { + return this.extensionsScanner.scanUserExtensions(false); + } + async install(vsix: URI, options: ServerInstallVSIXOptions = {}): Promise { this.logService.trace('ExtensionManagementService#install', vsix.toString()); @@ -151,8 +163,8 @@ export class ExtensionManagementService extends AbstractExtensionManagementServi return local; } - removeDeprecatedExtensions(): Promise { - return this.extensionsScanner.cleanUp(); + removeUninstalledExtensions(removeOutdated: boolean): Promise { + return this.extensionsScanner.cleanUp(removeOutdated); } private async downloadVsix(vsix: URI): Promise { @@ -168,7 +180,7 @@ export class ExtensionManagementService extends AbstractExtensionManagementServi return URI.isUri(extension) ? new InstallVSIXTask(manifest, extension, options, this.galleryService, this.extensionsScanner, this.logService) : new InstallGalleryExtensionTask(manifest, extension, options, this.extensionsDownloader, this.extensionsScanner, this.logService); } - protected createDefaultUninstallExtensionTask(extension: ILocalExtension, options: UninstallExtensionTaskOptions): IUninstallExtensionTask { + protected createDefaultUninstallExtensionTask(extension: ILocalExtension, options: ServerUninstallOptions): IUninstallExtensionTask { return new UninstallExtensionTask(extension, options, this.extensionsScanner); } @@ -215,9 +227,11 @@ class ExtensionsScanner extends Disposable { this.uninstalledFileLimiter = new Queue(); } - async cleanUp(): Promise { + async cleanUp(removeOutdated: boolean): Promise { await this.removeUninstalledExtensions(); - await this.removeOutdatedExtensions(); + if (removeOutdated) { + await this.removeOutdatedExtensions(); + } } async scanExtensions(type: ExtensionType | null, profileLocation: URI | undefined): Promise { @@ -696,7 +710,7 @@ class UninstallExtensionTask extends AbstractExtensionTask implements IUni constructor( readonly extension: ILocalExtension, - private readonly options: UninstallExtensionTaskOptions, + private readonly options: ServerUninstallOptions, private readonly extensionsScanner: ExtensionsScanner, ) { super(); diff --git a/src/vs/platform/extensionManagement/test/node/extensionsScannerService.test.ts b/src/vs/platform/extensionManagement/test/node/extensionsScannerService.test.ts index cdfaa38b842..54a7232c285 100644 --- a/src/vs/platform/extensionManagement/test/node/extensionsScannerService.test.ts +++ b/src/vs/platform/extensionManagement/test/node/extensionsScannerService.test.ts @@ -17,6 +17,7 @@ import { InMemoryFileSystemProvider } from 'vs/platform/files/common/inMemoryFil import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; import { ILogService, NullLogService } from 'vs/platform/log/common/log'; import { IProductService } from 'vs/platform/product/common/productService'; +import { UriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentityService'; import { IUserDataProfilesService, UserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile'; let translations: Translations = Object.create(null); @@ -69,7 +70,9 @@ suite('NativeExtensionsScanerService Test', () => { extensionsPath: userExtensionsLocation.fsPath, }); instantiationService.stub(IProductService, { version: '1.66.0' }); - instantiationService.stub(IExtensionsProfileScannerService, new ExtensionsProfileScannerService(fileService, logService)); + const uriIdentityService = new UriIdentityService(fileService); + const userDataProfilesService = new UserDataProfilesService(environmentService, fileService, logService); + instantiationService.stub(IExtensionsProfileScannerService, new ExtensionsProfileScannerService(fileService, uriIdentityService, userDataProfilesService, logService)); instantiationService.stub(IUserDataProfilesService, new UserDataProfilesService(environmentService, fileService, logService)); await fileService.createFolder(systemExtensionsLocation); await fileService.createFolder(userExtensionsLocation); diff --git a/src/vs/platform/userDataProfile/common/userDataProfile.ts b/src/vs/platform/userDataProfile/common/userDataProfile.ts index 39d0df3d6ba..9e9897e8cdc 100644 --- a/src/vs/platform/userDataProfile/common/userDataProfile.ts +++ b/src/vs/platform/userDataProfile/common/userDataProfile.ts @@ -81,6 +81,8 @@ if (!isWeb) { }); } +export type DidChangeProfilesEvent = { readonly added: IUserDataProfile[]; readonly removed: IUserDataProfile[]; readonly all: IUserDataProfile[] }; + export const IUserDataProfilesService = createDecorator('IUserDataProfilesService'); export interface IUserDataProfilesService { readonly _serviceBrand: undefined; @@ -88,7 +90,7 @@ export interface IUserDataProfilesService { readonly profilesHome: URI; readonly defaultProfile: IUserDataProfile; - readonly onDidChangeProfiles: Event; + readonly onDidChangeProfiles: Event; readonly profiles: IUserDataProfile[]; newProfile(name: string, useDefaultFlags?: UseDefaultProfileFlags): CustomUserDataProfile; @@ -140,7 +142,7 @@ export class UserDataProfilesService extends Disposable implements IUserDataProf get defaultProfile(): IUserDataProfile { return this.profiles[0] ?? this._defaultProfile; } get profiles(): IUserDataProfile[] { return []; } - protected readonly _onDidChangeProfiles = this._register(new Emitter()); + protected readonly _onDidChangeProfiles = this._register(new Emitter()); readonly onDidChangeProfiles = this._onDidChangeProfiles.event; constructor( diff --git a/src/vs/platform/userDataProfile/electron-main/userDataProfile.ts b/src/vs/platform/userDataProfile/electron-main/userDataProfile.ts index 3a7b9503f80..08974874814 100644 --- a/src/vs/platform/userDataProfile/electron-main/userDataProfile.ts +++ b/src/vs/platform/userDataProfile/electron-main/userDataProfile.ts @@ -85,7 +85,7 @@ export class UserDataProfilesMainService extends UserDataProfilesService impleme const storedProfile: StoredUserDataProfile = { name: profile.name, location: profile.location, useDefaultFlags: profile.useDefaultFlags }; const storedProfiles = [...this.getStoredProfiles(), storedProfile]; - this.setStoredProfiles(storedProfiles); + this.setStoredProfiles(storedProfiles, [profile], []); if (workspaceIdentifier) { await this.setProfileForWorkspace(profile, workspaceIdentifier); } @@ -128,7 +128,7 @@ export class UserDataProfilesMainService extends UserDataProfilesService impleme await Promises.settled(joiners); this.setStoredWorskpaceInfos(this.getStoredWorskpaceInfos().filter(p => !this.uriIdentityService.extUri.isEqual(p.profile, profile.location))); - this.setStoredProfiles(this.getStoredProfiles().filter(p => !this.uriIdentityService.extUri.isEqual(p.location, profile.location))); + this.setStoredProfiles(this.getStoredProfiles().filter(p => !this.uriIdentityService.extUri.isEqual(p.location, profile.location)), [], [profile]); try { if (this.profiles.length === 2) { @@ -141,10 +141,10 @@ export class UserDataProfilesMainService extends UserDataProfilesService impleme } } - private setStoredProfiles(storedProfiles: StoredUserDataProfile[]) { + private setStoredProfiles(storedProfiles: StoredUserDataProfile[], added: IUserDataProfile[], removed: IUserDataProfile[]): void { this.stateMainService.setItem(UserDataProfilesMainService.PROFILES_KEY, storedProfiles); this._profilesObject = undefined; - this._onDidChangeProfiles.fire(this.profiles); + this._onDidChangeProfiles.fire({ added, removed, all: this.profiles }); } private setStoredWorskpaceInfos(storedWorkspaceInfos: StoredWorkspaceInfo[]) { diff --git a/src/vs/platform/userDataProfile/electron-sandbox/userDataProfile.ts b/src/vs/platform/userDataProfile/electron-sandbox/userDataProfile.ts index 97ae03b8663..210bd2288b9 100644 --- a/src/vs/platform/userDataProfile/electron-sandbox/userDataProfile.ts +++ b/src/vs/platform/userDataProfile/electron-sandbox/userDataProfile.ts @@ -9,7 +9,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import { IFileService } from 'vs/platform/files/common/files'; import { IMainProcessService } from 'vs/platform/ipc/electron-sandbox/services'; import { ILogService } from 'vs/platform/log/common/log'; -import { IUserDataProfile, IUserDataProfilesService, reviveProfile, UserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile'; +import { DidChangeProfilesEvent, IUserDataProfile, IUserDataProfilesService, reviveProfile, UserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile'; import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspace/common/workspace'; export class UserDataProfilesNativeService extends UserDataProfilesService implements IUserDataProfilesService { @@ -29,9 +29,11 @@ export class UserDataProfilesNativeService extends UserDataProfilesService imple super(environmentService, fileService, logService); this.channel = mainProcessService.getChannel('userDataProfiles'); this._profiles = profiles.map(profile => reviveProfile(profile, this.profilesHome.scheme)); - this._register(this.channel.listen('onDidChangeProfiles')((profiles) => { - this._profiles = profiles.map(profile => reviveProfile(profile, this.profilesHome.scheme)); - this._onDidChangeProfiles.fire(this._profiles); + this._register(this.channel.listen('onDidChangeProfiles')(e => { + const added = e.added.map(profile => reviveProfile(profile, this.profilesHome.scheme)); + const removed = e.removed.map(profile => reviveProfile(profile, this.profilesHome.scheme)); + this._profiles = e.all.map(profile => reviveProfile(profile, this.profilesHome.scheme)); + this._onDidChangeProfiles.fire({ added, removed, all: this.profiles }); })); } diff --git a/src/vs/server/node/remoteExtensionHostAgentCli.ts b/src/vs/server/node/remoteExtensionHostAgentCli.ts index 631a6d18b12..653748724e0 100644 --- a/src/vs/server/node/remoteExtensionHostAgentCli.ts +++ b/src/vs/server/node/remoteExtensionHostAgentCli.ts @@ -12,9 +12,9 @@ import { IRequestService } from 'vs/platform/request/common/request'; import { RequestService } from 'vs/platform/request/node/requestService'; import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { IExtensionGalleryService, IExtensionManagementCLIService, IExtensionManagementService, InstallOptions } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionGalleryService, IExtensionManagementCLIService, InstallOptions } from 'vs/platform/extensionManagement/common/extensionManagement'; import { ExtensionGalleryServiceWithNoStorageService } from 'vs/platform/extensionManagement/common/extensionGalleryService'; -import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService'; +import { ExtensionManagementService, INativeServerExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService'; import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import product from 'vs/platform/product/common/product'; @@ -109,7 +109,7 @@ class CliMain extends Disposable { services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryServiceWithNoStorageService)); services.set(IExtensionsProfileScannerService, new SyncDescriptor(ExtensionsProfileScannerService)); services.set(IExtensionsScannerService, new SyncDescriptor(ExtensionsScannerService)); - services.set(IExtensionManagementService, new SyncDescriptor(ExtensionManagementService)); + services.set(INativeServerExtensionManagementService, new SyncDescriptor(ExtensionManagementService)); services.set(IExtensionManagementCLIService, new SyncDescriptor(ExtensionManagementCLIService)); services.set(ILanguagePackService, new SyncDescriptor(NativeLanguagePackService)); diff --git a/src/vs/server/node/serverServices.ts b/src/vs/server/node/serverServices.ts index fa2c8004a77..797f29fd9e5 100644 --- a/src/vs/server/node/serverServices.ts +++ b/src/vs/server/node/serverServices.ts @@ -24,10 +24,10 @@ import { IEncryptionMainService } from 'vs/platform/encryption/common/encryption import { EncryptionMainService } from 'vs/platform/encryption/node/encryptionMainService'; import { IEnvironmentService, INativeEnvironmentService } from 'vs/platform/environment/common/environment'; import { ExtensionGalleryServiceWithNoStorageService } from 'vs/platform/extensionManagement/common/extensionGalleryService'; -import { IExtensionGalleryService, IExtensionManagementCLIService, IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionGalleryService, IExtensionManagementCLIService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { ExtensionManagementCLIService } from 'vs/platform/extensionManagement/common/extensionManagementCLIService'; import { ExtensionManagementChannel } from 'vs/platform/extensionManagement/common/extensionManagementIpc'; -import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService'; +import { ExtensionManagementService, INativeServerExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService'; import { IFileService } from 'vs/platform/files/common/files'; import { FileService } from 'vs/platform/files/common/fileService'; import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider'; @@ -165,7 +165,7 @@ export async function setupServerServices(connectionToken: ServerConnectionToken services.set(IExtensionsProfileScannerService, new SyncDescriptor(ExtensionsProfileScannerService)); services.set(IExtensionsScannerService, new SyncDescriptor(ExtensionsScannerService)); - services.set(IExtensionManagementService, new SyncDescriptor(ExtensionManagementService)); + services.set(INativeServerExtensionManagementService, new SyncDescriptor(ExtensionManagementService)); const instantiationService: IInstantiationService = new InstantiationService(services); services.set(ILanguagePackService, instantiationService.createInstance(NativeLanguagePackService)); @@ -188,7 +188,7 @@ export async function setupServerServices(connectionToken: ServerConnectionToken services.set(ICredentialsMainService, new SyncDescriptor(CredentialsWebMainService)); instantiationService.invokeFunction(accessor => { - const extensionManagementService = accessor.get(IExtensionManagementService); + const extensionManagementService = accessor.get(INativeServerExtensionManagementService); const extensionsScannerService = accessor.get(IExtensionsScannerService); const remoteExtensionEnvironmentChannel = new RemoteAgentEnvironmentChannel(connectionToken, environmentService, userDataProfilesService, extensionManagementCLIService, logService, extensionHostStatusService, extensionsScannerService); socketServer.registerChannel('remoteextensionsenvironment', remoteExtensionEnvironmentChannel); @@ -213,7 +213,7 @@ export async function setupServerServices(connectionToken: ServerConnectionToken socketServer.registerChannel('credentials', credentialsChannel); // clean up deprecated extensions - (extensionManagementService as ExtensionManagementService).removeDeprecatedExtensions(); + extensionManagementService.removeUninstalledExtensions(true); disposables.add(new ErrorTelemetry(accessor.get(ITelemetryService))); diff --git a/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts b/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts index 6fbc52d18ba..57969a4ba9b 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts @@ -75,7 +75,8 @@ import { Event } from 'vs/base/common/event'; import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite'; import { UnsupportedExtensionsMigrationContrib } from 'vs/workbench/contrib/extensions/browser/unsupportedExtensionsMigrationContribution'; import { isWeb } from 'vs/base/common/platform'; -import { ExtensionsCleaner } from 'vs/workbench/contrib/extensions/browser/extensionsCleaner'; +import { ExtensionStorageService } from 'vs/platform/extensionManagement/common/extensionStorage'; +import { IStorageService } from 'vs/platform/storage/common/storage'; // Singletons registerSingleton(IExtensionsWorkbenchService, ExtensionsWorkbenchService); @@ -1559,6 +1560,16 @@ class ExtensionsContributions extends Disposable implements IWorkbenchContributi } +class ExtensionStorageCleaner implements IWorkbenchContribution { + + constructor( + @IExtensionManagementService extensionManagementService: IExtensionManagementService, + @IStorageService storageService: IStorageService, + ) { + ExtensionStorageService.removeOutdatedExtensionVersions(extensionManagementService, storageService); + } +} + const workbenchRegistry = Registry.as(WorkbenchExtensions.Workbench); workbenchRegistry.registerWorkbenchContribution(ExtensionsContributions, LifecyclePhase.Starting); workbenchRegistry.registerWorkbenchContribution(StatusUpdater, LifecyclePhase.Restored); @@ -1571,7 +1582,7 @@ workbenchRegistry.registerWorkbenchContribution(ExtensionEnablementWorkspaceTrus workbenchRegistry.registerWorkbenchContribution(ExtensionsCompletionItemsProvider, LifecyclePhase.Restored); workbenchRegistry.registerWorkbenchContribution(UnsupportedExtensionsMigrationContrib, LifecyclePhase.Eventually); if (isWeb) { - workbenchRegistry.registerWorkbenchContribution(ExtensionsCleaner, LifecyclePhase.Eventually); + workbenchRegistry.registerWorkbenchContribution(ExtensionStorageCleaner, LifecyclePhase.Eventually); } diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsCleaner.ts b/src/vs/workbench/contrib/extensions/browser/extensionsCleaner.ts deleted file mode 100644 index 2d9b7872491..00000000000 --- a/src/vs/workbench/contrib/extensions/browser/extensionsCleaner.ts +++ /dev/null @@ -1,19 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { ExtensionStorageService } from 'vs/platform/extensionManagement/common/extensionStorage'; -import { IStorageService } from 'vs/platform/storage/common/storage'; -import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; - -export class ExtensionsCleaner implements IWorkbenchContribution { - - constructor( - @IExtensionManagementService extensionManagementService: IExtensionManagementService, - @IStorageService storageService: IStorageService, - ) { - ExtensionStorageService.removeOutdatedExtensionVersions(extensionManagementService, storageService); - } -} diff --git a/src/vs/workbench/services/extensionManagement/common/webExtensionManagementService.ts b/src/vs/workbench/services/extensionManagement/common/webExtensionManagementService.ts index 6c1cba6e975..147936d4468 100644 --- a/src/vs/workbench/services/extensionManagement/common/webExtensionManagementService.ts +++ b/src/vs/workbench/services/extensionManagement/common/webExtensionManagementService.ts @@ -4,14 +4,14 @@ *--------------------------------------------------------------------------------------------*/ import { ExtensionType, IExtension, IExtensionIdentifier, IExtensionManifest, TargetPlatform } from 'vs/platform/extensions/common/extensions'; -import { IExtensionManagementService, ILocalExtension, IGalleryExtension, IGalleryMetadata, InstallOperation, IExtensionGalleryService, InstallOptions, Metadata } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionManagementService, ILocalExtension, IGalleryExtension, IGalleryMetadata, InstallOperation, IExtensionGalleryService, InstallOptions, Metadata, UninstallOptions } from 'vs/platform/extensionManagement/common/extensionManagement'; import { URI } from 'vs/base/common/uri'; import { Event } from 'vs/base/common/event'; import { areSameExtensions, getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { IProfileAwareExtensionManagementService, IScannedExtension, IWebExtensionsScannerService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { ILogService } from 'vs/platform/log/common/log'; import { CancellationToken } from 'vs/base/common/cancellation'; -import { AbstractExtensionManagementService, AbstractExtensionTask, IInstallExtensionTask, IUninstallExtensionTask, UninstallExtensionTaskOptions } from 'vs/platform/extensionManagement/common/abstractExtensionManagementService'; +import { AbstractExtensionManagementService, AbstractExtensionTask, IInstallExtensionTask, IUninstallExtensionTask } from 'vs/platform/extensionManagement/common/abstractExtensionManagementService'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService'; import { IProductService } from 'vs/platform/product/common/productService'; @@ -106,7 +106,7 @@ export class WebExtensionManagementService extends AbstractExtensionManagementSe return new InstallExtensionTask(manifest, extension, options, this.webExtensionsScannerService); } - protected createDefaultUninstallExtensionTask(extension: ILocalExtension, options: UninstallExtensionTaskOptions): IUninstallExtensionTask { + protected createDefaultUninstallExtensionTask(extension: ILocalExtension, options: UninstallOptions): IUninstallExtensionTask { return new UninstallExtensionTask(extension, options, this.webExtensionsScannerService); } @@ -191,7 +191,7 @@ class UninstallExtensionTask extends AbstractExtensionTask implements IUni constructor( readonly extension: ILocalExtension, - options: UninstallExtensionTaskOptions, + options: UninstallOptions, private readonly webExtensionsScannerService: IWebExtensionsScannerService, ) { super(); From 2fdf21622bab057bb9095a3fd62783f636564e01 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Sun, 26 Jun 2022 00:19:35 +0200 Subject: [PATCH 014/347] reset when all profiles are removed --- .../sharedProcess/contrib/extensionsCleaner.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/vs/code/electron-browser/sharedProcess/contrib/extensionsCleaner.ts b/src/vs/code/electron-browser/sharedProcess/contrib/extensionsCleaner.ts index 3ac907be458..1900df95a38 100644 --- a/src/vs/code/electron-browser/sharedProcess/contrib/extensionsCleaner.ts +++ b/src/vs/code/electron-browser/sharedProcess/contrib/extensionsCleaner.ts @@ -44,7 +44,7 @@ export class ExtensionsCleaner extends Disposable { class ProfileExtensionsCleaner extends Disposable { private profileExtensionsLocations = new Map; - private readonly initPromise: Promise; + private initPromise: Promise; constructor( @INativeServerExtensionManagementService private readonly extensionManagementService: INativeServerExtensionManagementService, @@ -62,6 +62,7 @@ class ProfileExtensionsCleaner extends Disposable { } private async initialize(): Promise { + this.profileExtensionsLocations.clear(); if (this.userDataProfilesService.profiles.length === 1) { return true; } @@ -80,12 +81,15 @@ class ProfileExtensionsCleaner extends Disposable { } } - private async onDidChangeProfiles({ added, removed }: DidChangeProfilesEvent): Promise { + private async onDidChangeProfiles({ added, removed, all }: DidChangeProfilesEvent): Promise { if (!(await this.initPromise)) { return; } await Promise.all(added.map(profile => profile.extensionsResource ? this.populateExtensionsFromProfile(profile.extensionsResource) : Promise.resolve())); await Promise.all(removed.map(profile => profile.extensionsResource ? this.removeExtensionsFromProfile(profile.extensionsResource) : Promise.resolve())); + if (all.length === 1) { + this.initPromise = this.initialize(); + } } private async onDidInstallExtensions(installedExtensions: readonly ServerInstallExtensionResult[]): Promise { From 36f67de44f9dfc40746b31e5cbc0a27c21e0f39f Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Sun, 26 Jun 2022 00:21:39 +0200 Subject: [PATCH 015/347] reset only map --- .../sharedProcess/contrib/extensionsCleaner.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/vs/code/electron-browser/sharedProcess/contrib/extensionsCleaner.ts b/src/vs/code/electron-browser/sharedProcess/contrib/extensionsCleaner.ts index 1900df95a38..ea6ed685b29 100644 --- a/src/vs/code/electron-browser/sharedProcess/contrib/extensionsCleaner.ts +++ b/src/vs/code/electron-browser/sharedProcess/contrib/extensionsCleaner.ts @@ -62,7 +62,6 @@ class ProfileExtensionsCleaner extends Disposable { } private async initialize(): Promise { - this.profileExtensionsLocations.clear(); if (this.userDataProfilesService.profiles.length === 1) { return true; } @@ -88,7 +87,7 @@ class ProfileExtensionsCleaner extends Disposable { await Promise.all(added.map(profile => profile.extensionsResource ? this.populateExtensionsFromProfile(profile.extensionsResource) : Promise.resolve())); await Promise.all(removed.map(profile => profile.extensionsResource ? this.removeExtensionsFromProfile(profile.extensionsResource) : Promise.resolve())); if (all.length === 1) { - this.initPromise = this.initialize(); + this.profileExtensionsLocations.clear(); } } From 59ca0494c8e78c777363bc4135b9d3049172aa3b Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Sun, 26 Jun 2022 02:05:23 +0200 Subject: [PATCH 016/347] - fix clean up logic - fix installing other versions do not uninstall in profile mode - add more logging --- .../contrib/extensionsCleaner.ts | 100 +++++++++++------- .../abstractExtensionManagementService.ts | 16 +-- .../node/extensionManagementService.ts | 4 +- 3 files changed, 70 insertions(+), 50 deletions(-) diff --git a/src/vs/code/electron-browser/sharedProcess/contrib/extensionsCleaner.ts b/src/vs/code/electron-browser/sharedProcess/contrib/extensionsCleaner.ts index ea6ed685b29..e266b173425 100644 --- a/src/vs/code/electron-browser/sharedProcess/contrib/extensionsCleaner.ts +++ b/src/vs/code/electron-browser/sharedProcess/contrib/extensionsCleaner.ts @@ -3,9 +3,10 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Disposable } from 'vs/base/common/lifecycle'; +import { Disposable, DisposableStore, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { IExtensionGalleryService, IExtensionIdentifier, IGlobalExtensionEnablementService, ServerDidUninstallExtensionEvent, ServerInstallExtensionResult, UninstallOptions } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { getIdAndVersion } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { IExtensionsProfileScannerService } from 'vs/platform/extensionManagement/common/extensionsProfileScannerService'; import { ExtensionStorageService, IExtensionStorageService } from 'vs/platform/extensionManagement/common/extensionStorage'; import { migrateUnsupportedExtensions } from 'vs/platform/extensionManagement/common/unsupportedExtensionsMigration'; @@ -44,7 +45,8 @@ export class ExtensionsCleaner extends Disposable { class ProfileExtensionsCleaner extends Disposable { private profileExtensionsLocations = new Map; - private initPromise: Promise; + + private readonly profileModeDisposables = this._register(new MutableDisposable()); constructor( @INativeServerExtensionManagementService private readonly extensionManagementService: INativeServerExtensionManagementService, @@ -54,47 +56,54 @@ class ProfileExtensionsCleaner extends Disposable { @ILogService private readonly logService: ILogService, ) { super(); - - this.initPromise = this.initialize(); - this._register(this.userDataProfilesService.onDidChangeProfiles(e => this.onDidChangeProfiles(e))); - this._register(this.extensionManagementService.onDidInstallExtensions(e => this.onDidInstallExtensions(e))); - this._register(this.extensionManagementService.onDidUninstallExtension(e => this.onDidUninstallExtension(e))); - } - - private async initialize(): Promise { - if (this.userDataProfilesService.profiles.length === 1) { - return true; - } - try { - const installed = await this.extensionManagementService.getAllUserInstalled(); - await Promise.all(this.userDataProfilesService.profiles.map(profile => profile.extensionsResource ? this.populateExtensionsFromProfile(profile.extensionsResource) : Promise.resolve())); - const toUninstall = installed.filter(installedExtension => !this.profileExtensionsLocations.has(this.getKey(installedExtension.identifier, installedExtension.manifest.version))); - if (toUninstall.length) { - await Promise.all(toUninstall.map(extension => this.extensionManagementService.uninstall(extension, uninstalOptions))); - } - return true; - } catch (error) { - this.logService.error('ExtensionsCleaner: Failed to initialize'); - this.logService.error(error); - return false; - } + this.onDidChangeProfiles({ added: this.userDataProfilesService.profiles, removed: [], all: this.userDataProfilesService.profiles }); } private async onDidChangeProfiles({ added, removed, all }: DidChangeProfilesEvent): Promise { - if (!(await this.initPromise)) { + try { + await Promise.all(removed.map(profile => profile.extensionsResource ? this.removeExtensionsFromProfile(profile.extensionsResource) : Promise.resolve())); + } catch (error) { + this.logService.error(error); + } + + if (all.length === 0) { + // Exit profile mode + this.profileModeDisposables.clear(); + // Listen for entering into profile mode + const disposable = this._register(this.userDataProfilesService.onDidChangeProfiles(() => { + disposable.dispose(); + this.onDidChangeProfiles({ added: this.userDataProfilesService.profiles, removed: [], all: this.userDataProfilesService.profiles }); + })); return; } - await Promise.all(added.map(profile => profile.extensionsResource ? this.populateExtensionsFromProfile(profile.extensionsResource) : Promise.resolve())); - await Promise.all(removed.map(profile => profile.extensionsResource ? this.removeExtensionsFromProfile(profile.extensionsResource) : Promise.resolve())); - if (all.length === 1) { - this.profileExtensionsLocations.clear(); + + try { + if (added.length) { + await Promise.all(added.map(profile => profile.extensionsResource ? this.populateExtensionsFromProfile(profile.extensionsResource) : Promise.resolve())); + // Enter profile mode + if (!this.profileModeDisposables.value) { + this.profileModeDisposables.value = new DisposableStore(); + this.profileModeDisposables.value.add(toDisposable(() => this.profileExtensionsLocations.clear())); + this.profileModeDisposables.value.add(this.userDataProfilesService.onDidChangeProfiles(e => this.onDidChangeProfiles(e))); + this.profileModeDisposables.value.add(this.extensionManagementService.onDidInstallExtensions(e => this.onDidInstallExtensions(e))); + this.profileModeDisposables.value.add(this.extensionManagementService.onDidUninstallExtension(e => this.onDidUninstallExtension(e))); + await this.uninstallExtensionsNotInProfiles(); + } + } + } catch (error) { + this.logService.error(error); + } + } + + private async uninstallExtensionsNotInProfiles(): Promise { + const installed = await this.extensionManagementService.getAllUserInstalled(); + const toUninstall = installed.filter(installedExtension => !this.profileExtensionsLocations.has(this.getKey(installedExtension.identifier, installedExtension.manifest.version))); + if (toUninstall.length) { + await Promise.all(toUninstall.map(extension => this.extensionManagementService.uninstall(extension, uninstalOptions))); } } private async onDidInstallExtensions(installedExtensions: readonly ServerInstallExtensionResult[]): Promise { - if (!(await this.initPromise)) { - return; - } for (const { local, profileLocation } of installedExtensions) { if (!local || !profileLocation) { continue; @@ -107,9 +116,6 @@ class ProfileExtensionsCleaner extends Disposable { if (!e.profileLocation || !e.version) { return; } - if (!(await this.initPromise)) { - return; - } if (this.removeExtensionWithKey(this.getKey(e.identifier, e.version), e.profileLocation)) { await this.uninstallExtensions([{ identifier: e.identifier, version: e.version }]); } @@ -123,8 +129,16 @@ class ProfileExtensionsCleaner extends Disposable { } private async removeExtensionsFromProfile(removedProfile: URI): Promise { - const profileExtensions = await this.extensionsProfileScannerService.scanProfileExtensions(removedProfile); - const extensionsToRemove = profileExtensions.filter(profileExtension => this.removeExtensionWithKey(this.getKey(profileExtension.identifier, profileExtension.version), removedProfile)); + const extensionsToRemove: { identifier: IExtensionIdentifier; version: string }[] = []; + for (const key of [...this.profileExtensionsLocations.keys()]) { + if (!this.removeExtensionWithKey(key, removedProfile)) { + continue; + } + const extensionToRemove = this.fromKey(key); + if (extensionToRemove) { + extensionsToRemove.push(extensionToRemove); + } + } if (extensionsToRemove.length) { await this.uninstallExtensions(extensionsToRemove); } @@ -149,8 +163,9 @@ class ProfileExtensionsCleaner extends Disposable { } if (!profiles?.length) { this.profileExtensionsLocations.delete(key); + return true; } - return !profiles?.length; + return false; } private async uninstallExtensions(extensionsToRemove: { identifier: IExtensionIdentifier; version: string }[]): Promise { @@ -165,4 +180,9 @@ class ProfileExtensionsCleaner extends Disposable { return `${ExtensionIdentifier.toKey(identifier.id)}@${version}`; } + private fromKey(key: string): { identifier: IExtensionIdentifier; version: string } | undefined { + const [id, version] = getIdAndVersion(key); + return version ? { identifier: { id }, version } : undefined; + } + } diff --git a/src/vs/platform/extensionManagement/common/abstractExtensionManagementService.ts b/src/vs/platform/extensionManagement/common/abstractExtensionManagementService.ts index c31a9e3c427..5e5353eed1f 100644 --- a/src/vs/platform/extensionManagement/common/abstractExtensionManagementService.ts +++ b/src/vs/platform/extensionManagement/common/abstractExtensionManagementService.ts @@ -436,9 +436,9 @@ export abstract class AbstractExtensionManagementService extends Disposable impl const uninstallExtensionTask = this.createUninstallExtensionTask(extension, uninstallOptions, options.profileLocation); this.uninstallingExtensions.set(getUninstallExtensionTaskKey(uninstallExtensionTask.extension.identifier), uninstallExtensionTask); if (options.profileLocation) { - this.logService.info('Uninstalling extension from the profile:', extension.identifier.id, options.profileLocation.toString()); + this.logService.info('Uninstalling extension from the profile:', `${extension.identifier.id}@${extension.manifest.version}`, options.profileLocation.toString()); } else { - this.logService.info('Uninstalling extension:', extension.identifier.id); + this.logService.info('Uninstalling extension:', `${extension.identifier.id}@${extension.manifest.version}`); } this._onUninstallExtension.fire({ identifier: extension.identifier, profileLocation: options.profileLocation, applicationScoped: extension.isApplicationScoped }); return uninstallExtensionTask; @@ -447,15 +447,15 @@ export abstract class AbstractExtensionManagementService extends Disposable impl const postUninstallExtension = (extension: ILocalExtension, error?: ExtensionManagementError): void => { if (error) { if (options.profileLocation) { - this.logService.error('Failed to uninstall extension from the profile:', extension.identifier.id, options.profileLocation.toString(), error.message); + this.logService.error('Failed to uninstall extension from the profile:', `${extension.identifier.id}@${extension.manifest.version}`, options.profileLocation.toString(), error.message); } else { - this.logService.error('Failed to uninstall extension:', extension.identifier.id, error.message); + this.logService.error('Failed to uninstall extension:', `${extension.identifier.id}@${extension.manifest.version}`, error.message); } } else { if (options.profileLocation) { - this.logService.info('Successfully uninstalled extension from the profile', extension.identifier.id, options.profileLocation.toString()); + this.logService.info('Successfully uninstalled extension from the profile', `${extension.identifier.id}@${extension.manifest.version}`, options.profileLocation.toString()); } else { - this.logService.info('Successfully uninstalled extension:', extension.identifier.id); + this.logService.info('Successfully uninstalled extension:', `${extension.identifier.id}@${extension.manifest.version}`); } } reportTelemetry(this.telemetryService, 'extensionGallery:uninstall', { extensionData: getLocalExtensionTelemetryData(extension), error }); @@ -469,7 +469,7 @@ export abstract class AbstractExtensionManagementService extends Disposable impl allTasks.push(createUninstallExtensionTask(extension, options)); const installed = await this.getInstalled(ExtensionType.User, options.profileLocation); if (options.donotIncludePack) { - this.logService.info('Uninstalling the extension without including packed extension', extension.identifier.id); + this.logService.info('Uninstalling the extension without including packed extension', `${extension.identifier.id}@${extension.manifest.version}`); } else { const packedExtensions = this.getAllPackExtensionsToUninstall(extension, installed); for (const packedExtension of packedExtensions) { @@ -482,7 +482,7 @@ export abstract class AbstractExtensionManagementService extends Disposable impl } if (options.donotCheckDependents) { - this.logService.info('Uninstalling the extension without checking dependents', extension.identifier.id); + this.logService.info('Uninstalling the extension without checking dependents', `${extension.identifier.id}@${extension.manifest.version}`); } else { this.checkForDependents(allTasks.map(task => task.extension), installed, extension); } diff --git a/src/vs/platform/extensionManagement/node/extensionManagementService.ts b/src/vs/platform/extensionManagement/node/extensionManagementService.ts index 3eadb31770b..56ea181d99e 100644 --- a/src/vs/platform/extensionManagement/node/extensionManagementService.ts +++ b/src/vs/platform/extensionManagement/node/extensionManagementService.ts @@ -595,7 +595,7 @@ class InstallGalleryExtensionTask extends InstallExtensionTask { const zipPath = await this.downloadExtension(this.gallery, this._operation); try { const local = await this.installExtension({ zipPath, key: ExtensionKey.create(this.gallery), metadata }, token); - if (existingExtension && (existingExtension.targetPlatform !== local.targetPlatform || semver.neq(existingExtension.manifest.version, local.manifest.version))) { + if (existingExtension && !this.options.profileLocation && (existingExtension.targetPlatform !== local.targetPlatform || semver.neq(existingExtension.manifest.version, local.manifest.version))) { await this.extensionsScanner.setUninstalled(existingExtension); } return { local, metadata }; @@ -664,7 +664,7 @@ class InstallVSIXTask extends InstallExtensionTask { } catch (e) { throw new Error(nls.localize('restartCode', "Please restart VS Code before reinstalling {0}.", this.manifest.displayName || this.manifest.name)); } - } else if (semver.gt(existing.manifest.version, this.manifest.version)) { + } else if (!this.options.profileLocation && semver.gt(existing.manifest.version, this.manifest.version)) { await this.extensionsScanner.setUninstalled(existing); } } else { From 60b75142de7e82b657ed89e87b0d71c26fa54cf8 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Sun, 26 Jun 2022 07:06:11 +0200 Subject: [PATCH 017/347] implement `IEditorInput#confirm` (#153211) implement `IEditorInput#confirm` to confirm with users that it is OK to close a merge editor despite unresolved conflicts. As a side-effect keep the merge editor dirty while it is unsed and while it has unresolved conflicts fixes https://github.com/microsoft/vscode/issues/151024 --- .../mergeEditor/browser/mergeEditorInput.ts | 71 ++++++++++++++++++- .../browser/model/mergeEditorModel.ts | 2 + 2 files changed, 71 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInput.ts b/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInput.ts index 7a248a0125b..6526f2eeee0 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInput.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInput.ts @@ -5,15 +5,18 @@ import { DisposableStore } from 'vs/base/common/lifecycle'; import { isEqual } from 'vs/base/common/resources'; +import Severity from 'vs/base/common/severity'; import { URI } from 'vs/base/common/uri'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { localize } from 'vs/nls'; +import { ConfirmResult, IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { IFileService } from 'vs/platform/files/common/files'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ILabelService } from 'vs/platform/label/common/label'; -import { IUntypedEditorInput } from 'vs/workbench/common/editor'; +import { IEditorIdentifier, IUntypedEditorInput } from 'vs/workbench/common/editor'; import { EditorInput } from 'vs/workbench/common/editor/editorInput'; import { AbstractTextResourceEditorInput } from 'vs/workbench/common/editor/textResourceEditorInput'; +import { autorun } from 'vs/workbench/contrib/audioCues/browser/observable'; import { MergeEditorModel } from 'vs/workbench/contrib/mergeEditor/browser/model/mergeEditorModel'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { ILanguageSupport, ITextFileEditorModel, ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; @@ -33,6 +36,7 @@ export class MergeEditorInput extends AbstractTextResourceEditorInput implements private _model?: MergeEditorModel; private _outTextModel?: ITextFileEditorModel; + private _ignoreUnhandledConflictsForDirtyState?: true; constructor( public readonly base: URI, @@ -41,6 +45,7 @@ export class MergeEditorInput extends AbstractTextResourceEditorInput implements public readonly result: URI, @IInstantiationService private readonly _instaService: IInstantiationService, @ITextModelService private readonly _textModelService: ITextModelService, + @IDialogService private readonly _dialogService: IDialogService, @IEditorService editorService: IEditorService, @ITextFileService textFileService: ITextFileService, @ILabelService labelService: ILabelService, @@ -112,7 +117,14 @@ export class MergeEditorInput extends AbstractTextResourceEditorInput implements this._store.add(input1); this._store.add(input2); this._store.add(result); + + this._store.add(autorun(reader => { + this._model?.hasUnhandledConflicts.read(reader); + this._onDidChangeDirty.fire(undefined); + }, 'drive::onDidChangeDirty')); } + + this._ignoreUnhandledConflictsForDirtyState = undefined; return this._model; } @@ -129,7 +141,62 @@ export class MergeEditorInput extends AbstractTextResourceEditorInput implements // ---- FileEditorInput override isDirty(): boolean { - return Boolean(this._outTextModel?.isDirty()); + const textModelDirty = Boolean(this._outTextModel?.isDirty()); + if (textModelDirty) { + // text model dirty -> 3wm is dirty + return true; + } + if (!this._ignoreUnhandledConflictsForDirtyState) { + // unhandled conflicts -> 3wm is dirty UNLESS we explicitly set this input + // to ignore unhandled conflicts for the dirty-state. This happens only + // after confirming to ignore unhandled changes + return Boolean(this._model && this._model.hasUnhandledConflicts.get()); + } + return false; + } + + override async confirm(editors?: ReadonlyArray): Promise { + + const inputs: MergeEditorInput[] = [this]; + if (editors) { + for (const { editor } of editors) { + if (editor instanceof MergeEditorInput) { + inputs.push(editor); + } + } + } + + const inputsWithUnhandledConflicts = inputs + .filter(input => input._model && input._model.hasUnhandledConflicts.get()); + + if (inputsWithUnhandledConflicts.length === 0) { + return ConfirmResult.SAVE; + } + + const { choice } = await this._dialogService.show( + Severity.Info, + localize('unhandledConflicts.msg', 'Do you want to continue with unhandled conflicts?'), + [ + localize('unhandledConflicts.ignore', "Continue with Conflicts"), + localize('unhandledConflicts.cancel', "Cancel") + ], + { + cancelId: 1, + detail: inputsWithUnhandledConflicts.length > 1 + ? localize('unhandledConflicts.detailN', 'Merge conflicts in {0} editors will remain unhandled.', inputsWithUnhandledConflicts.length) + : localize('unhandledConflicts.detail1', 'Merge conflicts in this editor will remain unhandled.') + } + ); + + if (choice !== 0) { + return ConfirmResult.CANCEL; + } + + // continue with conflicts, tell inputs to ignore unhandled changes + for (const input of inputsWithUnhandledConflicts) { + input._ignoreUnhandledConflictsForDirtyState = true; + } + return ConfirmResult.SAVE; } setLanguageId(languageId: string, _setExplicitly?: boolean): void { diff --git a/src/vs/workbench/contrib/mergeEditor/browser/model/mergeEditorModel.ts b/src/vs/workbench/contrib/mergeEditor/browser/model/mergeEditorModel.ts index 3165fafc2f0..da826139b03 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/model/mergeEditorModel.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/model/mergeEditorModel.ts @@ -91,6 +91,8 @@ export class MergeEditorModel extends EditorModel { return map.size - handledCount; }); + public readonly hasUnhandledConflicts = this.unhandledConflictsCount.map(value => value > 0); + public readonly input1ResultMapping = derivedObservable('input1ResultMapping', reader => { const resultDiffs = this.resultDiffs.read(reader); const modifiedBaseRanges = DocumentMapping.betweenOutputs(this.input1LinesDiffs.read(reader), resultDiffs, this.input1.getLineCount()); From 5db26d0a4fb1364e3d072c3383774e0dd9b8f794 Mon Sep 17 00:00:00 2001 From: Robo Date: Sun, 26 Jun 2022 15:39:47 +0900 Subject: [PATCH 018/347] chore: update electron@18.3.5 (#153231) From 4959d430669da1ff64557727811ad1d72bcc4dd2 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Sun, 26 Jun 2022 13:29:06 +0200 Subject: [PATCH 019/347] refactor: :stethoscope: use StorageScope.Application for update feature Related-to: #152679 --- .../contrib/update/browser/update.ts | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/vs/workbench/contrib/update/browser/update.ts b/src/vs/workbench/contrib/update/browser/update.ts index 0dc78c3dce4..1ff40d85b54 100644 --- a/src/vs/workbench/contrib/update/browser/update.ts +++ b/src/vs/workbench/contrib/update/browser/update.ts @@ -163,7 +163,7 @@ export class ProductContribution implements IWorkbenchContribution { return; } - const lastVersion = parseVersion(storageService.get(ProductContribution.KEY, StorageScope.PROFILE, '')); + const lastVersion = parseVersion(storageService.get(ProductContribution.KEY, StorageScope.APPLICATION, '')); const currentVersion = parseVersion(productService.version); const shouldShowReleaseNotes = configurationService.getValue('update.showReleaseNotes'); const releaseNotesUrl = productService.releaseNotesUrl; @@ -186,7 +186,7 @@ export class ProductContribution implements IWorkbenchContribution { }); } - storageService.store(ProductContribution.KEY, productService.version, StorageScope.PROFILE, StorageTarget.MACHINE); + storageService.store(ProductContribution.KEY, productService.version, StorageScope.APPLICATION, StorageTarget.MACHINE); }); } } @@ -224,12 +224,12 @@ export class UpdateContribution extends Disposable implements IWorkbenchContribu */ const currentVersion = this.productService.commit; - const lastKnownVersion = this.storageService.get('update/lastKnownVersion', StorageScope.PROFILE); + const lastKnownVersion = this.storageService.get('update/lastKnownVersion', StorageScope.APPLICATION); // if current version != stored version, clear both fields if (currentVersion !== lastKnownVersion) { - this.storageService.remove('update/lastKnownVersion', StorageScope.PROFILE); - this.storageService.remove('update/updateNotificationTime', StorageScope.PROFILE); + this.storageService.remove('update/lastKnownVersion', StorageScope.APPLICATION); + this.storageService.remove('update/updateNotificationTime', StorageScope.APPLICATION); } this.registerGlobalActivityActions(); @@ -400,15 +400,15 @@ export class UpdateContribution extends Disposable implements IWorkbenchContribu private shouldShowNotification(): boolean { const currentVersion = this.productService.commit; const currentMillis = new Date().getTime(); - const lastKnownVersion = this.storageService.get('update/lastKnownVersion', StorageScope.PROFILE); + const lastKnownVersion = this.storageService.get('update/lastKnownVersion', StorageScope.APPLICATION); // if version != stored version, save version and date if (currentVersion !== lastKnownVersion) { - this.storageService.store('update/lastKnownVersion', currentVersion!, StorageScope.PROFILE, StorageTarget.MACHINE); - this.storageService.store('update/updateNotificationTime', currentMillis, StorageScope.PROFILE, StorageTarget.MACHINE); + this.storageService.store('update/lastKnownVersion', currentVersion!, StorageScope.APPLICATION, StorageTarget.MACHINE); + this.storageService.store('update/updateNotificationTime', currentMillis, StorageScope.APPLICATION, StorageTarget.MACHINE); } - const updateNotificationMillis = this.storageService.getNumber('update/updateNotificationTime', StorageScope.PROFILE, currentMillis); + const updateNotificationMillis = this.storageService.getNumber('update/updateNotificationTime', StorageScope.APPLICATION, currentMillis); const diffDays = (currentMillis - updateNotificationMillis) / (1000 * 60 * 60 * 24); return diffDays > 5; @@ -536,12 +536,12 @@ export class SwitchProductQualityContribution extends Disposable implements IWor const userDataSyncStore = userDataSyncStoreManagementService.userDataSyncStore; let userDataSyncStoreType: UserDataSyncStoreType | undefined; if (userDataSyncStore && isSwitchingToInsiders && userDataSyncEnablementService.isEnabled() - && !storageService.getBoolean(selectSettingsSyncServiceDialogShownKey, StorageScope.PROFILE, false)) { + && !storageService.getBoolean(selectSettingsSyncServiceDialogShownKey, StorageScope.APPLICATION, false)) { userDataSyncStoreType = await this.selectSettingsSyncService(dialogService); if (!userDataSyncStoreType) { return; } - storageService.store(selectSettingsSyncServiceDialogShownKey, true, StorageScope.PROFILE, StorageTarget.USER); + storageService.store(selectSettingsSyncServiceDialogShownKey, true, StorageScope.APPLICATION, StorageTarget.USER); if (userDataSyncStoreType === 'stable') { // Update the stable service type in the current window, so that it uses stable service after switched to insiders version (after reload). await userDataSyncStoreManagementService.switch(userDataSyncStoreType); @@ -576,7 +576,7 @@ export class SwitchProductQualityContribution extends Disposable implements IWor } else { // Reset if (userDataSyncStoreType) { - storageService.remove(selectSettingsSyncServiceDialogShownKey, StorageScope.PROFILE); + storageService.remove(selectSettingsSyncServiceDialogShownKey, StorageScope.APPLICATION); } } } catch (error) { From 1b08a89fc82549c84c73195eac41244dd72cc9cb Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com> Date: Sun, 26 Jun 2022 13:33:27 +0200 Subject: [PATCH 020/347] SCM - Use default cursor for the action button list item (#153107) * Use default cursor for the action button list item * Remove !important --- src/vs/workbench/contrib/scm/browser/media/scm.css | 4 ++++ src/vs/workbench/contrib/scm/browser/scmViewPane.ts | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/scm/browser/media/scm.css b/src/vs/workbench/contrib/scm/browser/media/scm.css index 198babcb503..efe65fa662e 100644 --- a/src/vs/workbench/contrib/scm/browser/media/scm.css +++ b/src/vs/workbench/contrib/scm/browser/media/scm.css @@ -173,6 +173,10 @@ background: transparent !important; } +.scm-view .monaco-list .monaco-list-row.cursor-default { + cursor: default; +} + .scm-view.show-actions .scm-provider > .actions, .scm-view.show-actions > .monaco-list .monaco-list-row .resource-group > .actions, .scm-view.show-actions > .monaco-list .monaco-list-row .resource > .name > .monaco-icon-label > .actions { diff --git a/src/vs/workbench/contrib/scm/browser/scmViewPane.ts b/src/vs/workbench/contrib/scm/browser/scmViewPane.ts index df9e433c2fa..350110a01f9 100644 --- a/src/vs/workbench/contrib/scm/browser/scmViewPane.ts +++ b/src/vs/workbench/contrib/scm/browser/scmViewPane.ts @@ -119,8 +119,8 @@ class ActionButtonRenderer implements ICompressibleTreeRenderer Date: Sun, 26 Jun 2022 20:52:40 +0200 Subject: [PATCH 021/347] Allow dependabot to make yarn.lock changes (#153240) allow dependabot to make yarn.lock changes --- .github/workflows/no-yarn-lock-changes.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/no-yarn-lock-changes.yml b/.github/workflows/no-yarn-lock-changes.yml index ebd735bf7e5..300a98ad998 100644 --- a/.github/workflows/no-yarn-lock-changes.yml +++ b/.github/workflows/no-yarn-lock-changes.yml @@ -18,8 +18,9 @@ jobs: run: | echo "user: ${{ github.event.pull_request.user.login }}" echo "role: ${{ fromJson(steps.get_permissions.outputs.data).permission }}" + echo "is dependabot: ${{ github.event.pull_request.user.login == 'dependabot[bot]' }}" echo "should_run: ${{ !contains(fromJson('["admin", "write"]'), fromJson(steps.get_permissions.outputs.data).permission) }}" - echo "::set-output name=should_run::${{ !contains(fromJson('["admin", "write"]'), fromJson(steps.get_permissions.outputs.data).permission) }}" + echo "::set-output name=should_run::${{ !contains(fromJson('["admin", "write"]'), fromJson(steps.get_permissions.outputs.data).permission) && github.event.pull_request.user.login != 'dependabot[bot]' }}" - name: Get file changes uses: trilom/file-changes-action@ce38c8ce2459ca3c303415eec8cb0409857b4272 if: ${{ steps.control.outputs.should_run == 'true' }} From c52dd348a798fe566b015d744e5a6723fe765999 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 26 Jun 2022 19:27:19 +0000 Subject: [PATCH 022/347] Bump shell-quote from 1.7.2 to 1.7.3 in /test/smoke (#152842) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [shell-quote](https://github.com/substack/node-shell-quote) from 1.7.2 to 1.7.3. - [Release notes](https://github.com/substack/node-shell-quote/releases) - [Changelog](https://github.com/substack/node-shell-quote/blob/master/CHANGELOG.md) - [Commits](https://github.com/substack/node-shell-quote/compare/v1.7.2...1.7.3) --- updated-dependencies: - dependency-name: shell-quote dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: João Moreno --- test/smoke/yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/smoke/yarn.lock b/test/smoke/yarn.lock index ecc11bc9a50..e73fb8b7865 100644 --- a/test/smoke/yarn.lock +++ b/test/smoke/yarn.lock @@ -702,9 +702,9 @@ shebang-regex@^1.0.0: integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= shell-quote@^1.6.1: - version "1.7.2" - resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.2.tgz#67a7d02c76c9da24f99d20808fcaded0e0e04be2" - integrity sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg== + version "1.7.3" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.3.tgz#aa40edac170445b9a431e17bb62c0b881b9c4123" + integrity sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw== spdx-correct@^3.0.0: version "3.1.1" From 909f8417858d8ccb99b46f7ea0d0b1d4cc60f7e5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 26 Jun 2022 19:27:42 +0000 Subject: [PATCH 023/347] Bump got from 11.8.1 to 11.8.5 in /build (#152788) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [got](https://github.com/sindresorhus/got) from 11.8.1 to 11.8.5. - [Release notes](https://github.com/sindresorhus/got/releases) - [Commits](https://github.com/sindresorhus/got/compare/v11.8.1...v11.8.5) --- updated-dependencies: - dependency-name: got dependency-type: direct:development ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: João Moreno --- build/package.json | 2 +- build/yarn.lock | 25 +++++++++++++++---------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/build/package.json b/build/package.json index c259ad65063..b58f58be433 100644 --- a/build/package.json +++ b/build/package.json @@ -52,7 +52,7 @@ "esbuild": "^0.14.2", "extract-zip": "^2.0.1", "fs-extra": "^9.1.0", - "got": "11.8.1", + "got": "11.8.5", "gulp-merge-json": "^2.1.1", "gulp-shell": "^0.8.0", "jsonc-parser": "^2.3.0", diff --git a/build/yarn.lock b/build/yarn.lock index d65a62ebce3..bb6fcbcb482 100644 --- a/build/yarn.lock +++ b/build/yarn.lock @@ -1067,17 +1067,17 @@ cacheable-request@^6.0.0: normalize-url "^4.1.0" responselike "^1.0.2" -cacheable-request@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.1.tgz#062031c2856232782ed694a257fa35da93942a58" - integrity sha512-lt0mJ6YAnsrBErpTMWeu5kl/tg9xMAWjavYTN6VQXM1A/teBITuNcccXsCxF0tDQQJf9DfAaX5O4e0zp0KlfZw== +cacheable-request@^7.0.2: + version "7.0.2" + resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.2.tgz#ea0d0b889364a25854757301ca12b2da77f91d27" + integrity sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew== dependencies: clone-response "^1.0.2" get-stream "^5.1.0" http-cache-semantics "^4.0.0" keyv "^4.0.0" lowercase-keys "^2.0.0" - normalize-url "^4.1.0" + normalize-url "^6.0.1" responselike "^2.0.0" call-bind@^1.0.0: @@ -1974,17 +1974,17 @@ globby@^11.0.4: merge2 "^1.4.1" slash "^3.0.0" -got@11.8.1: - version "11.8.1" - resolved "https://registry.yarnpkg.com/got/-/got-11.8.1.tgz#df04adfaf2e782babb3daabc79139feec2f7e85d" - integrity sha512-9aYdZL+6nHmvJwHALLwKSUZ0hMwGaJGYv3hoPLPgnT8BoBXm1SjnZeky+91tfwJaDzun2s4RsBRy48IEYv2q2Q== +got@11.8.5: + version "11.8.5" + resolved "https://registry.yarnpkg.com/got/-/got-11.8.5.tgz#ce77d045136de56e8f024bebb82ea349bc730046" + integrity sha512-o0Je4NvQObAuZPHLFoRSkdG2lTgtcynqymzg2Vupdx6PorhaT5MCbIyXG6d4D94kk8ZG57QeosgdiqfJWhEhlQ== dependencies: "@sindresorhus/is" "^4.0.0" "@szmarczak/http-timer" "^4.0.5" "@types/cacheable-request" "^6.0.1" "@types/responselike" "^1.0.0" cacheable-lookup "^5.0.3" - cacheable-request "^7.0.1" + cacheable-request "^7.0.2" decompress-response "^6.0.0" http2-wrapper "^1.0.0-beta.5.2" lowercase-keys "^2.0.0" @@ -2604,6 +2604,11 @@ normalize-url@^4.1.0: resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.1.tgz#0dd90cf1288ee1d1313b87081c9a5932ee48518a" integrity sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA== +normalize-url@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" + integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A== + npm-conf@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/npm-conf/-/npm-conf-1.1.3.tgz#256cc47bd0e218c259c4e9550bf413bc2192aff9" From 4d427d6aa9b30487ad9bf397caae66c699962339 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 26 Jun 2022 19:29:13 +0000 Subject: [PATCH 024/347] Bump shell-quote from 1.7.2 to 1.7.3 (#152789) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [shell-quote](https://github.com/substack/node-shell-quote) from 1.7.2 to 1.7.3. - [Release notes](https://github.com/substack/node-shell-quote/releases) - [Changelog](https://github.com/substack/node-shell-quote/blob/master/CHANGELOG.md) - [Commits](https://github.com/substack/node-shell-quote/compare/v1.7.2...1.7.3) --- updated-dependencies: - dependency-name: shell-quote dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: João Moreno --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index cfa2dc717d5..e1813ce55da 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10292,9 +10292,9 @@ shebang-regex@^3.0.0: integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== shell-quote@^1.6.1: - version "1.7.2" - resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.2.tgz#67a7d02c76c9da24f99d20808fcaded0e0e04be2" - integrity sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg== + version "1.7.3" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.3.tgz#aa40edac170445b9a431e17bb62c0b881b9c4123" + integrity sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw== shimmer@^1.1.0, shimmer@^1.2.0: version "1.2.1" From 81113e2d4bbfa2f55d7b8061ff406456ef39f854 Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com> Date: Mon, 27 Jun 2022 08:59:17 +0200 Subject: [PATCH 025/347] Engineering - Update notebooks (#153273) Update notebooks --- .vscode/notebooks/endgame.github-issues | 2 +- .vscode/notebooks/my-endgame.github-issues | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.vscode/notebooks/endgame.github-issues b/.vscode/notebooks/endgame.github-issues index 48195c79000..e1a91c7b80a 100644 --- a/.vscode/notebooks/endgame.github-issues +++ b/.vscode/notebooks/endgame.github-issues @@ -7,7 +7,7 @@ { "kind": 2, "language": "github-issues", - "value": "$REPOS=repo:microsoft/vscode repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-dev repo:microsoft/vscode-js-debug repo:microsoft/vscode-remote-release repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-remotehub repo:microsoft/vscode-remote-repositories-github repo:microsoft/vscode-livepreview repo:microsoft/vscode-python repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal repo:microsoft/vscode-unpkg\r\n\r\n$MILESTONE=milestone:\"May 2022\"" + "value": "$REPOS=repo:microsoft/vscode repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-dev repo:microsoft/vscode-js-debug repo:microsoft/vscode-remote-release repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-remotehub repo:microsoft/vscode-remote-repositories-github repo:microsoft/vscode-livepreview repo:microsoft/vscode-python repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal repo:microsoft/vscode-unpkg\n\n$MILESTONE=milestone:\"June 2022\"" }, { "kind": 1, diff --git a/.vscode/notebooks/my-endgame.github-issues b/.vscode/notebooks/my-endgame.github-issues index 4ce504b017f..342cb52b014 100644 --- a/.vscode/notebooks/my-endgame.github-issues +++ b/.vscode/notebooks/my-endgame.github-issues @@ -7,7 +7,7 @@ { "kind": 2, "language": "github-issues", - "value": "$REPOS=repo:microsoft/vscode repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-dev repo:microsoft/vscode-js-debug repo:microsoft/vscode-remote-release repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-remotehub repo:microsoft/vscode-remote-repositories-github repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-livepreview repo:microsoft/vscode-python repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal\n\n$MILESTONE=milestone:\"May 2022\"\n\n$MINE=assignee:@me" + "value": "$REPOS=repo:microsoft/vscode repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-dev repo:microsoft/vscode-js-debug repo:microsoft/vscode-remote-release repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-remotehub repo:microsoft/vscode-remote-repositories-github repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-livepreview repo:microsoft/vscode-python repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal\n\n$MILESTONE=milestone:\"June 2022\"\n\n$MINE=assignee:@me" }, { "kind": 1, From a3ee1bfbd9e2877fd0be8d84804332c76f9c0333 Mon Sep 17 00:00:00 2001 From: SteVen Batten <6561887+sbatten@users.noreply.github.com> Date: Mon, 27 Jun 2022 00:18:23 -0700 Subject: [PATCH 026/347] remember view containers that aren't registered yet (#153150) fixes #149503 The comments panel was being registered later so by the time we went to save it back to the cache, we thought were removing it. Then, once it was registered, we would pin it since we thought it was new. Following, the behavior of the activity bar, we save it back to the cache as is. --- src/vs/workbench/browser/parts/panel/panelPart.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/vs/workbench/browser/parts/panel/panelPart.ts b/src/vs/workbench/browser/parts/panel/panelPart.ts index ae801b2921a..2263ec0769e 100644 --- a/src/vs/workbench/browser/parts/panel/panelPart.ts +++ b/src/vs/workbench/browser/parts/panel/panelPart.ts @@ -823,6 +823,8 @@ export abstract class BasePanelPart extends CompositePart impleme const viewContainerModel = this.viewDescriptorService.getViewContainerModel(viewContainer); state.push({ id: compositeItem.id, name: viewContainerModel.title, pinned: compositeItem.pinned, order: compositeItem.order, visible: compositeItem.visible }); placeholders.push({ id: compositeItem.id, name: this.getCompositeActions(compositeItem.id).activityAction.label }); + } else { + state.push({ id: compositeItem.id, name: compositeItem.name, pinned: compositeItem.pinned, order: compositeItem.order, visible: compositeItem.visible }); } } From e71b6105ebb4fbcfbf38a1b62bcbafdb048d3468 Mon Sep 17 00:00:00 2001 From: Robo Date: Mon, 27 Jun 2022 16:43:27 +0900 Subject: [PATCH 027/347] fix: rpm dependency on gdk-pixbuf (#153276) --- build/linux/rpm/dep-lists.js | 3 --- build/linux/rpm/dep-lists.ts | 3 --- 2 files changed, 6 deletions(-) diff --git a/build/linux/rpm/dep-lists.js b/build/linux/rpm/dep-lists.js index 0896b1bb6ca..02886a53b12 100644 --- a/build/linux/rpm/dep-lists.js +++ b/build/linux/rpm/dep-lists.js @@ -74,7 +74,6 @@ exports.referenceGeneratedDepsByArch = { 'libgbm.so.1()(64bit)', 'libgcc_s.so.1()(64bit)', 'libgcc_s.so.1(GCC_3.0)(64bit)', - 'libgdk_pixbuf-2.0.so.0()(64bit)', 'libgio-2.0.so.0()(64bit)', 'libglib-2.0.so.0()(64bit)', 'libgobject-2.0.so.0()(64bit)', @@ -157,7 +156,6 @@ exports.referenceGeneratedDepsByArch = { 'libgcc_s.so.1(GCC_3.0)', 'libgcc_s.so.1(GCC_3.4)', 'libgcc_s.so.1(GCC_3.5)', - 'libgdk_pixbuf-2.0.so.0', 'libgio-2.0.so.0', 'libglib-2.0.so.0', 'libgobject-2.0.so.0', @@ -247,7 +245,6 @@ exports.referenceGeneratedDepsByArch = { 'libgcc_s.so.1(GCC_3.0)(64bit)', 'libgcc_s.so.1(GCC_4.2.0)(64bit)', 'libgcc_s.so.1(GCC_4.5.0)(64bit)', - 'libgdk_pixbuf-2.0.so.0()(64bit)', 'libgio-2.0.so.0()(64bit)', 'libglib-2.0.so.0()(64bit)', 'libgobject-2.0.so.0()(64bit)', diff --git a/build/linux/rpm/dep-lists.ts b/build/linux/rpm/dep-lists.ts index 8ef34d0320f..012755a04c5 100644 --- a/build/linux/rpm/dep-lists.ts +++ b/build/linux/rpm/dep-lists.ts @@ -74,7 +74,6 @@ export const referenceGeneratedDepsByArch = { 'libgbm.so.1()(64bit)', 'libgcc_s.so.1()(64bit)', 'libgcc_s.so.1(GCC_3.0)(64bit)', - 'libgdk_pixbuf-2.0.so.0()(64bit)', 'libgio-2.0.so.0()(64bit)', 'libglib-2.0.so.0()(64bit)', 'libgobject-2.0.so.0()(64bit)', @@ -157,7 +156,6 @@ export const referenceGeneratedDepsByArch = { 'libgcc_s.so.1(GCC_3.0)', 'libgcc_s.so.1(GCC_3.4)', 'libgcc_s.so.1(GCC_3.5)', - 'libgdk_pixbuf-2.0.so.0', 'libgio-2.0.so.0', 'libglib-2.0.so.0', 'libgobject-2.0.so.0', @@ -247,7 +245,6 @@ export const referenceGeneratedDepsByArch = { 'libgcc_s.so.1(GCC_3.0)(64bit)', 'libgcc_s.so.1(GCC_4.2.0)(64bit)', 'libgcc_s.so.1(GCC_4.5.0)(64bit)', - 'libgdk_pixbuf-2.0.so.0()(64bit)', 'libgio-2.0.so.0()(64bit)', 'libglib-2.0.so.0()(64bit)', 'libgobject-2.0.so.0()(64bit)', From ffe53e8d710a6fce5e2bdc67f25914aea3c40d42 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Mon, 27 Jun 2022 09:56:36 +0200 Subject: [PATCH 028/347] Add a Share menu and a share vscode.dev command (#152765) * Add a share menu Fixes #146309 * Add vscod.dev command in github extension * Make share menu proposed * Add share submenu into editor context * Add proposed to editor share menu --- extensions/github/package.json | 23 ++++++ extensions/github/src/commands.ts | 12 +++ extensions/github/src/extension.ts | 20 ++++- extensions/github/src/links.ts | 78 +++++++++++++++++++ extensions/github/src/remoteSourceProvider.ts | 12 +-- extensions/github/src/util.ts | 16 ++++ .../contrib/clipboard/browser/clipboard.ts | 1 + src/vs/platform/actions/common/actions.ts | 2 + src/vs/platform/actions/common/menuService.ts | 17 +++- .../parts/editor/editor.contribution.ts | 7 ++ .../actions/common/menusExtensionPoint.ts | 12 +++ .../common/extensionsApiProposals.ts | 1 + .../vscode.proposed.contribShareMenu.d.ts | 6 ++ 13 files changed, 190 insertions(+), 17 deletions(-) create mode 100644 extensions/github/src/links.ts create mode 100644 src/vscode-dts/vscode.proposed.contribShareMenu.d.ts diff --git a/extensions/github/package.json b/extensions/github/package.json index af7b544f596..fd5b8a9dfca 100644 --- a/extensions/github/package.json +++ b/extensions/github/package.json @@ -25,11 +25,18 @@ "supported": true } }, + "enabledApiProposals": [ + "contribShareMenu" + ], "contributes": { "commands": [ { "command": "github.publish", "title": "Publish to GitHub" + }, + { + "command": "github.copyVscodeDevLink", + "title": "Copy vscode.dev Link" } ], "menus": { @@ -37,6 +44,22 @@ { "command": "github.publish", "when": "git-base.gitEnabled" + }, + { + "command": "github.copyVscodeDevLink", + "when": "false" + } + ], + "file/share": [ + { + "command": "github.copyVscodeDevLink", + "when": "github.hasGitHubRepo" + } + ], + "editor/context/share": [ + { + "command": "github.copyVscodeDevLink", + "when": "github.hasGitHubRepo" } ] }, diff --git a/extensions/github/src/commands.ts b/extensions/github/src/commands.ts index 42ed8198287..d2d4fb814f7 100644 --- a/extensions/github/src/commands.ts +++ b/extensions/github/src/commands.ts @@ -7,6 +7,7 @@ import * as vscode from 'vscode'; import { API as GitAPI } from './typings/git'; import { publishRepository } from './publish'; import { DisposableStore } from './util'; +import { getPermalink } from './links'; export function registerCommands(gitAPI: GitAPI): vscode.Disposable { const disposables = new DisposableStore(); @@ -19,5 +20,16 @@ export function registerCommands(gitAPI: GitAPI): vscode.Disposable { } })); + disposables.add(vscode.commands.registerCommand('github.copyVscodeDevLink', async () => { + try { + const permalink = getPermalink(gitAPI, 'https://vscode.dev/github'); + if (permalink) { + vscode.env.clipboard.writeText(permalink); + } + } catch (err) { + vscode.window.showErrorMessage(err.message); + } + })); + return disposables; } diff --git a/extensions/github/src/extension.ts b/extensions/github/src/extension.ts index 2fbe1d597fd..a3a84b033dd 100644 --- a/extensions/github/src/extension.ts +++ b/extensions/github/src/extension.ts @@ -5,10 +5,10 @@ import { commands, Disposable, ExtensionContext, extensions } from 'vscode'; import { GithubRemoteSourceProvider } from './remoteSourceProvider'; -import { GitExtension } from './typings/git'; +import { API, GitExtension } from './typings/git'; import { registerCommands } from './commands'; import { GithubCredentialProviderManager } from './credentialProvider'; -import { DisposableStore } from './util'; +import { DisposableStore, repositoryHasGitHubRemote } from './util'; import { GithubPushErrorHandler } from './pushErrorHandler'; import { GitBaseExtension } from './typings/git-base'; import { GithubRemoteSourcePublisher } from './remoteSourcePublisher'; @@ -48,6 +48,21 @@ function initializeGitBaseExtension(): Disposable { return disposables; } +function setGitHubContext(gitAPI: API, disposables: DisposableStore) { + if (gitAPI.repositories.find(repo => repositoryHasGitHubRemote(repo))) { + commands.executeCommand('setContext', 'github.hasGitHubRepo', true); + } else { + const openRepoDisposable = gitAPI.onDidOpenRepository(async e => { + await e.status(); + if (repositoryHasGitHubRemote(e)) { + commands.executeCommand('setContext', 'github.hasGitHubRepo', true); + openRepoDisposable.dispose(); + } + }); + disposables.add(openRepoDisposable); + } +} + function initializeGitExtension(): Disposable { const disposables = new DisposableStore(); @@ -64,6 +79,7 @@ function initializeGitExtension(): Disposable { disposables.add(new GithubCredentialProviderManager(gitAPI)); disposables.add(gitAPI.registerPushErrorHandler(new GithubPushErrorHandler())); disposables.add(gitAPI.registerRemoteSourcePublisher(new GithubRemoteSourcePublisher(gitAPI))); + setGitHubContext(gitAPI, disposables); commands.executeCommand('setContext', 'git-base.gitEnabled', true); } else { diff --git a/extensions/github/src/links.ts b/extensions/github/src/links.ts new file mode 100644 index 00000000000..3b0bc3ce8aa --- /dev/null +++ b/extensions/github/src/links.ts @@ -0,0 +1,78 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as vscode from 'vscode'; +import { API as GitAPI, Repository } from './typings/git'; +import { getRepositoryFromUrl } from './util'; + +export function isFileInRepo(repository: Repository, file: vscode.Uri): boolean { + return file.path.toLowerCase() === repository.rootUri.path.toLowerCase() || + (file.path.toLowerCase().startsWith(repository.rootUri.path.toLowerCase()) && + file.path.substring(repository.rootUri.path.length).startsWith('/')); +} + +export function getRepositoryForFile(gitAPI: GitAPI, file: vscode.Uri): Repository | undefined { + for (const repository of gitAPI.repositories) { + if (isFileInRepo(repository, file)) { + return repository; + } + } + return undefined; +} + +function getFileAndPosition(): { uri: vscode.Uri | undefined; range: vscode.Range | undefined } { + let uri: vscode.Uri | undefined; + let range: vscode.Range | undefined; + if (vscode.window.activeTextEditor) { + uri = vscode.window.activeTextEditor.document.uri; + range = vscode.window.activeTextEditor.selection; + } + return { uri, range }; +} + +function rangeString(range: vscode.Range | undefined) { + if (!range) { + return ''; + } + let hash = `#L${range.start.line + 1}`; + if (range.start.line !== range.end.line) { + hash += `-L${range.end.line + 1}`; + } + return hash; +} + +export function getPermalink(gitAPI: GitAPI, hostPrefix?: string): string | undefined { + hostPrefix = hostPrefix ?? 'https://github.com'; + const { uri, range } = getFileAndPosition(); + if (!uri) { + return; + } + const gitRepo = getRepositoryForFile(gitAPI, uri); + if (!gitRepo) { + return; + } + let repo: { owner: string; repo: string } | undefined; + gitRepo.state.remotes.find(remote => { + if (remote.fetchUrl) { + const foundRepo = getRepositoryFromUrl(remote.fetchUrl); + if (foundRepo && (remote.name === gitRepo.state.HEAD?.upstream?.remote)) { + repo = foundRepo; + return; + } else if (foundRepo && !repo) { + repo = foundRepo; + } + } + return; + }); + if (!repo) { + return; + } + + const commitHash = gitRepo.state.HEAD?.commit; + const pathSegment = uri.path.substring(gitRepo.rootUri.path.length); + + return `${hostPrefix}/${repo.owner}/${repo.repo}/blob/${commitHash + }${pathSegment}${rangeString(range)}`; +} diff --git a/extensions/github/src/remoteSourceProvider.ts b/extensions/github/src/remoteSourceProvider.ts index e365a7172b7..e8eeb851549 100644 --- a/extensions/github/src/remoteSourceProvider.ts +++ b/extensions/github/src/remoteSourceProvider.ts @@ -7,17 +7,7 @@ import { workspace } from 'vscode'; import { RemoteSourceProvider, RemoteSource } from './typings/git-base'; import { getOctokit } from './auth'; import { Octokit } from '@octokit/rest'; - -function getRepositoryFromUrl(url: string): { owner: string; repo: string } | undefined { - const match = /^https:\/\/github\.com\/([^/]+)\/([^/]+)\.git/i.exec(url) - || /^git@github\.com:([^/]+)\/([^/]+)\.git/i.exec(url); - return match ? { owner: match[1], repo: match[2] } : undefined; -} - -function getRepositoryFromQuery(query: string): { owner: string; repo: string } | undefined { - const match = /^([^/]+)\/([^/]+)$/i.exec(query); - return match ? { owner: match[1], repo: match[2] } : undefined; -} +import { getRepositoryFromQuery, getRepositoryFromUrl } from './util'; function asRemoteSource(raw: any): RemoteSource { const protocol = workspace.getConfiguration('github').get<'https' | 'ssh'>('gitProtocol'); diff --git a/extensions/github/src/util.ts b/extensions/github/src/util.ts index c7d23a82301..3d8bf4a40be 100644 --- a/extensions/github/src/util.ts +++ b/extensions/github/src/util.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as vscode from 'vscode'; +import { Repository } from './typings/git'; export class DisposableStore { @@ -21,3 +22,18 @@ export class DisposableStore { this.disposables.clear(); } } + +export function getRepositoryFromUrl(url: string): { owner: string; repo: string } | undefined { + const match = /^https:\/\/github\.com\/([^/]+)\/([^/]+?)(\.git)?$/i.exec(url) + || /^git@github\.com:([^/]+)\/([^/]+?)(\.git)?$/i.exec(url); + return match ? { owner: match[1], repo: match[2] } : undefined; +} + +export function getRepositoryFromQuery(query: string): { owner: string; repo: string } | undefined { + const match = /^([^/]+)\/([^/]+)$/i.exec(query); + return match ? { owner: match[1], repo: match[2] } : undefined; +} + +export function repositoryHasGitHubRemote(repository: Repository) { + return !!repository.state.remotes.find(remote => remote.fetchUrl ? getRepositoryFromUrl(remote.fetchUrl) : undefined); +} diff --git a/src/vs/editor/contrib/clipboard/browser/clipboard.ts b/src/vs/editor/contrib/clipboard/browser/clipboard.ts index e9a71900cf1..488fc8a6056 100644 --- a/src/vs/editor/contrib/clipboard/browser/clipboard.ts +++ b/src/vs/editor/contrib/clipboard/browser/clipboard.ts @@ -107,6 +107,7 @@ export const CopyAction = supportsCopy ? registerCommand(new MultiCommand({ MenuRegistry.appendMenuItem(MenuId.MenubarEditMenu, { submenu: MenuId.MenubarCopy, title: { value: nls.localize('copy as', "Copy As"), original: 'Copy As', }, group: '2_ccp', order: 3 }); MenuRegistry.appendMenuItem(MenuId.EditorContext, { submenu: MenuId.EditorContextCopy, title: { value: nls.localize('copy as', "Copy As"), original: 'Copy As', }, group: CLIPBOARD_CONTEXT_MENU_GROUP, order: 3 }); +MenuRegistry.appendMenuItem(MenuId.EditorContext, { submenu: MenuId.EditorContextShare, title: { value: nls.localize('share', "Share"), original: 'Share', }, group: '11_share', order: -1 }); export const PasteAction = supportsPaste ? registerCommand(new MultiCommand({ id: 'editor.action.clipboardPasteAction', diff --git a/src/vs/platform/actions/common/actions.ts b/src/vs/platform/actions/common/actions.ts index 1f9da3b627a..d1cd1197cce 100644 --- a/src/vs/platform/actions/common/actions.ts +++ b/src/vs/platform/actions/common/actions.ts @@ -59,6 +59,7 @@ export class MenuId { static readonly SimpleEditorContext = new MenuId('SimpleEditorContext'); static readonly EditorContextCopy = new MenuId('EditorContextCopy'); static readonly EditorContextPeek = new MenuId('EditorContextPeek'); + static readonly EditorContextShare = new MenuId('EditorContextShare'); static readonly EditorTitle = new MenuId('EditorTitle'); static readonly EditorTitleRun = new MenuId('EditorTitleRun'); static readonly EditorTitleContext = new MenuId('EditorTitleContext'); @@ -85,6 +86,7 @@ export class MenuId { static readonly MenubarPreferencesMenu = new MenuId('MenubarPreferencesMenu'); static readonly MenubarRecentMenu = new MenuId('MenubarRecentMenu'); static readonly MenubarSelectionMenu = new MenuId('MenubarSelectionMenu'); + static readonly MenubarShare = new MenuId('MenubarShare'); static readonly MenubarSwitchEditorMenu = new MenuId('MenubarSwitchEditorMenu'); static readonly MenubarSwitchGroupMenu = new MenuId('MenubarSwitchGroupMenu'); static readonly MenubarTerminalMenu = new MenuId('MenubarTerminalMenu'); diff --git a/src/vs/platform/actions/common/menuService.ts b/src/vs/platform/actions/common/menuService.ts index 4b8f39a1840..e0f60280e33 100644 --- a/src/vs/platform/actions/common/menuService.ts +++ b/src/vs/platform/actions/common/menuService.ts @@ -150,11 +150,20 @@ class Menu implements IMenu { const activeActions: Array = []; for (const item of items) { if (this._contextKeyService.contextMatchesRules(item.when)) { - const action = isIMenuItem(item) - ? new MenuItemAction(item.command, item.alt, options, this._contextKeyService, this._commandService) - : new SubmenuItemAction(item, this._menuService, this._contextKeyService, options); + let action: MenuItemAction | SubmenuItemAction | undefined; + if (isIMenuItem(item)) { + action = new MenuItemAction(item.command, item.alt, options, this._contextKeyService, this._commandService); + } else { + action = new SubmenuItemAction(item, this._menuService, this._contextKeyService, options); + if (action.actions.length === 0) { + action.dispose(); + action = undefined; + } + } - activeActions.push(action); + if (action) { + activeActions.push(action); + } } } if (activeActions.length > 0) { diff --git a/src/vs/workbench/browser/parts/editor/editor.contribution.ts b/src/vs/workbench/browser/parts/editor/editor.contribution.ts index 18bc56414ed..399f58c4f6a 100644 --- a/src/vs/workbench/browser/parts/editor/editor.contribution.ts +++ b/src/vs/workbench/browser/parts/editor/editor.contribution.ts @@ -579,6 +579,13 @@ MenuRegistry.appendMenuItem(MenuId.MenubarRecentMenu, { order: 1 }); +MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { + title: localize('miShare', "Share"), + submenu: MenuId.MenubarShare, + group: '45_share', + order: 1, +}); + // Layout menu MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, { group: '2_appearance', diff --git a/src/vs/workbench/services/actions/common/menusExtensionPoint.ts b/src/vs/workbench/services/actions/common/menusExtensionPoint.ts index 6bb3eca341a..c78225da320 100644 --- a/src/vs/workbench/services/actions/common/menusExtensionPoint.ts +++ b/src/vs/workbench/services/actions/common/menusExtensionPoint.ts @@ -61,6 +61,12 @@ const apiMenus: IAPIMenu[] = [ id: MenuId.EditorContextCopy, description: localize('menus.editorContextCopyAs', "'Copy as' submenu in the editor context menu") }, + { + key: 'editor/context/share', + id: MenuId.EditorContextShare, + description: localize('menus.editorContextShare', "'Share' submenu in the editor context menu"), + proposed: 'contribShareMenu' + }, { key: 'explorer/context', id: MenuId.ExplorerContext, @@ -249,6 +255,12 @@ const apiMenus: IAPIMenu[] = [ description: localize('file.newFile', "The 'New File...' quick pick, shown on welcome page and File menu."), supportsSubmenus: false, }, + { + key: 'file/share', + id: MenuId.MenubarShare, + description: localize('menus.share', "Share submenu shown in the top level File menu."), + proposed: 'contribShareMenu' + }, { key: 'editor/inlineCompletions/actions', id: MenuId.InlineCompletionsActions, diff --git a/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts b/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts index b6d9980d7ef..f735af27335 100644 --- a/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts +++ b/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts @@ -14,6 +14,7 @@ export const allApiProposals = Object.freeze({ contribMenuBarHome: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribMenuBarHome.d.ts', contribMergeEditorToolbar: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribMergeEditorToolbar.d.ts', contribRemoteHelp: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribRemoteHelp.d.ts', + contribShareMenu: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribShareMenu.d.ts', contribViewsRemote: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribViewsRemote.d.ts', contribViewsWelcome: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.contribViewsWelcome.d.ts', customEditorMove: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.customEditorMove.d.ts', diff --git a/src/vscode-dts/vscode.proposed.contribShareMenu.d.ts b/src/vscode-dts/vscode.proposed.contribShareMenu.d.ts new file mode 100644 index 00000000000..a38d03f4fde --- /dev/null +++ b/src/vscode-dts/vscode.proposed.contribShareMenu.d.ts @@ -0,0 +1,6 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +// empty placeholder declaration for the `file/share`-submenu contribution point From a60ffd7029f73ab612e2109008d12234e7ed74c1 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 27 Jun 2022 11:47:36 +0200 Subject: [PATCH 029/347] apply new language to all 3wm models (#153278) refines https://github.com/microsoft/vscode/issues/151136#issuecomment-1166196944 --- .../contrib/mergeEditor/browser/model/mergeEditorModel.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/mergeEditor/browser/model/mergeEditorModel.ts b/src/vs/workbench/contrib/mergeEditor/browser/model/mergeEditorModel.ts index da826139b03..ad978496388 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/model/mergeEditorModel.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/model/mergeEditorModel.ts @@ -337,7 +337,11 @@ export class MergeEditorModel extends EditorModel { } public setLanguageId(languageId: string): void { - this.modelService.setMode(this.result, this.languageService.createById(languageId)); + const language = this.languageService.createById(languageId); + this.modelService.setMode(this.base, language); + this.modelService.setMode(this.input1, language); + this.modelService.setMode(this.input2, language); + this.modelService.setMode(this.result, language); } } From e5301ee66cfc245c01945e51e5e34db7004b7da1 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 27 Jun 2022 11:48:47 +0200 Subject: [PATCH 030/347] when comparing suggestions then use their `textLabel` (#153283) fixes https://github.com/microsoft/vscode/issues/153026 --- src/vs/editor/contrib/suggest/browser/suggest.ts | 4 ++-- .../suggest/test/browser/completionModel.test.ts | 15 +++++++++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/vs/editor/contrib/suggest/browser/suggest.ts b/src/vs/editor/contrib/suggest/browser/suggest.ts index af54cf55c79..59e61786894 100644 --- a/src/vs/editor/contrib/suggest/browser/suggest.ts +++ b/src/vs/editor/contrib/suggest/browser/suggest.ts @@ -323,9 +323,9 @@ function defaultComparator(a: CompletionItem, b: CompletionItem): number { } } // check with 'label' - if (a.completion.label < b.completion.label) { + if (a.textLabel < b.textLabel) { return -1; - } else if (a.completion.label > b.completion.label) { + } else if (a.textLabel > b.textLabel) { return 1; } // check with 'type' diff --git a/src/vs/editor/contrib/suggest/test/browser/completionModel.test.ts b/src/vs/editor/contrib/suggest/test/browser/completionModel.test.ts index 7a474b09e9e..42b961a69ad 100644 --- a/src/vs/editor/contrib/suggest/test/browser/completionModel.test.ts +++ b/src/vs/editor/contrib/suggest/test/browser/completionModel.test.ts @@ -10,13 +10,13 @@ import { CompletionModel } from 'vs/editor/contrib/suggest/browser/completionMod import { CompletionItem, getSuggestionComparator, SnippetSortOrder } from 'vs/editor/contrib/suggest/browser/suggest'; import { WordDistance } from 'vs/editor/contrib/suggest/browser/wordDistance'; -export function createSuggestItem(label: string, overwriteBefore: number, kind = languages.CompletionItemKind.Property, incomplete: boolean = false, position: IPosition = { lineNumber: 1, column: 1 }, sortText?: string, filterText?: string): CompletionItem { +export function createSuggestItem(label: string | languages.CompletionItemLabel, overwriteBefore: number, kind = languages.CompletionItemKind.Property, incomplete: boolean = false, position: IPosition = { lineNumber: 1, column: 1 }, sortText?: string, filterText?: string): CompletionItem { const suggestion: languages.CompletionItem = { label, sortText, filterText, range: { startLineNumber: position.lineNumber, startColumn: position.column - overwriteBefore, endLineNumber: position.lineNumber, endColumn: position.column }, - insertText: label, + insertText: typeof label === 'string' ? label : label.label, kind }; const container: languages.CompletionList = { @@ -275,6 +275,17 @@ suite('CompletionModel', function () { assert.strictEqual(second.completion.label, '<- groups'); }); + test('Completion item sorting broken when using label details #153026', function () { + const itemZZZ = createSuggestItem({ label: 'ZZZ' }, 0, languages.CompletionItemKind.Operator, false); + const itemAAA = createSuggestItem({ label: 'AAA' }, 0, languages.CompletionItemKind.Operator, false); + const itemIII = createSuggestItem('III', 0, languages.CompletionItemKind.Operator, false); + + const cmp = getSuggestionComparator(SnippetSortOrder.Inline); + const actual = [itemZZZ, itemAAA, itemIII].sort(cmp); + + assert.deepStrictEqual(actual, [itemAAA, itemIII, itemZZZ]); + }); + test('Score only filtered items when typing more, score all when typing less', function () { model = new CompletionModel([ createSuggestItem('console', 0), From 0182e175eb9b67163878b6230377c2e2f41b2981 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 27 Jun 2022 12:01:17 +0200 Subject: [PATCH 031/347] fix transpile on windows (#153285) make sure to normalize paths before entering internal TS API, also add better error logging to know what file paths fail --- build/lib/tsb/transpiler.js | 33 ++++++++++++++++++++------------ build/lib/tsb/transpiler.ts | 38 ++++++++++++++++++++++++------------- 2 files changed, 46 insertions(+), 25 deletions(-) diff --git a/build/lib/tsb/transpiler.js b/build/lib/tsb/transpiler.js index 7da255d529f..38e6b5c00e4 100644 --- a/build/lib/tsb/transpiler.js +++ b/build/lib/tsb/transpiler.js @@ -121,20 +121,29 @@ class Transpiler { this._allJobs = []; logFn('Transpile', `will use ${Transpiler.P} transpile worker`); this._getOutputFileName = (file) => { - if (!_cmdLine.options.configFilePath) { - // this is needed for the INTERNAL getOutputFileNames-call below... - _cmdLine.options.configFilePath = configFilePath; + try { + // windows: path-sep normalizing + file = ts.normalizePath(file); + if (!_cmdLine.options.configFilePath) { + // this is needed for the INTERNAL getOutputFileNames-call below... + _cmdLine.options.configFilePath = configFilePath; + } + const isDts = file.endsWith('.d.ts'); + if (isDts) { + file = file.slice(0, -5) + '.ts'; + _cmdLine.fileNames.push(file); + } + const outfile = ts.getOutputFileNames(_cmdLine, file, true)[0]; + if (isDts) { + _cmdLine.fileNames.pop(); + } + return outfile; } - const isDts = file.endsWith('.d.ts'); - if (isDts) { - file = file.slice(0, -5) + '.ts'; - _cmdLine.fileNames.push(file); + catch (err) { + console.error(file, _cmdLine.fileNames); + console.error(err); + throw new err; } - const outfile = ts.getOutputFileNames(_cmdLine, file, true)[0]; - if (isDts) { - _cmdLine.fileNames.pop(); - } - return outfile; }; } async join() { diff --git a/build/lib/tsb/transpiler.ts b/build/lib/tsb/transpiler.ts index 3afc3547dd5..7bd789ef6eb 100644 --- a/build/lib/tsb/transpiler.ts +++ b/build/lib/tsb/transpiler.ts @@ -166,23 +166,35 @@ export class Transpiler { // very complicated logic to re-use TS internal functions to know the output path // given a TS input path and its config type InternalTsApi = typeof ts & { + normalizePath(path: string): string; getOutputFileNames(commandLine: ts.ParsedCommandLine, inputFileName: string, ignoreCase: boolean): readonly string[]; }; this._getOutputFileName = (file) => { - if (!_cmdLine.options.configFilePath) { - // this is needed for the INTERNAL getOutputFileNames-call below... - _cmdLine.options.configFilePath = configFilePath; + try { + + // windows: path-sep normalizing + file = (ts).normalizePath(file); + + if (!_cmdLine.options.configFilePath) { + // this is needed for the INTERNAL getOutputFileNames-call below... + _cmdLine.options.configFilePath = configFilePath; + } + const isDts = file.endsWith('.d.ts'); + if (isDts) { + file = file.slice(0, -5) + '.ts'; + _cmdLine.fileNames.push(file); + } + const outfile = (ts).getOutputFileNames(_cmdLine, file, true)[0]; + if (isDts) { + _cmdLine.fileNames.pop(); + } + return outfile; + + } catch (err) { + console.error(file, _cmdLine.fileNames); + console.error(err); + throw new err; } - const isDts = file.endsWith('.d.ts'); - if (isDts) { - file = file.slice(0, -5) + '.ts'; - _cmdLine.fileNames.push(file); - } - const outfile = (ts).getOutputFileNames(_cmdLine, file, true)[0]; - if (isDts) { - _cmdLine.fileNames.pop(); - } - return outfile; }; } From d9ccb7eff15945c823c72a7e8c96a1c5e5e0214f Mon Sep 17 00:00:00 2001 From: Prashant Cholachagudda Date: Mon, 27 Jun 2022 15:46:18 +0530 Subject: [PATCH 032/347] assign 'VSCode-SessionId' header in marketplace.ts --- .../common/extensionGalleryService.ts | 11 +++- .../common/extensionGalleryService.test.ts | 59 ++++++++++++++++++- .../externalServices/common/marketplace.ts | 13 +++- .../platform/windows/electron-main/window.ts | 9 ++- 4 files changed, 83 insertions(+), 9 deletions(-) diff --git a/src/vs/platform/extensionManagement/common/extensionGalleryService.ts b/src/vs/platform/extensionManagement/common/extensionGalleryService.ts index cfea8e58f80..3515dea4464 100644 --- a/src/vs/platform/extensionManagement/common/extensionGalleryService.ts +++ b/src/vs/platform/extensionManagement/common/extensionGalleryService.ts @@ -584,7 +584,14 @@ abstract class AbstractExtensionGalleryService implements IExtensionGalleryServi const config = productService.extensionsGallery; this.extensionsGalleryUrl = config && config.serviceUrl; this.extensionsControlUrl = config && config.controlUrl; - this.commonHeadersPromise = resolveMarketplaceHeaders(productService.version, productService, this.environmentService, this.configurationService, this.fileService, storageService); + this.commonHeadersPromise = resolveMarketplaceHeaders( + productService.version, + productService, + this.environmentService, + this.configurationService, + this.fileService, + storageService, + this.telemetryService); } private api(path = ''): string { @@ -923,14 +930,12 @@ abstract class AbstractExtensionGalleryService implements IExtensionGalleryServi const commonHeaders = await this.commonHeadersPromise; const data = JSON.stringify(query.raw); - const { sessionId } = await this.telemetryService.getTelemetryInfo(); const headers = { ...commonHeaders, 'Content-Type': 'application/json', 'Accept': 'application/json;api-version=3.0-preview.1', 'Accept-Encoding': 'gzip', 'Content-Length': String(data.length), - 'VSCode-SessionId': sessionId }; const startTime = new Date().getTime(); diff --git a/src/vs/platform/extensionManagement/test/common/extensionGalleryService.test.ts b/src/vs/platform/extensionManagement/test/common/extensionGalleryService.test.ts index 4312de805f8..4db659c6fc8 100644 --- a/src/vs/platform/extensionManagement/test/common/extensionGalleryService.test.ts +++ b/src/vs/platform/extensionManagement/test/common/extensionGalleryService.test.ts @@ -21,8 +21,11 @@ import product from 'vs/platform/product/common/product'; import { IProductService } from 'vs/platform/product/common/productService'; import { resolveMarketplaceHeaders } from 'vs/platform/externalServices/common/marketplace'; import { InMemoryStorageService, IStorageService } from 'vs/platform/storage/common/storage'; -import { TelemetryConfiguration, TELEMETRY_SETTING_ID } from 'vs/platform/telemetry/common/telemetry'; +import { ITelemetryInfo, ITelemetryService, TelemetryConfiguration, TelemetryLevel, TELEMETRY_SETTING_ID } from 'vs/platform/telemetry/common/telemetry'; import { TargetPlatform } from 'vs/platform/extensions/common/extensions'; +import { ClassifiedEvent, GDPRClassification, StrictPropertyCheck } from 'vs/platform/telemetry/common/gdprTypings'; +import { staticObservableValue } from 'vs/base/common/observableValue'; +import { Emitter, Event } from 'vs/base/common/event'; class EnvironmentServiceMock extends mock() { override readonly serviceMachineIdResource: URI; @@ -36,6 +39,7 @@ class EnvironmentServiceMock extends mock() { suite('Extension Gallery Service', () => { const disposables: DisposableStore = new DisposableStore(); let fileService: IFileService, environmentService: IEnvironmentService, storageService: IStorageService, productService: IProductService, configurationService: IConfigurationService; + let telemetryService: ITelemetryService; setup(() => { const serviceMachineIdResource = joinPath(URI.file('tests').with({ scheme: 'vscode-tests' }), 'machineid'); @@ -47,14 +51,15 @@ suite('Extension Gallery Service', () => { configurationService = new TestConfigurationService({ [TELEMETRY_SETTING_ID]: TelemetryConfiguration.ON }); configurationService.updateValue(TELEMETRY_SETTING_ID, TelemetryConfiguration.ON); productService = { _serviceBrand: undefined, ...product, enableTelemetry: true }; + telemetryService = new MockTelemetryService(); }); teardown(() => disposables.clear()); test('marketplace machine id', async () => { - const headers = await resolveMarketplaceHeaders(product.version, productService, environmentService, configurationService, fileService, storageService); + const headers = await resolveMarketplaceHeaders(product.version, productService, environmentService, configurationService, fileService, storageService, telemetryService); assert.ok(isUUID(headers['X-Market-User-Id'])); - const headers2 = await resolveMarketplaceHeaders(product.version, productService, environmentService, configurationService, fileService, storageService); + const headers2 = await resolveMarketplaceHeaders(product.version, productService, environmentService, configurationService, fileService, storageService, telemetryService); assert.strictEqual(headers['X-Market-User-Id'], headers2['X-Market-User-Id']); }); @@ -153,3 +158,51 @@ suite('Extension Gallery Service', () => { return { version, targetPlatform } as IRawGalleryExtensionVersion; } }); + +class MockTelemetryService implements ITelemetryService { + public _serviceBrand: undefined; + public telemetryLevel = staticObservableValue(TelemetryLevel.USAGE); + public sendErrorTelemetry = true; + + public events: any[] = []; + + private readonly emitter = new Emitter(); + + public get eventLogged(): Event { + return this.emitter.event; + } + + public setEnabled(value: boolean): void { + } + + public setExperimentProperty(name: string, value: string): void { + } + + public publicLog(eventName: string, data?: any): Promise { + const event = { name: eventName, data: data }; + this.events.push(event); + this.emitter.fire(event); + return Promise.resolve(); + } + + public publicLog2 = never, T extends GDPRClassification = never>(eventName: string, data?: StrictPropertyCheck) { + return this.publicLog(eventName, data as any); + } + + public publicLogError(eventName: string, data?: any): Promise { + return this.publicLog(eventName, data); + } + + public publicLogError2 = never, T extends GDPRClassification = never>(eventName: string, data?: StrictPropertyCheck) { + return this.publicLogError(eventName, data as any); + } + + public getTelemetryInfo(): Promise { + return Promise.resolve({ + instanceId: 'someValue.instanceId', + sessionId: 'someValue.sessionId', + machineId: 'someValue.machineId', + firstSessionDate: 'someValue.firstSessionDate' + }); + } +} diff --git a/src/vs/platform/externalServices/common/marketplace.ts b/src/vs/platform/externalServices/common/marketplace.ts index 6d2c25ab86d..5923e1cd8e8 100644 --- a/src/vs/platform/externalServices/common/marketplace.ts +++ b/src/vs/platform/externalServices/common/marketplace.ts @@ -10,17 +10,26 @@ import { getServiceMachineId } from 'vs/platform/externalServices/common/service import { IFileService } from 'vs/platform/files/common/files'; import { IProductService } from 'vs/platform/product/common/productService'; import { IStorageService } from 'vs/platform/storage/common/storage'; -import { TelemetryLevel } from 'vs/platform/telemetry/common/telemetry'; +import { ITelemetryService, TelemetryLevel } from 'vs/platform/telemetry/common/telemetry'; import { getTelemetryLevel, supportsTelemetry } from 'vs/platform/telemetry/common/telemetryUtils'; -export async function resolveMarketplaceHeaders(version: string, productService: IProductService, environmentService: IEnvironmentService, configurationService: IConfigurationService, fileService: IFileService, storageService: IStorageService | undefined): Promise { +export async function resolveMarketplaceHeaders(version: string, + productService: IProductService, + environmentService: IEnvironmentService, + configurationService: IConfigurationService, + fileService: IFileService, + storageService: IStorageService | undefined, + telemetryService: ITelemetryService): Promise { const headers: IHeaders = { 'X-Market-Client-Id': `VSCode ${version}`, 'User-Agent': `VSCode ${version} (${productService.nameShort})` }; const uuid = await getServiceMachineId(environmentService, fileService, storageService); + const { sessionId } = await telemetryService.getTelemetryInfo(); + if (supportsTelemetry(productService, environmentService) && getTelemetryLevel(configurationService) === TelemetryLevel.USAGE) { headers['X-Market-User-Id'] = uuid; + headers['VSCode-SessionId'] = sessionId; } return headers; } diff --git a/src/vs/platform/windows/electron-main/window.ts b/src/vs/platform/windows/electron-main/window.ts index 02524b2235b..fcc8c93ee47 100644 --- a/src/vs/platform/windows/electron-main/window.ts +++ b/src/vs/platform/windows/electron-main/window.ts @@ -542,7 +542,14 @@ export class CodeWindow extends Disposable implements ICodeWindow { private marketplaceHeadersPromise: Promise | undefined; private getMarketplaceHeaders(): Promise { if (!this.marketplaceHeadersPromise) { - this.marketplaceHeadersPromise = resolveMarketplaceHeaders(this.productService.version, this.productService, this.environmentMainService, this.configurationService, this.fileService, this.applicationStorageMainService); + this.marketplaceHeadersPromise = resolveMarketplaceHeaders( + this.productService.version, + this.productService, + this.environmentMainService, + this.configurationService, + this.fileService, + this.applicationStorageMainService, + this.telemetryService); } return this.marketplaceHeadersPromise; From aae22c16051016f084d49d0904de73599afe5a47 Mon Sep 17 00:00:00 2001 From: Johannes Date: Mon, 27 Jun 2022 12:54:55 +0200 Subject: [PATCH 033/347] rename setting to `git.mergeEditor`, no more experimental --- extensions/git/package.json | 9 +++------ extensions/git/package.nls.json | 2 +- extensions/git/src/repository.ts | 4 ++-- extensions/merge-conflict/src/services.ts | 2 +- 4 files changed, 7 insertions(+), 10 deletions(-) diff --git a/extensions/git/package.json b/extensions/git/package.json index b572d9edf68..7e4cc563f34 100644 --- a/extensions/git/package.json +++ b/extensions/git/package.json @@ -2500,14 +2500,11 @@ "markdownDescription": "%config.logLevel%", "scope": "window" }, - "git.experimental.mergeEditor": { + "git.mergeEditor": { "type": "boolean", "default": false, - "markdownDescription": "%config.experimental.mergeEditor%", - "scope": "window", - "tags": [ - "experimental" - ] + "markdownDescription": "%config.mergeEditor%", + "scope": "window" } } }, diff --git a/extensions/git/package.nls.json b/extensions/git/package.nls.json index 40b832ef200..e632bb47202 100644 --- a/extensions/git/package.nls.json +++ b/extensions/git/package.nls.json @@ -243,7 +243,7 @@ "config.logLevel.error": "Log only error, and critical information", "config.logLevel.critical": "Log only critical information", "config.logLevel.off": "Log nothing", - "config.experimental.mergeEditor": "Open the _experimental_ merge editor for files that are currently under conflict.", + "config.mergeEditor": "Open the merge editor for files that are currently under conflict.", "submenu.explorer": "Git", "submenu.commit": "Commit", "submenu.commit.amend": "Amend", diff --git a/extensions/git/src/repository.ts b/extensions/git/src/repository.ts index dd5d72e890c..eb0de19bcf6 100644 --- a/extensions/git/src/repository.ts +++ b/extensions/git/src/repository.ts @@ -616,7 +616,7 @@ class ResourceCommandResolver { if (!resource.leftUri) { const bothModified = resource.type === Status.BOTH_MODIFIED; - if (resource.rightUri && bothModified && workspace.getConfiguration('git').get('experimental.mergeEditor', false)) { + if (resource.rightUri && bothModified && workspace.getConfiguration('git').get('mergeEditor', false)) { return { command: '_git.openMergeEditor', title: localize('open.merge', "Open Merge"), @@ -935,7 +935,7 @@ export class Repository implements Disposable { updateIndexGroupVisibility(); workspace.onDidChangeConfiguration(e => { - if (e.affectsConfiguration('git.experimental.mergeEditor')) { + if (e.affectsConfiguration('git.mergeEditor')) { this.mergeGroup.resourceStates = this.mergeGroup.resourceStates.map(r => r.clone()); } }, undefined, this.disposables); diff --git a/extensions/merge-conflict/src/services.ts b/extensions/merge-conflict/src/services.ts index 1b0f875aace..932a665f4bc 100644 --- a/extensions/merge-conflict/src/services.ts +++ b/extensions/merge-conflict/src/services.ts @@ -53,7 +53,7 @@ export default class ServiceWrapper implements vscode.Disposable { // using the merge editor we disable this extension - for the merge editor but also // for "other" editors const gitConfig = vscode.workspace.getConfiguration('git'); - if (gitConfig.get('experimental.mergeEditor')) { + if (gitConfig.get('mergeEditor')) { return { enableCodeLens: false, enableDecorations: false, From 7c78e2ea8ec922caf4520ec1f48cf0e0b5ed78a2 Mon Sep 17 00:00:00 2001 From: Johannes Date: Mon, 27 Jun 2022 12:55:05 +0200 Subject: [PATCH 034/347] enable merge editor for the team --- .vscode/settings.json | 1 + 1 file changed, 1 insertion(+) diff --git a/.vscode/settings.json b/.vscode/settings.json index e698d02574e..71bded80a79 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -73,6 +73,7 @@ ], "git.branchProtectionPrompt": "alwaysCommitToNewBranch", "git.branchRandomName.enable": true, + "git.mergeEditor": true, "remote.extensionKind": { "msjsdiag.debugger-for-chrome": "workspace" }, From 0c2c74c60a4a05236d2c5d51c566171b11f63ca0 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 27 Jun 2022 13:44:57 +0200 Subject: [PATCH 035/347] Fix #153122 (#153287) --- .../browser/extensionEnablementService.ts | 6 ++--- .../extensionEnablementService.test.ts | 23 ++++++++++++++++--- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts b/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts index 264a59acbc7..b72ed20cef2 100644 --- a/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts +++ b/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts @@ -580,9 +580,9 @@ export class ExtensionEnablementService extends Disposable implements IWorkbench } private _onDidChangeExtensions(added: ReadonlyArray, removed: ReadonlyArray): void { - const disabledByTrustExtensions = added.filter(e => this.getEnablementState(e) === EnablementState.DisabledByTrustRequirement); - if (disabledByTrustExtensions.length) { - this._onEnablementChanged.fire(disabledByTrustExtensions); + const disabledExtensions = added.filter(e => !this.isEnabledEnablementState(this.getEnablementState(e))); + if (disabledExtensions.length) { + this._onEnablementChanged.fire(disabledExtensions); } removed.forEach(({ identifier }) => this._reset(identifier)); } diff --git a/src/vs/workbench/services/extensionManagement/test/browser/extensionEnablementService.test.ts b/src/vs/workbench/services/extensionManagement/test/browser/extensionEnablementService.test.ts index 3fc8b045751..0577f060b4d 100644 --- a/src/vs/workbench/services/extensionManagement/test/browser/extensionEnablementService.test.ts +++ b/src/vs/workbench/services/extensionManagement/test/browser/extensionEnablementService.test.ts @@ -5,10 +5,10 @@ import * as assert from 'assert'; import * as sinon from 'sinon'; import { IExtensionManagementService, DidUninstallExtensionEvent, ILocalExtension, InstallExtensionEvent, InstallExtensionResult, UninstallExtensionEvent } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { IWorkbenchExtensionEnablementService, EnablementState, IExtensionManagementServerService, IExtensionManagementServer, IWorkbenchExtensionManagementService, ExtensionInstallLocation, IProfileAwareExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; +import { IWorkbenchExtensionEnablementService, EnablementState, IExtensionManagementServerService, IExtensionManagementServer, IWorkbenchExtensionManagementService, ExtensionInstallLocation, IProfileAwareExtensionManagementService, DidChangeProfileExtensionsEvent } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { ExtensionEnablementService } from 'vs/workbench/services/extensionManagement/browser/extensionEnablementService'; import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; -import { Emitter, Event } from 'vs/base/common/event'; +import { Emitter } from 'vs/base/common/event'; import { IWorkspace, IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { IStorageService, InMemoryStorageService } from 'vs/platform/storage/common/storage'; @@ -116,6 +116,7 @@ suite('ExtensionEnablementService Test', () => { const didInstallEvent = new Emitter(); const didUninstallEvent = new Emitter(); + const didChangeProfileExtensionsEvent = new Emitter(); const installed: ILocalExtension[] = []; setup(() => { @@ -128,7 +129,7 @@ suite('ExtensionEnablementService Test', () => { extensionManagementService: { onDidInstallExtensions: didInstallEvent.event, onDidUninstallExtension: didUninstallEvent.event, - onDidChangeProfileExtensions: Event.None, + onDidChangeProfileExtensions: didChangeProfileExtensionsEvent.event, getInstalled: () => Promise.resolve(installed) }, }, null, null)); @@ -950,6 +951,22 @@ suite('ExtensionEnablementService Test', () => { assert.deepStrictEqual((target.args[0][0][1]).identifier, { id: 'pub.c' }); }); + test('test adding an extension that was disabled', async () => { + const extension = aLocalExtension('pub.a'); + installed.push(extension); + testObject = new TestExtensionEnablementService(instantiationService); + await testObject.setEnablement([extension], EnablementState.DisabledGlobally); + + const target = sinon.spy(); + testObject.onEnablementChanged(target); + didChangeProfileExtensionsEvent.fire({ added: [extension], removed: [] }); + + assert.ok(!testObject.isEnabled(extension)); + assert.strictEqual(testObject.getEnablementState(extension), EnablementState.DisabledGlobally); + assert.strictEqual(target.args[0][0].length, 1); + assert.deepStrictEqual((target.args[0][0][0]).identifier, { id: 'pub.a' }); + }); + }); function anExtensionManagementServer(authority: string, instantiationService: TestInstantiationService): IExtensionManagementServer { From 1df4b3ceb899d54063793463ead4baea009d5fa5 Mon Sep 17 00:00:00 2001 From: Alexandru Dima Date: Mon, 27 Jun 2022 14:18:28 +0200 Subject: [PATCH 036/347] Adopt `StorageScope.Application` (#153297) Adopt `StorageScope.Application` (#152679) --- .../services/integrity/electron-sandbox/integrityService.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/services/integrity/electron-sandbox/integrityService.ts b/src/vs/workbench/services/integrity/electron-sandbox/integrityService.ts index 3dd5d8dbc16..7125f82440e 100644 --- a/src/vs/workbench/services/integrity/electron-sandbox/integrityService.ts +++ b/src/vs/workbench/services/integrity/electron-sandbox/integrityService.ts @@ -33,7 +33,7 @@ class IntegrityStorage { } private _read(): IStorageData | null { - const jsonValue = this.storageService.get(IntegrityStorage.KEY, StorageScope.PROFILE); + const jsonValue = this.storageService.get(IntegrityStorage.KEY, StorageScope.APPLICATION); if (!jsonValue) { return null; } @@ -50,7 +50,7 @@ class IntegrityStorage { set(data: IStorageData | null): void { this.value = data; - this.storageService.store(IntegrityStorage.KEY, JSON.stringify(this.value), StorageScope.PROFILE, StorageTarget.MACHINE); + this.storageService.store(IntegrityStorage.KEY, JSON.stringify(this.value), StorageScope.APPLICATION, StorageTarget.MACHINE); } } From 9b1c6cb3fffa41f6e308f8221b53d3882ab163ca Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 27 Jun 2022 15:26:49 +0200 Subject: [PATCH 037/347] joh/issue152834 (#153298) * update sample * dynamically alias `ms-vscode.references-view` onto `vscode.references-view` --- .../references-view/src/references-view.d.ts | 24 +++++++++---------- .../workbench/api/common/extHost.api.impl.ts | 6 +++++ 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/extensions/references-view/src/references-view.d.ts b/extensions/references-view/src/references-view.d.ts index 70fd932a19f..9ec370029a7 100644 --- a/extensions/references-view/src/references-view.d.ts +++ b/extensions/references-view/src/references-view.d.ts @@ -6,14 +6,14 @@ import * as vscode from 'vscode'; /** - * This interface describes the shape for the references viewlet API. It consists - * of a single `setInput` function which must be called with a full implementation + * This interface describes the shape for the references viewlet API. It consists + * of a single `setInput` function which must be called with a full implementation * of the `SymbolTreeInput`-interface. To acquire this API use the default mechanics, e.g: - * + * * ```ts * // get references viewlet API - * const api = await vscode.extensions.getExtension('ms-vscode.references-view').activate(); - * + * const api = await vscode.extensions.getExtension('vscode.references-view').activate(); + * * // instantiate and set input which updates the view * const myInput: SymbolTreeInput = ... * api.setInput(myInput) @@ -22,8 +22,8 @@ import * as vscode from 'vscode'; export interface SymbolTree { /** - * Set the contents of the references viewlet. - * + * Set the contents of the references viewlet. + * * @param input A symbol tree input object */ setInput(input: SymbolTreeInput): void; @@ -31,7 +31,7 @@ export interface SymbolTree { /** * A symbol tree input is the entry point for populating the references viewlet. - * Inputs must be anchored at a code location, they must have a title, and they + * Inputs must be anchored at a code location, they must have a title, and they * must resolve to a model. */ export interface SymbolTreeInput { @@ -54,17 +54,17 @@ export interface SymbolTreeInput { readonly location: vscode.Location; /** - * Resolve this input to a model that contains the actual data. When there are no result + * Resolve this input to a model that contains the actual data. When there are no result * than `undefined` or `null` should be returned. */ resolve(): vscode.ProviderResult>; /** * This function is called when re-running from history. The symbols tree has tracked - * the original location of this input and that is now passed to this input. The + * the original location of this input and that is now passed to this input. The * implementation of this function should return a clone where the `location`-property * uses the provided `location` - * + * * @param location The location at which the new input should be anchored. * @returns A new input which location is anchored at the position. */ @@ -94,7 +94,7 @@ export interface SymbolTreeModel { navigation?: SymbolItemNavigation; /** - * Optional support for editor highlights. WHen implemented, the editor will highlight + * Optional support for editor highlights. WHen implemented, the editor will highlight * symbol ranges in the source code. */ highlights?: SymbolItemEditorHighlights; diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index b438fb90ead..24d3391bc2c 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -92,6 +92,7 @@ import { ExtHostInteractive } from 'vs/workbench/api/common/extHostInteractive'; import { combinedDisposable } from 'vs/base/common/lifecycle'; import { checkProposedApiEnabled, ExtensionIdentifierSet, isProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions'; import { DebugConfigurationProviderTriggerKind } from 'vs/workbench/contrib/debug/common/debug'; +import { equalsIgnoreCase } from 'vs/base/common/strings'; export interface IExtensionRegistries { mine: ExtensionDescriptionRegistry; @@ -392,6 +393,11 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I const extensions: typeof vscode.extensions = { getExtension(extensionId: string, includeFromDifferentExtensionHosts?: boolean): vscode.Extension | undefined { + if (equalsIgnoreCase(extensionId, 'ms-vscode.references-view')) { + extHostApiDeprecation.report(`The extension 'ms-vscode.references-view' has been renamed.`, extension, `Use 'vscode.references-view' instead.`); + extensionId = 'vscode.references-view'; + } + if (!isProposedApiEnabled(extension, 'extensionsAny')) { includeFromDifferentExtensionHosts = false; } From f148d86fd2894d42913b99bc1e0b7c200a5d7250 Mon Sep 17 00:00:00 2001 From: David Dossett Date: Mon, 27 Jun 2022 06:49:10 -0700 Subject: [PATCH 038/347] Add "Do Not Disturb" Mode (#149645) * Add mute icon to notification center toolbar * Add placeholder mute method * Add config service support * Refactor mute toggle behavior * More refactoring * Add hack for switching actions on toggle * Use do-not-disturb icons * Update status bar icon * Add comment for hack todo * Add experimental tag * Update setting name references * Fix typo * Update status bar icon and filter all errors * Update icons * Updates icon and toggle behavior * Update codicons ttf * cleanups * Use UI state instead of setting * Show window progress instead of notification * Update Storage scopes * Update Storage scopes * Refactor to use NotificationService * Minor fixes * Update tests * Address PR feedback * Update tests * :lipstick: * :lipstick: * zen - use dnd mode for filtering * set filters right on startup Co-authored-by: Benjamin Pasero --- .../standalone/browser/standaloneServices.ts | 8 ++-- .../common/abstractKeybindingService.test.ts | 5 ++- .../notification/common/notification.ts | 19 +++++---- .../test/common/testNotificationService.ts | 8 ++-- .../browser/extHostMessagerService.test.ts | 13 +++--- src/vs/workbench/browser/layout.ts | 20 ++++++---- src/vs/workbench/browser/layoutState.ts | 1 + .../notifications/notificationsActions.ts | 21 +++++++++- .../notifications/notificationsCenter.ts | 18 ++++++++- .../notifications/notificationsCommands.ts | 12 +++++- .../notifications/notificationsStatus.ts | 20 ++++++++-- .../browser/workbench.contribution.ts | 2 +- .../configurationEditingService.test.ts | 2 +- .../common/notificationService.ts | 40 ++++++++++++++++++- .../progress/browser/progressService.ts | 2 +- 15 files changed, 149 insertions(+), 42 deletions(-) diff --git a/src/vs/editor/standalone/browser/standaloneServices.ts b/src/vs/editor/standalone/browser/standaloneServices.ts index 5e96676ba40..8356bd94844 100644 --- a/src/vs/editor/standalone/browser/standaloneServices.ts +++ b/src/vs/editor/standalone/browser/standaloneServices.ts @@ -40,7 +40,7 @@ import { IKeybindingItem, KeybindingsRegistry } from 'vs/platform/keybinding/com import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem'; import { USLayoutResolvedKeybinding } from 'vs/platform/keybinding/common/usLayoutResolvedKeybinding'; import { ILabelService, ResourceLabelFormatter, IFormatterChangeEvent } from 'vs/platform/label/common/label'; -import { INotification, INotificationHandle, INotificationService, IPromptChoice, IPromptOptions, NoOpNotification, IStatusMessageOptions, NotificationsFilter } from 'vs/platform/notification/common/notification'; +import { INotification, INotificationHandle, INotificationService, IPromptChoice, IPromptOptions, NoOpNotification, IStatusMessageOptions } from 'vs/platform/notification/common/notification'; import { IProgressRunner, IEditorProgressService } from 'vs/platform/progress/common/progress'; import { ITelemetryInfo, ITelemetryService, TelemetryLevel } from 'vs/platform/telemetry/common/telemetry'; import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier, IWorkspace, IWorkspaceContextService, IWorkspaceFolder, IWorkspaceFoldersChangeEvent, IWorkspaceFoldersWillChangeEvent, WorkbenchState, WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; @@ -232,8 +232,12 @@ export class StandaloneNotificationService implements INotificationService { readonly onDidRemoveNotification: Event = Event.None; + readonly onDidChangeDoNotDisturbMode: Event = Event.None; + public _serviceBrand: undefined; + public doNotDisturbMode: boolean = false; + private static readonly NO_OP: INotificationHandle = new NoOpNotification(); public info(message: string): INotificationHandle { @@ -271,8 +275,6 @@ export class StandaloneNotificationService implements INotificationService { public status(message: string | Error, options?: IStatusMessageOptions): IDisposable { return Disposable.None; } - - public setFilter(filter: NotificationsFilter): void { } } export class StandaloneCommandService implements ICommandService { diff --git a/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts b/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts index a0d963aa542..cada490a6a0 100644 --- a/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts +++ b/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts @@ -141,8 +141,10 @@ suite('AbstractKeybindingService', () => { const notificationService: INotificationService = { _serviceBrand: undefined, + doNotDisturbMode: false, onDidAddNotification: undefined!, onDidRemoveNotification: undefined!, + onDidChangeDoNotDisturbMode: undefined!, notify: (notification: INotification) => { showMessageCalls.push({ sev: notification.severity, message: notification.message }); return new NoOpNotification(); @@ -169,8 +171,7 @@ suite('AbstractKeybindingService', () => { statusMessageCallsDisposed!.push(message); } }; - }, - setFilter() { } + } }; const resolver = new KeybindingResolver(items, [], () => { }); diff --git a/src/vs/platform/notification/common/notification.ts b/src/vs/platform/notification/common/notification.ts index e662f5a0016..3c82e108ea0 100644 --- a/src/vs/platform/notification/common/notification.ts +++ b/src/vs/platform/notification/common/notification.ts @@ -319,6 +319,13 @@ export interface INotificationService { readonly _serviceBrand: undefined; + /** + * The DND mode can be enabled or disabled + * and will result in all info and warning + * notifications to be silent. + */ + doNotDisturbMode: boolean; + /** * Emitted when a new notification is added. */ @@ -329,6 +336,11 @@ export interface INotificationService { */ readonly onDidRemoveNotification: Event; + /** + * Emitted when a do not disturb mode has changed. + */ + readonly onDidChangeDoNotDisturbMode: Event; + /** * Show the provided notification to the user. The returned `INotificationHandle` * can be used to control the notification afterwards. @@ -381,13 +393,6 @@ export interface INotificationService { * @returns a disposable to hide the status message */ status(message: NotificationMessage, options?: IStatusMessageOptions): IDisposable; - - /** - * Allows to configure a filter for notifications. - * - * @param filter the filter to use - */ - setFilter(filter: NotificationsFilter): void; } export class NoOpNotification implements INotificationHandle { diff --git a/src/vs/platform/notification/test/common/testNotificationService.ts b/src/vs/platform/notification/test/common/testNotificationService.ts index fe227b1f9fd..9d248ee5cd5 100644 --- a/src/vs/platform/notification/test/common/testNotificationService.ts +++ b/src/vs/platform/notification/test/common/testNotificationService.ts @@ -5,7 +5,7 @@ import { Event } from 'vs/base/common/event'; import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; -import { INotification, INotificationHandle, INotificationService, IPromptChoice, IPromptOptions, IStatusMessageOptions, NoOpNotification, NotificationsFilter, Severity } from 'vs/platform/notification/common/notification'; +import { INotification, INotificationHandle, INotificationService, IPromptChoice, IPromptOptions, IStatusMessageOptions, NoOpNotification, Severity } from 'vs/platform/notification/common/notification'; export class TestNotificationService implements INotificationService { @@ -13,8 +13,12 @@ export class TestNotificationService implements INotificationService { readonly onDidRemoveNotification: Event = Event.None; + readonly onDidChangeDoNotDisturbMode: Event = Event.None; + declare readonly _serviceBrand: undefined; + doNotDisturbMode: boolean = false; + private static readonly NO_OP: INotificationHandle = new NoOpNotification(); info(message: string): INotificationHandle { @@ -40,6 +44,4 @@ export class TestNotificationService implements INotificationService { status(message: string | Error, options?: IStatusMessageOptions): IDisposable { return Disposable.None; } - - setFilter(filter: NotificationsFilter): void { } } diff --git a/src/vs/workbench/api/test/browser/extHostMessagerService.test.ts b/src/vs/workbench/api/test/browser/extHostMessagerService.test.ts index 052719d3f41..e158253f4dc 100644 --- a/src/vs/workbench/api/test/browser/extHostMessagerService.test.ts +++ b/src/vs/workbench/api/test/browser/extHostMessagerService.test.ts @@ -6,7 +6,7 @@ import * as assert from 'assert'; import { MainThreadMessageService } from 'vs/workbench/api/browser/mainThreadMessageService'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; -import { INotificationService, INotification, NoOpNotification, INotificationHandle, Severity, IPromptChoice, IPromptOptions, IStatusMessageOptions, NotificationsFilter } from 'vs/platform/notification/common/notification'; +import { INotificationService, INotification, NoOpNotification, INotificationHandle, Severity, IPromptChoice, IPromptOptions, IStatusMessageOptions } from 'vs/platform/notification/common/notification'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { mock } from 'vs/base/test/common/mock'; import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; @@ -24,8 +24,10 @@ const emptyCommandService: ICommandService = { const emptyNotificationService = new class implements INotificationService { declare readonly _serviceBrand: undefined; + doNotDisturbMode: boolean = false; onDidAddNotification: Event = Event.None; onDidRemoveNotification: Event = Event.None; + onDidChangeDoNotDisturbMode: Event = Event.None; notify(...args: any[]): never { throw new Error('not implemented'); } @@ -44,19 +46,17 @@ const emptyNotificationService = new class implements INotificationService { status(message: string | Error, options?: IStatusMessageOptions): IDisposable { return Disposable.None; } - setFilter(filter: NotificationsFilter): void { - throw new Error('not implemented.'); - } }; class EmptyNotificationService implements INotificationService { declare readonly _serviceBrand: undefined; - + doNotDisturbMode: boolean = false; constructor(private withNotify: (notification: INotification) => void) { } onDidAddNotification: Event = Event.None; onDidRemoveNotification: Event = Event.None; + onDidChangeDoNotDisturbMode: Event = Event.None; notify(notification: INotification): INotificationHandle { this.withNotify(notification); @@ -77,9 +77,6 @@ class EmptyNotificationService implements INotificationService { status(message: string, options?: IStatusMessageOptions): IDisposable { return Disposable.None; } - setFilter(filter: NotificationsFilter): void { - throw new Error('Method not implemented.'); - } } suite('ExtHostMessageService', function () { diff --git a/src/vs/workbench/browser/layout.ts b/src/vs/workbench/browser/layout.ts index 0258b818920..240b52cc2b9 100644 --- a/src/vs/workbench/browser/layout.ts +++ b/src/vs/workbench/browser/layout.ts @@ -33,7 +33,7 @@ import { IFileService } from 'vs/platform/files/common/files'; import { isCodeEditor } from 'vs/editor/browser/editorBrowser'; import { coalesce } from 'vs/base/common/arrays'; import { assertIsDefined, isNumber } from 'vs/base/common/types'; -import { INotificationService, NotificationsFilter } from 'vs/platform/notification/common/notification'; +import { INotificationService } from 'vs/platform/notification/common/notification'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { WINDOW_ACTIVE_BORDER, WINDOW_INACTIVE_BORDER } from 'vs/workbench/common/theme'; import { LineNumbersType } from 'vs/editor/common/config/editorOptions'; @@ -1087,6 +1087,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi if (!restoring) { zenModeExitInfo.transitionedToFullScreen = toggleFullScreen; zenModeExitInfo.transitionedToCenteredEditorLayout = !this.isEditorLayoutCentered() && config.centerLayout; + zenModeExitInfo.handleNotificationsDoNotDisturbMode = !this.notificationService.doNotDisturbMode; zenModeExitInfo.wasVisible.sideBar = this.isVisible(Parts.SIDEBAR_PART); zenModeExitInfo.wasVisible.panel = this.isVisible(Parts.PANEL_PART); zenModeExitInfo.wasVisible.auxiliaryBar = this.isVisible(Parts.AUXILIARYBAR_PART); @@ -1114,13 +1115,15 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi this.windowState.runtime.zenMode.transitionDisposables.add(this.editorGroupService.enforcePartOptions({ showTabs: false })); } - if (config.silentNotifications) { - this.notificationService.setFilter(NotificationsFilter.ERROR); + if (config.silentNotifications && zenModeExitInfo.handleNotificationsDoNotDisturbMode) { + this.notificationService.doNotDisturbMode = true; } this.windowState.runtime.zenMode.transitionDisposables.add(this.configurationService.onDidChangeConfiguration(e => { if (e.affectsConfiguration(WorkbenchLayoutSettings.ZEN_MODE_SILENT_NOTIFICATIONS)) { - const filter = this.configurationService.getValue(WorkbenchLayoutSettings.ZEN_MODE_SILENT_NOTIFICATIONS) ? NotificationsFilter.ERROR : NotificationsFilter.OFF; - this.notificationService.setFilter(filter); + const zenModeSilentNotifications = !!this.configurationService.getValue(WorkbenchLayoutSettings.ZEN_MODE_SILENT_NOTIFICATIONS); + if (zenModeExitInfo.handleNotificationsDoNotDisturbMode) { + this.notificationService.doNotDisturbMode = zenModeSilentNotifications; + } } })); @@ -1155,13 +1158,14 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi this.centerEditorLayout(false, true); } + if (zenModeExitInfo.handleNotificationsDoNotDisturbMode) { + this.notificationService.doNotDisturbMode = false; + } + setLineNumbers(); this.focus(); - // Clear notifications filter - this.notificationService.setFilter(NotificationsFilter.OFF); - toggleFullScreen = zenModeExitInfo.transitionedToFullScreen && this.windowState.runtime.fullscreen; } diff --git a/src/vs/workbench/browser/layoutState.ts b/src/vs/workbench/browser/layoutState.ts index 0e4cac0dddd..70a4e637a26 100644 --- a/src/vs/workbench/browser/layoutState.ts +++ b/src/vs/workbench/browser/layoutState.ts @@ -46,6 +46,7 @@ export const LayoutStateKeys = { ZEN_MODE_EXIT_INFO: new RuntimeStateKey('zenMode.exitInfo', StorageScope.WORKSPACE, StorageTarget.USER, { transitionedToCenteredEditorLayout: false, transitionedToFullScreen: false, + handleNotificationsDoNotDisturbMode: false, wasVisible: { auxiliaryBar: false, panel: false, diff --git a/src/vs/workbench/browser/parts/notifications/notificationsActions.ts b/src/vs/workbench/browser/parts/notifications/notificationsActions.ts index 3402b0d5987..b4b01e896e8 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsActions.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsActions.ts @@ -9,7 +9,7 @@ import { localize } from 'vs/nls'; import { Action, IAction, ActionRunner, WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification } from 'vs/base/common/actions'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { INotificationService } from 'vs/platform/notification/common/notification'; -import { CLEAR_NOTIFICATION, EXPAND_NOTIFICATION, COLLAPSE_NOTIFICATION, CLEAR_ALL_NOTIFICATIONS, HIDE_NOTIFICATIONS_CENTER } from 'vs/workbench/browser/parts/notifications/notificationsCommands'; +import { CLEAR_NOTIFICATION, EXPAND_NOTIFICATION, COLLAPSE_NOTIFICATION, CLEAR_ALL_NOTIFICATIONS, HIDE_NOTIFICATIONS_CENTER, TOGGLE_DO_NOT_DISTURB_MODE } from 'vs/workbench/browser/parts/notifications/notificationsCommands'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; import { Codicon } from 'vs/base/common/codicons'; @@ -23,6 +23,7 @@ const hideIcon = registerIcon('notifications-hide', Codicon.chevronDown, localiz const expandIcon = registerIcon('notifications-expand', Codicon.chevronUp, localize('expandIcon', 'Icon for the expand action in notifications.')); const collapseIcon = registerIcon('notifications-collapse', Codicon.chevronDown, localize('collapseIcon', 'Icon for the collapse action in notifications.')); const configureIcon = registerIcon('notifications-configure', Codicon.gear, localize('configureIcon', 'Icon for the configure action in notifications.')); +const doNotDisturbIcon = registerIcon('notifications-do-not-disturb', Codicon.bellSlash, localize('doNotDisturbIcon', 'Icon for the mute all action in notifications.')); export class ClearNotificationAction extends Action { @@ -60,6 +61,24 @@ export class ClearAllNotificationsAction extends Action { } } +export class ToggleDoNotDisturbAction extends Action { + + static readonly ID = TOGGLE_DO_NOT_DISTURB_MODE; + static readonly LABEL = localize('toggleDoNotDisturbMode', "Toggle Do Not Disturb Mode"); + + constructor( + id: string, + label: string, + @ICommandService private readonly commandService: ICommandService + ) { + super(id, label, ThemeIcon.asClassName(doNotDisturbIcon)); + } + + override async run(): Promise { + this.commandService.executeCommand(TOGGLE_DO_NOT_DISTURB_MODE); + } +} + export class HideNotificationsCenterAction extends Action { static readonly ID = HIDE_NOTIFICATIONS_CENTER; diff --git a/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts b/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts index c99553bf978..8a6cafd8971 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts @@ -19,11 +19,12 @@ import { widgetShadow } from 'vs/platform/theme/common/colorRegistry'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { localize } from 'vs/nls'; import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; -import { ClearAllNotificationsAction, HideNotificationsCenterAction, NotificationActionRunner } from 'vs/workbench/browser/parts/notifications/notificationsActions'; +import { ClearAllNotificationsAction, HideNotificationsCenterAction, NotificationActionRunner, ToggleDoNotDisturbAction } from 'vs/workbench/browser/parts/notifications/notificationsActions'; import { IAction } from 'vs/base/common/actions'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { assertAllDefined, assertIsDefined } from 'vs/base/common/types'; import { NotificationsCenterVisibleContext } from 'vs/workbench/common/contextkeys'; +import { INotificationService } from 'vs/platform/notification/common/notification'; export class NotificationsCenter extends Themable implements INotificationsCenterController { @@ -40,6 +41,7 @@ export class NotificationsCenter extends Themable implements INotificationsCente private workbenchDimensions: Dimension | undefined; private readonly notificationsCenterVisibleContextKey = NotificationsCenterVisibleContext.bindTo(this.contextKeyService); private clearAllAction: ClearAllNotificationsAction | undefined; + private toggleDoNotDisturbAction: ToggleDoNotDisturbAction | undefined; constructor( private readonly container: HTMLElement, @@ -49,7 +51,8 @@ export class NotificationsCenter extends Themable implements INotificationsCente @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService, @IContextKeyService private readonly contextKeyService: IContextKeyService, @IEditorGroupsService private readonly editorGroupService: IEditorGroupsService, - @IKeybindingService private readonly keybindingService: IKeybindingService + @IKeybindingService private readonly keybindingService: IKeybindingService, + @INotificationService private readonly notificationService: INotificationService, ) { super(themeService); @@ -61,6 +64,13 @@ export class NotificationsCenter extends Themable implements INotificationsCente private registerListeners(): void { this._register(this.model.onDidChangeNotification(e => this.onDidChangeNotification(e))); this._register(this.layoutService.onDidLayout(dimension => this.layout(Dimension.lift(dimension)))); + this._register(this.notificationService.onDidChangeDoNotDisturbMode(() => this.onDidChangeDoNotDisturbMode())); + } + + private onDidChangeDoNotDisturbMode(): void { + if (this.notificationService.doNotDisturbMode) { + this.hide(); // hide the notification center when do not disturb is enabled + } } get isVisible(): boolean { @@ -154,6 +164,9 @@ export class NotificationsCenter extends Themable implements INotificationsCente this.clearAllAction = this._register(this.instantiationService.createInstance(ClearAllNotificationsAction, ClearAllNotificationsAction.ID, ClearAllNotificationsAction.LABEL)); notificationsToolBar.push(this.clearAllAction, { icon: true, label: false, keybinding: this.getKeybindingLabel(this.clearAllAction) }); + this.toggleDoNotDisturbAction = this._register(this.instantiationService.createInstance(ToggleDoNotDisturbAction, ToggleDoNotDisturbAction.ID, ToggleDoNotDisturbAction.LABEL)); + notificationsToolBar.push(this.toggleDoNotDisturbAction, { icon: true, label: false, keybinding: this.getKeybindingLabel(this.toggleDoNotDisturbAction) }); + const hideAllAction = this._register(this.instantiationService.createInstance(HideNotificationsCenterAction, HideNotificationsCenterAction.ID, HideNotificationsCenterAction.LABEL)); notificationsToolBar.push(hideAllAction, { icon: true, label: false, keybinding: this.getKeybindingLabel(hideAllAction) }); @@ -316,6 +329,7 @@ export class NotificationsCenter extends Themable implements INotificationsCente } } + registerThemingParticipant((theme, collector) => { const notificationBorderColor = theme.getColor(NOTIFICATIONS_BORDER); if (notificationBorderColor) { diff --git a/src/vs/workbench/browser/parts/notifications/notificationsCommands.ts b/src/vs/workbench/browser/parts/notifications/notificationsCommands.ts index ee0cd3f780c..7649aba7b08 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsCommands.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsCommands.ts @@ -14,6 +14,7 @@ import { IListService, WorkbenchList } from 'vs/platform/list/browser/listServic import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { NotificationMetrics, NotificationMetricsClassification, notificationToMetrics } from 'vs/workbench/browser/parts/notifications/notificationsTelemetry'; import { NotificationFocusedContext, NotificationsCenterVisibleContext, NotificationsToastsVisibleContext } from 'vs/workbench/common/contextkeys'; +import { INotificationService } from 'vs/platform/notification/common/notification'; // Center export const SHOW_NOTIFICATIONS_CENTER = 'notifications.showList'; @@ -34,6 +35,7 @@ export const EXPAND_NOTIFICATION = 'notification.expand'; const TOGGLE_NOTIFICATION = 'notification.toggle'; export const CLEAR_NOTIFICATION = 'notification.clear'; export const CLEAR_ALL_NOTIFICATIONS = 'notifications.clearAll'; +export const TOGGLE_DO_NOT_DISTURB_MODE = 'notifications.toggleDoNotDisturbMode'; export interface INotificationsCenterController { readonly isVisible: boolean; @@ -240,13 +242,21 @@ export function registerNotificationCommands(center: INotificationsCenterControl } }); - /// Clear All Notifications + // Clear All Notifications CommandsRegistry.registerCommand(CLEAR_ALL_NOTIFICATIONS, () => center.clearAll()); + // Toggle Do Not Disturb Mode + CommandsRegistry.registerCommand(TOGGLE_DO_NOT_DISTURB_MODE, accessor => { + const notificationService = accessor.get(INotificationService); + + notificationService.doNotDisturbMode = !notificationService.doNotDisturbMode; + }); + // Commands for Command Palette const category = { value: localize('notifications', "Notifications"), original: 'Notifications' }; MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: SHOW_NOTIFICATIONS_CENTER, title: { value: localize('showNotifications', "Show Notifications"), original: 'Show Notifications' }, category } }); MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: HIDE_NOTIFICATIONS_CENTER, title: { value: localize('hideNotifications', "Hide Notifications"), original: 'Hide Notifications' }, category }, when: NotificationsCenterVisibleContext }); MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: CLEAR_ALL_NOTIFICATIONS, title: { value: localize('clearAllNotifications', "Clear All Notifications"), original: 'Clear All Notifications' }, category } }); + MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: TOGGLE_DO_NOT_DISTURB_MODE, title: { value: localize('toggleDoNotDisturbMode', "Toggle Do Not Disturb Mode"), original: 'Toggle Do Not Disturb Mode' }, category } }); MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: { id: FOCUS_NOTIFICATION_TOAST, title: { value: localize('focusNotificationToasts', "Focus Notification Toast"), original: 'Focus Notification Toast' }, category }, when: NotificationsToastsVisibleContext }); } diff --git a/src/vs/workbench/browser/parts/notifications/notificationsStatus.ts b/src/vs/workbench/browser/parts/notifications/notificationsStatus.ts index ec31db99758..9b15769a6c3 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsStatus.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsStatus.ts @@ -8,6 +8,7 @@ import { IStatusbarService, StatusbarAlignment, IStatusbarEntryAccessor, IStatus import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle'; import { HIDE_NOTIFICATIONS_CENTER, SHOW_NOTIFICATIONS_CENTER } from 'vs/workbench/browser/parts/notifications/notificationsCommands'; import { localize } from 'vs/nls'; +import { INotificationService } from 'vs/platform/notification/common/notification'; export class NotificationsStatus extends Disposable { @@ -21,7 +22,8 @@ export class NotificationsStatus extends Disposable { constructor( private readonly model: INotificationsModel, - @IStatusbarService private readonly statusbarService: IStatusbarService + @IStatusbarService private readonly statusbarService: IStatusbarService, + @INotificationService private readonly notificationService: INotificationService ) { super(); @@ -37,6 +39,7 @@ export class NotificationsStatus extends Disposable { private registerListeners(): void { this._register(this.model.onDidChangeNotification(e => this.onDidChangeNotification(e))); this._register(this.model.onDidChangeStatusMessage(e => this.onDidChangeStatusMessage(e))); + this._register(this.notificationService.onDidChangeDoNotDisturbMode(() => this.updateNotificationsCenterStatusItem())); } private onDidChangeNotification(e: INotificationChangeEvent): void { @@ -69,8 +72,9 @@ export class NotificationsStatus extends Disposable { } } - // Show the bell with a dot if there are unread or in-progress notifications - const statusProperties: IStatusbarEntry = { + // Show the status bar entry depending on do not disturb setting + + let statusProperties: IStatusbarEntry = { name: localize('status.notifications', "Notifications"), text: `${notificationsInProgress > 0 || this.newNotificationsCount > 0 ? '$(bell-dot)' : '$(bell)'}`, ariaLabel: localize('status.notifications', "Notifications"), @@ -79,6 +83,16 @@ export class NotificationsStatus extends Disposable { showBeak: this.isNotificationsCenterVisible }; + if (this.notificationService.doNotDisturbMode) { + statusProperties = { + ...statusProperties, + name: localize('status.doNotDisturb', "Do Not Disturb"), + text: '$(bell-slash)', + ariaLabel: localize('status.doNotDisturb', "Do Not Disturb"), + tooltip: localize('status.doNotDisturbTooltip', "Do Not Disturb Mode is Enabled") + }; + } + if (!this.notificationsCenterStatusItem) { this.notificationsCenterStatusItem = this.statusbarService.addEntry( statusProperties, diff --git a/src/vs/workbench/browser/workbench.contribution.ts b/src/vs/workbench/browser/workbench.contribution.ts index 017f41f481a..fd5b98e1620 100644 --- a/src/vs/workbench/browser/workbench.contribution.ts +++ b/src/vs/workbench/browser/workbench.contribution.ts @@ -677,7 +677,7 @@ const registry = Registry.as(ConfigurationExtensions.Con 'zenMode.silentNotifications': { 'type': 'boolean', 'default': true, - 'description': localize('zenMode.silentNotifications', "Controls whether notifications are shown while in zen mode. If true, only error notifications will pop out.") + 'description': localize('zenMode.silentNotifications', "Controls whether notifications do not disturb mode should be enabled while in zen mode. If true, only error notifications will pop out.") } } }); diff --git a/src/vs/workbench/services/configuration/test/browser/configurationEditingService.test.ts b/src/vs/workbench/services/configuration/test/browser/configurationEditingService.test.ts index 8b7fb8df39f..243add76058 100644 --- a/src/vs/workbench/services/configuration/test/browser/configurationEditingService.test.ts +++ b/src/vs/workbench/services/configuration/test/browser/configurationEditingService.test.ts @@ -192,7 +192,7 @@ suite('ConfigurationEditingService', () => { test('do not notify error', async () => { instantiationService.stub(ITextFileService, 'isDirty', true); const target = sinon.stub(); - instantiationService.stub(INotificationService, { prompt: target, _serviceBrand: undefined, onDidAddNotification: undefined!, onDidRemoveNotification: undefined!, notify: null!, error: null!, info: null!, warn: null!, status: null!, setFilter: null! }); + instantiationService.stub(INotificationService, { prompt: target, _serviceBrand: undefined, doNotDisturbMode: false, onDidAddNotification: undefined!, onDidRemoveNotification: undefined!, onDidChangeDoNotDisturbMode: undefined!, notify: null!, error: null!, info: null!, warn: null!, status: null! }); try { await testObject.writeConfiguration(EditableConfigurationTarget.USER_LOCAL, { key: 'configurationEditing.service.testSetting', value: 'value' }, { donotNotifyError: true }); } catch (error) { diff --git a/src/vs/workbench/services/notification/common/notificationService.ts b/src/vs/workbench/services/notification/common/notificationService.ts index 32ade1ac946..1a768532b79 100644 --- a/src/vs/workbench/services/notification/common/notificationService.ts +++ b/src/vs/workbench/services/notification/common/notificationService.ts @@ -24,11 +24,15 @@ export class NotificationService extends Disposable implements INotificationServ private readonly _onDidRemoveNotification = this._register(new Emitter()); readonly onDidRemoveNotification = this._onDidRemoveNotification.event; + private readonly _onDidChangeDoNotDisturbMode = this._register(new Emitter()); + readonly onDidChangeDoNotDisturbMode = this._onDidChangeDoNotDisturbMode.event; + constructor( @IStorageService private readonly storageService: IStorageService ) { super(); + this.updateDoNotDisturbFilters(); this.registerListeners(); } @@ -58,10 +62,44 @@ export class NotificationService extends Disposable implements INotificationServ })); } - setFilter(filter: NotificationsFilter): void { + //#region Do not disturb mode + + static readonly DND_SETTINGS_KEY = 'notifications.doNotDisturbMode'; + + private _doNotDisturbMode = this.storageService.getBoolean(NotificationService.DND_SETTINGS_KEY, StorageScope.APPLICATION, false); + + get doNotDisturbMode() { + return this._doNotDisturbMode; + } + + set doNotDisturbMode(enabled: boolean) { + if (this._doNotDisturbMode === enabled) { + return; // no change + } + + this.storageService.store(NotificationService.DND_SETTINGS_KEY, enabled, StorageScope.APPLICATION, StorageTarget.MACHINE); + this._doNotDisturbMode = enabled; + + // Toggle via filter + this.updateDoNotDisturbFilters(); + + // Events + this._onDidChangeDoNotDisturbMode.fire(); + } + + private updateDoNotDisturbFilters(): void { + let filter: NotificationsFilter; + if (this._doNotDisturbMode) { + filter = NotificationsFilter.ERROR; + } else { + filter = NotificationsFilter.OFF; + } + this.model.setFilter(filter); } + //#endregion + info(message: NotificationMessage | NotificationMessage[]): void { if (Array.isArray(message)) { message.forEach(m => this.info(m)); diff --git a/src/vs/workbench/services/progress/browser/progressService.ts b/src/vs/workbench/services/progress/browser/progressService.ts index e4bffd568d0..8172f41fa24 100644 --- a/src/vs/workbench/services/progress/browser/progressService.ts +++ b/src/vs/workbench/services/progress/browser/progressService.ts @@ -70,7 +70,7 @@ export class ProgressService extends Disposable implements IProgressService { switch (location) { case ProgressLocation.Notification: - return this.withNotificationProgress({ ...options, location }, task, onDidCancel); + return this.withNotificationProgress({ ...options, location, silent: this.notificationService.doNotDisturbMode }, task, onDidCancel); case ProgressLocation.Window: if ((options as IProgressWindowOptions).command) { // Window progress with command get's shown in the status bar From af06b93a03dfa654977cef6e23c6a4ffd362affa Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Mon, 27 Jun 2022 15:50:56 +0200 Subject: [PATCH 039/347] Sets max debounce rate for inline completions to 50. (#152747) * Sets max debounce rate for inline completions to 50. See #151447 * Fixes tests. --- .../inlineCompletions/browser/inlineCompletionsModel.ts | 2 +- .../test/browser/inlineCompletionsProvider.test.ts | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/vs/editor/contrib/inlineCompletions/browser/inlineCompletionsModel.ts b/src/vs/editor/contrib/inlineCompletions/browser/inlineCompletionsModel.ts index 13a8e3b840c..3c1fbb69804 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/inlineCompletionsModel.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/inlineCompletionsModel.ts @@ -47,7 +47,7 @@ export class InlineCompletionsModel extends Disposable implements GhostTextWidge private readonly debounceValue = this.debounceService.for( this.languageFeaturesService.inlineCompletionsProvider, 'InlineCompletionsDebounce', - { min: 50, max: 200 } + { min: 50, max: 50 } ); constructor( diff --git a/src/vs/editor/contrib/inlineCompletions/test/browser/inlineCompletionsProvider.test.ts b/src/vs/editor/contrib/inlineCompletions/test/browser/inlineCompletionsProvider.test.ts index d144f3e7e0f..d9091fdea2d 100644 --- a/src/vs/editor/contrib/inlineCompletions/test/browser/inlineCompletionsProvider.test.ts +++ b/src/vs/editor/contrib/inlineCompletions/test/browser/inlineCompletionsProvider.test.ts @@ -524,7 +524,9 @@ suite('Inline Completions', () => { context.cursorDown(); context.keyboardType('hello'); - await timeout(100); + await timeout(40); + + assert.deepStrictEqual(provider.getAndClearCallHistory(), []); // Update ghost text context.keyboardType('w'); From 8d888665f9089651b506eb46f43ca7d59fb05494 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 27 Jun 2022 15:51:43 +0200 Subject: [PATCH 040/347] add icon, colors to settings profile status bar entry (#153308) --- .../browser/userDataProfile.ts | 32 +++++++++++++++---- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/contrib/userDataProfile/browser/userDataProfile.ts b/src/vs/workbench/contrib/userDataProfile/browser/userDataProfile.ts index 5d97df3951c..d2732a12138 100644 --- a/src/vs/workbench/contrib/userDataProfile/browser/userDataProfile.ts +++ b/src/vs/workbench/contrib/userDataProfile/browser/userDataProfile.ts @@ -3,17 +3,20 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { Codicon } from 'vs/base/common/codicons'; import { Event } from 'vs/base/common/event'; import { Disposable, DisposableStore, IDisposable, MutableDisposable } from 'vs/base/common/lifecycle'; import { ServicesAccessor } from 'vs/editor/browser/editorExtensions'; import { localize } from 'vs/nls'; import { Action2, ISubmenuItem, MenuId, MenuRegistry, registerAction2 } from 'vs/platform/actions/common/actions'; import { ContextKeyExpr, IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; +import { registerColor } from 'vs/platform/theme/common/colorRegistry'; +import { themeColorFromId } from 'vs/platform/theme/common/themeService'; import { IUserDataProfile, IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { WorkbenchStateContext } from 'vs/workbench/common/contextkeys'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; -import { IStatusbarEntryAccessor, IStatusbarService, StatusbarAlignment } from 'vs/workbench/services/statusbar/browser/statusbar'; +import { IStatusbarEntry, IStatusbarEntryAccessor, IStatusbarService, StatusbarAlignment } from 'vs/workbench/services/statusbar/browser/statusbar'; import { IUserDataProfileManagementService, IUserDataProfileService, ManageProfilesSubMenu, PROFILES_CATEGORY, PROFILES_ENABLEMENT_CONTEXT, PROFILES_TTILE } from 'vs/workbench/services/userDataProfile/common/userDataProfile'; const CONTEXT_CURRENT_PROFILE = new RawContextKey('currentUserDataProfile', ''); @@ -109,17 +112,20 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements private profileStatusAccessor: IStatusbarEntryAccessor | undefined; private updateStatus(): void { - if (this.userDataProfilesService.profiles.length > 1 && this.workspaceContextService.getWorkbenchState() !== WorkbenchState.EMPTY) { - const statusBarEntry = { - name: this.userDataProfileService.currentProfile.name!, + if (this.userDataProfilesService.profiles.length && this.workspaceContextService.getWorkbenchState() !== WorkbenchState.EMPTY) { + const statusBarEntry: IStatusbarEntry = { + name: PROFILES_CATEGORY, command: 'workbench.profiles.actions.switchProfile', ariaLabel: localize('currentProfile', "Current Settings Profile is {0}", this.userDataProfileService.currentProfile.name), - text: `${PROFILES_CATEGORY}: ${this.userDataProfileService.currentProfile.name!}`, + text: `$(${Codicon.multipleWindows.id}) ${this.userDataProfileService.currentProfile.name!}`, + tooltip: localize('profileTooltip', "{0}: {1}", PROFILES_CATEGORY, this.userDataProfileService.currentProfile.name), + color: themeColorFromId(STATUS_BAR_SETTINGS_PROFILE_FOREGROUND), + backgroundColor: themeColorFromId(STATUS_BAR_SETTINGS_PROFILE_BACKGROUND) }; if (this.profileStatusAccessor) { this.profileStatusAccessor.update(statusBarEntry); } else { - this.profileStatusAccessor = this.statusBarService.addEntry(statusBarEntry, 'status.userDataProfile', StatusbarAlignment.LEFT, 1); + this.profileStatusAccessor = this.statusBarService.addEntry(statusBarEntry, 'status.userDataProfile', StatusbarAlignment.LEFT, Number.MAX_VALUE - 1); } } else { if (this.profileStatusAccessor) { @@ -129,3 +135,17 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements } } } + +const STATUS_BAR_SETTINGS_PROFILE_FOREGROUND = registerColor('statusBarItem.settingsProfilesForeground', { + dark: null, + light: null, + hcDark: null, + hcLight: null +}, localize('statusBarItemSettingsProfileForeground', "Foreground color for the settings profile entry on the status bar.")); + +const STATUS_BAR_SETTINGS_PROFILE_BACKGROUND = registerColor('statusBarItem.settingsProfilesBackground', { + dark: null, + light: null, + hcDark: null, + hcLight: null +}, localize('statusBarItemSettingsProfileBackground', "Background color for the settings profile entry on the status bar.")); From e3da63433141d9ecaacf168867b793a06cfb550c Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 27 Jun 2022 16:09:21 +0200 Subject: [PATCH 041/347] fix #153183 (#153313) * fix #153183 * fix compilation --- .../userDataProfile/electron-main/userDataProfile.ts | 9 +++++++++ .../electron-main/workspacesManagementMainService.ts | 5 +++++ .../workspacesManagementMainService.test.ts | 8 +++++++- .../browser/abstractWorkspaceEditingService.ts | 3 +++ 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/vs/platform/userDataProfile/electron-main/userDataProfile.ts b/src/vs/platform/userDataProfile/electron-main/userDataProfile.ts index 08974874814..b2090d2b62c 100644 --- a/src/vs/platform/userDataProfile/electron-main/userDataProfile.ts +++ b/src/vs/platform/userDataProfile/electron-main/userDataProfile.ts @@ -28,6 +28,7 @@ export type WillRemoveProfileEvent = { export const IUserDataProfilesMainService = refineServiceDecorator(IUserDataProfilesService); export interface IUserDataProfilesMainService extends IUserDataProfilesService { + unsetWorkspace(workspaceIdentifier: ISingleFolderWorkspaceIdentifier | IWorkspaceIdentifier): Promise; readonly onWillCreateProfile: Event; readonly onWillRemoveProfile: Event; } @@ -106,6 +107,14 @@ export class UserDataProfilesMainService extends UserDataProfilesService impleme return this.profilesObject.profiles.find(p => this.uriIdentityService.extUri.isEqual(p.location, profile.location))!; } + async unsetWorkspace(workspaceIdentifier: ISingleFolderWorkspaceIdentifier | IWorkspaceIdentifier): Promise { + if (!this.enabled) { + throw new Error(`Settings Profiles are disabled. Enable them via the '${PROFILES_ENABLEMENT_CONFIG}' setting.`); + } + const workspace = this.getWorkspace(workspaceIdentifier); + this.setStoredWorskpaceInfos(this.getStoredWorskpaceInfos().filter(info => !this.uriIdentityService.extUri.isEqual(info.workspace, workspace))); + } + override async removeProfile(profile: IUserDataProfile): Promise { if (!this.enabled) { throw new Error(`Settings Profiles are disabled. Enable them via the '${PROFILES_ENABLEMENT_CONFIG}' setting.`); diff --git a/src/vs/platform/workspaces/electron-main/workspacesManagementMainService.ts b/src/vs/platform/workspaces/electron-main/workspacesManagementMainService.ts index deda0faf8d4..2ee6816721e 100644 --- a/src/vs/platform/workspaces/electron-main/workspacesManagementMainService.ts +++ b/src/vs/platform/workspaces/electron-main/workspacesManagementMainService.ts @@ -23,6 +23,7 @@ import { IEnvironmentMainService } from 'vs/platform/environment/electron-main/e import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { ILogService } from 'vs/platform/log/common/log'; import { IProductService } from 'vs/platform/product/common/productService'; +import { IUserDataProfilesMainService } from 'vs/platform/userDataProfile/electron-main/userDataProfile'; import { ICodeWindow } from 'vs/platform/window/electron-main/window'; import { findWindowOnWorkspaceOrFolder } from 'vs/platform/windows/electron-main/windowsFinder'; import { isWorkspaceIdentifier, IWorkspaceIdentifier, IResolvedWorkspace, hasWorkspaceFileExtension, UNTITLED_WORKSPACE_NAME, isUntitledWorkspace } from 'vs/platform/workspace/common/workspace'; @@ -75,6 +76,7 @@ export class WorkspacesManagementMainService extends Disposable implements IWork constructor( @IEnvironmentMainService private readonly environmentMainService: IEnvironmentMainService, @ILogService private readonly logService: ILogService, + @IUserDataProfilesMainService private readonly userDataProfilesMainService: IUserDataProfilesMainService, @IBackupMainService private readonly backupMainService: IBackupMainService, @IDialogMainService private readonly dialogMainService: IDialogMainService, @IProductService private readonly productService: IProductService @@ -203,6 +205,9 @@ export class WorkspacesManagementMainService extends Disposable implements IWork // Delete from disk this.doDeleteUntitledWorkspaceSync(workspace); + // unset workspace from profiles + this.userDataProfilesMainService.unsetWorkspace(workspace); + // Event this._onDidDeleteUntitledWorkspace.fire(workspace); } diff --git a/src/vs/platform/workspaces/test/electron-main/workspacesManagementMainService.test.ts b/src/vs/platform/workspaces/test/electron-main/workspacesManagementMainService.test.ts index 25fb2b4a852..197938f32e4 100644 --- a/src/vs/platform/workspaces/test/electron-main/workspacesManagementMainService.test.ts +++ b/src/vs/platform/workspaces/test/electron-main/workspacesManagementMainService.test.ts @@ -20,9 +20,13 @@ import { INativeOpenDialogOptions } from 'vs/platform/dialogs/common/dialogs'; import { IDialogMainService } from 'vs/platform/dialogs/electron-main/dialogMainService'; import { EnvironmentMainService } from 'vs/platform/environment/electron-main/environmentMainService'; import { OPTIONS, parseArgs } from 'vs/platform/environment/node/argv'; +import { FileService } from 'vs/platform/files/common/fileService'; import { NullLogService } from 'vs/platform/log/common/log'; import product from 'vs/platform/product/common/product'; import { IProductService } from 'vs/platform/product/common/productService'; +import { StateMainService } from 'vs/platform/state/electron-main/stateMainService'; +import { UriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentityService'; +import { UserDataProfilesMainService } from 'vs/platform/userDataProfile/electron-main/userDataProfile'; import { IRawFileWorkspaceFolder, IRawUriWorkspaceFolder, IWorkspaceIdentifier, WORKSPACE_EXTENSION } from 'vs/platform/workspace/common/workspace'; import { IStoredWorkspace, IStoredWorkspaceFolder, IWorkspaceFolderCreationData, rewriteWorkspaceFileForNewLocation } from 'vs/platform/workspaces/common/workspaces'; import { WorkspacesManagementMainService } from 'vs/platform/workspaces/electron-main/workspacesManagementMainService'; @@ -109,7 +113,9 @@ flakySuite('WorkspacesManagementMainService', () => { } }; - service = new WorkspacesManagementMainService(environmentMainService, new NullLogService(), new TestBackupMainService(), new TestDialogMainService(), productService); + const logService = new NullLogService(); + const fileService = new FileService(logService); + service = new WorkspacesManagementMainService(environmentMainService, logService, new UserDataProfilesMainService(new StateMainService(environmentMainService, logService, fileService), new UriIdentityService(fileService), environmentMainService, fileService, logService), new TestBackupMainService(), new TestDialogMainService(), productService); return pfs.Promises.mkdir(untitledWorkspacesHomePath, { recursive: true }); }); diff --git a/src/vs/workbench/services/workspaces/browser/abstractWorkspaceEditingService.ts b/src/vs/workbench/services/workspaces/browser/abstractWorkspaceEditingService.ts index 4dcab81a9d1..a7ab9d54798 100644 --- a/src/vs/workbench/services/workspaces/browser/abstractWorkspaceEditingService.ts +++ b/src/vs/workbench/services/workspaces/browser/abstractWorkspaceEditingService.ts @@ -245,6 +245,9 @@ export abstract class AbstractWorkspaceEditingService implements IWorkspaceEditi } } else { path = untitledWorkspace.configPath; + if (!this.userDataProfileService.currentProfile.isDefault) { + await this.userDataProfilesService.setProfileForWorkspace(this.userDataProfileService.currentProfile, untitledWorkspace); + } } return this.enterWorkspace(path); From ade80ca128741e2aa97e836a1ff0ad7cf8d67fa7 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 27 Jun 2022 16:20:15 +0200 Subject: [PATCH 042/347] refresh extension view on profile change (#153302) * refresh extension view on profile change * fix tests --- .../extensions/browser/extensionsViewlet.ts | 1 + .../browser/extensionsWorkbenchService.ts | 31 +++++++++++++++++-- .../contrib/extensions/common/extensions.ts | 1 + .../extensionEnablementService.test.ts | 1 + 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts b/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts index ae5a743a290..8de65a5b170 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts @@ -473,6 +473,7 @@ export class ExtensionsViewPaneContainer extends ViewPaneContainer implements IE this.searchBuiltInExtensionsContextKey = SearchBuiltInExtensionsContext.bindTo(contextKeyService); this.recommendedExtensionsContextKey = RecommendedExtensionsContext.bindTo(contextKeyService); this._register(this.paneCompositeService.onDidPaneCompositeOpen(e => { if (e.viewContainerLocation === ViewContainerLocation.Sidebar) { this.onViewletOpen(e.composite); } }, this)); + this._register(extensionsWorkbenchService.onReset(() => this.refresh())); this.searchViewletState = this.getMemento(StorageScope.WORKSPACE, StorageTarget.USER); } diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts b/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts index e23dee80a2c..d04b4af2ef6 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts @@ -416,8 +416,11 @@ class Extensions extends Disposable { extension.deprecationInfo = extensionsControlManifest.deprecated ? extensionsControlManifest.deprecated[extension.identifier.id.toLowerCase()] : undefined; } - private readonly _onChange: Emitter<{ extension: Extension; operation?: InstallOperation } | undefined> = this._register(new Emitter<{ extension: Extension; operation?: InstallOperation } | undefined>()); - get onChange(): Event<{ extension: Extension; operation?: InstallOperation } | undefined> { return this._onChange.event; } + private readonly _onChange = this._register(new Emitter<{ extension: Extension; operation?: InstallOperation } | undefined>()); + get onChange() { return this._onChange.event; } + + private readonly _onReset = this._register(new Emitter()); + get onReset() { return this._onReset.event; } private installing: Extension[] = []; private uninstalling: Extension[] = []; @@ -435,6 +438,7 @@ class Extensions extends Disposable { this._register(server.extensionManagementService.onDidInstallExtensions(e => this.onDidInstallExtensions(e))); this._register(server.extensionManagementService.onUninstallExtension(e => this.onUninstallExtension(e.identifier))); this._register(server.extensionManagementService.onDidUninstallExtension(e => this.onDidUninstallExtension(e))); + this._register(server.extensionManagementService.onDidChangeProfileExtensions(e => this.onDidChangeProfileExtensions(e.added, e.removed))); this._register(extensionEnablementService.onEnablementChanged(e => this.onEnablementChanged(e))); } @@ -554,6 +558,23 @@ class Extensions extends Disposable { } } + private async onDidChangeProfileExtensions(added: ILocalExtension[], removed: ILocalExtension[]): Promise { + const extensionsControlManifest = await this.server.extensionManagementService.getExtensionsControlManifest(); + for (const addedExtension of added) { + if (this.installed.find(e => areSameExtensions(e.identifier, addedExtension.identifier))) { + const extension = this.instantiationService.createInstance(Extension, this.stateProvider, this.server, addedExtension, undefined); + this.installed.push(extension); + Extensions.updateExtensionFromControlManifest(extension, extensionsControlManifest); + } + } + + if (removed.length) { + this.installed = this.installed.filter(e => !removed.some(removedExtension => areSameExtensions(e.identifier, removedExtension.identifier))); + } + + this._onReset.fire(); + } + private async onDidInstallExtensions(results: readonly InstallExtensionResult[]): Promise { for (const event of results) { const { local, source } = event; @@ -660,6 +681,9 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension private readonly _onChange: Emitter = new Emitter(); get onChange(): Event { return this._onChange.event; } + private readonly _onReset = new Emitter(); + get onReset() { return this._onReset.event; } + readonly preferPreReleases = this.productService.quality !== 'stable'; private installing: IExtension[] = []; @@ -696,14 +720,17 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension if (extensionManagementServerService.localExtensionManagementServer) { this.localExtensions = this._register(instantiationService.createInstance(Extensions, extensionManagementServerService.localExtensionManagementServer, ext => this.getExtensionState(ext))); this._register(this.localExtensions.onChange(e => this._onChange.fire(e ? e.extension : undefined))); + this._register(this.localExtensions.onReset(e => { this._onChange.fire(undefined); this._onReset.fire(); })); } if (extensionManagementServerService.remoteExtensionManagementServer) { this.remoteExtensions = this._register(instantiationService.createInstance(Extensions, extensionManagementServerService.remoteExtensionManagementServer, ext => this.getExtensionState(ext))); this._register(this.remoteExtensions.onChange(e => this._onChange.fire(e ? e.extension : undefined))); + this._register(this.remoteExtensions.onReset(e => { this._onChange.fire(undefined); this._onReset.fire(); })); } if (extensionManagementServerService.webExtensionManagementServer) { this.webExtensions = this._register(instantiationService.createInstance(Extensions, extensionManagementServerService.webExtensionManagementServer, ext => this.getExtensionState(ext))); this._register(this.webExtensions.onChange(e => this._onChange.fire(e ? e.extension : undefined))); + this._register(this.webExtensions.onReset(e => { this._onChange.fire(undefined); this._onReset.fire(); })); } this.updatesCheckDelayer = new ThrottledDelayer(ExtensionsWorkbenchService.UpdatesCheckInterval); diff --git a/src/vs/workbench/contrib/extensions/common/extensions.ts b/src/vs/workbench/contrib/extensions/common/extensions.ts index 4065b9d8ddf..60c5b415c54 100644 --- a/src/vs/workbench/contrib/extensions/common/extensions.ts +++ b/src/vs/workbench/contrib/extensions/common/extensions.ts @@ -91,6 +91,7 @@ export const IExtensionsWorkbenchService = createDecorator; + readonly onReset: Event; readonly preferPreReleases: boolean; readonly local: IExtension[]; readonly installed: IExtension[]; diff --git a/src/vs/workbench/services/extensionManagement/test/browser/extensionEnablementService.test.ts b/src/vs/workbench/services/extensionManagement/test/browser/extensionEnablementService.test.ts index 0577f060b4d..0f5aacd40a3 100644 --- a/src/vs/workbench/services/extensionManagement/test/browser/extensionEnablementService.test.ts +++ b/src/vs/workbench/services/extensionManagement/test/browser/extensionEnablementService.test.ts @@ -64,6 +64,7 @@ export class TestExtensionEnablementService extends ExtensionEnablementService { onDidInstallExtensions: new Emitter().event, onUninstallExtension: new Emitter().event, onDidUninstallExtension: new Emitter().event, + onDidChangeProfileExtensions: new Emitter().event, }, }, null, null)); const extensionManagementService = instantiationService.createInstance(ExtensionManagementService); From d48f343f8c01ad45831a5f9670d9f511f55c6186 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Mon, 27 Jun 2022 07:51:41 -0700 Subject: [PATCH 043/347] Change view size to change term view by 4 cells Fixes #152381 --- .../contrib/terminal/browser/terminalGroup.ts | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalGroup.ts b/src/vs/workbench/contrib/terminal/browser/terminalGroup.ts index e94818dd002..d311e6feb1c 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalGroup.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalGroup.ts @@ -15,7 +15,17 @@ import { IShellLaunchConfig, ITerminalTabLayoutInfoById } from 'vs/platform/term import { TerminalStatus } from 'vs/workbench/contrib/terminal/browser/terminalStatusList'; import { getPartByLocation } from 'vs/workbench/browser/parts/views/viewsService'; -const SPLIT_PANE_MIN_SIZE = 120; +const enum Constants { + /** + * The minimum size in pixels of a split pane. + */ + SplitPaneMinSize = 120, + /** + * The number of cells the terminal gets added or removed when asked to increase or decrease + * the view size. + */ + ResizePartCellCount = 4 +} class SplitPaneContainer extends Disposable { private _height: number; @@ -91,10 +101,10 @@ class SplitPaneContainer extends Disposable { } // Ensure the size is not reduced beyond the minimum, otherwise weird things can happen - if (sizes[index] + amount < SPLIT_PANE_MIN_SIZE) { - amount = SPLIT_PANE_MIN_SIZE - sizes[index]; - } else if (sizes[indexToChange] - amount < SPLIT_PANE_MIN_SIZE) { - amount = sizes[indexToChange] - SPLIT_PANE_MIN_SIZE; + if (sizes[index] + amount < Constants.SplitPaneMinSize) { + amount = Constants.SplitPaneMinSize - sizes[index]; + } else if (sizes[indexToChange] - amount < Constants.SplitPaneMinSize) { + amount = sizes[indexToChange] - Constants.SplitPaneMinSize; } // Apply the size change @@ -207,7 +217,7 @@ class SplitPaneContainer extends Disposable { } class SplitPane implements IView { - minimumSize: number = SPLIT_PANE_MIN_SIZE; + minimumSize: number = Constants.SplitPaneMinSize; maximumSize: number = Number.MAX_VALUE; orientation: Orientation | undefined; @@ -560,9 +570,9 @@ export class TerminalGroup extends Disposable implements ITerminalGroup { const isHorizontal = (direction === Direction.Left || direction === Direction.Right); const font = this._terminalService.configHelper.getFont(); // TODO: Support letter spacing and line height - const amount = isHorizontal ? font.charWidth : font.charHeight; - if (amount) { - this._splitPaneContainer.resizePane(this._activeInstanceIndex, direction, amount, getPartByLocation(this._terminalLocation)); + const charSize = (isHorizontal ? font.charWidth : font.charHeight); + if (charSize) { + this._splitPaneContainer.resizePane(this._activeInstanceIndex, direction, charSize * Constants.ResizePartCellCount, getPartByLocation(this._terminalLocation)); } } From 2509cd53dd869bac68a845e69cd6773e56a133db Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 27 Jun 2022 17:08:47 +0200 Subject: [PATCH 044/347] implement `tracksEditorViewState` and `computeEditorViewState` (#153315) fixes https://github.com/microsoft/vscode/issues/150804 --- .../mergeEditor/browser/view/mergeEditor.ts | 50 ++++++++++++++++--- 1 file changed, 43 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/mergeEditor.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/mergeEditor.ts index 6c618b81d56..1b31a6532f5 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/mergeEditor.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/mergeEditor.ts @@ -17,7 +17,7 @@ import 'vs/css!./media/mergeEditor'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; import { IEditorOptions as ICodeEditorOptions } from 'vs/editor/common/config/editorOptions'; -import { ScrollType } from 'vs/editor/common/editorCommon'; +import { ICodeEditorViewState, ScrollType } from 'vs/editor/common/editorCommon'; import { ITextResourceConfigurationService } from 'vs/editor/common/services/textResourceConfiguration'; import { localize } from 'vs/nls'; import { createAndFillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; @@ -83,7 +83,7 @@ class MergeEditorLayout { } } -export class MergeEditor extends AbstractTextEditor { +export class MergeEditor extends AbstractTextEditor { static readonly ID = 'mergeEditor'; @@ -282,6 +282,9 @@ export class MergeEditor extends AbstractTextEditor { this.inputResultView.setModel(viewModel, model.result, localize('result', 'Result',), this._labelService.getUriLabel(model.result.uri, { relative: true }), undefined); this._ctxBaseResourceScheme.set(model.base.uri.scheme); + const viewState = this.loadEditorViewState(input, context); + this._applyViewState(viewState); + this._sessionDisposables.add(thenIfNotDisposed(model.onInitialized, () => { const firstConflict = model.modifiedBaseRanges.get().find(r => r.isConflicting); if (!firstConflict) { @@ -439,17 +442,50 @@ export class MergeEditor extends AbstractTextEditor { this._ctxUsesColumnLayout.set(newValue); } - // --- view state (TODO@bpasero revisit with https://github.com/microsoft/vscode/issues/150804) - - protected computeEditorViewState(resource: URI): undefined { - return undefined; + private _applyViewState(state: IMergeEditorViewState | undefined) { + if (!state) { + return; + } + this.inputResultView.editor.restoreViewState(state); + if (state.input1State) { + this.input1View.editor.restoreViewState(state.input1State); + } + if (state.input2State) { + this.input2View.editor.restoreViewState(state.input2State); + } + if (state.focusIndex >= 0) { + [this.input1View.editor, this.input2View.editor, this.inputResultView.editor][state.focusIndex].focus(); + } } + protected computeEditorViewState(resource: URI): IMergeEditorViewState | undefined { + if (isEqual(this.model?.result.uri, resource)) { + // TODO@bpasero Why not check `input#resource` and don't ask me for "forgein" resources? + return undefined; + } + const result = this.inputResultView.editor.saveViewState(); + if (!result) { + return undefined; + } + const input1State = this.input1View.editor.saveViewState() ?? undefined; + const input2State = this.input2View.editor.saveViewState() ?? undefined; + const focusIndex = [this.input1View.editor, this.input2View.editor, this.inputResultView.editor].findIndex(editor => editor.hasWidgetFocus()); + return { ...result, input1State, input2State, focusIndex }; + } + + protected tracksEditorViewState(input: EditorInput): boolean { - return false; + return input instanceof MergeEditorInput; } } +type IMergeEditorViewState = ICodeEditorViewState & { + readonly input1State?: ICodeEditorViewState; + readonly input2State?: ICodeEditorViewState; + readonly focusIndex: number; +}; + + function synchronizeScrolling(scrollingEditor: CodeEditorWidget, targetEditor: CodeEditorWidget, mapping: DocumentMapping | undefined, source: MappingDirection) { if (!mapping) { return; From d1dd57e3c93ce6bf0c051d931cdc3fa1abf6fc15 Mon Sep 17 00:00:00 2001 From: Anthony Stewart <150152+a-stewart@users.noreply.github.com> Date: Mon, 27 Jun 2022 16:37:07 +0100 Subject: [PATCH 045/347] Remove duplicate declarations in terminal (#153280) Co-authored-by: Anthony Stewart --- src/vs/platform/terminal/common/terminal.ts | 5 ----- src/vs/workbench/contrib/terminal/common/terminal.ts | 5 ----- 2 files changed, 10 deletions(-) diff --git a/src/vs/platform/terminal/common/terminal.ts b/src/vs/platform/terminal/common/terminal.ts index fd5f4734492..008d1e468ad 100644 --- a/src/vs/platform/terminal/common/terminal.ts +++ b/src/vs/platform/terminal/common/terminal.ts @@ -181,11 +181,6 @@ export enum TitleEventSource { export type ITerminalsLayoutInfo = IRawTerminalsLayoutInfo; export type ITerminalsLayoutInfoById = IRawTerminalsLayoutInfo; -export interface IRawTerminalInstanceLayoutInfo { - relativeSize: number; - terminal: T; -} - export enum TerminalIpcChannels { /** * Communicates between the renderer process and shared process. diff --git a/src/vs/workbench/contrib/terminal/common/terminal.ts b/src/vs/workbench/contrib/terminal/common/terminal.ts index 791a2673e07..829b45a66d0 100644 --- a/src/vs/workbench/contrib/terminal/common/terminal.ts +++ b/src/vs/workbench/contrib/terminal/common/terminal.ts @@ -457,11 +457,6 @@ export interface IStartExtensionTerminalRequest { callback: (error: ITerminalLaunchError | undefined) => void; } -export interface IDefaultShellAndArgsRequest { - useAutomationShell: boolean; - callback: (shell: string, args: string[] | string | undefined) => void; -} - export const QUICK_LAUNCH_PROFILE_CHOICE = 'workbench.action.terminal.profile.choice'; export const enum TerminalCommandId { From ba343473bc775fa3df69e69272368095876b6951 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 27 Jun 2022 17:55:44 +0200 Subject: [PATCH 046/347] Fix #152997 (#153325) --- .../extensions/browser/extensionsViewlet.ts | 22 +++++++++- .../extensions/browser/extensionsViews.ts | 42 +++++++++++-------- 2 files changed, 46 insertions(+), 18 deletions(-) diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts b/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts index 8de65a5b170..3a96117a194 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts @@ -21,7 +21,7 @@ import { InstallLocalExtensionsInRemoteAction, InstallRemoteExtensionsInLocalAct import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IWorkbenchExtensionEnablementService, IExtensionManagementServerService, IExtensionManagementServer } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { ExtensionsInput } from 'vs/workbench/contrib/extensions/common/extensionsInput'; -import { ExtensionsListView, EnabledExtensionsView, DisabledExtensionsView, RecommendedExtensionsView, WorkspaceRecommendedExtensionsView, BuiltInFeatureExtensionsView, BuiltInThemesExtensionsView, BuiltInProgrammingLanguageExtensionsView, ServerInstalledExtensionsView, DefaultRecommendedExtensionsView, UntrustedWorkspaceUnsupportedExtensionsView, UntrustedWorkspacePartiallySupportedExtensionsView, VirtualWorkspaceUnsupportedExtensionsView, VirtualWorkspacePartiallySupportedExtensionsView, DefaultPopularExtensionsView } from 'vs/workbench/contrib/extensions/browser/extensionsViews'; +import { ExtensionsListView, EnabledExtensionsView, DisabledExtensionsView, RecommendedExtensionsView, WorkspaceRecommendedExtensionsView, BuiltInFeatureExtensionsView, BuiltInThemesExtensionsView, BuiltInProgrammingLanguageExtensionsView, ServerInstalledExtensionsView, DefaultRecommendedExtensionsView, UntrustedWorkspaceUnsupportedExtensionsView, UntrustedWorkspacePartiallySupportedExtensionsView, VirtualWorkspaceUnsupportedExtensionsView, VirtualWorkspacePartiallySupportedExtensionsView, DefaultPopularExtensionsView, DeprecatedExtensionsView } from 'vs/workbench/contrib/extensions/browser/extensionsViews'; import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import Severity from 'vs/base/common/severity'; @@ -70,6 +70,7 @@ const HasInstalledExtensionsContext = new RawContextKey('hasInstalledEx const BuiltInExtensionsContext = new RawContextKey('builtInExtensions', false); const SearchBuiltInExtensionsContext = new RawContextKey('searchBuiltInExtensions', false); const SearchUnsupportedWorkspaceExtensionsContext = new RawContextKey('searchUnsupportedWorkspaceExtensions', false); +const SearchDeprecatedExtensionsContext = new RawContextKey('searchDeprecatedExtensions', false); const RecommendedExtensionsContext = new RawContextKey('recommendedExtensions', false); export class ExtensionsViewletViewsContribution implements IWorkbenchContribution { @@ -104,6 +105,9 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio /* Trust Required extensions views */ viewDescriptors.push(...this.createUnsupportedWorkspaceExtensionsViewDescriptors()); + /* Other Local Filtered extensions views */ + viewDescriptors.push(...this.createOtherLocalFilteredExtensionsViewDescriptors()); + Registry.as(Extensions.ViewsRegistry).registerViews(viewDescriptors, this.container); } @@ -414,6 +418,19 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio return viewDescriptors; } + private createOtherLocalFilteredExtensionsViewDescriptors(): IViewDescriptor[] { + const viewDescriptors: IViewDescriptor[] = []; + + viewDescriptors.push({ + id: 'workbench.views.extensions.deprecatedExtensions', + name: localize('deprecated', "Deprecated"), + ctorDescriptor: new SyncDescriptor(DeprecatedExtensionsView, [{}]), + when: ContextKeyExpr.and(SearchDeprecatedExtensionsContext), + }); + + return viewDescriptors; + } + } export class ExtensionsViewPaneContainer extends ViewPaneContainer implements IExtensionsViewPaneContainer { @@ -429,6 +446,7 @@ export class ExtensionsViewPaneContainer extends ViewPaneContainer implements IE private builtInExtensionsContextKey: IContextKey; private searchBuiltInExtensionsContextKey: IContextKey; private searchWorkspaceUnsupportedExtensionsContextKey: IContextKey; + private searchDeprecatedExtensionsContextKey: IContextKey; private recommendedExtensionsContextKey: IContextKey; private searchDelayer: Delayer; @@ -465,6 +483,7 @@ export class ExtensionsViewPaneContainer extends ViewPaneContainer implements IE this.searchMarketplaceExtensionsContextKey = SearchMarketplaceExtensionsContext.bindTo(contextKeyService); this.searchInstalledExtensionsContextKey = SearchIntalledExtensionsContext.bindTo(contextKeyService); this.searchWorkspaceUnsupportedExtensionsContextKey = SearchUnsupportedWorkspaceExtensionsContext.bindTo(contextKeyService); + this.searchDeprecatedExtensionsContextKey = SearchDeprecatedExtensionsContext.bindTo(contextKeyService); this.searchOutdatedExtensionsContextKey = SearchOutdatedExtensionsContext.bindTo(contextKeyService); this.searchEnabledExtensionsContextKey = SearchEnabledExtensionsContext.bindTo(contextKeyService); this.searchDisabledExtensionsContextKey = SearchDisabledExtensionsContext.bindTo(contextKeyService); @@ -635,6 +654,7 @@ export class ExtensionsViewPaneContainer extends ViewPaneContainer implements IE this.searchDisabledExtensionsContextKey.set(ExtensionsListView.isDisabledExtensionsQuery(value)); this.searchBuiltInExtensionsContextKey.set(ExtensionsListView.isSearchBuiltInExtensionsQuery(value)); this.searchWorkspaceUnsupportedExtensionsContextKey.set(ExtensionsListView.isSearchWorkspaceUnsupportedExtensionsQuery(value)); + this.searchDeprecatedExtensionsContextKey.set(ExtensionsListView.isSearchDeprecatedExtensionsQuery(value)); this.builtInExtensionsContextKey.set(ExtensionsListView.isBuiltInExtensionsQuery(value)); this.recommendedExtensionsContextKey.set(isRecommendedExtensionsQuery); this.searchMarketplaceExtensionsContextKey.set(!!value && !ExtensionsListView.isLocalExtensionsQuery(value) && !isRecommendedExtensionsQuery); diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsViews.ts b/src/vs/workbench/contrib/extensions/browser/extensionsViews.ts index 01dd09f76fa..9e8a0486ee0 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsViews.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsViews.ts @@ -345,7 +345,7 @@ export class ExtensionsListView extends ViewPane { private async queryLocal(query: Query, options: IQueryOptions): Promise { const local = await this.extensionsWorkbenchService.queryLocal(this.options.server); const runningExtensions = await this.extensionService.getExtensions(); - let { extensions, canIncludeInstalledExtensions } = this.filterLocal(local, runningExtensions, query, options); + let { extensions, canIncludeInstalledExtensions } = await this.filterLocal(local, runningExtensions, query, options); const disposables = new DisposableStore(); const onDidChangeModel = disposables.add(new Emitter>()); @@ -358,7 +358,7 @@ export class ExtensionsListView extends ViewPane { ), () => undefined)(async () => { const local = this.options.server ? this.extensionsWorkbenchService.installed.filter(e => e.server === this.options.server) : this.extensionsWorkbenchService.local; const runningExtensions = await this.extensionService.getExtensions(); - const { extensions: newExtensions } = this.filterLocal(local, runningExtensions, query, options); + const { extensions: newExtensions } = await this.filterLocal(local, runningExtensions, query, options); if (!isDisposed) { const mergedExtensions = this.mergeAddedExtensions(extensions, newExtensions); if (mergedExtensions) { @@ -376,7 +376,7 @@ export class ExtensionsListView extends ViewPane { }; } - private filterLocal(local: IExtension[], runningExtensions: IExtensionDescription[], query: Query, options: IQueryOptions): { extensions: IExtension[]; canIncludeInstalledExtensions: boolean } { + private async filterLocal(local: IExtension[], runningExtensions: IExtensionDescription[], query: Query, options: IQueryOptions): Promise<{ extensions: IExtension[]; canIncludeInstalledExtensions: boolean }> { const value = query.value; let extensions: IExtension[] = []; let canIncludeInstalledExtensions = true; @@ -406,6 +406,10 @@ export class ExtensionsListView extends ViewPane { extensions = this.filterWorkspaceUnsupportedExtensions(local, query, options); } + else if (/@deprecated/i.test(query.value)) { + extensions = await this.filterDeprecatedExtensions(local, query, options); + } + return { extensions, canIncludeInstalledExtensions }; } @@ -616,6 +620,13 @@ export class ExtensionsListView extends ViewPane { return this.sortExtensions(local, options); } + private async filterDeprecatedExtensions(local: IExtension[], query: Query, options: IQueryOptions): Promise { + const value = query.value.replace(/@deprecated/g, '').replace(/@sort:(\w+)(-\w*)?/g, '').trim().toLowerCase(); + const extensionsControlManifest = await this.extensionManagementService.getExtensionsControlManifest(); + const deprecatedExtensionIds = Object.keys(extensionsControlManifest.deprecated); + local = local.filter(e => deprecatedExtensionIds.includes(e.identifier.id) && (!value || e.name.toLowerCase().indexOf(value) > -1 || e.displayName.toLowerCase().indexOf(value) > -1)); + return this.sortExtensions(local, options); + } private mergeAddedExtensions(extensions: IExtension[], newExtensions: IExtension[]): IExtension[] | undefined { const oldExtensions = [...extensions]; @@ -653,10 +664,6 @@ export class ExtensionsListView extends ViewPane { return this.queryRecommendations(query, options, token); } - if (/@deprecated/i.test(query.value)) { - return this.getDeprecatedExtensions(options, token); - } - if (/\bcurated:([^\s]+)\b/.test(query.value)) { return this.getCuratedModel(query, options, token); } @@ -752,16 +759,6 @@ export class ExtensionsListView extends ViewPane { return new PagedModel([]); } - private async getDeprecatedExtensions(options: IQueryOptions, token: CancellationToken): Promise> { - const extensionsControlManifest = await this.extensionManagementService.getExtensionsControlManifest(); - const deprecatedExtensionIds = Object.keys(extensionsControlManifest.deprecated); - if (deprecatedExtensionIds.length) { - const pager = await this.extensionsWorkbenchService.queryGallery({ ...options, names: deprecatedExtensionIds, text: undefined }, token); - return this.getPagedModel(pager); - } - return this.getPagedModel([]); - } - private isRecommendationsQuery(query: Query): boolean { return ExtensionsListView.isWorkspaceRecommendedExtensionsQuery(query.value) || ExtensionsListView.isKeymapsRecommendedExtensionsQuery(query.value) @@ -1024,6 +1021,7 @@ export class ExtensionsListView extends ViewPane { || this.isBuiltInExtensionsQuery(query) || this.isSearchBuiltInExtensionsQuery(query) || this.isBuiltInGroupExtensionsQuery(query) + || this.isSearchDeprecatedExtensionsQuery(query) || this.isSearchWorkspaceUnsupportedExtensionsQuery(query); } @@ -1059,6 +1057,10 @@ export class ExtensionsListView extends ViewPane { return /@disabled/i.test(query); } + static isSearchDeprecatedExtensionsQuery(query: string): boolean { + return /@deprecated\s?.*/i.test(query); + } + static isRecommendedExtensionsQuery(query: string): boolean { return /^@recommended$/i.test(query.trim()); } @@ -1194,6 +1196,12 @@ export class VirtualWorkspacePartiallySupportedExtensionsView extends Extensions } } +export class DeprecatedExtensionsView extends ExtensionsListView { + override async show(query: string): Promise> { + return ExtensionsListView.isSearchDeprecatedExtensionsQuery(query) ? super.show(query) : this.showEmptyModel(); + } +} + export class DefaultRecommendedExtensionsView extends ExtensionsListView { private readonly recommendedExtensionsQuery = '@recommended:all'; From 46106c7ac3e4643b574c157b568369ecb0c00cee Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Mon, 27 Jun 2022 18:06:32 +0200 Subject: [PATCH 047/347] Enable commenting before revealing the comment (#153332) --- src/vs/workbench/contrib/comments/browser/commentsView.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/vs/workbench/contrib/comments/browser/commentsView.ts b/src/vs/workbench/contrib/comments/browser/commentsView.ts index d339596f24d..d6883919fa6 100644 --- a/src/vs/workbench/contrib/comments/browser/commentsView.ts +++ b/src/vs/workbench/contrib/comments/browser/commentsView.ts @@ -215,6 +215,10 @@ export class CommentsPanel extends ViewPane { return false; } + if (!this.commentService.isCommentingEnabled) { + this.commentService.enableCommenting(true); + } + const range = element instanceof ResourceWithCommentThreads ? element.commentThreads[0].range : element.range; const activeEditor = this.editorService.activeTextEditorControl; From 2219a2c5adf83f09a34f1fa7ad304e983f3e6fa4 Mon Sep 17 00:00:00 2001 From: Andrea Mah <31675041+andreamah@users.noreply.github.com> Date: Mon, 27 Jun 2022 11:16:53 -0700 Subject: [PATCH 048/347] Quick Access For Loaded Scripts (#152680) * add quick access for loaded scripts --- .../debug/browser/debug.contribution.ts | 3 +- .../contrib/debug/browser/debugCommands.ts | 13 +++ .../debug/common/loadedScriptsPicker.ts | 110 ++++++++++++++++++ 3 files changed, 125 insertions(+), 1 deletion(-) create mode 100644 src/vs/workbench/contrib/debug/common/loadedScriptsPicker.ts diff --git a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts index 3b56252432d..7d10f4b8263 100644 --- a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts +++ b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts @@ -20,7 +20,7 @@ import { } from 'vs/workbench/contrib/debug/common/debug'; import { DebugToolBar } from 'vs/workbench/contrib/debug/browser/debugToolBar'; import { DebugService } from 'vs/workbench/contrib/debug/browser/debugService'; -import { ADD_CONFIGURATION_ID, TOGGLE_INLINE_BREAKPOINT_ID, COPY_STACK_TRACE_ID, RESTART_SESSION_ID, TERMINATE_THREAD_ID, STEP_OVER_ID, STEP_INTO_ID, STEP_OUT_ID, PAUSE_ID, DISCONNECT_ID, STOP_ID, RESTART_FRAME_ID, CONTINUE_ID, FOCUS_REPL_ID, JUMP_TO_CURSOR_ID, RESTART_LABEL, STEP_INTO_LABEL, STEP_OVER_LABEL, STEP_OUT_LABEL, PAUSE_LABEL, DISCONNECT_LABEL, STOP_LABEL, CONTINUE_LABEL, DEBUG_START_LABEL, DEBUG_START_COMMAND_ID, DEBUG_RUN_LABEL, DEBUG_RUN_COMMAND_ID, EDIT_EXPRESSION_COMMAND_ID, REMOVE_EXPRESSION_COMMAND_ID, SELECT_AND_START_ID, SELECT_AND_START_LABEL, SET_EXPRESSION_COMMAND_ID, DISCONNECT_AND_SUSPEND_ID, DISCONNECT_AND_SUSPEND_LABEL, NEXT_DEBUG_CONSOLE_ID, NEXT_DEBUG_CONSOLE_LABEL, PREV_DEBUG_CONSOLE_ID, PREV_DEBUG_CONSOLE_LABEL, SELECT_DEBUG_CONSOLE_ID, SELECT_DEBUG_CONSOLE_LABEL, DEBUG_CONSOLE_QUICK_ACCESS_PREFIX, DEBUG_QUICK_ACCESS_PREFIX, STEP_INTO_TARGET_ID, STEP_INTO_TARGET_LABEL } from 'vs/workbench/contrib/debug/browser/debugCommands'; +import { ADD_CONFIGURATION_ID, TOGGLE_INLINE_BREAKPOINT_ID, COPY_STACK_TRACE_ID, RESTART_SESSION_ID, TERMINATE_THREAD_ID, STEP_OVER_ID, STEP_INTO_ID, STEP_OUT_ID, PAUSE_ID, DISCONNECT_ID, STOP_ID, RESTART_FRAME_ID, CONTINUE_ID, FOCUS_REPL_ID, JUMP_TO_CURSOR_ID, RESTART_LABEL, STEP_INTO_LABEL, STEP_OVER_LABEL, STEP_OUT_LABEL, PAUSE_LABEL, DISCONNECT_LABEL, STOP_LABEL, CONTINUE_LABEL, DEBUG_START_LABEL, DEBUG_START_COMMAND_ID, DEBUG_RUN_LABEL, DEBUG_RUN_COMMAND_ID, EDIT_EXPRESSION_COMMAND_ID, REMOVE_EXPRESSION_COMMAND_ID, SELECT_AND_START_ID, SELECT_AND_START_LABEL, SET_EXPRESSION_COMMAND_ID, DISCONNECT_AND_SUSPEND_ID, DISCONNECT_AND_SUSPEND_LABEL, NEXT_DEBUG_CONSOLE_ID, NEXT_DEBUG_CONSOLE_LABEL, PREV_DEBUG_CONSOLE_ID, PREV_DEBUG_CONSOLE_LABEL, SHOW_LOADED_SCRIPTS_LABEL, SHOW_LOADED_SCRIPTS_ID, DEBUG_QUICK_ACCESS_PREFIX, DEBUG_CONSOLE_QUICK_ACCESS_PREFIX, SELECT_DEBUG_CONSOLE_ID, SELECT_DEBUG_CONSOLE_LABEL, STEP_INTO_TARGET_LABEL, STEP_INTO_TARGET_ID } from 'vs/workbench/contrib/debug/browser/debugCommands'; import { StatusBarColorProvider } from 'vs/workbench/contrib/debug/browser/statusbarColorProvider'; import { IViewsRegistry, Extensions as ViewExtensions, IViewContainersRegistry, ViewContainerLocation, ViewContainer } from 'vs/workbench/common/views'; import { isMacintosh, isWeb } from 'vs/base/common/platform'; @@ -133,6 +133,7 @@ registerDebugCommandPaletteItem(DEBUG_RUN_COMMAND_ID, DEBUG_RUN_LABEL, ContextKe registerDebugCommandPaletteItem(SELECT_AND_START_ID, SELECT_AND_START_LABEL, ContextKeyExpr.and(CONTEXT_DEBUGGERS_AVAILABLE, CONTEXT_DEBUG_STATE.notEqualsTo(getStateLabel(State.Initializing)))); registerDebugCommandPaletteItem(NEXT_DEBUG_CONSOLE_ID, NEXT_DEBUG_CONSOLE_LABEL); registerDebugCommandPaletteItem(PREV_DEBUG_CONSOLE_ID, PREV_DEBUG_CONSOLE_LABEL); +registerDebugCommandPaletteItem(SHOW_LOADED_SCRIPTS_ID, SHOW_LOADED_SCRIPTS_LABEL, CONTEXT_IN_DEBUG_MODE); registerDebugCommandPaletteItem(SELECT_DEBUG_CONSOLE_ID, SELECT_DEBUG_CONSOLE_LABEL); diff --git a/src/vs/workbench/contrib/debug/browser/debugCommands.ts b/src/vs/workbench/contrib/debug/browser/debugCommands.ts index d5524d02f0a..dbd6b0e23fc 100644 --- a/src/vs/workbench/contrib/debug/browser/debugCommands.ts +++ b/src/vs/workbench/contrib/debug/browser/debugCommands.ts @@ -31,6 +31,7 @@ import { deepClone } from 'vs/base/common/objects'; import { isWeb, isWindows } from 'vs/base/common/platform'; import { saveAllBeforeDebugStart } from 'vs/workbench/contrib/debug/common/debugUtils'; import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite'; +import { showLoadedScriptMenu } from 'vs/workbench/contrib/debug/common/loadedScriptsPicker'; export const ADD_CONFIGURATION_ID = 'debug.addConfiguration'; export const TOGGLE_INLINE_BREAKPOINT_ID = 'editor.debug.action.toggleInlineBreakpoint'; @@ -62,6 +63,7 @@ export const SET_EXPRESSION_COMMAND_ID = 'debug.setWatchExpression'; export const REMOVE_EXPRESSION_COMMAND_ID = 'debug.removeWatchExpression'; export const NEXT_DEBUG_CONSOLE_ID = 'workbench.action.debug.nextConsole'; export const PREV_DEBUG_CONSOLE_ID = 'workbench.action.debug.prevConsole'; +export const SHOW_LOADED_SCRIPTS_ID = 'workbench.action.debug.showLoadedScripts'; export const RESTART_LABEL = nls.localize('restartDebug', "Restart"); export const STEP_OVER_LABEL = nls.localize('stepOverDebug', "Step Over"); @@ -80,6 +82,8 @@ export const DEBUG_START_LABEL = nls.localize('startDebug', "Start Debugging"); export const DEBUG_RUN_LABEL = nls.localize('startWithoutDebugging', "Start Without Debugging"); export const NEXT_DEBUG_CONSOLE_LABEL = nls.localize('nextDebugConsole', "Focus Next Debug Console"); export const PREV_DEBUG_CONSOLE_LABEL = nls.localize('prevDebugConsole', "Focus Previous Debug Console"); +export const SHOW_LOADED_SCRIPTS_LABEL = nls.localize('showLoadedScripts', "Show Loaded Scripts"); + export const SELECT_DEBUG_CONSOLE_LABEL = nls.localize('selectDebugConsole', "Select Debug Console"); export const DEBUG_QUICK_ACCESS_PREFIX = 'debug '; @@ -511,6 +515,15 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ } }); +CommandsRegistry.registerCommand({ + id: SHOW_LOADED_SCRIPTS_ID, + handler: async (accessor) => { + + await showLoadedScriptMenu(accessor); + + } +}); + CommandsRegistry.registerCommand({ id: FOCUS_REPL_ID, handler: async (accessor) => { diff --git a/src/vs/workbench/contrib/debug/common/loadedScriptsPicker.ts b/src/vs/workbench/contrib/debug/common/loadedScriptsPicker.ts new file mode 100644 index 00000000000..51218a3475d --- /dev/null +++ b/src/vs/workbench/contrib/debug/common/loadedScriptsPicker.ts @@ -0,0 +1,110 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +import * as nls from 'vs/nls'; +import { matchesFuzzy } from 'vs/base/common/filters'; +import { Source } from 'vs/workbench/contrib/debug/common/debugSource'; +import { IQuickInputService, IQuickPickItem, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput'; +import { IDebugService, IDebugSession } from 'vs/workbench/contrib/debug/common/debug'; +import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { getIconClasses } from 'vs/editor/common/services/getIconClasses'; +import { IModelService } from 'vs/editor/common/services/model'; +import { ILanguageService } from 'vs/editor/common/languages/language'; +import { DisposableStore } from 'vs/base/common/lifecycle'; + +import { dirname } from 'vs/base/common/resources'; +import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { ILabelService } from 'vs/platform/label/common/label'; + + +interface IPickerLoadedScriptItem extends IQuickPickItem { + accept(): void; +} + + +/** + * This function takes a regular quickpick and makes one for loaded scripts that has persistent headers + * e.g. when some picks are filtered out, the ones that are visible still have its header. + */ +export async function showLoadedScriptMenu(accessor: ServicesAccessor) { + const quickInputService = accessor.get(IQuickInputService); + const debugService = accessor.get(IDebugService); + const editorService = accessor.get(IEditorService); + const sessions = debugService.getModel().getSessions(false); + const modelService = accessor.get(IModelService); + const languageService = accessor.get(ILanguageService); + const labelService = accessor.get(ILabelService); + + const localDisposableStore = new DisposableStore(); + const quickPick = quickInputService.createQuickPick(); + localDisposableStore.add(quickPick); + quickPick.matchOnLabel = quickPick.matchOnDescription = quickPick.matchOnDetail = quickPick.sortByLabel = false; + quickPick.placeholder = nls.localize('moveFocusedView.selectView', "Search loaded scripts by name"); + quickPick.items = await _getPicks(quickPick.value, sessions, editorService, modelService, languageService, labelService); + + localDisposableStore.add(quickPick.onDidChangeValue(async () => { + quickPick.items = await _getPicks(quickPick.value, sessions, editorService, modelService, languageService, labelService); + })); + localDisposableStore.add(quickPick.onDidAccept(() => { + const selectedItem = quickPick.selectedItems[0]; + selectedItem.accept(); + quickPick.hide(); + localDisposableStore.dispose(); + })); + quickPick.show(); +} + +async function _getPicksFromSession(session: IDebugSession, filter: string, editorService: IEditorService, modelService: IModelService, languageService: ILanguageService, labelService: ILabelService): Promise> { + const items: Array = []; + items.push({ type: 'separator', label: session.name }); + const sources = await session.getLoadedSources(); + + sources.forEach((element: Source) => { + const pick = _createPick(element, filter, editorService, modelService, languageService, labelService); + if (pick) { + items.push(pick); + } + + }); + return items; +} +async function _getPicks(filter: string, sessions: IDebugSession[], editorService: IEditorService, modelService: IModelService, languageService: ILanguageService, labelService: ILabelService): Promise> { + const loadedScriptPicks: Array = []; + + + const picks = await Promise.all( + sessions.map((session) => _getPicksFromSession(session, filter, editorService, modelService, languageService, labelService)) + ); + + for (const row of picks) { + for (const elem of row) { + loadedScriptPicks.push(elem); + } + } + return loadedScriptPicks; +} + +function _createPick(source: Source, filter: string, editorService: IEditorService, modelService: IModelService, languageService: ILanguageService, labelService: ILabelService): IPickerLoadedScriptItem | undefined { + + const label = labelService.getUriBasenameLabel(source.uri); + const desc = labelService.getUriLabel(dirname(source.uri)); + + // manually filter so that headers don't get filtered out + const labelHighlights = matchesFuzzy(filter, label, true); + const descHighlights = matchesFuzzy(filter, desc, true); + if (labelHighlights || descHighlights) { + return { + label, + description: desc === '.' ? undefined : desc, + highlights: { label: labelHighlights ?? undefined, description: descHighlights ?? undefined }, + iconClasses: getIconClasses(modelService, languageService, source.uri), + accept: () => { + if (source.available) { + source.openInEditor(editorService, { startLineNumber: 0, startColumn: 0, endLineNumber: 0, endColumn: 0 }); + } + } + }; + } + return undefined; +} From b247d94c3c2595a0cbd155e89630148b35e48e02 Mon Sep 17 00:00:00 2001 From: David Dossett Date: Mon, 27 Jun 2022 11:21:07 -0700 Subject: [PATCH 049/347] Fix #150170 (#153348) --- src/vs/base/browser/ui/menu/menubar.css | 1 - 1 file changed, 1 deletion(-) diff --git a/src/vs/base/browser/ui/menu/menubar.css b/src/vs/base/browser/ui/menu/menubar.css index 80ef6a39a57..64e309bf5dc 100644 --- a/src/vs/base/browser/ui/menu/menubar.css +++ b/src/vs/base/browser/ui/menu/menubar.css @@ -27,7 +27,6 @@ zoom: 1; white-space: nowrap; outline: 0 !important; - align-self: center; } .monaco-workbench .menubar:not(.compact) > .menubar-menu-button:focus .menubar-menu-title { From 7defe640cb1830cf149dc3373e0b3e2c9161f453 Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Mon, 27 Jun 2022 10:51:59 -0800 Subject: [PATCH 050/347] show more link results (#153263) --- .../browser/links/terminalLinkManager.ts | 19 +++++++++++++---- .../browser/links/terminalLinkQuickpick.ts | 21 +++++++++++++++---- .../terminal/browser/terminalInstance.ts | 11 ++++++---- 3 files changed, 39 insertions(+), 12 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/links/terminalLinkManager.ts b/src/vs/workbench/contrib/terminal/browser/links/terminalLinkManager.ts index 42b01b307bf..28d0c22794f 100644 --- a/src/vs/workbench/contrib/terminal/browser/links/terminalLinkManager.ts +++ b/src/vs/workbench/contrib/terminal/browser/links/terminalLinkManager.ts @@ -57,6 +57,8 @@ export class TerminalLinkManager extends DisposableStore { // both local and remote terminals are present private readonly _resolvedLinkCache = new LinkCache(); + private _lastTopLine: number | undefined; + constructor( private readonly _xterm: Terminal, private readonly _processManager: ITerminalProcessManager, @@ -141,12 +143,20 @@ export class TerminalLinkManager extends DisposableStore { return links[0]; } - async getLinks(): Promise { + async getLinks(extended?: boolean): Promise { const wordResults: ILink[] = []; const webResults: ILink[] = []; const fileResults: ILink[] = []; - - for (let i = this._xterm.buffer.active.length - 1; i >= this._xterm.buffer.active.viewportY; i--) { + let noMoreResults: boolean = false; + let topLine = !extended ? this._xterm.buffer.active.viewportY - Math.min(this._xterm.rows, 50) : this._lastTopLine! - 1000; + if (topLine < 0 || topLine - Math.min(this._xterm.rows, 50) < 0) { + noMoreResults = true; + } + if (topLine < 0) { + topLine = 0; + } + this._lastTopLine = topLine; + for (let i = this._xterm.buffer.active.length - 1; i >= topLine; i--) { const links = await this._getLinksForLine(i); if (links) { const { wordLinks, webLinks, fileLinks } = links; @@ -161,7 +171,7 @@ export class TerminalLinkManager extends DisposableStore { } } } - return { webLinks: webResults, fileLinks: fileResults, wordLinks: wordResults }; + return { webLinks: webResults, fileLinks: fileResults, wordLinks: wordResults, noMoreResults }; } private async _getLinksForLine(y: number): Promise { @@ -469,6 +479,7 @@ export interface IDetectedLinks { wordLinks?: ILink[]; webLinks?: ILink[]; fileLinks?: ILink[]; + noMoreResults?: boolean; } const enum LinkCacheConstants { diff --git a/src/vs/workbench/contrib/terminal/browser/links/terminalLinkQuickpick.ts b/src/vs/workbench/contrib/terminal/browser/links/terminalLinkQuickpick.ts index 1a2b18727b5..3a44a394e62 100644 --- a/src/vs/workbench/contrib/terminal/browser/links/terminalLinkQuickpick.ts +++ b/src/vs/workbench/contrib/terminal/browser/links/terminalLinkQuickpick.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { EventType } from 'vs/base/browser/dom'; +import { Emitter } from 'vs/base/common/event'; import { localize } from 'vs/nls'; import { IQuickInputService, IQuickPickItem, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput'; import { IDetectedLinks } from 'vs/workbench/contrib/terminal/browser/links/terminalLinkManager'; @@ -11,6 +12,9 @@ import { TerminalLinkQuickPickEvent } from 'vs/workbench/contrib/terminal/browse import { ILink } from 'xterm'; export class TerminalLinkQuickpick { + + private readonly _onDidRequestMoreLinks = new Emitter(); + readonly onDidRequestMoreLinks = this._onDidRequestMoreLinks.event; constructor( @IQuickInputService private readonly _quickInputService: IQuickInputService ) { } @@ -21,7 +25,8 @@ export class TerminalLinkQuickpick { const webPicks = links.webLinks ? await this._generatePicks(links.webLinks) : undefined; const options = { placeHolder: localize('terminal.integrated.openDetectedLink', "Select the link to open"), - canPickMany: false + canPickMany: false, + }; const picks: LinkQuickPickItem[] = []; if (webPicks) { @@ -36,13 +41,21 @@ export class TerminalLinkQuickpick { picks.push({ type: 'separator', label: localize('terminal.integrated.searchLinks', "Workspace Search") }); picks.push(...wordPicks); } - + picks.push({ type: 'separator' }); + if (!links.noMoreResults) { + const showMoreItem = { label: localize('terminal.integrated.showMoreLinks', "Show more links") }; + picks.push(showMoreItem); + } const pick = await this._quickInputService.pick(picks, options); if (!pick) { return; } const event = new TerminalLinkQuickPickEvent(EventType.CLICK); - pick.link.activate(event, pick.label); + if ('link' in pick) { + pick.link.activate(event, pick.label); + } else { + this._onDidRequestMoreLinks.fire(); + } return; } @@ -67,4 +80,4 @@ export interface ITerminalLinkQuickPickItem extends IQuickPickItem { link: ILink; } -type LinkQuickPickItem = ITerminalLinkQuickPickItem | IQuickPickSeparator; +type LinkQuickPickItem = ITerminalLinkQuickPickItem | IQuickPickSeparator | IQuickPickItem; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 4401c00feeb..dd3b0ea9a66 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -778,25 +778,28 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { } } - async showLinkQuickpick(): Promise { + async showLinkQuickpick(extended?: boolean): Promise { if (!this._terminalLinkQuickpick) { this._terminalLinkQuickpick = this._instantiationService.createInstance(TerminalLinkQuickpick); + this._terminalLinkQuickpick.onDidRequestMoreLinks(() => { + this.showLinkQuickpick(true); + }); } - const links = await this._getLinks(); + const links = await this._getLinks(extended); if (!links) { return; } return await this._terminalLinkQuickpick.show(links); } - private async _getLinks(): Promise { + private async _getLinks(extended?: boolean): Promise { if (!this.areLinksReady || !this._linkManager) { throw new Error('terminal links are not ready, cannot generate link quick pick'); } if (!this.xterm) { throw new Error('no xterm'); } - return this._linkManager.getLinks(); + return this._linkManager.getLinks(extended); } async openRecentLink(type: 'localFile' | 'url'): Promise { From 8721752a3c4e233584163f8b0772770f697bc3a7 Mon Sep 17 00:00:00 2001 From: Raymond Zhao <7199958+rzhao271@users.noreply.github.com> Date: Mon, 27 Jun 2022 11:55:48 -0700 Subject: [PATCH 051/347] Add classlist check (#153346) Fixes #148427 --- .../workbench/contrib/preferences/browser/settingsEditor2.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts b/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts index 3412eac14fc..83d1addd26d 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts @@ -907,7 +907,8 @@ export class SettingsEditor2 extends EditorPane { })); this._register(this.settingsTree.onDidFocus(() => { - if (document.activeElement?.classList.contains('monaco-list')) { + const classList = document.activeElement?.classList; + if (classList && classList.contains('monaco-list') && classList.contains('settings-editor-tree')) { this._currentFocusContext = SettingsFocusContext.SettingTree; this.settingRowFocused.set(true); } From 9051021473067eb89fa5193b90b98a82ec067ee0 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Mon, 27 Jun 2022 12:01:41 -0700 Subject: [PATCH 052/347] Clarify label on source action (#153356) Clairify label on source action For https://github.com/microsoft/vscode-eslint/issues/1428 --- .../typescript-language-features/src/languageFeatures/fixAll.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/typescript-language-features/src/languageFeatures/fixAll.ts b/extensions/typescript-language-features/src/languageFeatures/fixAll.ts index ad8630f70e7..9119b5b66ba 100644 --- a/extensions/typescript-language-features/src/languageFeatures/fixAll.ts +++ b/extensions/typescript-language-features/src/languageFeatures/fixAll.ts @@ -133,7 +133,7 @@ class SourceFixAll extends SourceAction { static readonly kind = vscode.CodeActionKind.SourceFixAll.append('ts'); constructor() { - super(localize('autoFix.label', 'Fix All'), SourceFixAll.kind); + super(localize('autoFix.label', 'Fix all fixable JS/TS issues'), SourceFixAll.kind); } async build(client: ITypeScriptServiceClient, file: string, diagnostics: readonly vscode.Diagnostic[], token: vscode.CancellationToken): Promise { From b7ee22af27adc2ddbac0465edd23cf0612defb5b Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Mon, 27 Jun 2022 11:38:34 -0800 Subject: [PATCH 053/347] trim right when copying output (#153359) fix #153242 --- .../terminal/common/capabilities/commandDetectionCapability.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts index b7b62ad5439..95aa53d305c 100644 --- a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts +++ b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts @@ -602,7 +602,7 @@ function getOutputForCommand(executedMarker: IMarker | undefined, endMarker: IMa } let output = ''; for (let i = startLine; i < endLine; i++) { - output += buffer.getLine(i)?.translateToString() + '\n'; + output += buffer.getLine(i)?.translateToString(true) + '\n'; } return output === '' ? undefined : output; } From b3fff289c3857a72ae621f3f88779e81de2947cf Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Mon, 27 Jun 2022 11:38:46 -0800 Subject: [PATCH 054/347] update xterm.js (#153354) --- package.json | 10 +++++----- remote/package.json | 10 +++++----- remote/web/package.json | 6 +++--- remote/web/yarn.lock | 24 ++++++++++++------------ remote/yarn.lock | 40 ++++++++++++++++++++-------------------- yarn.lock | 40 ++++++++++++++++++++-------------------- 6 files changed, 65 insertions(+), 65 deletions(-) diff --git a/package.json b/package.json index ebb9a26db70..58d436d3da8 100644 --- a/package.json +++ b/package.json @@ -87,12 +87,12 @@ "vscode-proxy-agent": "^0.12.0", "vscode-regexpp": "^3.1.0", "vscode-textmate": "7.0.1", - "xterm": "4.19.0-beta.60", - "xterm-addon-search": "0.9.0-beta.39", - "xterm-addon-serialize": "0.7.0-beta.13", + "xterm": "4.19.0-beta.67", + "xterm-addon-search": "0.9.0-beta.41", + "xterm-addon-serialize": "0.7.0-beta.15", "xterm-addon-unicode11": "0.4.0-beta.3", - "xterm-addon-webgl": "0.12.0-beta.41", - "xterm-headless": "4.19.0-beta.60", + "xterm-addon-webgl": "0.12.0-beta.43", + "xterm-headless": "4.19.0-beta.67", "yauzl": "^2.9.2", "yazl": "^2.4.3" }, diff --git a/remote/package.json b/remote/package.json index e6fdc7a871b..0f9cc3386d1 100644 --- a/remote/package.json +++ b/remote/package.json @@ -26,12 +26,12 @@ "vscode-proxy-agent": "^0.12.0", "vscode-regexpp": "^3.1.0", "vscode-textmate": "7.0.1", - "xterm": "4.19.0-beta.60", - "xterm-addon-search": "0.9.0-beta.39", - "xterm-addon-serialize": "0.7.0-beta.13", + "xterm": "4.19.0-beta.67", + "xterm-addon-search": "0.9.0-beta.41", + "xterm-addon-serialize": "0.7.0-beta.15", "xterm-addon-unicode11": "0.4.0-beta.3", - "xterm-addon-webgl": "0.12.0-beta.41", - "xterm-headless": "4.19.0-beta.60", + "xterm-addon-webgl": "0.12.0-beta.43", + "xterm-headless": "4.19.0-beta.67", "yauzl": "^2.9.2", "yazl": "^2.4.3" }, diff --git a/remote/web/package.json b/remote/web/package.json index fcc462b5733..cb364eb1e14 100644 --- a/remote/web/package.json +++ b/remote/web/package.json @@ -12,9 +12,9 @@ "tas-client-umd": "0.1.6", "vscode-oniguruma": "1.6.1", "vscode-textmate": "7.0.1", - "xterm": "4.19.0-beta.60", - "xterm-addon-search": "0.9.0-beta.39", + "xterm": "4.19.0-beta.67", + "xterm-addon-search": "0.9.0-beta.41", "xterm-addon-unicode11": "0.4.0-beta.3", - "xterm-addon-webgl": "0.12.0-beta.41" + "xterm-addon-webgl": "0.12.0-beta.43" } } diff --git a/remote/web/yarn.lock b/remote/web/yarn.lock index 643265cb38c..7e38ab06f98 100644 --- a/remote/web/yarn.lock +++ b/remote/web/yarn.lock @@ -131,22 +131,22 @@ vscode-textmate@7.0.1: resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-7.0.1.tgz#8118a32b02735dccd14f893b495fa5389ad7de79" integrity sha512-zQ5U/nuXAAMsh691FtV0wPz89nSkHbs+IQV8FDk+wew9BlSDhf4UmWGlWJfTR2Ti6xZv87Tj5fENzKf6Qk7aLw== -xterm-addon-search@0.9.0-beta.39: - version "0.9.0-beta.39" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.9.0-beta.39.tgz#e8376e1485ee7d763c07d1a8f1354114f65b3e3e" - integrity sha512-h45wkecgfqXXoAUqgNytAfSd6g0xNT6rZy/enVaEU0aes7QoL9pxHUKkCry8PP6hs03Slk0VxQ4AGsbSZGvK/w== +xterm-addon-search@0.9.0-beta.41: + version "0.9.0-beta.41" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.9.0-beta.41.tgz#0992da36fe01ff6d71449265a9dabeef7f9d0a3f" + integrity sha512-b1vuWR5JZ8QIiObbKkwSzpzf4x0B9hdzGCHJG+PXWT/xbxk65DOe/X9rgrRyOnCWe5ylQGG4DIHTiREigTp0lg== xterm-addon-unicode11@0.4.0-beta.3: version "0.4.0-beta.3" resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.4.0-beta.3.tgz#f350184155fafd5ad0d6fbf31d13e6ca7dea1efa" integrity sha512-FryZAVwbUjKTmwXnm1trch/2XO60F5JsDvOkZhzobV1hm10sFLVuZpFyHXiUx7TFeeFsvNP+S77LAtWoeT5z+Q== -xterm-addon-webgl@0.12.0-beta.41: - version "0.12.0-beta.41" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.12.0-beta.41.tgz#17dbca975b6e9b34526ebc57f4de59ee295da1b6" - integrity sha512-wvQxC5diMYEJEMaILfz+4CWB2GgtzjzNQRNDnK7R7Y9wDI+P4idDlQKgyH0nA93sl9R4zgqlBVha//wuq4vfZg== +xterm-addon-webgl@0.12.0-beta.43: + version "0.12.0-beta.43" + resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.12.0-beta.43.tgz#916ed4e390371403aab0d277097cd8a61be436e8" + integrity sha512-hGXfwT6TOmp0tBDiS/iF8s0SLHLd3shJ5zQyS4HNtq99B5cEhHhwaUAZAfjLt5rnUt0kvqR9YWtGsDux5dWVLA== -xterm@4.19.0-beta.60: - version "4.19.0-beta.60" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.19.0-beta.60.tgz#de89d93153ae3ec17b53f3e5d03b8ea859126081" - integrity sha512-YQjvp4xtSAyNm9+gF4OA5+QzkSWdKMCy4WABETpe7CsrEGx+mJVoXCZ9wgopmvwRXz7DeJvKM5dWz1HPjVLDtA== +xterm@4.19.0-beta.67: + version "4.19.0-beta.67" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.19.0-beta.67.tgz#9a7d79be64469c91bb693b9f5a50b5a22e921cd3" + integrity sha512-4bYTnT6g91N5QId1qPaiSvkpsxMQYpuPdPJItvBZFOcQLTuFSX85x5NeFuDvhNqi33eMFPimyGhzH/JvAV1v/Q== diff --git a/remote/yarn.lock b/remote/yarn.lock index 6ee84100308..793a5a42ea6 100644 --- a/remote/yarn.lock +++ b/remote/yarn.lock @@ -932,35 +932,35 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= -xterm-addon-search@0.9.0-beta.39: - version "0.9.0-beta.39" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.9.0-beta.39.tgz#e8376e1485ee7d763c07d1a8f1354114f65b3e3e" - integrity sha512-h45wkecgfqXXoAUqgNytAfSd6g0xNT6rZy/enVaEU0aes7QoL9pxHUKkCry8PP6hs03Slk0VxQ4AGsbSZGvK/w== +xterm-addon-search@0.9.0-beta.41: + version "0.9.0-beta.41" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.9.0-beta.41.tgz#0992da36fe01ff6d71449265a9dabeef7f9d0a3f" + integrity sha512-b1vuWR5JZ8QIiObbKkwSzpzf4x0B9hdzGCHJG+PXWT/xbxk65DOe/X9rgrRyOnCWe5ylQGG4DIHTiREigTp0lg== -xterm-addon-serialize@0.7.0-beta.13: - version "0.7.0-beta.13" - resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.7.0-beta.13.tgz#5c859c8657cab7f28405aab1a0715daf54bc7714" - integrity sha512-TYFlm/gds0pOmpzXw7ZWx8Cy48lMaOZZqZgfm5pWU37HPvzfKxXSVdYL1biWpRCH2zCH+3cWmOma8W1pBRr+Eg== +xterm-addon-serialize@0.7.0-beta.15: + version "0.7.0-beta.15" + resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.7.0-beta.15.tgz#0f7d5f9b423802ac67c2a891d74de530a4fe6a65" + integrity sha512-gO/dxqGgOAuj7DN2ETTeCHyalkb655XogZh5408CmH5D6mjI1lxqVLGUdiFeBVU/OHfWZT2PZ95k06VXqLU5kA== xterm-addon-unicode11@0.4.0-beta.3: version "0.4.0-beta.3" resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.4.0-beta.3.tgz#f350184155fafd5ad0d6fbf31d13e6ca7dea1efa" integrity sha512-FryZAVwbUjKTmwXnm1trch/2XO60F5JsDvOkZhzobV1hm10sFLVuZpFyHXiUx7TFeeFsvNP+S77LAtWoeT5z+Q== -xterm-addon-webgl@0.12.0-beta.41: - version "0.12.0-beta.41" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.12.0-beta.41.tgz#17dbca975b6e9b34526ebc57f4de59ee295da1b6" - integrity sha512-wvQxC5diMYEJEMaILfz+4CWB2GgtzjzNQRNDnK7R7Y9wDI+P4idDlQKgyH0nA93sl9R4zgqlBVha//wuq4vfZg== +xterm-addon-webgl@0.12.0-beta.43: + version "0.12.0-beta.43" + resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.12.0-beta.43.tgz#916ed4e390371403aab0d277097cd8a61be436e8" + integrity sha512-hGXfwT6TOmp0tBDiS/iF8s0SLHLd3shJ5zQyS4HNtq99B5cEhHhwaUAZAfjLt5rnUt0kvqR9YWtGsDux5dWVLA== -xterm-headless@4.19.0-beta.60: - version "4.19.0-beta.60" - resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-4.19.0-beta.60.tgz#ccd09a7c69ba487d3fd87d6a8d159f1a6a10e9b2" - integrity sha512-mJ24BRnEDCASJDTGFZysZxiXkCmed3eMFiWCPvIF48LVrqxt1cImoVKBlxqkdgUkHKjfF2c92S1TTBL5aT1I0w== +xterm-headless@4.19.0-beta.67: + version "4.19.0-beta.67" + resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-4.19.0-beta.67.tgz#fe44a243974bf307c9a0694114ab45289734c7f9" + integrity sha512-rpxUsE/te2LN4B/erI108uaAhuLTUsnRl9zIZgcqMqZGFRqDUTtyVM05jIA/8A32g06wFd3WioTkeKc6ow+sLg== -xterm@4.19.0-beta.60: - version "4.19.0-beta.60" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.19.0-beta.60.tgz#de89d93153ae3ec17b53f3e5d03b8ea859126081" - integrity sha512-YQjvp4xtSAyNm9+gF4OA5+QzkSWdKMCy4WABETpe7CsrEGx+mJVoXCZ9wgopmvwRXz7DeJvKM5dWz1HPjVLDtA== +xterm@4.19.0-beta.67: + version "4.19.0-beta.67" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.19.0-beta.67.tgz#9a7d79be64469c91bb693b9f5a50b5a22e921cd3" + integrity sha512-4bYTnT6g91N5QId1qPaiSvkpsxMQYpuPdPJItvBZFOcQLTuFSX85x5NeFuDvhNqi33eMFPimyGhzH/JvAV1v/Q== yallist@^4.0.0: version "4.0.0" diff --git a/yarn.lock b/yarn.lock index e1813ce55da..2fac594f909 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12256,35 +12256,35 @@ xtend@~2.1.1: dependencies: object-keys "~0.4.0" -xterm-addon-search@0.9.0-beta.39: - version "0.9.0-beta.39" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.9.0-beta.39.tgz#e8376e1485ee7d763c07d1a8f1354114f65b3e3e" - integrity sha512-h45wkecgfqXXoAUqgNytAfSd6g0xNT6rZy/enVaEU0aes7QoL9pxHUKkCry8PP6hs03Slk0VxQ4AGsbSZGvK/w== +xterm-addon-search@0.9.0-beta.41: + version "0.9.0-beta.41" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.9.0-beta.41.tgz#0992da36fe01ff6d71449265a9dabeef7f9d0a3f" + integrity sha512-b1vuWR5JZ8QIiObbKkwSzpzf4x0B9hdzGCHJG+PXWT/xbxk65DOe/X9rgrRyOnCWe5ylQGG4DIHTiREigTp0lg== -xterm-addon-serialize@0.7.0-beta.13: - version "0.7.0-beta.13" - resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.7.0-beta.13.tgz#5c859c8657cab7f28405aab1a0715daf54bc7714" - integrity sha512-TYFlm/gds0pOmpzXw7ZWx8Cy48lMaOZZqZgfm5pWU37HPvzfKxXSVdYL1biWpRCH2zCH+3cWmOma8W1pBRr+Eg== +xterm-addon-serialize@0.7.0-beta.15: + version "0.7.0-beta.15" + resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.7.0-beta.15.tgz#0f7d5f9b423802ac67c2a891d74de530a4fe6a65" + integrity sha512-gO/dxqGgOAuj7DN2ETTeCHyalkb655XogZh5408CmH5D6mjI1lxqVLGUdiFeBVU/OHfWZT2PZ95k06VXqLU5kA== xterm-addon-unicode11@0.4.0-beta.3: version "0.4.0-beta.3" resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.4.0-beta.3.tgz#f350184155fafd5ad0d6fbf31d13e6ca7dea1efa" integrity sha512-FryZAVwbUjKTmwXnm1trch/2XO60F5JsDvOkZhzobV1hm10sFLVuZpFyHXiUx7TFeeFsvNP+S77LAtWoeT5z+Q== -xterm-addon-webgl@0.12.0-beta.41: - version "0.12.0-beta.41" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.12.0-beta.41.tgz#17dbca975b6e9b34526ebc57f4de59ee295da1b6" - integrity sha512-wvQxC5diMYEJEMaILfz+4CWB2GgtzjzNQRNDnK7R7Y9wDI+P4idDlQKgyH0nA93sl9R4zgqlBVha//wuq4vfZg== +xterm-addon-webgl@0.12.0-beta.43: + version "0.12.0-beta.43" + resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.12.0-beta.43.tgz#916ed4e390371403aab0d277097cd8a61be436e8" + integrity sha512-hGXfwT6TOmp0tBDiS/iF8s0SLHLd3shJ5zQyS4HNtq99B5cEhHhwaUAZAfjLt5rnUt0kvqR9YWtGsDux5dWVLA== -xterm-headless@4.19.0-beta.60: - version "4.19.0-beta.60" - resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-4.19.0-beta.60.tgz#ccd09a7c69ba487d3fd87d6a8d159f1a6a10e9b2" - integrity sha512-mJ24BRnEDCASJDTGFZysZxiXkCmed3eMFiWCPvIF48LVrqxt1cImoVKBlxqkdgUkHKjfF2c92S1TTBL5aT1I0w== +xterm-headless@4.19.0-beta.67: + version "4.19.0-beta.67" + resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-4.19.0-beta.67.tgz#fe44a243974bf307c9a0694114ab45289734c7f9" + integrity sha512-rpxUsE/te2LN4B/erI108uaAhuLTUsnRl9zIZgcqMqZGFRqDUTtyVM05jIA/8A32g06wFd3WioTkeKc6ow+sLg== -xterm@4.19.0-beta.60: - version "4.19.0-beta.60" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.19.0-beta.60.tgz#de89d93153ae3ec17b53f3e5d03b8ea859126081" - integrity sha512-YQjvp4xtSAyNm9+gF4OA5+QzkSWdKMCy4WABETpe7CsrEGx+mJVoXCZ9wgopmvwRXz7DeJvKM5dWz1HPjVLDtA== +xterm@4.19.0-beta.67: + version "4.19.0-beta.67" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.19.0-beta.67.tgz#9a7d79be64469c91bb693b9f5a50b5a22e921cd3" + integrity sha512-4bYTnT6g91N5QId1qPaiSvkpsxMQYpuPdPJItvBZFOcQLTuFSX85x5NeFuDvhNqi33eMFPimyGhzH/JvAV1v/Q== y18n@^3.2.1: version "3.2.2" From 89864bb8dd9298c705e93a490e51ca3aa74f47ab Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Mon, 27 Jun 2022 11:38:59 -0800 Subject: [PATCH 055/347] drop status for background tasks when process exits (#153337) fix #152141 --- .../tasks/browser/taskTerminalStatus.ts | 8 +++++++- .../test/browser/taskTerminalStatus.test.ts | 20 ++++++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/tasks/browser/taskTerminalStatus.ts b/src/vs/workbench/contrib/tasks/browser/taskTerminalStatus.ts index a2d5cc1d2a7..e74c85e3f74 100644 --- a/src/vs/workbench/contrib/tasks/browser/taskTerminalStatus.ts +++ b/src/vs/workbench/contrib/tasks/browser/taskTerminalStatus.ts @@ -85,7 +85,13 @@ export class TaskTerminalStatus extends Disposable { terminalData.taskRunEnded = true; terminalData.terminal.statusList.remove(terminalData.status); if ((event.exitCode === 0) && (terminalData.problemMatcher.numberOfMatches === 0)) { - terminalData.terminal.statusList.add(SUCCEEDED_TASK_STATUS); + if (terminalData.task.configurationProperties.isBackground) { + for (const status of terminalData.terminal.statusList.statuses) { + terminalData.terminal.statusList.remove(status); + } + } else { + terminalData.terminal.statusList.add(SUCCEEDED_TASK_STATUS); + } } else if (event.exitCode || terminalData.problemMatcher.maxMarkerSeverity === MarkerSeverity.Error) { terminalData.terminal.statusList.add(FAILED_TASK_STATUS); } else if (terminalData.problemMatcher.maxMarkerSeverity === MarkerSeverity.Warning) { diff --git a/src/vs/workbench/contrib/tasks/test/browser/taskTerminalStatus.test.ts b/src/vs/workbench/contrib/tasks/test/browser/taskTerminalStatus.test.ts index cbbf65c9c47..45b60a78489 100644 --- a/src/vs/workbench/contrib/tasks/test/browser/taskTerminalStatus.test.ts +++ b/src/vs/workbench/contrib/tasks/test/browser/taskTerminalStatus.test.ts @@ -70,7 +70,7 @@ suite('Task Terminal Status', () => { taskService.triggerStateChange({ kind: TaskEventKind.End, exitCode: 2 }); await poll(async () => Promise.resolve(), () => testTerminal?.statusList.primary?.id === FAILED_TASK_STATUS.id, 'terminal status should be updated'); }); - test('Should add active status when a non-background task is run for a second time in the same terminal', async () => { + test('Should add active status when a non-background task is run for a second time in the same terminal', () => { taskTerminalStatus.addTerminal(testTask, testTerminal, problemCollector); taskService.triggerStateChange({ kind: TaskEventKind.ProcessStarted }); assertStatus(testTerminal.statusList, ACTIVE_TASK_STATUS); @@ -81,6 +81,24 @@ suite('Task Terminal Status', () => { taskService.triggerStateChange({ kind: TaskEventKind.Inactive }); assertStatus(testTerminal.statusList, SUCCEEDED_TASK_STATUS); }); + test('Should drop status when a background task exits', async () => { + taskTerminalStatus.addTerminal(testTask, testTerminal, problemCollector); + taskService.triggerStateChange({ kind: TaskEventKind.ProcessStarted, runType: TaskRunType.Background }); + assertStatus(testTerminal.statusList, ACTIVE_TASK_STATUS); + taskService.triggerStateChange({ kind: TaskEventKind.Inactive }); + assertStatus(testTerminal.statusList, SUCCEEDED_TASK_STATUS); + taskService.triggerStateChange({ kind: TaskEventKind.ProcessEnded, exitCode: 0 }); + await poll(async () => Promise.resolve(), () => testTerminal?.statusList.statuses?.includes(SUCCEEDED_TASK_STATUS) === false, 'terminal should have dropped status'); + }); + test('Should add succeeded status when a non-background task exits', () => { + taskTerminalStatus.addTerminal(testTask, testTerminal, problemCollector); + taskService.triggerStateChange({ kind: TaskEventKind.ProcessStarted, runType: TaskRunType.SingleRun }); + assertStatus(testTerminal.statusList, ACTIVE_TASK_STATUS); + taskService.triggerStateChange({ kind: TaskEventKind.Inactive }); + assertStatus(testTerminal.statusList, SUCCEEDED_TASK_STATUS); + taskService.triggerStateChange({ kind: TaskEventKind.ProcessEnded, exitCode: 0 }); + assertStatus(testTerminal.statusList, SUCCEEDED_TASK_STATUS); + }); }); function assertStatus(actual: ITerminalStatusList, expected: ITerminalStatus): void { From 57749636a42cacd26934c279cd360fb904a1675f Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Mon, 27 Jun 2022 11:39:14 -0800 Subject: [PATCH 056/347] update simple find widget to use modified search addon return result (#153264) * find count set to 0 not less than 0 * update search according to new xterm return result --- .../contrib/codeEditor/browser/find/simpleFindWidget.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/codeEditor/browser/find/simpleFindWidget.ts b/src/vs/workbench/contrib/codeEditor/browser/find/simpleFindWidget.ts index 21018be3fee..bc5c6adca32 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/find/simpleFindWidget.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/find/simpleFindWidget.ts @@ -330,7 +330,7 @@ export abstract class SimpleFindWidget extends Widget { this._matchesCount.innerText = ''; let label = ''; this._matchesCount.classList.toggle('no-results', false); - if (count?.resultCount && count?.resultCount <= 0) { + if (count?.resultCount !== undefined && count?.resultCount === 0) { label = NLS_NO_RESULTS; if (!!this.inputValue) { this._matchesCount.classList.toggle('no-results', true); From 464c3dc728f870ecc724802f2636027f55311ac3 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 27 Jun 2022 21:48:23 +0200 Subject: [PATCH 057/347] improve confirmation when closing merge editor in the presense of conflicts (#153341) * auto save -> only inform about not resolved all conflicts yet * manual save -> inform but also enable to discard related to https://github.com/microsoft/vscode/issues/151040#issuecomment-1145090232 --- .../mergeEditor/browser/mergeEditorInput.ts | 61 ++++++++++++++----- 1 file changed, 46 insertions(+), 15 deletions(-) diff --git a/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInput.ts b/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInput.ts index 6526f2eeee0..660eca9666b 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInput.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInput.ts @@ -19,6 +19,7 @@ import { AbstractTextResourceEditorInput } from 'vs/workbench/common/editor/text import { autorun } from 'vs/workbench/contrib/audioCues/browser/observable'; import { MergeEditorModel } from 'vs/workbench/contrib/mergeEditor/browser/model/mergeEditorModel'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { AutoSaveMode, IFilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; import { ILanguageSupport, ITextFileEditorModel, ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; export class MergeEditorInputData { @@ -46,6 +47,7 @@ export class MergeEditorInput extends AbstractTextResourceEditorInput implements @IInstantiationService private readonly _instaService: IInstantiationService, @ITextModelService private readonly _textModelService: ITextModelService, @IDialogService private readonly _dialogService: IDialogService, + @IFilesConfigurationService private readonly _filesConfigurationService: IFilesConfigurationService, @IEditorService editorService: IEditorService, @ITextFileService textFileService: ITextFileService, @ILabelService labelService: ILabelService, @@ -173,30 +175,59 @@ export class MergeEditorInput extends AbstractTextResourceEditorInput implements return ConfirmResult.SAVE; } + const actions: string[] = []; + const options = { + cancelId: 0, + detail: inputs.length > 1 + ? localize('unhandledConflicts.detailN', 'Merge conflicts in {0} editors will remain unhandled.', inputs.length) + : localize('unhandledConflicts.detail1', 'Merge conflicts in this editor will remain unhandled.') + }; + + const isAnyAutoSave = this._filesConfigurationService.getAutoSaveMode() !== AutoSaveMode.OFF; + if (!isAnyAutoSave) { + // manual-save: FYI and discard + actions.push( + localize('unhandledConflicts.manualSaveIgnore', "Save and Continue with Conflicts"), // 0 + localize('unhandledConflicts.manualSaveNoSave', "Don't Save") // 1 + ); + + } else { + // auto-save: only FYI + actions.push( + localize('unhandledConflicts.ignore', "Continue with Conflicts"), // 0 + ); + } + + actions.push(localize('unhandledConflicts.cancel', "Cancel")); + options.cancelId = actions.length - 1; + const { choice } = await this._dialogService.show( Severity.Info, - localize('unhandledConflicts.msg', 'Do you want to continue with unhandled conflicts?'), - [ - localize('unhandledConflicts.ignore', "Continue with Conflicts"), - localize('unhandledConflicts.cancel', "Cancel") - ], - { - cancelId: 1, - detail: inputsWithUnhandledConflicts.length > 1 - ? localize('unhandledConflicts.detailN', 'Merge conflicts in {0} editors will remain unhandled.', inputsWithUnhandledConflicts.length) - : localize('unhandledConflicts.detail1', 'Merge conflicts in this editor will remain unhandled.') - } + localize('unhandledConflicts.msg', 'Do you want to continue with unhandled conflicts?'), // 1 + actions, + options ); - if (choice !== 0) { + if (choice === options.cancelId) { + // cancel: stay in editor return ConfirmResult.CANCEL; } - // continue with conflicts, tell inputs to ignore unhandled changes - for (const input of inputsWithUnhandledConflicts) { + // save or revert: in both cases we tell the inputs to ignore unhandled conflicts + // for the dirty state computation. + for (const input of inputs) { input._ignoreUnhandledConflictsForDirtyState = true; } - return ConfirmResult.SAVE; + + if (choice === 0) { + // conflicts: continue with remaining conflicts + return ConfirmResult.SAVE; + } + + // don't save: revert model and no save + console.assert(!isAnyAutoSave); + this._outTextModel?.revert({ force: true }); + return ConfirmResult.DONT_SAVE; } setLanguageId(languageId: string, _setExplicitly?: boolean): void { From da0f64881a7db98bf22813b1b2a37074bddb2c92 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Mon, 27 Jun 2022 12:52:59 -0700 Subject: [PATCH 058/347] Dispose in markdown tests (#153345) Updates the markdown tests to dispose of disposables created during the test --- .../src/test/definitionProvider.test.ts | 51 ++-- .../src/test/diagnostic.test.ts | 237 +++++++++--------- .../src/test/documentSymbolProvider.test.ts | 103 +++++--- .../src/test/fileReferences.test.ts | 50 ++-- .../src/test/foldingProvider.test.ts | 110 ++++---- .../src/test/inMemoryWorkspace.ts | 10 +- .../src/test/references.test.ts | 237 ++++++++++-------- .../src/test/rename.test.ts | 227 +++++++++-------- .../src/test/util.ts | 12 + .../src/test/workspaceSymbolProvider.test.ts | 73 +++--- .../src/util/dispose.ts | 52 +++- 11 files changed, 652 insertions(+), 510 deletions(-) diff --git a/extensions/markdown-language-features/src/test/definitionProvider.test.ts b/extensions/markdown-language-features/src/test/definitionProvider.test.ts index 8c1a51223a8..66c8919b5ba 100644 --- a/extensions/markdown-language-features/src/test/definitionProvider.test.ts +++ b/extensions/markdown-language-features/src/test/definitionProvider.test.ts @@ -10,17 +10,19 @@ import { MdVsCodeDefinitionProvider } from '../languageFeatures/definitions'; import { MdReferencesProvider } from '../languageFeatures/references'; import { MdTableOfContentsProvider } from '../tableOfContents'; import { noopToken } from '../util/cancellation'; +import { DisposableStore } from '../util/dispose'; import { InMemoryDocument } from '../util/inMemoryDocument'; import { IMdWorkspace } from '../workspace'; import { createNewMarkdownEngine } from './engine'; import { InMemoryMdWorkspace } from './inMemoryWorkspace'; import { nulLogger } from './nulLogging'; -import { joinLines, workspacePath } from './util'; +import { joinLines, withStore, workspacePath } from './util'; -function getDefinition(doc: InMemoryDocument, pos: vscode.Position, workspace: IMdWorkspace) { +function getDefinition(store: DisposableStore, doc: InMemoryDocument, pos: vscode.Position, workspace: IMdWorkspace) { const engine = createNewMarkdownEngine(); - const referencesProvider = new MdReferencesProvider(engine, workspace, new MdTableOfContentsProvider(engine, workspace, nulLogger), nulLogger); + const tocProvider = store.add(new MdTableOfContentsProvider(engine, workspace, nulLogger)); + const referencesProvider = store.add(new MdReferencesProvider(engine, workspace, tocProvider, nulLogger)); const provider = new MdVsCodeDefinitionProvider(referencesProvider); return provider.provideDefinition(doc, pos, noopToken); } @@ -46,31 +48,33 @@ function assertDefinitionsEqual(actualDef: vscode.Definition, ...expectedDefs: { } suite('markdown: Go to definition', () => { - test('Should not return definition when on link text', async () => { + test('Should not return definition when on link text', withStore(async (store) => { const doc = new InMemoryDocument(workspacePath('doc.md'), joinLines( `[ref](#abc)`, `[ref]: http://example.com`, )); + const workspace = store.add(new InMemoryMdWorkspace([doc])); - const defs = await getDefinition(doc, new vscode.Position(0, 1), new InMemoryMdWorkspace([doc])); + const defs = await getDefinition(store, doc, new vscode.Position(0, 1), workspace); assert.deepStrictEqual(defs, undefined); - }); + })); - test('Should find definition links within file from link', async () => { + test('Should find definition links within file from link', withStore(async (store) => { const docUri = workspacePath('doc.md'); const doc = new InMemoryDocument(docUri, joinLines( `[link 1][abc]`, // trigger here ``, `[abc]: https://example.com`, )); + const workspace = store.add(new InMemoryMdWorkspace([doc])); - const defs = await getDefinition(doc, new vscode.Position(0, 12), new InMemoryMdWorkspace([doc])); + const defs = await getDefinition(store, doc, new vscode.Position(0, 12), workspace); assertDefinitionsEqual(defs!, { uri: docUri, line: 2 }, ); - }); + })); - test('Should find definition links using shorthand', async () => { + test('Should find definition links using shorthand', withStore(async (store) => { const docUri = workspacePath('doc.md'); const doc = new InMemoryDocument(docUri, joinLines( `[ref]`, // trigger 1 @@ -79,59 +83,62 @@ suite('markdown: Go to definition', () => { ``, `[ref]: /Hello.md` // trigger 3 )); + const workspace = store.add(new InMemoryMdWorkspace([doc])); { - const defs = await getDefinition(doc, new vscode.Position(0, 2), new InMemoryMdWorkspace([doc])); + const defs = await getDefinition(store, doc, new vscode.Position(0, 2), workspace); assertDefinitionsEqual(defs!, { uri: docUri, line: 4 }, ); } { - const defs = await getDefinition(doc, new vscode.Position(2, 7), new InMemoryMdWorkspace([doc])); + const defs = await getDefinition(store, doc, new vscode.Position(2, 7), workspace); assertDefinitionsEqual(defs!, { uri: docUri, line: 4 }, ); } { - const defs = await getDefinition(doc, new vscode.Position(4, 2), new InMemoryMdWorkspace([doc])); + const defs = await getDefinition(store, doc, new vscode.Position(4, 2), workspace); assertDefinitionsEqual(defs!, { uri: docUri, line: 4 }, ); } - }); + })); - test('Should find definition links within file from definition', async () => { + test('Should find definition links within file from definition', withStore(async (store) => { const docUri = workspacePath('doc.md'); const doc = new InMemoryDocument(docUri, joinLines( `[link 1][abc]`, ``, `[abc]: https://example.com`, // trigger here )); + const workspace = store.add(new InMemoryMdWorkspace([doc])); - const defs = await getDefinition(doc, new vscode.Position(2, 3), new InMemoryMdWorkspace([doc])); + const defs = await getDefinition(store, doc, new vscode.Position(2, 3), workspace); assertDefinitionsEqual(defs!, { uri: docUri, line: 2 }, ); - }); + })); - test('Should not find definition links across files', async () => { + test('Should not find definition links across files', withStore(async (store) => { const docUri = workspacePath('doc.md'); const doc = new InMemoryDocument(docUri, joinLines( `[link 1][abc]`, ``, `[abc]: https://example.com`, )); - - const defs = await getDefinition(doc, new vscode.Position(0, 12), new InMemoryMdWorkspace([ + const workspace = store.add(new InMemoryMdWorkspace([ doc, new InMemoryDocument(workspacePath('other.md'), joinLines( `[link 1][abc]`, ``, - `[abc]: https://example.com?bad`, + `[abc]: https://example.com?bad` )) ])); + + const defs = await getDefinition(store, doc, new vscode.Position(0, 12), workspace); assertDefinitionsEqual(defs!, { uri: docUri, line: 2 }, ); - }); + })); }); diff --git a/extensions/markdown-language-features/src/test/diagnostic.test.ts b/extensions/markdown-language-features/src/test/diagnostic.test.ts index 3c8a8aed8ef..49600ea16b5 100644 --- a/extensions/markdown-language-features/src/test/diagnostic.test.ts +++ b/extensions/markdown-language-features/src/test/diagnostic.test.ts @@ -11,14 +11,14 @@ import { MdLinkProvider } from '../languageFeatures/documentLinks'; import { MdReferencesProvider } from '../languageFeatures/references'; import { MdTableOfContentsProvider } from '../tableOfContents'; import { noopToken } from '../util/cancellation'; -import { disposeAll } from '../util/dispose'; +import { DisposableStore } from '../util/dispose'; import { InMemoryDocument } from '../util/inMemoryDocument'; import { ResourceMap } from '../util/resourceMap'; import { IMdWorkspace } from '../workspace'; import { createNewMarkdownEngine } from './engine'; import { InMemoryMdWorkspace } from './inMemoryWorkspace'; import { nulLogger } from './nulLogging'; -import { assertRangeEqual, joinLines, workspacePath } from './util'; +import { assertRangeEqual, joinLines, withStore, workspacePath } from './util'; const defaultDiagnosticsOptions = Object.freeze({ enabled: true, @@ -29,10 +29,10 @@ const defaultDiagnosticsOptions = Object.freeze({ ignoreLinks: [], }); -async function getComputedDiagnostics(doc: InMemoryDocument, workspace: IMdWorkspace, options: Partial = {}): Promise { +async function getComputedDiagnostics(store: DisposableStore, doc: InMemoryDocument, workspace: IMdWorkspace, options: Partial = {}): Promise { const engine = createNewMarkdownEngine(); - const linkProvider = new MdLinkProvider(engine, workspace, nulLogger); - const tocProvider = new MdTableOfContentsProvider(engine, workspace, nulLogger); + const linkProvider = store.add(new MdLinkProvider(engine, workspace, nulLogger)); + const tocProvider = store.add(new MdTableOfContentsProvider(engine, workspace, nulLogger)); const computer = new DiagnosticComputer(workspace, linkProvider, tocProvider); return ( await computer.getDiagnostics(doc, { ...defaultDiagnosticsOptions, ...options, }, noopToken) @@ -108,31 +108,33 @@ class MemoryDiagnosticReporter extends DiagnosticReporter { suite('markdown: Diagnostic Computer', () => { - test('Should not return any diagnostics for empty document', async () => { + test('Should not return any diagnostics for empty document', withStore(async (store) => { const doc = new InMemoryDocument(workspacePath('doc.md'), joinLines( `text`, )); + const workspace = store.add(new InMemoryMdWorkspace([doc])); - const diagnostics = await getComputedDiagnostics(doc, new InMemoryMdWorkspace([doc])); + const diagnostics = await getComputedDiagnostics(store, doc, workspace); assert.deepStrictEqual(diagnostics, []); - }); + })); - test('Should generate diagnostic for link to file that does not exist', async () => { + test('Should generate diagnostic for link to file that does not exist', withStore(async (store) => { const doc = new InMemoryDocument(workspacePath('doc.md'), joinLines( `[bad](/no/such/file.md)`, `[good](/doc.md)`, `[good-ref]: /doc.md`, `[bad-ref]: /no/such/file.md`, )); + const workspace = store.add(new InMemoryMdWorkspace([doc])); - const diagnostics = await getComputedDiagnostics(doc, new InMemoryMdWorkspace([doc])); + const diagnostics = await getComputedDiagnostics(store, doc, workspace); assertDiagnosticsEqual(diagnostics, [ new vscode.Range(0, 6, 0, 22), new vscode.Range(3, 11, 3, 27), ]); - }); + })); - test('Should generate diagnostics for links to header that does not exist in current file', async () => { + test('Should generate diagnostics for links to header that does not exist in current file', withStore(async (store) => { const doc = new InMemoryDocument(workspacePath('doc.md'), joinLines( `[good](#good-header)`, `# Good Header`, @@ -141,15 +143,16 @@ suite('markdown: Diagnostic Computer', () => { `[good-ref]: #good-header`, `[bad-ref]: #no-such-header`, )); + const workspace = store.add(new InMemoryMdWorkspace([doc])); - const diagnostics = await getComputedDiagnostics(doc, new InMemoryMdWorkspace([doc])); + const diagnostics = await getComputedDiagnostics(store, doc, workspace); assertDiagnosticsEqual(diagnostics, [ new vscode.Range(2, 6, 2, 21), new vscode.Range(5, 11, 5, 26), ]); - }); + })); - test('Should generate diagnostics for links to non-existent headers in other files', async () => { + test('Should generate diagnostics for links to non-existent headers in other files', withStore(async (store) => { const doc1 = new InMemoryDocument(workspacePath('doc1.md'), joinLines( `# My header`, `[good](#my-header)`, @@ -163,13 +166,13 @@ suite('markdown: Diagnostic Computer', () => { `# Other header`, )); - const diagnostics = await getComputedDiagnostics(doc1, new InMemoryMdWorkspace([doc1, doc2])); + const diagnostics = await getComputedDiagnostics(store, doc1, new InMemoryMdWorkspace([doc1, doc2])); assertDiagnosticsEqual(diagnostics, [ new vscode.Range(5, 14, 5, 35), ]); - }); + })); - test('Should support links both with and without .md file extension', async () => { + test('Should support links both with and without .md file extension', withStore(async (store) => { const doc = new InMemoryDocument(workspacePath('doc.md'), joinLines( `# My header`, `[good](#my-header)`, @@ -178,188 +181,182 @@ suite('markdown: Diagnostic Computer', () => { `[good](/doc#my-header)`, `[good](doc#my-header)`, )); + const workspace = store.add(new InMemoryMdWorkspace([doc])); - const diagnostics = await getComputedDiagnostics(doc, new InMemoryMdWorkspace([doc])); + const diagnostics = await getComputedDiagnostics(store, doc, workspace); assertDiagnosticsEqual(diagnostics, []); - }); + })); - test('Should generate diagnostics for non-existent link reference', async () => { + test('Should generate diagnostics for non-existent link reference', withStore(async (store) => { const doc = new InMemoryDocument(workspacePath('doc.md'), joinLines( `[good link][good]`, `[bad link][no-such]`, ``, `[good]: http://example.com`, )); + const workspace = store.add(new InMemoryMdWorkspace([doc])); - const diagnostics = await getComputedDiagnostics(doc, new InMemoryMdWorkspace([doc])); + const diagnostics = await getComputedDiagnostics(store, doc, workspace); assertDiagnosticsEqual(diagnostics, [ new vscode.Range(1, 11, 1, 18), ]); - }); + })); - test('Should not generate diagnostics when validate is disabled', async () => { + test('Should not generate diagnostics when validate is disabled', withStore(async (store) => { const doc1 = new InMemoryDocument(workspacePath('doc1.md'), joinLines( `[text](#no-such-header)`, `[text][no-such-ref]`, )); - - const workspace = new InMemoryMdWorkspace([doc1]); - const diagnostics = await getComputedDiagnostics(doc1, workspace, new MemoryDiagnosticConfiguration({ enabled: false }).getOptions(doc1.uri)); + const workspace = store.add(new InMemoryMdWorkspace([doc1])); + const diagnostics = await getComputedDiagnostics(store, doc1, workspace, new MemoryDiagnosticConfiguration({ enabled: false }).getOptions(doc1.uri)); assertDiagnosticsEqual(diagnostics, []); - }); + })); - test('Should not generate diagnostics for email autolink', async () => { + test('Should not generate diagnostics for email autolink', withStore(async (store) => { const doc1 = new InMemoryDocument(workspacePath('doc1.md'), joinLines( `a c`, )); - const diagnostics = await getComputedDiagnostics(doc1, new InMemoryMdWorkspace([doc1])); + const diagnostics = await getComputedDiagnostics(store, doc1, new InMemoryMdWorkspace([doc1])); assertDiagnosticsEqual(diagnostics, []); - }); + })); - test('Should not generate diagnostics for html tag that looks like an autolink', async () => { + test('Should not generate diagnostics for html tag that looks like an autolink', withStore(async (store) => { const doc1 = new InMemoryDocument(workspacePath('doc1.md'), joinLines( `a b c`, `a b c`, )); - const diagnostics = await getComputedDiagnostics(doc1, new InMemoryMdWorkspace([doc1])); + const diagnostics = await getComputedDiagnostics(store, doc1, new InMemoryMdWorkspace([doc1])); assertDiagnosticsEqual(diagnostics, []); - }); + })); - test('Should allow ignoring invalid file link using glob', async () => { + test('Should allow ignoring invalid file link using glob', withStore(async (store) => { const doc1 = new InMemoryDocument(workspacePath('doc1.md'), joinLines( `[text](/no-such-file)`, `![img](/no-such-file)`, `[text]: /no-such-file`, )); - - const workspace = new InMemoryMdWorkspace([doc1]); - const diagnostics = await getComputedDiagnostics(doc1, workspace, { ignoreLinks: ['/no-such-file'] }); + const workspace = store.add(new InMemoryMdWorkspace([doc1])); + const diagnostics = await getComputedDiagnostics(store, doc1, workspace, { ignoreLinks: ['/no-such-file'] }); assertDiagnosticsEqual(diagnostics, []); - }); + })); - test('Should be able to disable fragment validation for external files', async () => { + test('Should be able to disable fragment validation for external files', withStore(async (store) => { const doc1 = new InMemoryDocument(workspacePath('doc1.md'), joinLines( `![i](/doc2.md#no-such)`, )); const doc2 = new InMemoryDocument(workspacePath('doc2.md'), joinLines('')); - const workspace = new InMemoryMdWorkspace([doc1, doc2]); - const diagnostics = await getComputedDiagnostics(doc1, workspace, { validateMarkdownFileLinkFragments: DiagnosticLevel.ignore }); + const diagnostics = await getComputedDiagnostics(store, doc1, workspace, { validateMarkdownFileLinkFragments: DiagnosticLevel.ignore }); assertDiagnosticsEqual(diagnostics, []); - }); + })); - test('Disabling own fragment validation should also disable path fragment validation by default', async () => { + test('Disabling own fragment validation should also disable path fragment validation by default', withStore(async (store) => { const doc1 = new InMemoryDocument(workspacePath('doc1.md'), joinLines( `[b](#no-head)`, `![i](/doc2.md#no-such)`, )); const doc2 = new InMemoryDocument(workspacePath('doc2.md'), joinLines('')); - const workspace = new InMemoryMdWorkspace([doc1, doc2]); { - const diagnostics = await getComputedDiagnostics(doc1, workspace, { validateFragmentLinks: DiagnosticLevel.ignore }); + const diagnostics = await getComputedDiagnostics(store, doc1, workspace, { validateFragmentLinks: DiagnosticLevel.ignore }); assertDiagnosticsEqual(diagnostics, []); } { // But we should be able to override the default - const diagnostics = await getComputedDiagnostics(doc1, workspace, { validateFragmentLinks: DiagnosticLevel.ignore, validateMarkdownFileLinkFragments: DiagnosticLevel.warning }); + const diagnostics = await getComputedDiagnostics(store, doc1, workspace, { validateFragmentLinks: DiagnosticLevel.ignore, validateMarkdownFileLinkFragments: DiagnosticLevel.warning }); assertDiagnosticsEqual(diagnostics, [ new vscode.Range(1, 13, 1, 21), ]); } - }); + })); - test('ignoreLinks should allow skipping link to non-existent file', async () => { + test('ignoreLinks should allow skipping link to non-existent file', withStore(async (store) => { const doc1 = new InMemoryDocument(workspacePath('doc1.md'), joinLines( `[text](/no-such-file#header)`, )); + const workspace = store.add(new InMemoryMdWorkspace([doc1])); - const workspace = new InMemoryMdWorkspace([doc1]); - - const diagnostics = await getComputedDiagnostics(doc1, workspace, { ignoreLinks: ['/no-such-file'] }); + const diagnostics = await getComputedDiagnostics(store, doc1, workspace, { ignoreLinks: ['/no-such-file'] }); assertDiagnosticsEqual(diagnostics, []); - }); + })); - test('ignoreLinks should not consider link fragment', async () => { + test('ignoreLinks should not consider link fragment', withStore(async (store) => { const doc1 = new InMemoryDocument(workspacePath('doc1.md'), joinLines( `[text](/no-such-file#header)`, )); + const workspace = store.add(new InMemoryMdWorkspace([doc1])); - const workspace = new InMemoryMdWorkspace([doc1]); - - const diagnostics = await getComputedDiagnostics(doc1, workspace, { ignoreLinks: ['/no-such-file'] }); + const diagnostics = await getComputedDiagnostics(store, doc1, workspace, { ignoreLinks: ['/no-such-file'] }); assertDiagnosticsEqual(diagnostics, []); - }); + })); - test('ignoreLinks should support globs', async () => { + test('ignoreLinks should support globs', withStore(async (store) => { const doc1 = new InMemoryDocument(workspacePath('doc1.md'), joinLines( `![i](/images/aaa.png)`, `![i](/images/sub/bbb.png)`, `![i](/images/sub/sub2/ccc.png)`, )); + const workspace = store.add(new InMemoryMdWorkspace([doc1])); - const workspace = new InMemoryMdWorkspace([doc1]); - const diagnostics = await getComputedDiagnostics(doc1, workspace, { ignoreLinks: ['/images/**/*.png'] }); + const diagnostics = await getComputedDiagnostics(store, doc1, workspace, { ignoreLinks: ['/images/**/*.png'] }); assertDiagnosticsEqual(diagnostics, []); - }); + })); - test('ignoreLinks should support ignoring header', async () => { + test('ignoreLinks should support ignoring header', withStore(async (store) => { const doc1 = new InMemoryDocument(workspacePath('doc1.md'), joinLines( `![i](#no-such)`, )); - const workspace = new InMemoryMdWorkspace([doc1]); + const workspace = store.add(new InMemoryMdWorkspace([doc1])); - const diagnostics = await getComputedDiagnostics(doc1, workspace, { ignoreLinks: ['#no-such'] }); + const diagnostics = await getComputedDiagnostics(store, doc1, workspace, { ignoreLinks: ['#no-such'] }); assertDiagnosticsEqual(diagnostics, []); - }); + })); - test('ignoreLinks should support ignoring header in file', async () => { + test('ignoreLinks should support ignoring header in file', withStore(async (store) => { const doc1 = new InMemoryDocument(workspacePath('doc1.md'), joinLines( `![i](/doc2.md#no-such)`, )); const doc2 = new InMemoryDocument(workspacePath('doc2.md'), joinLines('')); + const workspace = store.add(new InMemoryMdWorkspace([doc1, doc2])); - const workspace = new InMemoryMdWorkspace([doc1, doc2]); { - const diagnostics = await getComputedDiagnostics(doc1, workspace, { ignoreLinks: ['/doc2.md#no-such'] }); + const diagnostics = await getComputedDiagnostics(store, doc1, workspace, { ignoreLinks: ['/doc2.md#no-such'] }); assertDiagnosticsEqual(diagnostics, []); } { - const diagnostics = await getComputedDiagnostics(doc1, workspace, { ignoreLinks: ['/doc2.md#*'] }); + const diagnostics = await getComputedDiagnostics(store, doc1, workspace, { ignoreLinks: ['/doc2.md#*'] }); assertDiagnosticsEqual(diagnostics, []); } - }); + })); - test('ignoreLinks should support ignore header links if file is ignored', async () => { + test('ignoreLinks should support ignore header links if file is ignored', withStore(async (store) => { const doc1 = new InMemoryDocument(workspacePath('doc1.md'), joinLines( `![i](/doc2.md#no-such)`, )); const doc2 = new InMemoryDocument(workspacePath('doc2.md'), joinLines('')); - const workspace = new InMemoryMdWorkspace([doc1, doc2]); - const diagnostics = await getComputedDiagnostics(doc1, workspace, { ignoreLinks: ['/doc2.md'] }); + const diagnostics = await getComputedDiagnostics(store, doc1, workspace, { ignoreLinks: ['/doc2.md'] }); assertDiagnosticsEqual(diagnostics, []); - }); + })); - test('Should not detect checkboxes as invalid links', async () => { + test('Should not detect checkboxes as invalid links', withStore(async (store) => { const doc1 = new InMemoryDocument(workspacePath('doc1.md'), joinLines( `- [x]`, `- [X]`, `- [ ]`, )); + const workspace = store.add(new InMemoryMdWorkspace([doc1])); - const workspace = new InMemoryMdWorkspace([doc1]); - - const diagnostics = await getComputedDiagnostics(doc1, workspace, { ignoreLinks: ['/doc2.md'] }); + const diagnostics = await getComputedDiagnostics(store, doc1, workspace, { ignoreLinks: ['/doc2.md'] }); assertDiagnosticsEqual(diagnostics, []); - }); + })); - test('Should detect invalid links with titles', async () => { + test('Should detect invalid links with titles', withStore(async (store) => { const doc = new InMemoryDocument(workspacePath('doc1.md'), joinLines( `[link]( "text")`, `[link]( 'text')`, @@ -368,7 +365,9 @@ suite('markdown: Diagnostic Computer', () => { `[link](no-such.md 'text')`, `[link](no-such.md (text))`, )); - const diagnostics = await getComputedDiagnostics(doc, new InMemoryMdWorkspace([doc])); + const workspace = store.add(new InMemoryMdWorkspace([doc])); + + const diagnostics = await getComputedDiagnostics(store, doc, workspace); assertDiagnosticsEqual(diagnostics, [ new vscode.Range(0, 8, 0, 18), new vscode.Range(1, 8, 1, 18), @@ -377,36 +376,36 @@ suite('markdown: Diagnostic Computer', () => { new vscode.Range(4, 7, 4, 17), new vscode.Range(5, 7, 5, 17), ]); - }); + })); - test('Should generate diagnostics for non-existent header using file link to own file', async () => { + test('Should generate diagnostics for non-existent header using file link to own file', withStore(async (store) => { const doc = new InMemoryDocument(workspacePath('sub', 'doc.md'), joinLines( `[bad](doc.md#no-such)`, `[bad](doc#no-such)`, `[bad](/sub/doc.md#no-such)`, `[bad](/sub/doc#no-such)`, )); + const workspace = store.add(new InMemoryMdWorkspace([doc])); - const diagnostics = await getComputedDiagnostics(doc, new InMemoryMdWorkspace([doc])); + const diagnostics = await getComputedDiagnostics(store, doc, workspace); assertDiagnosticsEqual(orderDiagnosticsByRange(diagnostics), [ new vscode.Range(0, 12, 0, 20), new vscode.Range(1, 9, 1, 17), new vscode.Range(2, 17, 2, 25), new vscode.Range(3, 14, 3, 22), ]); - }); + })); - test('Own header link using file path link should be controlled by "validateMarkdownFileLinkFragments" instead of "validateFragmentLinks"', async () => { + test('Own header link using file path link should be controlled by "validateMarkdownFileLinkFragments" instead of "validateFragmentLinks"', withStore(async (store) => { const doc1 = new InMemoryDocument(workspacePath('sub', 'doc.md'), joinLines( `[bad](doc.md#no-such)`, `[bad](doc#no-such)`, `[bad](/sub/doc.md#no-such)`, `[bad](/sub/doc#no-such)`, )); + const workspace = store.add(new InMemoryMdWorkspace([doc1])); - const workspace = new InMemoryMdWorkspace([doc1]); - - const diagnostics = await getComputedDiagnostics(doc1, workspace, { + const diagnostics = await getComputedDiagnostics(store, doc1, workspace, { validateFragmentLinks: DiagnosticLevel.ignore, validateMarkdownFileLinkFragments: DiagnosticLevel.warning, }); @@ -416,31 +415,22 @@ suite('markdown: Diagnostic Computer', () => { new vscode.Range(2, 17, 2, 25), new vscode.Range(3, 14, 3, 22), ]); - }); + })); }); suite('Markdown: Diagnostics manager', () => { - const _disposables: vscode.Disposable[] = []; - - setup(() => { - disposeAll(_disposables); - }); - - teardown(() => { - disposeAll(_disposables); - }); - function createDiagnosticsManager( + store: DisposableStore, workspace: IMdWorkspace, configuration = new MemoryDiagnosticConfiguration({}), reporter: DiagnosticReporter = new DiagnosticCollectionReporter(), ) { const engine = createNewMarkdownEngine(); - const linkProvider = new MdLinkProvider(engine, workspace, nulLogger); - const tocProvider = new MdTableOfContentsProvider(engine, workspace, nulLogger); - const referencesProvider = new MdReferencesProvider(engine, workspace, tocProvider, nulLogger); - const manager = new DiagnosticManager( + const linkProvider = store.add(new MdLinkProvider(engine, workspace, nulLogger)); + const tocProvider = store.add(new MdTableOfContentsProvider(engine, workspace, nulLogger)); + const referencesProvider = store.add(new MdReferencesProvider(engine, workspace, tocProvider, nulLogger)); + const manager = store.add(new DiagnosticManager( workspace, new DiagnosticComputer(workspace, linkProvider, tocProvider), configuration, @@ -448,27 +438,26 @@ suite('Markdown: Diagnostics manager', () => { referencesProvider, tocProvider, nulLogger, - 0); - _disposables.push(linkProvider, tocProvider, referencesProvider, manager); + 0)); return manager; } - test('Changing enable/disable should recompute diagnostics', async () => { + test('Changing enable/disable should recompute diagnostics', withStore(async (store) => { const doc1Uri = workspacePath('doc1.md'); const doc2Uri = workspacePath('doc2.md'); - const workspace = new InMemoryMdWorkspace([ + const workspace = store.add(new InMemoryMdWorkspace([ new InMemoryDocument(doc1Uri, joinLines( `[text](#no-such-1)`, )), new InMemoryDocument(doc2Uri, joinLines( `[text](#no-such-2)`, )) - ]); + ])); - const reporter = new MemoryDiagnosticReporter(); + const reporter = store.add(new MemoryDiagnosticReporter()); const config = new MemoryDiagnosticConfiguration({ enabled: true }); - const manager = createDiagnosticsManager(workspace, config, reporter); + const manager = createDiagnosticsManager(store, workspace, config, reporter); await manager.ready; // Check initial state (Enabled) @@ -495,9 +484,9 @@ suite('Markdown: Diagnostics manager', () => { assertDiagnosticsEqual(reporter.get(doc2Uri), [ new vscode.Range(0, 7, 0, 17), ]); - }); + })); - test('Should revalidate linked files when header changes', async () => { + test('Should revalidate linked files when header changes', withStore(async (store) => { const doc1Uri = workspacePath('doc1.md'); const doc1 = new InMemoryDocument(doc1Uri, joinLines( `[text](#no-such)`, @@ -509,11 +498,10 @@ suite('Markdown: Diagnostics manager', () => { `[text](#header)`, `[text](#no-such-2)`, )); + const workspace = store.add(new InMemoryMdWorkspace([doc1, doc2])); + const reporter = store.add(new MemoryDiagnosticReporter()); - const workspace = new InMemoryMdWorkspace([doc1, doc2]); - const reporter = new MemoryDiagnosticReporter(); - - const manager = createDiagnosticsManager(workspace, new MemoryDiagnosticConfiguration({}), reporter); + const manager = createDiagnosticsManager(store, workspace, new MemoryDiagnosticConfiguration({}), reporter); await manager.ready; // Check initial state @@ -553,9 +541,9 @@ suite('Markdown: Diagnostics manager', () => { assertDiagnosticsEqual(reporter.get(doc2Uri), [ new vscode.Range(2, 7, 2, 17), ]); - }); + })); - test('Should revalidate linked files when file is deleted/created', async () => { + test('Should revalidate linked files when file is deleted/created', withStore(async (store) => { const doc1Uri = workspacePath('doc1.md'); const doc1 = new InMemoryDocument(doc1Uri, joinLines( `[text](/doc2.md)`, @@ -565,11 +553,10 @@ suite('Markdown: Diagnostics manager', () => { const doc2 = new InMemoryDocument(doc2Uri, joinLines( `# Header` )); + const workspace = store.add(new InMemoryMdWorkspace([doc1, doc2])); + const reporter = store.add(new MemoryDiagnosticReporter()); - const workspace = new InMemoryMdWorkspace([doc1, doc2]); - const reporter = new MemoryDiagnosticReporter(); - - const manager = createDiagnosticsManager(workspace, new MemoryDiagnosticConfiguration({}), reporter); + const manager = createDiagnosticsManager(store, workspace, new MemoryDiagnosticConfiguration({}), reporter); await manager.ready; // Check initial state @@ -589,5 +576,5 @@ suite('Markdown: Diagnostics manager', () => { workspace.createDocument(doc2); await reporter.waitPendingWork(); assertDiagnosticsEqual(reporter.get(doc1Uri), []); - }); + })); }); diff --git a/extensions/markdown-language-features/src/test/documentSymbolProvider.test.ts b/extensions/markdown-language-features/src/test/documentSymbolProvider.test.ts index 66609941dc9..c4570303868 100644 --- a/extensions/markdown-language-features/src/test/documentSymbolProvider.test.ts +++ b/extensions/markdown-language-features/src/test/documentSymbolProvider.test.ts @@ -7,92 +7,115 @@ import * as assert from 'assert'; import 'mocha'; import { MdDocumentSymbolProvider } from '../languageFeatures/documentSymbols'; import { MdTableOfContentsProvider } from '../tableOfContents'; +import { DisposableStore } from '../util/dispose'; import { InMemoryDocument } from '../util/inMemoryDocument'; import { createNewMarkdownEngine } from './engine'; import { InMemoryMdWorkspace } from './inMemoryWorkspace'; import { nulLogger } from './nulLogging'; -import { workspacePath } from './util'; +import { joinLines, withStore, workspacePath } from './util'; -function getSymbolsForFile(fileContents: string) { +function getSymbolsForFile(store: DisposableStore, fileContents: string) { const doc = new InMemoryDocument(workspacePath('test.md'), fileContents); - const workspace = new InMemoryMdWorkspace([doc]); + const workspace = store.add(new InMemoryMdWorkspace([doc])); const engine = createNewMarkdownEngine(); - const provider = new MdDocumentSymbolProvider(new MdTableOfContentsProvider(engine, workspace, nulLogger), nulLogger); + const tocProvider = store.add(new MdTableOfContentsProvider(engine, workspace, nulLogger)); + const provider = new MdDocumentSymbolProvider(tocProvider, nulLogger); return provider.provideDocumentSymbols(doc); } -suite('markdown.DocumentSymbolProvider', () => { - test('Should not return anything for empty document', async () => { - const symbols = await getSymbolsForFile(''); +suite('Markdown: DocumentSymbolProvider', () => { + test('Should not return anything for empty document', withStore(async (store) => { + const symbols = await getSymbolsForFile(store, ''); assert.strictEqual(symbols.length, 0); - }); + })); - test('Should not return anything for document with no headers', async () => { - const symbols = await getSymbolsForFile('a\na'); + test('Should not return anything for document with no headers', withStore(async (store) => { + const symbols = await getSymbolsForFile(store, joinLines( + `a`, + `a`, + )); assert.strictEqual(symbols.length, 0); - }); + })); - test('Should not return anything for document with # but no real headers', async () => { - const symbols = await getSymbolsForFile('a#a\na#'); + test('Should not return anything for document with # but no real headers', withStore(async (store) => { + const symbols = await getSymbolsForFile(store, joinLines( + `a#a`, + `a#`, + )); assert.strictEqual(symbols.length, 0); - }); + })); - test('Should return single symbol for single header', async () => { - const symbols = await getSymbolsForFile('# h'); + test('Should return single symbol for single header', withStore(async (store) => { + const symbols = await getSymbolsForFile(store, '# h'); assert.strictEqual(symbols.length, 1); assert.strictEqual(symbols[0].name, '# h'); - }); + })); - test('Should not care about symbol level for single header', async () => { - const symbols = await getSymbolsForFile('### h'); + test('Should not care about symbol level for single header', withStore(async (store) => { + const symbols = await getSymbolsForFile(store, '### h'); assert.strictEqual(symbols.length, 1); assert.strictEqual(symbols[0].name, '### h'); - }); + })); - test('Should put symbols of same level in flat list', async () => { - const symbols = await getSymbolsForFile('## h\n## h2'); + test('Should put symbols of same level in flat list', withStore(async (store) => { + const symbols = await getSymbolsForFile(store, joinLines( + `## h`, + `## h2`, + )); assert.strictEqual(symbols.length, 2); assert.strictEqual(symbols[0].name, '## h'); assert.strictEqual(symbols[1].name, '## h2'); - }); + })); - test('Should nest symbol of level - 1 under parent', async () => { - - const symbols = await getSymbolsForFile('# h\n## h2\n## h3'); + test('Should nest symbol of level - 1 under parent', withStore(async (store) => { + const symbols = await getSymbolsForFile(store, joinLines( + `# h`, + `## h2`, + `## h3`, + )); assert.strictEqual(symbols.length, 1); assert.strictEqual(symbols[0].name, '# h'); assert.strictEqual(symbols[0].children.length, 2); assert.strictEqual(symbols[0].children[0].name, '## h2'); assert.strictEqual(symbols[0].children[1].name, '## h3'); - }); + })); - test('Should nest symbol of level - n under parent', async () => { - const symbols = await getSymbolsForFile('# h\n#### h2'); + test('Should nest symbol of level - n under parent', withStore(async (store) => { + const symbols = await getSymbolsForFile(store, joinLines( + `# h`, + `#### h2`, + )); assert.strictEqual(symbols.length, 1); assert.strictEqual(symbols[0].name, '# h'); assert.strictEqual(symbols[0].children.length, 1); assert.strictEqual(symbols[0].children[0].name, '#### h2'); - }); + })); - test('Should flatten children where lower level occurs first', async () => { - const symbols = await getSymbolsForFile('# h\n### h2\n## h3'); + test('Should flatten children where lower level occurs first', withStore(async (store) => { + const symbols = await getSymbolsForFile(store, joinLines( + `# h`, + `### h2`, + `## h3`, + )); assert.strictEqual(symbols.length, 1); assert.strictEqual(symbols[0].name, '# h'); assert.strictEqual(symbols[0].children.length, 2); assert.strictEqual(symbols[0].children[0].name, '### h2'); assert.strictEqual(symbols[0].children[1].name, '## h3'); - }); + })); - test('Should handle line separator in file. Issue #63749', async () => { - const symbols = await getSymbolsForFile(`# A -- foo - -# B -- bar`); + test('Should handle line separator in file. Issue #63749', withStore(async (store) => { + const symbols = await getSymbolsForFile(store, joinLines( + `# A`, + `- foo`, + ``, + `# B`, + `- bar`, + )); assert.strictEqual(symbols.length, 2); assert.strictEqual(symbols[0].name, '# A'); assert.strictEqual(symbols[1].name, '# B'); - }); + })); }); diff --git a/extensions/markdown-language-features/src/test/fileReferences.test.ts b/extensions/markdown-language-features/src/test/fileReferences.test.ts index 3044d176a92..d277e8aedbb 100644 --- a/extensions/markdown-language-features/src/test/fileReferences.test.ts +++ b/extensions/markdown-language-features/src/test/fileReferences.test.ts @@ -9,17 +9,19 @@ import * as vscode from 'vscode'; import { MdReference, MdReferencesProvider } from '../languageFeatures/references'; import { MdTableOfContentsProvider } from '../tableOfContents'; import { noopToken } from '../util/cancellation'; +import { DisposableStore } from '../util/dispose'; import { InMemoryDocument } from '../util/inMemoryDocument'; import { IMdWorkspace } from '../workspace'; import { createNewMarkdownEngine } from './engine'; import { InMemoryMdWorkspace } from './inMemoryWorkspace'; import { nulLogger } from './nulLogging'; -import { joinLines, workspacePath } from './util'; +import { joinLines, withStore, workspacePath } from './util'; -function getFileReferences(resource: vscode.Uri, workspace: IMdWorkspace) { +function getFileReferences(store: DisposableStore, resource: vscode.Uri, workspace: IMdWorkspace) { const engine = createNewMarkdownEngine(); - const computer = new MdReferencesProvider(engine, workspace, new MdTableOfContentsProvider(engine, workspace, nulLogger), nulLogger); + const tocProvider = store.add(new MdTableOfContentsProvider(engine, workspace, nulLogger)); + const computer = store.add(new MdReferencesProvider(engine, workspace, tocProvider, nulLogger)); return computer.getAllReferencesToFile(resource, noopToken); } @@ -37,82 +39,82 @@ function assertReferencesEqual(actualRefs: readonly MdReference[], ...expectedRe suite('markdown: find file references', () => { - test('Should find basic references', async () => { + test('Should find basic references', withStore(async (store) => { const docUri = workspacePath('doc.md'); const otherUri = workspacePath('other.md'); - - const refs = await getFileReferences(otherUri, new InMemoryMdWorkspace([ + const workspace = store.add(new InMemoryMdWorkspace([ new InMemoryDocument(docUri, joinLines( `# header`, `[link 1](./other.md)`, - `[link 2](./other.md)`, + `[link 2](./other.md)` )), new InMemoryDocument(otherUri, joinLines( `# header`, `pre`, `[link 3](./other.md)`, - `post`, + `post` )), ])); - assertReferencesEqual(refs!, + const refs = await getFileReferences(store, otherUri, workspace); + assertReferencesEqual(refs, { uri: docUri, line: 1 }, { uri: docUri, line: 2 }, { uri: otherUri, line: 2 }, ); - }); + })); - test('Should find references with and without file extensions', async () => { + test('Should find references with and without file extensions', withStore(async (store) => { const docUri = workspacePath('doc.md'); const otherUri = workspacePath('other.md'); - - const refs = await getFileReferences(otherUri, new InMemoryMdWorkspace([ + const workspace = store.add(new InMemoryMdWorkspace([ new InMemoryDocument(docUri, joinLines( `# header`, `[link 1](./other.md)`, - `[link 2](./other)`, + `[link 2](./other)` )), new InMemoryDocument(otherUri, joinLines( `# header`, `pre`, `[link 3](./other.md)`, `[link 4](./other)`, - `post`, + `post` )), ])); - assertReferencesEqual(refs!, + const refs = await getFileReferences(store, otherUri, workspace); + assertReferencesEqual(refs, { uri: docUri, line: 1 }, { uri: docUri, line: 2 }, { uri: otherUri, line: 2 }, { uri: otherUri, line: 3 }, ); - }); + })); - test('Should find references with headers on links', async () => { + test('Should find references with headers on links', withStore(async (store) => { const docUri = workspacePath('doc.md'); const otherUri = workspacePath('other.md'); - - const refs = await getFileReferences(otherUri, new InMemoryMdWorkspace([ + const workspace = store.add(new InMemoryMdWorkspace([ new InMemoryDocument(docUri, joinLines( `# header`, `[link 1](./other.md#sub-bla)`, - `[link 2](./other#sub-bla)`, + `[link 2](./other#sub-bla)` )), new InMemoryDocument(otherUri, joinLines( `# header`, `pre`, `[link 3](./other.md#sub-bla)`, `[link 4](./other#sub-bla)`, - `post`, + `post` )), ])); - assertReferencesEqual(refs!, + const refs = await getFileReferences(store, otherUri, workspace); + assertReferencesEqual(refs, { uri: docUri, line: 1 }, { uri: docUri, line: 2 }, { uri: otherUri, line: 2 }, { uri: otherUri, line: 3 }, ); - }); + })); }); diff --git a/extensions/markdown-language-features/src/test/foldingProvider.test.ts b/extensions/markdown-language-features/src/test/foldingProvider.test.ts index 5f5f3f874e6..85cbd84c581 100644 --- a/extensions/markdown-language-features/src/test/foldingProvider.test.ts +++ b/extensions/markdown-language-features/src/test/foldingProvider.test.ts @@ -8,32 +8,43 @@ import 'mocha'; import * as vscode from 'vscode'; import { MdFoldingProvider } from '../languageFeatures/folding'; import { MdTableOfContentsProvider } from '../tableOfContents'; +import { noopToken } from '../util/cancellation'; +import { DisposableStore } from '../util/dispose'; import { InMemoryDocument } from '../util/inMemoryDocument'; import { createNewMarkdownEngine } from './engine'; import { InMemoryMdWorkspace } from './inMemoryWorkspace'; import { nulLogger } from './nulLogging'; -import { joinLines } from './util'; +import { joinLines, withStore } from './util'; const testFileName = vscode.Uri.file('test.md'); -suite('markdown.FoldingProvider', () => { - test('Should not return anything for empty document', async () => { - const folds = await getFoldsForDocument(``); - assert.strictEqual(folds.length, 0); - }); +async function getFoldsForDocument(store: DisposableStore, contents: string) { + const doc = new InMemoryDocument(testFileName, contents); + const workspace = store.add(new InMemoryMdWorkspace([doc])); + const engine = createNewMarkdownEngine(); + const tocProvider = store.add(new MdTableOfContentsProvider(engine, workspace, nulLogger)); + const provider = new MdFoldingProvider(engine, tocProvider); + return provider.provideFoldingRanges(doc, {}, noopToken); +} - test('Should not return anything for document without headers', async () => { - const folds = await getFoldsForDocument(joinLines( +suite('markdown.FoldingProvider', () => { + test('Should not return anything for empty document', withStore(async (store) => { + const folds = await getFoldsForDocument(store, ``); + assert.strictEqual(folds.length, 0); + })); + + test('Should not return anything for document without headers', withStore(async (store) => { + const folds = await getFoldsForDocument(store, joinLines( `a`, `**b** afas`, `a#b`, `a`, )); assert.strictEqual(folds.length, 0); - }); + })); - test('Should fold from header to end of document', async () => { - const folds = await getFoldsForDocument(joinLines( + test('Should fold from header to end of document', withStore(async (store) => { + const folds = await getFoldsForDocument(store, joinLines( `a`, `# b`, `c`, @@ -43,10 +54,10 @@ suite('markdown.FoldingProvider', () => { const firstFold = folds[0]; assert.strictEqual(firstFold.start, 1); assert.strictEqual(firstFold.end, 3); - }); + })); - test('Should leave single newline before next header', async () => { - const folds = await getFoldsForDocument(joinLines( + test('Should leave single newline before next header', withStore(async (store) => { + const folds = await getFoldsForDocument(store, joinLines( ``, `# a`, `x`, @@ -58,10 +69,10 @@ suite('markdown.FoldingProvider', () => { const firstFold = folds[0]; assert.strictEqual(firstFold.start, 1); assert.strictEqual(firstFold.end, 2); - }); + })); - test('Should collapse multiple newlines to single newline before next header', async () => { - const folds = await getFoldsForDocument(joinLines( + test('Should collapse multiple newlines to single newline before next header', withStore(async (store) => { + const folds = await getFoldsForDocument(store, joinLines( ``, `# a`, `x`, @@ -75,10 +86,10 @@ suite('markdown.FoldingProvider', () => { const firstFold = folds[0]; assert.strictEqual(firstFold.start, 1); assert.strictEqual(firstFold.end, 4); - }); + })); - test('Should not collapse if there is no newline before next header', async () => { - const folds = await getFoldsForDocument(joinLines( + test('Should not collapse if there is no newline before next header', withStore(async (store) => { + const folds = await getFoldsForDocument(store, joinLines( ``, `# a`, `x`, @@ -89,10 +100,10 @@ suite('markdown.FoldingProvider', () => { const firstFold = folds[0]; assert.strictEqual(firstFold.start, 1); assert.strictEqual(firstFold.end, 2); - }); + })); - test('Should fold nested markers', async () => { - const folds = await getFoldsForDocument(joinLines( + test('Should fold nested markers', withStore(async (store) => { + const folds = await getFoldsForDocument(store, joinLines( `a`, ``, `b`, @@ -116,10 +127,10 @@ suite('markdown.FoldingProvider', () => { assert.strictEqual(first.end, 5); assert.strictEqual(second.start, 7); assert.strictEqual(second.end, 9); - }); + })); - test('Should fold from list to end of document', async () => { - const folds = await getFoldsForDocument(joinLines( + test('Should fold from list to end of document', withStore(async (store) => { + const folds = await getFoldsForDocument(store, joinLines( `a`, `- b`, `c`, @@ -129,10 +140,10 @@ suite('markdown.FoldingProvider', () => { const firstFold = folds[0]; assert.strictEqual(firstFold.start, 1); assert.strictEqual(firstFold.end, 3); - }); + })); - test('lists folds should span multiple lines of content', async () => { - const folds = await getFoldsForDocument(joinLines( + test('lists folds should span multiple lines of content', withStore(async (store) => { + const folds = await getFoldsForDocument(store, joinLines( `a`, `- This list item\n spans multiple\n lines.`, )); @@ -140,10 +151,10 @@ suite('markdown.FoldingProvider', () => { const firstFold = folds[0]; assert.strictEqual(firstFold.start, 1); assert.strictEqual(firstFold.end, 3); - }); + })); - test('List should leave single blankline before new element', async () => { - const folds = await getFoldsForDocument(joinLines( + test('List should leave single blankline before new element', withStore(async (store) => { + const folds = await getFoldsForDocument(store, joinLines( `- a`, `a`, ``, @@ -154,10 +165,10 @@ suite('markdown.FoldingProvider', () => { const firstFold = folds[0]; assert.strictEqual(firstFold.start, 0); assert.strictEqual(firstFold.end, 2); - }); + })); - test('Should fold fenced code blocks', async () => { - const folds = await getFoldsForDocument(joinLines( + test('Should fold fenced code blocks', withStore(async (store) => { + const folds = await getFoldsForDocument(store, joinLines( `~~~ts`, `a`, `~~~`, @@ -167,10 +178,10 @@ suite('markdown.FoldingProvider', () => { const firstFold = folds[0]; assert.strictEqual(firstFold.start, 0); assert.strictEqual(firstFold.end, 2); - }); + })); - test('Should fold fenced code blocks with yaml front matter', async () => { - const folds = await getFoldsForDocument(joinLines( + test('Should fold fenced code blocks with yaml front matter', withStore(async (store) => { + const folds = await getFoldsForDocument(store, joinLines( `---`, `title: bla`, `---`, @@ -188,10 +199,10 @@ suite('markdown.FoldingProvider', () => { const firstFold = folds[0]; assert.strictEqual(firstFold.start, 4); assert.strictEqual(firstFold.end, 6); - }); + })); - test('Should fold html blocks', async () => { - const folds = await getFoldsForDocument(joinLines( + test('Should fold html blocks', withStore(async (store) => { + const folds = await getFoldsForDocument(store, joinLines( `x`, `
`, ` fa`, @@ -201,10 +212,10 @@ suite('markdown.FoldingProvider', () => { const firstFold = folds[0]; assert.strictEqual(firstFold.start, 1); assert.strictEqual(firstFold.end, 3); - }); + })); - test('Should fold html block comments', async () => { - const folds = await getFoldsForDocument(joinLines( + test('Should fold html block comments', withStore(async (store) => { + const folds = await getFoldsForDocument(store, joinLines( `x`, ` - - - - - - - - - - - - - - - - - - diff --git a/src/vs/code/electron-browser/workbench/workbench.js b/src/vs/code/electron-browser/workbench/workbench.js deleted file mode 100644 index 7ceef489fcc..00000000000 --- a/src/vs/code/electron-browser/workbench/workbench.js +++ /dev/null @@ -1,213 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -/// - -//@ts-check -(function () { - 'use strict'; - - const bootstrapWindow = bootstrapWindowLib(); - - // Add a perf entry right from the top - performance.mark('code/didStartRenderer'); - - // Load workbench main JS, CSS and NLS all in parallel. This is an - // optimization to prevent a waterfall of loading to happen, because - // we know for a fact that workbench.desktop.main will depend on - // the related CSS and NLS counterparts. - bootstrapWindow.load([ - 'vs/workbench/workbench.desktop.main', - 'vs/nls!vs/workbench/workbench.desktop.main', - 'vs/css!vs/workbench/workbench.desktop.main' - ], - function (_, configuration) { - - // Mark start of workbench - performance.mark('code/didLoadWorkbenchMain'); - - // @ts-ignore - return require('vs/workbench/electron-sandbox/desktop.main').main(configuration); - }, - { - configureDeveloperSettings: function (windowConfig) { - return { - // disable automated devtools opening on error when running extension tests - // as this can lead to nondeterministic test execution (devtools steals focus) - forceDisableShowDevtoolsOnError: typeof windowConfig.extensionTestsPath === 'string', - // enable devtools keybindings in extension development window - forceEnableDeveloperKeybindings: Array.isArray(windowConfig.extensionDevelopmentPath) && windowConfig.extensionDevelopmentPath.length > 0, - removeDeveloperKeybindingsAfterLoad: true - }; - }, - canModifyDOM: function (windowConfig) { - showSplash(windowConfig); - }, - beforeLoaderConfig: function (loaderConfig) { - loaderConfig.recordStats = true; - }, - beforeRequire: function () { - performance.mark('code/willLoadWorkbenchMain'); - - // It looks like browsers only lazily enable - // the element when needed. Since we - // leverage canvas elements in our code in many - // locations, we try to help the browser to - // initialize canvas when it is idle, right - // before we wait for the scripts to be loaded. - // @ts-ignore - window.requestIdleCallback(() => { - const canvas = document.createElement('canvas'); - const context = canvas.getContext('2d'); - context.clearRect(0, 0, canvas.width, canvas.height); - canvas.remove(); - }, { timeout: 50 }); - } - } - ); - - //#region Helpers - - /** - * @typedef {import('../../../platform/window/common/window').INativeWindowConfiguration} INativeWindowConfiguration - * @typedef {import('../../../platform/environment/common/argv').NativeParsedArgs} NativeParsedArgs - * - * @returns {{ - * load: ( - * modules: string[], - * resultCallback: (result, configuration: INativeWindowConfiguration & NativeParsedArgs) => unknown, - * options?: { - * configureDeveloperSettings?: (config: INativeWindowConfiguration & NativeParsedArgs) => { - * forceDisableShowDevtoolsOnError?: boolean, - * forceEnableDeveloperKeybindings?: boolean, - * disallowReloadKeybinding?: boolean, - * removeDeveloperKeybindingsAfterLoad?: boolean - * }, - * canModifyDOM?: (config: INativeWindowConfiguration & NativeParsedArgs) => void, - * beforeLoaderConfig?: (loaderConfig: object) => void, - * beforeRequire?: () => void - * } - * ) => Promise - * }} - */ - function bootstrapWindowLib() { - // @ts-ignore (defined in bootstrap-window.js) - return window.MonacoBootstrapWindow; - } - - /** - * @param {INativeWindowConfiguration & NativeParsedArgs} configuration - */ - function showSplash(configuration) { - performance.mark('code/willShowPartsSplash'); - - let data = configuration.partsSplash; - - if (data) { - // high contrast mode has been turned by the OS -> ignore stored colors and layouts - if (configuration.autoDetectHighContrast && configuration.colorScheme.highContrast) { - if ((configuration.colorScheme.dark && data.baseTheme !== 'hc-black') || (!configuration.colorScheme.dark && data.baseTheme !== 'hc-light')) { - data = undefined; - } - } else if (configuration.autoDetectColorScheme) { - // OS color scheme is tracked and has changed - if ((configuration.colorScheme.dark && data.baseTheme !== 'vs-dark') || (!configuration.colorScheme.dark && data.baseTheme !== 'vs')) { - data = undefined; - } - } - } - - // developing an extension -> ignore stored layouts - if (data && configuration.extensionDevelopmentPath) { - data.layoutInfo = undefined; - } - - // minimal color configuration (works with or without persisted data) - let baseTheme, shellBackground, shellForeground; - if (data) { - baseTheme = data.baseTheme; - shellBackground = data.colorInfo.editorBackground; - shellForeground = data.colorInfo.foreground; - } else if (configuration.autoDetectHighContrast && configuration.colorScheme.highContrast) { - if (configuration.colorScheme.dark) { - baseTheme = 'hc-black'; - shellBackground = '#000000'; - shellForeground = '#FFFFFF'; - } else { - baseTheme = 'hc-light'; - shellBackground = '#FFFFFF'; - shellForeground = '#000000'; - } - } else if (configuration.autoDetectColorScheme) { - if (configuration.colorScheme.dark) { - baseTheme = 'vs-dark'; - shellBackground = '#1E1E1E'; - shellForeground = '#CCCCCC'; - } else { - baseTheme = 'vs'; - shellBackground = '#FFFFFF'; - shellForeground = '#000000'; - } - } - - const style = document.createElement('style'); - style.className = 'initialShellColors'; - document.head.appendChild(style); - style.textContent = `body { background-color: ${shellBackground}; color: ${shellForeground}; margin: 0; padding: 0; }`; - - // restore parts if possible (we might not always store layout info) - if (data?.layoutInfo) { - const { layoutInfo, colorInfo } = data; - - const splash = document.createElement('div'); - splash.id = 'monaco-parts-splash'; - splash.className = baseTheme; - - if (layoutInfo.windowBorder) { - splash.style.position = 'relative'; - splash.style.height = 'calc(100vh - 2px)'; - splash.style.width = 'calc(100vw - 2px)'; - splash.style.border = '1px solid var(--window-border-color)'; - splash.style.setProperty('--window-border-color', colorInfo.windowBorder); - - if (layoutInfo.windowBorderRadius) { - splash.style.borderRadius = layoutInfo.windowBorderRadius; - } - } - - // ensure there is enough space - layoutInfo.sideBarWidth = Math.min(layoutInfo.sideBarWidth, window.innerWidth - (layoutInfo.activityBarWidth + layoutInfo.editorPartMinWidth)); - - // part: title - const titleDiv = document.createElement('div'); - titleDiv.setAttribute('style', `position: absolute; width: 100%; left: 0; top: 0; height: ${layoutInfo.titleBarHeight}px; background-color: ${colorInfo.titleBarBackground}; -webkit-app-region: drag;`); - splash.appendChild(titleDiv); - - // part: activity bar - const activityDiv = document.createElement('div'); - activityDiv.setAttribute('style', `position: absolute; height: calc(100% - ${layoutInfo.titleBarHeight}px); top: ${layoutInfo.titleBarHeight}px; ${layoutInfo.sideBarSide}: 0; width: ${layoutInfo.activityBarWidth}px; background-color: ${colorInfo.activityBarBackground};`); - splash.appendChild(activityDiv); - - // part: side bar (only when opening workspace/folder) - // folder or workspace -> status bar color, sidebar - if (configuration.workspace) { - const sideDiv = document.createElement('div'); - sideDiv.setAttribute('style', `position: absolute; height: calc(100% - ${layoutInfo.titleBarHeight}px); top: ${layoutInfo.titleBarHeight}px; ${layoutInfo.sideBarSide}: ${layoutInfo.activityBarWidth}px; width: ${layoutInfo.sideBarWidth}px; background-color: ${colorInfo.sideBarBackground};`); - splash.appendChild(sideDiv); - } - - // part: statusbar - const statusDiv = document.createElement('div'); - statusDiv.setAttribute('style', `position: absolute; width: 100%; bottom: 0; left: 0; height: ${layoutInfo.statusBarHeight}px; background-color: ${configuration.workspace ? colorInfo.statusBarBackground : colorInfo.statusBarNoFolderBackground};`); - splash.appendChild(statusDiv); - - document.body.appendChild(splash); - } - - performance.mark('code/didShowPartsSplash'); - } - - //#endregion -}()); diff --git a/src/vs/code/electron-sandbox/workbench/workbench.js b/src/vs/code/electron-sandbox/workbench/workbench.js index e271fdf1bf4..0af36c6e1ac 100644 --- a/src/vs/code/electron-sandbox/workbench/workbench.js +++ b/src/vs/code/electron-sandbox/workbench/workbench.js @@ -16,10 +16,10 @@ // Load workbench main JS, CSS and NLS all in parallel. This is an // optimization to prevent a waterfall of loading to happen, because - // we know for a fact that workbench.desktop.sandbox.main will depend on + // we know for a fact that workbench.desktop.main will depend on // the related CSS and NLS counterparts. bootstrapWindow.load([ - 'vs/workbench/workbench.desktop.sandbox.main', + 'vs/workbench/workbench.desktop.main', 'vs/nls!vs/workbench/workbench.desktop.main', 'vs/css!vs/workbench/workbench.desktop.main' ], @@ -61,7 +61,7 @@ window.requestIdleCallback(() => { const canvas = document.createElement('canvas'); const context = canvas.getContext('2d'); - context.clearRect(0, 0, canvas.width, canvas.height); + context?.clearRect(0, 0, canvas.width, canvas.height); canvas.remove(); }, { timeout: 50 }); } diff --git a/src/vs/platform/environment/common/argv.ts b/src/vs/platform/environment/common/argv.ts index aa9c2407af0..0e8ccc14714 100644 --- a/src/vs/platform/environment/common/argv.ts +++ b/src/vs/platform/environment/common/argv.ts @@ -86,7 +86,6 @@ export interface NativeParsedArgs { 'force-user-env'?: boolean; 'force-disable-user-env'?: boolean; 'sync'?: 'on' | 'off'; - '__sandbox'?: boolean; 'logsPath'?: string; '__enable-file-policy'?: boolean; editSessionId?: string; diff --git a/src/vs/platform/environment/electron-main/environmentMainService.ts b/src/vs/platform/environment/electron-main/environmentMainService.ts index 6834b8115fe..53aabe4147c 100644 --- a/src/vs/platform/environment/electron-main/environmentMainService.ts +++ b/src/vs/platform/environment/electron-main/environmentMainService.ts @@ -34,7 +34,6 @@ export interface IEnvironmentMainService extends INativeEnvironmentService { mainLockfile: string; // --- config - sandbox: boolean; disableUpdates: boolean; } @@ -55,9 +54,6 @@ export class EnvironmentMainService extends NativeEnvironmentService implements @memoize get mainLockfile(): string { return join(this.userDataPath, 'code.lock'); } - @memoize - get sandbox(): boolean { return !!this.args['__sandbox']; } - @memoize get disableUpdates(): boolean { return !!this.args['disable-updates']; } diff --git a/src/vs/platform/environment/node/argv.ts b/src/vs/platform/environment/node/argv.ts index bb409289757..e27a89390c2 100644 --- a/src/vs/platform/environment/node/argv.ts +++ b/src/vs/platform/environment/node/argv.ts @@ -124,7 +124,6 @@ export const OPTIONS: OptionDescriptions> = { 'force-user-env': { type: 'boolean' }, 'force-disable-user-env': { type: 'boolean' }, 'open-devtools': { type: 'boolean' }, - '__sandbox': { type: 'boolean' }, 'logsPath': { type: 'string' }, '__enable-file-policy': { type: 'boolean' }, 'editSessionId': { type: 'string' }, diff --git a/src/vs/platform/window/common/window.ts b/src/vs/platform/window/common/window.ts index 1b68d3a166f..39b7fbba2c0 100644 --- a/src/vs/platform/window/common/window.ts +++ b/src/vs/platform/window/common/window.ts @@ -135,6 +135,7 @@ export interface IWindowSettings { readonly enableMenuBarMnemonics: boolean; readonly closeWhenEmpty: boolean; readonly clickThroughInactive: boolean; + readonly experimental?: { useSandbox: boolean }; } interface IWindowBorderColors { diff --git a/src/vs/platform/windows/electron-main/window.ts b/src/vs/platform/windows/electron-main/window.ts index f2a671d7b97..216d743026f 100644 --- a/src/vs/platform/windows/electron-main/window.ts +++ b/src/vs/platform/windows/electron-main/window.ts @@ -205,7 +205,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { // Enable experimental css highlight api https://chromestatus.com/feature/5436441440026624 // Refs https://github.com/microsoft/vscode/issues/140098 enableBlinkFeatures: 'HighlightAPI', - ...this.environmentMainService.sandbox ? + ...windowSettings?.experimental?.useSandbox ? // Sandbox { @@ -800,10 +800,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { this.readyState = ReadyState.NAVIGATING; // Load URL - this._win.loadURL(FileAccess.asBrowserUri(this.environmentMainService.sandbox ? - 'vs/code/electron-sandbox/workbench/workbench.html' : - 'vs/code/electron-browser/workbench/workbench.html', require - ).toString(true)); + this._win.loadURL(FileAccess.asBrowserUri('vs/code/electron-sandbox/workbench/workbench.html', require).toString(true)); // Remember that we did load const wasLoaded = this.wasLoaded; diff --git a/src/vs/workbench/browser/workbench.ts b/src/vs/workbench/browser/workbench.ts index 8094c87aca2..d505032b79a 100644 --- a/src/vs/workbench/browser/workbench.ts +++ b/src/vs/workbench/browser/workbench.ts @@ -188,11 +188,8 @@ export class Workbench extends Layout { // // NOTE: Please do NOT register services here. Use `registerSingleton()` // from `workbench.common.main.ts` if the service is shared between - // native and web or `workbench.sandbox.main.ts` if the service - // is native only. - // - // DO NOT add services to `workbench.desktop.main.ts`, always add - // to `workbench.sandbox.main.ts` to support our Electron sandbox + // desktop and web or `workbench.desktop.main.ts` if the service + // is desktop only. // // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! diff --git a/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts b/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts index f64e267746c..b3c51e8a568 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts @@ -77,6 +77,7 @@ import { UnsupportedExtensionsMigrationContrib } from 'vs/workbench/contrib/exte import { isWeb } from 'vs/base/common/platform'; import { ExtensionStorageService } from 'vs/platform/extensionManagement/common/extensionStorage'; import { IStorageService } from 'vs/platform/storage/common/storage'; +import product from 'vs/platform/product/common/product'; // Singletons registerSingleton(IExtensionsWorkbenchService, ExtensionsWorkbenchService); @@ -228,7 +229,7 @@ Registry.as(ConfigurationExtensions.Configuration) 'extensions.experimental.useUtilityProcess': { type: 'boolean', description: localize('extensionsUseUtilityProcess', "When enabled, the extension host will be launched using the new UtilityProcess Electron API."), - default: false + default: product.quality === 'stable' ? false : true // disabled by default in stable for now }, [WORKSPACE_TRUST_EXTENSION_SUPPORT]: { type: 'object', diff --git a/src/vs/workbench/contrib/relauncher/browser/relauncher.contribution.ts b/src/vs/workbench/contrib/relauncher/browser/relauncher.contribution.ts index 148c6c8d379..1680881aeb1 100644 --- a/src/vs/workbench/contrib/relauncher/browser/relauncher.contribution.ts +++ b/src/vs/workbench/contrib/relauncher/browser/relauncher.contribution.ts @@ -26,7 +26,7 @@ interface IConfiguration extends IWindowsConfiguration { debug?: { console?: { wordWrap?: boolean } }; editor?: { accessibilitySupport?: 'on' | 'off' | 'auto' }; security?: { workspace?: { trust?: { enabled?: boolean } } }; - window: IWindowSettings & { experimental?: { windowControlsOverlay?: { enabled?: boolean } } }; + window: IWindowSettings & { experimental?: { windowControlsOverlay?: { enabled?: boolean }; useSandbox?: boolean } }; workbench?: { experimental?: { settingsProfiles?: { enabled?: boolean } } }; } @@ -34,6 +34,7 @@ export class SettingsChangeRelauncher extends Disposable implements IWorkbenchCo private titleBarStyle: 'native' | 'custom' | undefined; private windowControlsOverlayEnabled: boolean | undefined; + private windowSandboxEnabled: boolean | undefined; private nativeTabs: boolean | undefined; private nativeFullScreen: boolean | undefined; private clickThroughInactive: boolean | undefined; @@ -66,11 +67,16 @@ export class SettingsChangeRelauncher extends Disposable implements IWorkbenchCo } // Windows: Window Controls Overlay - if (isWindows && typeof config.window?.experimental?.windowControlsOverlay?.enabled === 'boolean' && config.window?.experimental?.windowControlsOverlay?.enabled !== this.windowControlsOverlayEnabled) { + if (isWindows && typeof config.window?.experimental?.windowControlsOverlay?.enabled === 'boolean' && config.window.experimental.windowControlsOverlay.enabled !== this.windowControlsOverlayEnabled) { this.windowControlsOverlayEnabled = config.window.experimental.windowControlsOverlay.enabled; changed = true; } + // Windows: Sandbox + if (typeof config.window?.experimental?.useSandbox === 'boolean' && config.window.experimental.useSandbox !== this.windowSandboxEnabled) { + this.windowSandboxEnabled = config.window.experimental.useSandbox; + changed = true; + } // macOS: Native tabs if (isMacintosh && typeof config.window?.nativeTabs === 'boolean' && config.window.nativeTabs !== this.nativeTabs) { diff --git a/src/vs/workbench/electron-sandbox/desktop.contribution.ts b/src/vs/workbench/electron-sandbox/desktop.contribution.ts index 15bcde982e2..9e045e9638c 100644 --- a/src/vs/workbench/electron-sandbox/desktop.contribution.ts +++ b/src/vs/workbench/electron-sandbox/desktop.contribution.ts @@ -237,7 +237,12 @@ import { ModifierKeyEmitter } from 'vs/base/browser/dom'; 'scope': ConfigurationScope.APPLICATION, 'description': localize('window.clickThroughInactive', "If enabled, clicking on an inactive window will both activate the window and trigger the element under the mouse if it is clickable. If disabled, clicking anywhere on an inactive window will activate it only and a second click is required on the element."), 'included': isMacintosh - } + }, + 'window.experimental.useSandbox': { + type: 'boolean', + description: localize('experimentalUseSandbox', "Experimental: When enabled, the window will have sandbox mode enabled via Electron API."), + default: false + }, } }); diff --git a/src/vs/workbench/electron-sandbox/desktop.main.ts b/src/vs/workbench/electron-sandbox/desktop.main.ts index 86706f54945..706079b5ea7 100644 --- a/src/vs/workbench/electron-sandbox/desktop.main.ts +++ b/src/vs/workbench/electron-sandbox/desktop.main.ts @@ -148,12 +148,9 @@ export class DesktopMain extends Disposable { // // NOTE: Please do NOT register services here. Use `registerSingleton()` // from `workbench.common.main.ts` if the service is shared between - // desktop and web or `workbench.sandbox.main.ts` if the service + // desktop and web or `workbench.desktop.main.ts` if the service // is desktop only. // - // DO NOT add services to `workbench.desktop.main.ts`, always add - // to `workbench.sandbox.main.ts` to support our Electron sandbox - // // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! @@ -205,12 +202,9 @@ export class DesktopMain extends Disposable { // // NOTE: Please do NOT register services here. Use `registerSingleton()` // from `workbench.common.main.ts` if the service is shared between - // desktop and web or `workbench.sandbox.main.ts` if the service + // desktop and web or `workbench.desktop.main.ts` if the service // is desktop only. // - // DO NOT add services to `workbench.desktop.main.ts`, always add - // to `workbench.sandbox.main.ts` to support our Electron sandbox - // // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! @@ -250,12 +244,9 @@ export class DesktopMain extends Disposable { // // NOTE: Please do NOT register services here. Use `registerSingleton()` // from `workbench.common.main.ts` if the service is shared between - // desktop and web or `workbench.sandbox.main.ts` if the service + // desktop and web or `workbench.desktop.main.ts` if the service // is desktop only. // - // DO NOT add services to `workbench.desktop.main.ts`, always add - // to `workbench.sandbox.main.ts` to support our Electron sandbox - // // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! @@ -306,12 +297,9 @@ export class DesktopMain extends Disposable { // // NOTE: Please do NOT register services here. Use `registerSingleton()` // from `workbench.common.main.ts` if the service is shared between - // desktop and web or `workbench.sandbox.main.ts` if the service + // desktop and web or `workbench.desktop.main.ts` if the service // is desktop only. // - // DO NOT add services to `workbench.desktop.main.ts`, always add - // to `workbench.sandbox.main.ts` to support our Electron sandbox - // // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! diff --git a/src/vs/workbench/services/extensions/electron-browser/nativeExtensionService.ts b/src/vs/workbench/services/extensions/electron-browser/nativeExtensionService.ts deleted file mode 100644 index 2e4c745a9f8..00000000000 --- a/src/vs/workbench/services/extensions/electron-browser/nativeExtensionService.ts +++ /dev/null @@ -1,20 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { ExtensionHostKind, ExtensionRunningLocation, IExtensionHost, IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; -import { NativeLocalProcessExtensionHost } from 'vs/workbench/services/extensions/electron-browser/nativeLocalProcessExtensionHost'; -import { ElectronExtensionService } from 'vs/workbench/services/extensions/electron-sandbox/electronExtensionService'; - -export class NativeExtensionService extends ElectronExtensionService { - protected override _createExtensionHost(runningLocation: ExtensionRunningLocation, isInitialStart: boolean): IExtensionHost | null { - if (runningLocation.kind === ExtensionHostKind.LocalProcess) { - return this._instantiationService.createInstance(NativeLocalProcessExtensionHost, runningLocation, this._createLocalExtensionHostDataProvider(isInitialStart, runningLocation)); - } - return super._createExtensionHost(runningLocation, isInitialStart); - } -} - -registerSingleton(IExtensionService, NativeExtensionService); diff --git a/src/vs/workbench/services/extensions/electron-browser/nativeLocalProcessExtensionHost.ts b/src/vs/workbench/services/extensions/electron-sandbox/nativeLocalProcessExtensionHost.ts similarity index 88% rename from src/vs/workbench/services/extensions/electron-browser/nativeLocalProcessExtensionHost.ts rename to src/vs/workbench/services/extensions/electron-sandbox/nativeLocalProcessExtensionHost.ts index 888db160609..35d0657b669 100644 --- a/src/vs/workbench/services/extensions/electron-browser/nativeLocalProcessExtensionHost.ts +++ b/src/vs/workbench/services/extensions/electron-sandbox/nativeLocalProcessExtensionHost.ts @@ -3,7 +3,9 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { createServer, Server } from 'net'; +/* eslint-disable code-import-patterns */ +/* eslint-disable code-layering */ + import { Disposable, toDisposable } from 'vs/base/common/lifecycle'; import * as platform from 'vs/base/common/platform'; import { StopWatch } from 'vs/base/common/stopwatch'; @@ -15,11 +17,12 @@ import { ILogService } from 'vs/platform/log/common/log'; import { IPCExtHostConnection, writeExtHostConnection } from 'vs/workbench/services/extensions/common/extensionHostEnv'; import { createMessageOfType, MessageType } from 'vs/workbench/services/extensions/common/extensionHostProtocol'; import { ExtensionHostProcess, ExtHostMessagePortCommunication, IExtHostCommunication, SandboxLocalProcessExtensionHost } from 'vs/workbench/services/extensions/electron-sandbox/localProcessExtensionHost'; +import { process } from 'vs/base/parts/sandbox/electron-sandbox/globals'; export class NativeLocalProcessExtensionHost extends SandboxLocalProcessExtensionHost { protected override async _start(): Promise { const canUseUtilityProcess = await this._extensionHostStarter.canUseUtilityProcess(); - if (canUseUtilityProcess && this._configurationService.getValue('extensions.experimental.useUtilityProcess')) { + if (canUseUtilityProcess && (this._configurationService.getValue('extensions.experimental.useUtilityProcess') || process.sandboxed)) { const communication = this._toDispose.add(new ExtHostMessagePortCommunication(this._logService)); return this._startWithCommunication(communication); } else { @@ -31,7 +34,7 @@ export class NativeLocalProcessExtensionHost extends SandboxLocalProcessExtensio interface INamedPipePreparedData { pipeName: string; - namedPipeServer: Server; + namedPipeServer: import('net').Server; } class ExtHostNamedPipeCommunication extends Disposable implements IExtHostCommunication { @@ -44,8 +47,9 @@ class ExtHostNamedPipeCommunication extends Disposable implements IExtHostCommun super(); } - prepare(): Promise { - return new Promise<{ pipeName: string; namedPipeServer: Server }>((resolve, reject) => { + async prepare(): Promise { + const { createServer } = await import('net'); + return new Promise<{ pipeName: string; namedPipeServer: import('net').Server }>((resolve, reject) => { const pipeName = createRandomIPCHandle(); const namedPipeServer = createServer(); diff --git a/src/vs/workbench/services/extensions/electron-sandbox/sandboxExtensionService.ts b/src/vs/workbench/services/extensions/electron-sandbox/sandboxExtensionService.ts index ea51d7abc8f..58e5c5bf71c 100644 --- a/src/vs/workbench/services/extensions/electron-sandbox/sandboxExtensionService.ts +++ b/src/vs/workbench/services/extensions/electron-sandbox/sandboxExtensionService.ts @@ -4,10 +4,19 @@ *--------------------------------------------------------------------------------------------*/ import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; +import { ExtensionHostKind, ExtensionRunningLocation, IExtensionHost, IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { ElectronExtensionService } from 'vs/workbench/services/extensions/electron-sandbox/electronExtensionService'; +import { NativeLocalProcessExtensionHost } from 'vs/workbench/services/extensions/electron-sandbox/nativeLocalProcessExtensionHost'; +import { process } from 'vs/base/parts/sandbox/electron-sandbox/globals'; export class SandboxExtensionService extends ElectronExtensionService { + protected override _createExtensionHost(runningLocation: ExtensionRunningLocation, isInitialStart: boolean): IExtensionHost | null { + if (!process.sandboxed && runningLocation.kind === ExtensionHostKind.LocalProcess) { + // TODO@bpasero remove me once electron utility process has landed + return this._instantiationService.createInstance(NativeLocalProcessExtensionHost, runningLocation, this._createLocalExtensionHostDataProvider(isInitialStart, runningLocation)); + } + return super._createExtensionHost(runningLocation, isInitialStart); + } } registerSingleton(IExtensionService, SandboxExtensionService); diff --git a/src/vs/workbench/workbench.desktop.main.ts b/src/vs/workbench/workbench.desktop.main.ts index 6b7b44d4155..8831bf9469b 100644 --- a/src/vs/workbench/workbench.desktop.main.ts +++ b/src/vs/workbench/workbench.desktop.main.ts @@ -4,51 +4,157 @@ *--------------------------------------------------------------------------------------------*/ -// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -// -// NOTE: Please do NOT register services here. Use `registerSingleton()` -// from `workbench.common.main.ts` if the service is shared between -// desktop and web or `workbench.sandbox.main.ts` if the service -// is desktop only. -// -// The `node` & `electron-browser` layer is deprecated for workbench! -// -// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// ####################################################################### +// ### ### +// ### !!! PLEASE ADD COMMON IMPORTS INTO WORKBENCH.COMMON.MAIN.TS !!! ### +// ### ### +// ####################################################################### + +//#region --- workbench common + +import 'vs/workbench/workbench.common.main'; + +//#endregion -//#region --- workbench common & sandbox +//#region --- workbench (desktop main) -import 'vs/workbench/workbench.sandbox.main'; +import 'vs/workbench/electron-sandbox/desktop.main'; +import 'vs/workbench/electron-sandbox/desktop.contribution'; + +//#endregion + + +//#region --- workbench parts + +import 'vs/workbench/electron-sandbox/parts/dialogs/dialog.contribution'; //#endregion //#region --- workbench services +import 'vs/workbench/services/textfile/electron-sandbox/nativeTextFileService'; +import 'vs/workbench/services/dialogs/electron-sandbox/fileDialogService'; +import 'vs/workbench/services/workspaces/electron-sandbox/workspacesService'; +import 'vs/workbench/services/textMate/browser/nativeTextMateService'; +import 'vs/workbench/services/menubar/electron-sandbox/menubarService'; +import 'vs/workbench/services/issue/electron-sandbox/issueService'; +import 'vs/workbench/services/update/electron-sandbox/updateService'; +import 'vs/workbench/services/url/electron-sandbox/urlService'; +import 'vs/workbench/services/lifecycle/electron-sandbox/lifecycleService'; +import 'vs/workbench/services/title/electron-sandbox/titleService'; +import 'vs/workbench/services/host/electron-sandbox/nativeHostService'; +import 'vs/workbench/services/request/electron-sandbox/requestService'; +import 'vs/workbench/services/extensionResourceLoader/electron-sandbox/extensionResourceLoaderService'; +import 'vs/workbench/services/clipboard/electron-sandbox/clipboardService'; +import 'vs/workbench/services/contextmenu/electron-sandbox/contextmenuService'; +import 'vs/workbench/services/workspaces/electron-sandbox/workspaceEditingService'; +import 'vs/workbench/services/configurationResolver/electron-sandbox/configurationResolverService'; +import 'vs/workbench/services/accessibility/electron-sandbox/accessibilityService'; +import 'vs/workbench/services/path/electron-sandbox/pathService'; +import 'vs/workbench/services/themes/electron-sandbox/nativeHostColorSchemeService'; +import 'vs/workbench/services/extensionManagement/electron-sandbox/extensionManagementService'; +import 'vs/workbench/services/extensionManagement/electron-sandbox/extensionUrlTrustService'; +import 'vs/workbench/services/credentials/electron-sandbox/credentialsService'; +import 'vs/workbench/services/encryption/electron-sandbox/encryptionService'; +import 'vs/workbench/services/localization/electron-sandbox/languagePackService'; +import 'vs/workbench/services/telemetry/electron-sandbox/telemetryService'; +import 'vs/workbench/services/extensions/electron-sandbox/extensionHostStarter'; +import 'vs/platform/extensionManagement/electron-sandbox/extensionsScannerService'; +import 'vs/workbench/services/extensionManagement/electron-sandbox/extensionManagementServerService'; +import 'vs/workbench/services/extensionManagement/electron-sandbox/extensionTipsService'; +import 'vs/workbench/services/userDataSync/electron-sandbox/userDataSyncMachinesService'; +import 'vs/workbench/services/userDataSync/electron-sandbox/userDataSyncService'; +import 'vs/workbench/services/userDataSync/electron-sandbox/userDataSyncAccountService'; +import 'vs/workbench/services/userDataSync/electron-sandbox/userDataSyncStoreManagementService'; +import 'vs/workbench/services/userDataSync/electron-sandbox/userDataAutoSyncService'; +import 'vs/workbench/services/timer/electron-sandbox/timerService'; +import 'vs/workbench/services/environment/electron-sandbox/shellEnvironmentService'; +import 'vs/workbench/services/integrity/electron-sandbox/integrityService'; +import 'vs/workbench/services/workingCopy/electron-sandbox/workingCopyBackupService'; +import 'vs/workbench/services/checksum/electron-sandbox/checksumService'; +import 'vs/platform/remote/electron-sandbox/sharedProcessTunnelService'; +import 'vs/workbench/services/tunnel/electron-sandbox/tunnelService'; +import 'vs/platform/diagnostics/electron-sandbox/diagnosticsService'; +import 'vs/platform/profiling/electron-sandbox/profilingService'; +import 'vs/platform/telemetry/electron-sandbox/customEndpointTelemetryService'; +import 'vs/workbench/services/files/electron-sandbox/elevatedFileService'; +import 'vs/workbench/services/search/electron-sandbox/searchService'; +import 'vs/workbench/services/workingCopy/electron-sandbox/workingCopyHistoryService'; +import 'vs/workbench/services/userDataSync/browser/userDataSyncEnablementService'; +import 'vs/workbench/services/extensions/electron-sandbox/sandboxExtensionService'; -// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -// -// NOTE: Please do NOT register services here. Use `registerSingleton()` -// from `workbench.common.main.ts` if the service is shared between -// desktop and web or `workbench.sandbox.main.ts` if the service -// is desktop only. -// -// The `node` & `electron-browser` layer is deprecated for workbench! -// -// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - -import 'vs/workbench/services/extensions/electron-browser/nativeExtensionService'; - -// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -// -// NOTE: Please do NOT register services here. Use `registerSingleton()` -// from `workbench.common.main.ts` if the service is shared between -// desktop and web or `workbench.sandbox.main.ts` if the service -// is desktop only. -// -// The `node` & `electron-browser` layer is deprecated for workbench! -// -// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { IUserDataInitializationService, UserDataInitializationService } from 'vs/workbench/services/userData/browser/userDataInit'; +registerSingleton(IUserDataInitializationService, UserDataInitializationService); + +//#endregion + + +//#region --- workbench contributions + +// Logs +import 'vs/workbench/contrib/logs/electron-sandbox/logs.contribution'; + +// Localizations +import 'vs/workbench/contrib/localization/electron-sandbox/localization.contribution'; + +// Explorer +import 'vs/workbench/contrib/files/electron-sandbox/files.contribution'; +import 'vs/workbench/contrib/files/electron-sandbox/fileActions.contribution'; + +// CodeEditor Contributions +import 'vs/workbench/contrib/codeEditor/electron-sandbox/codeEditor.contribution'; + +// Debug +import 'vs/workbench/contrib/debug/electron-sandbox/extensionHostDebugService'; + +// Extensions Management +import 'vs/workbench/contrib/extensions/electron-sandbox/extensions.contribution'; + +// Issues +import 'vs/workbench/contrib/issue/electron-sandbox/issue.contribution'; + +// Remote +import 'vs/workbench/contrib/remote/electron-sandbox/remote.contribution'; + +// Configuration Exporter +import 'vs/workbench/contrib/configExporter/electron-sandbox/configurationExportHelper.contribution'; + +// Terminal +import 'vs/workbench/contrib/terminal/electron-sandbox/terminal.contribution'; + +// Themes Support +import 'vs/workbench/contrib/themes/browser/themes.test.contribution'; + +// User Data Sync +import 'vs/workbench/contrib/userDataSync/electron-sandbox/userDataSync.contribution'; + +// Output +import 'vs/workbench/contrib/output/electron-sandbox/outputChannelModelService'; + +// Tags +import 'vs/workbench/contrib/tags/electron-sandbox/workspaceTagsService'; +import 'vs/workbench/contrib/tags/electron-sandbox/tags.contribution'; + +// Performance +import 'vs/workbench/contrib/performance/electron-sandbox/performance.contribution'; + +// Tasks +import 'vs/workbench/contrib/tasks/electron-sandbox/taskService'; + +// External terminal +import 'vs/workbench/contrib/externalTerminal/electron-sandbox/externalTerminal.contribution'; + +// Webview +import 'vs/workbench/contrib/webview/electron-sandbox/webview.contribution'; + +// Splash +import 'vs/workbench/contrib/splash/electron-sandbox/splash.contribution'; + +// Local History +import 'vs/workbench/contrib/localHistory/electron-sandbox/localHistory.contribution'; //#endregion diff --git a/src/vs/workbench/workbench.desktop.sandbox.main.ts b/src/vs/workbench/workbench.desktop.sandbox.main.ts deleted file mode 100644 index 894e6785212..00000000000 --- a/src/vs/workbench/workbench.desktop.sandbox.main.ts +++ /dev/null @@ -1,32 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - - -// ####################################################################### -// ### ### -// ### !!! PLEASE ADD COMMON IMPORTS INTO WORKBENCH.COMMON.MAIN.TS !!! ### -// ### ### -// ####################################################################### - - -//#region --- workbench common & sandbox - -import 'vs/workbench/workbench.sandbox.main'; - -//#endregion - - -//#region --- workbench (desktop main) - -import 'vs/workbench/electron-sandbox/desktop.main'; - -//#endregion - - -//#region --- workbench services - -import 'vs/workbench/services/extensions/electron-sandbox/sandboxExtensionService'; - -//#endregion diff --git a/src/vs/workbench/workbench.sandbox.main.ts b/src/vs/workbench/workbench.sandbox.main.ts deleted file mode 100644 index dd9ddd715b1..00000000000 --- a/src/vs/workbench/workbench.sandbox.main.ts +++ /dev/null @@ -1,159 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - - -// ####################################################################### -// ### ### -// ### !!! PLEASE ADD COMMON IMPORTS INTO WORKBENCH.COMMON.MAIN.TS !!! ### -// ### ### -// ####################################################################### - -//#region --- workbench common - -import 'vs/workbench/workbench.common.main'; - -//#endregion - - -//#region --- workbench (desktop main) - -import 'vs/workbench/electron-sandbox/desktop.main'; -import 'vs/workbench/electron-sandbox/desktop.contribution'; - -//#endregion - - -//#region --- workbench parts - -import 'vs/workbench/electron-sandbox/parts/dialogs/dialog.contribution'; - -//#endregion - - -//#region --- workbench services - -import 'vs/workbench/services/textfile/electron-sandbox/nativeTextFileService'; -import 'vs/workbench/services/dialogs/electron-sandbox/fileDialogService'; -import 'vs/workbench/services/workspaces/electron-sandbox/workspacesService'; -import 'vs/workbench/services/textMate/browser/nativeTextMateService'; -import 'vs/workbench/services/menubar/electron-sandbox/menubarService'; -import 'vs/workbench/services/issue/electron-sandbox/issueService'; -import 'vs/workbench/services/update/electron-sandbox/updateService'; -import 'vs/workbench/services/url/electron-sandbox/urlService'; -import 'vs/workbench/services/lifecycle/electron-sandbox/lifecycleService'; -import 'vs/workbench/services/title/electron-sandbox/titleService'; -import 'vs/workbench/services/host/electron-sandbox/nativeHostService'; -import 'vs/workbench/services/request/electron-sandbox/requestService'; -import 'vs/workbench/services/extensionResourceLoader/electron-sandbox/extensionResourceLoaderService'; -import 'vs/workbench/services/clipboard/electron-sandbox/clipboardService'; -import 'vs/workbench/services/contextmenu/electron-sandbox/contextmenuService'; -import 'vs/workbench/services/workspaces/electron-sandbox/workspaceEditingService'; -import 'vs/workbench/services/configurationResolver/electron-sandbox/configurationResolverService'; -import 'vs/workbench/services/accessibility/electron-sandbox/accessibilityService'; -import 'vs/workbench/services/path/electron-sandbox/pathService'; -import 'vs/workbench/services/themes/electron-sandbox/nativeHostColorSchemeService'; -import 'vs/workbench/services/extensionManagement/electron-sandbox/extensionManagementService'; -import 'vs/workbench/services/extensionManagement/electron-sandbox/extensionUrlTrustService'; -import 'vs/workbench/services/credentials/electron-sandbox/credentialsService'; -import 'vs/workbench/services/encryption/electron-sandbox/encryptionService'; -import 'vs/workbench/services/localization/electron-sandbox/languagePackService'; -import 'vs/workbench/services/telemetry/electron-sandbox/telemetryService'; -import 'vs/workbench/services/extensions/electron-sandbox/extensionHostStarter'; -import 'vs/platform/extensionManagement/electron-sandbox/extensionsScannerService'; -import 'vs/workbench/services/extensionManagement/electron-sandbox/extensionManagementServerService'; -import 'vs/workbench/services/extensionManagement/electron-sandbox/extensionTipsService'; -import 'vs/workbench/services/userDataSync/electron-sandbox/userDataSyncMachinesService'; -import 'vs/workbench/services/userDataSync/electron-sandbox/userDataSyncService'; -import 'vs/workbench/services/userDataSync/electron-sandbox/userDataSyncAccountService'; -import 'vs/workbench/services/userDataSync/electron-sandbox/userDataSyncStoreManagementService'; -import 'vs/workbench/services/userDataSync/electron-sandbox/userDataAutoSyncService'; -import 'vs/workbench/services/timer/electron-sandbox/timerService'; -import 'vs/workbench/services/environment/electron-sandbox/shellEnvironmentService'; -import 'vs/workbench/services/integrity/electron-sandbox/integrityService'; -import 'vs/workbench/services/workingCopy/electron-sandbox/workingCopyBackupService'; -import 'vs/workbench/services/checksum/electron-sandbox/checksumService'; -import 'vs/platform/remote/electron-sandbox/sharedProcessTunnelService'; -import 'vs/workbench/services/tunnel/electron-sandbox/tunnelService'; -import 'vs/platform/diagnostics/electron-sandbox/diagnosticsService'; -import 'vs/platform/profiling/electron-sandbox/profilingService'; -import 'vs/platform/telemetry/electron-sandbox/customEndpointTelemetryService'; -import 'vs/workbench/services/files/electron-sandbox/elevatedFileService'; -import 'vs/workbench/services/search/electron-sandbox/searchService'; -import 'vs/workbench/services/workingCopy/electron-sandbox/workingCopyHistoryService'; -import 'vs/workbench/services/userDataSync/browser/userDataSyncEnablementService'; - -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { IUserDataInitializationService, UserDataInitializationService } from 'vs/workbench/services/userData/browser/userDataInit'; - -registerSingleton(IUserDataInitializationService, UserDataInitializationService); - -//#endregion - - -//#region --- workbench contributions - -// Logs -import 'vs/workbench/contrib/logs/electron-sandbox/logs.contribution'; - -// Localizations -import 'vs/workbench/contrib/localization/electron-sandbox/localization.contribution'; - -// Explorer -import 'vs/workbench/contrib/files/electron-sandbox/files.contribution'; -import 'vs/workbench/contrib/files/electron-sandbox/fileActions.contribution'; - -// CodeEditor Contributions -import 'vs/workbench/contrib/codeEditor/electron-sandbox/codeEditor.contribution'; - -// Debug -import 'vs/workbench/contrib/debug/electron-sandbox/extensionHostDebugService'; - -// Extensions Management -import 'vs/workbench/contrib/extensions/electron-sandbox/extensions.contribution'; - -// Issues -import 'vs/workbench/contrib/issue/electron-sandbox/issue.contribution'; - -// Remote -import 'vs/workbench/contrib/remote/electron-sandbox/remote.contribution'; - -// Configuration Exporter -import 'vs/workbench/contrib/configExporter/electron-sandbox/configurationExportHelper.contribution'; - -// Terminal -import 'vs/workbench/contrib/terminal/electron-sandbox/terminal.contribution'; - -// Themes Support -import 'vs/workbench/contrib/themes/browser/themes.test.contribution'; - -// User Data Sync -import 'vs/workbench/contrib/userDataSync/electron-sandbox/userDataSync.contribution'; - -// Output -import 'vs/workbench/contrib/output/electron-sandbox/outputChannelModelService'; - -// Tags -import 'vs/workbench/contrib/tags/electron-sandbox/workspaceTagsService'; -import 'vs/workbench/contrib/tags/electron-sandbox/tags.contribution'; - -// Performance -import 'vs/workbench/contrib/performance/electron-sandbox/performance.contribution'; - -// Tasks -import 'vs/workbench/contrib/tasks/electron-sandbox/taskService'; - -// External terminal -import 'vs/workbench/contrib/externalTerminal/electron-sandbox/externalTerminal.contribution'; - -// Webview -import 'vs/workbench/contrib/webview/electron-sandbox/webview.contribution'; - -// Splash -import 'vs/workbench/contrib/splash/electron-sandbox/splash.contribution'; - -// Local History -import 'vs/workbench/contrib/localHistory/electron-sandbox/localHistory.contribution'; - -//#endregion From a365f655a84e10f1377151bc2ea230e5d1037cc7 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 5 Jul 2022 11:33:56 +0200 Subject: [PATCH 236/347] Fix #151370 (#154144) --- .../extensionManagement/common/extensionsScannerService.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/vs/platform/extensionManagement/common/extensionsScannerService.ts b/src/vs/platform/extensionManagement/common/extensionsScannerService.ts index 29a0264d9cc..e166e75fd6e 100644 --- a/src/vs/platform/extensionManagement/common/extensionsScannerService.ts +++ b/src/vs/platform/extensionManagement/common/extensionsScannerService.ts @@ -512,7 +512,9 @@ class ExtensionsScanner extends Disposable { const extensionScannerInput = new ExtensionScannerInput(c.resource, input.mtime, input.applicationExtensionslocation, input.applicationExtensionslocationMtime, input.profile, input.type, input.excludeObsolete, input.validate, input.productVersion, input.productDate, input.productCommit, input.devMode, input.language, input.translations); return this.scanExtension(extensionScannerInput); })); - return coalesce(extensions); + return coalesce(extensions) + // Sort: Make sure extensions are in the same order always. Helps cache invalidation even if the order changes. + .sort((a, b) => a.location.path < b.location.path ? -1 : 1); } private async scanExtensionsFromProfile(input: ExtensionScannerInput): Promise { From d508c2c2e439995a557e98d30f4748c6155ac794 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Tue, 5 Jul 2022 11:54:31 +0200 Subject: [PATCH 237/347] Improves observable name. --- .../contrib/mergeEditor/browser/model/mergeEditorModel.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/mergeEditor/browser/model/mergeEditorModel.ts b/src/vs/workbench/contrib/mergeEditor/browser/model/mergeEditorModel.ts index 6bf21e30d44..06a3dcbf827 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/model/mergeEditorModel.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/model/mergeEditorModel.ts @@ -62,7 +62,7 @@ export class MergeEditorModel extends EditorModel { private readonly modifiedBaseRangeStateStores = derived('modifiedBaseRangeStateStores', reader => { const map = new Map( - this.modifiedBaseRanges.read(reader).map(s => ([s, observableValue('State', ModifiedBaseRangeState.default)])) + this.modifiedBaseRanges.read(reader).map(s => ([s, observableValue(`BaseRangeState${s.baseRange}`, ModifiedBaseRangeState.default)])) ); return map; }); @@ -70,7 +70,7 @@ export class MergeEditorModel extends EditorModel { private readonly modifiedBaseRangeHandlingStateStores = derived('modifiedBaseRangeHandlingStateStores', reader => { const map = new Map( - this.modifiedBaseRanges.read(reader).map(s => ([s, observableValue('State', false)])) + this.modifiedBaseRanges.read(reader).map(s => ([s, observableValue(`BaseRangeHandledState${s.baseRange}`, false)])) ); return map; }); From c86b009309aaca9ab18d977df578949cac16bcec Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Tue, 5 Jul 2022 12:48:45 +0200 Subject: [PATCH 238/347] Fixes merge editor bug, improves testing infrastructure and adds test. --- .../mergeEditor/browser/commands/commands.ts | 28 ++++ .../browser/commands/devCommands.ts | 9 +- .../browser/mergeEditor.contribution.ts | 3 +- .../mergeEditor/browser/mergeEditorInput.ts | 3 + .../browser/model/mergeEditorModel.ts | 9 +- .../browser/model/modifiedBaseRange.ts | 18 ++- .../mergeEditor/test/browser/model.test.ts | 132 +++++++++++++++--- 7 files changed, 172 insertions(+), 30 deletions(-) diff --git a/src/vs/workbench/contrib/mergeEditor/browser/commands/commands.ts b/src/vs/workbench/contrib/mergeEditor/browser/commands/commands.ts index 7e100501342..892febf378e 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/commands/commands.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/commands/commands.ts @@ -10,6 +10,7 @@ import { ILocalizedString } from 'vs/platform/action/common/action'; import { Action2, MenuId } from 'vs/platform/actions/common/actions'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { IOpenerService } from 'vs/platform/opener/common/opener'; import { API_OPEN_DIFF_EDITOR_COMMAND_ID } from 'vs/workbench/browser/parts/editor/editorCommands'; import { MergeEditorInput, MergeEditorInputData } from 'vs/workbench/contrib/mergeEditor/browser/mergeEditorInput'; import { MergeEditor } from 'vs/workbench/contrib/mergeEditor/browser/view/mergeEditor'; @@ -350,3 +351,30 @@ function mergeEditorCompare(editorService: IEditorService, commandService: IComm function openDiffEditor(commandService: ICommandService, left: URI, right: URI, label?: string) { commandService.executeCommand(API_OPEN_DIFF_EDITOR_COMMAND_ID, left, right, label); } + +export class OpenBaseFile extends Action2 { + constructor() { + super({ + id: 'merge.openBaseEditor', + category: mergeEditorCategory, + title: { + value: localize('merge.openBaseEditor', 'Open Base File'), + original: 'Open Base File', + }, + f1: true, + precondition: ctxIsMergeEditor, + }); + } + + run(accessor: ServicesAccessor): void { + const openerService = accessor.get(IOpenerService); + const { activeEditorPane } = accessor.get(IEditorService); + if (activeEditorPane instanceof MergeEditor) { + const vm = activeEditorPane.viewModel.get(); + if (!vm) { + return; + } + openerService.open(vm.model.base.uri); + } + } +} diff --git a/src/vs/workbench/contrib/mergeEditor/browser/commands/devCommands.ts b/src/vs/workbench/contrib/mergeEditor/browser/commands/devCommands.ts index aaf15c771da..6728dc93b1a 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/commands/devCommands.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/commands/devCommands.ts @@ -29,7 +29,6 @@ interface MergeEditorContents { } export class MergeEditorCopyContentsToJSON extends Action2 { - constructor() { super({ id: 'merge.dev.copyContents', @@ -81,7 +80,6 @@ export class MergeEditorCopyContentsToJSON extends Action2 { } export class MergeEditorOpenContents extends Action2 { - constructor() { super({ id: 'merge.dev.openContents', @@ -110,11 +108,14 @@ export class MergeEditorOpenContents extends Action2 { prompt: localize('mergeEditor.enterJSON', 'Enter JSON'), value: await clipboardService.readText(), }); - if (!result) { + if (result === undefined) { return; } - const content: MergeEditorContents = JSON.parse(result); + const content: MergeEditorContents = + result !== '' + ? JSON.parse(result) + : { base: '', input1: '', input2: '', result: '', languageId: 'plaintext' }; const scheme = 'merge-editor-dev'; diff --git a/src/vs/workbench/contrib/mergeEditor/browser/mergeEditor.contribution.ts b/src/vs/workbench/contrib/mergeEditor/browser/mergeEditor.contribution.ts index 136249c41fa..8dc07e6463f 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/mergeEditor.contribution.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/mergeEditor.contribution.ts @@ -9,7 +9,7 @@ import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { Registry } from 'vs/platform/registry/common/platform'; import { EditorPaneDescriptor, IEditorPaneRegistry } from 'vs/workbench/browser/editor'; import { EditorExtensions, IEditorFactoryRegistry } from 'vs/workbench/common/editor'; -import { CompareInput1WithBaseCommand, CompareInput2WithBaseCommand, GoToNextConflict, GoToPreviousConflict, OpenMergeEditor, ToggleActiveConflictInput1, ToggleActiveConflictInput2, SetColumnLayout, SetMixedLayout } from 'vs/workbench/contrib/mergeEditor/browser/commands/commands'; +import { CompareInput1WithBaseCommand, CompareInput2WithBaseCommand, GoToNextConflict, GoToPreviousConflict, OpenMergeEditor, ToggleActiveConflictInput1, ToggleActiveConflictInput2, SetColumnLayout, SetMixedLayout, OpenBaseFile } from 'vs/workbench/contrib/mergeEditor/browser/commands/commands'; import { MergeEditorCopyContentsToJSON, MergeEditorOpenContents } from 'vs/workbench/contrib/mergeEditor/browser/commands/devCommands'; import { MergeEditorInput } from 'vs/workbench/contrib/mergeEditor/browser/mergeEditorInput'; import { MergeEditor } from 'vs/workbench/contrib/mergeEditor/browser/view/mergeEditor'; @@ -34,6 +34,7 @@ Registry.as(EditorExtensions.EditorFactory).registerEdit registerAction2(SetMixedLayout); registerAction2(SetColumnLayout); registerAction2(OpenMergeEditor); +registerAction2(OpenBaseFile); registerAction2(MergeEditorCopyContentsToJSON); registerAction2(MergeEditorOpenContents); diff --git a/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInput.ts b/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInput.ts index 660d10cb487..053c7309754 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInput.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInput.ts @@ -113,6 +113,9 @@ export class MergeEditorInput extends AbstractTextResourceEditorInput implements this.input2.description, result.object.textEditorModel, this._instaService.createInstance(EditorWorkerServiceDiffComputer), + { + resetUnknownOnInitialization: true + }, ); await this._model.onInitialized; diff --git a/src/vs/workbench/contrib/mergeEditor/browser/model/mergeEditorModel.ts b/src/vs/workbench/contrib/mergeEditor/browser/model/mergeEditorModel.ts index 06a3dcbf827..255615448d3 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/model/mergeEditorModel.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/model/mergeEditorModel.ts @@ -134,6 +134,7 @@ export class MergeEditorModel extends EditorModel { readonly input2Description: string | undefined, readonly result: ITextModel, private readonly diffComputer: IDiffComputer, + options: { resetUnknownOnInitialization: boolean }, @IModelService private readonly modelService: IModelService, @ILanguageService private readonly languageService: ILanguageService, ) { @@ -183,9 +184,11 @@ export class MergeEditorModel extends EditorModel { ) ); - this.onInitialized.then(() => { - this.resetUnknown(); - }); + if (options.resetUnknownOnInitialization) { + this.onInitialized.then(() => { + this.resetUnknown(); + }); + } } public getRangeInResult(baseRange: LineRange, reader?: IReader): LineRange { diff --git a/src/vs/workbench/contrib/mergeEditor/browser/model/modifiedBaseRange.ts b/src/vs/workbench/contrib/mergeEditor/browser/model/modifiedBaseRange.ts index 028b9afe986..2e6b6031382 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/model/modifiedBaseRange.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/model/modifiedBaseRange.ts @@ -281,21 +281,29 @@ export class ModifiedBaseRangeState { } public toString(): string { - const arr: ('1' | '2')[] = []; + const arr: string[] = []; if (this.input1) { - arr.push('1'); + arr.push('1✓'); } if (this.input2) { - arr.push('2'); + arr.push('2✓'); } if (this.input2First) { arr.reverse(); } + if (this.conflicting) { + arr.push('conflicting'); + } return arr.join(','); } - equals(newState: ModifiedBaseRangeState): boolean { - return this.input1 === newState.input1 && this.input2 === newState.input2 && this.input2First === newState.input2First; + equals(other: ModifiedBaseRangeState): boolean { + return ( + this.input1 === other.input1 && + this.input2 === other.input2 && + this.input2First === other.input2First && + this.conflicting === other.conflicting + ); } } diff --git a/src/vs/workbench/contrib/mergeEditor/test/browser/model.test.ts b/src/vs/workbench/contrib/mergeEditor/test/browser/model.test.ts index ea1a9794545..ebef4581ab6 100644 --- a/src/vs/workbench/contrib/mergeEditor/test/browser/model.test.ts +++ b/src/vs/workbench/contrib/mergeEditor/test/browser/model.test.ts @@ -8,7 +8,7 @@ import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { transaction } from 'vs/base/common/observable'; import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; import { Range } from 'vs/editor/common/core/range'; -import { ITextModel } from 'vs/editor/common/model'; +import { EndOfLinePreference, ITextModel } from 'vs/editor/common/model'; import { EditorSimpleWorker } from 'vs/editor/common/services/editorSimpleWorker'; import { createModelServices, createTextModel } from 'vs/editor/test/common/testTextModel'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -29,9 +29,10 @@ suite('merge editor model', () => { }, model => { assert.deepStrictEqual(model.getProjections(), { - base: '⟦⟧₀line1\nline2', - input1: '⟦0\n⟧₀line1\nline2', - input2: '⟦0\n⟧₀line1\nline2', + base: ['⟦⟧₀line1', 'line2'], + input1: ['⟦0', '⟧₀line1', 'line2'], + input2: ['⟦0', '⟧₀line1', 'line2'], + result: ['⟦⟧{conflicting}₀'], }); model.toggleConflict(0, 1); @@ -59,7 +60,12 @@ suite('merge editor model', () => { "result": "" }, model => { - assert.deepStrictEqual(model.getProjections(), ({ base: "⟦⟧₀", input1: "⟦input1⟧₀", input2: "⟦input2⟧₀" })); + assert.deepStrictEqual(model.getProjections(), { + base: ['⟦⟧₀'], + input1: ['⟦input1⟧₀'], + input2: ['⟦input2⟧₀'], + result: ['⟦⟧{}₀'], + }); model.toggleConflict(0, 1); assert.deepStrictEqual( @@ -87,9 +93,10 @@ suite('merge editor model', () => { }, model => { assert.deepStrictEqual(model.getProjections(), { - base: '⟦hello⟧₀', - input1: '⟦hallo⟧₀', - input2: '⟦helloworld⟧₀', + base: ['⟦hello⟧₀'], + input1: ['⟦hallo⟧₀'], + input2: ['⟦helloworld⟧₀'], + result: ['⟦⟧{conflicting}₀'], }); model.toggleConflict(0, 1); @@ -115,11 +122,34 @@ suite('merge editor model', () => { }, model => { assert.deepStrictEqual(model.getProjections(), { - base: 'Zürich\nBern\n⟦Basel\n⟧₀Chur\n⟦⟧₁Genf\nThun⟦⟧₂', - input1: - 'Zürich\nBern\n⟦⟧₀Chur\n⟦Davos\n⟧₁Genf\nThun\n⟦function f(b:boolean) {}⟧₂', - input2: - 'Zürich\nBern\n⟦Basel (FCB)\n⟧₀Chur\n⟦⟧₁Genf\nThun\n⟦function f(a:number) {}⟧₂', + base: ['Zürich', 'Bern', '⟦Basel', '⟧₀Chur', '⟦⟧₁Genf', 'Thun⟦⟧₂'], + input1: [ + 'Zürich', + 'Bern', + '⟦⟧₀Chur', + '⟦Davos', + '⟧₁Genf', + 'Thun', + '⟦function f(b:boolean) {}⟧₂', + ], + input2: [ + 'Zürich', + 'Bern', + '⟦Basel (FCB)', + '⟧₀Chur', + '⟦⟧₁Genf', + 'Thun', + '⟦function f(a:number) {}⟧₂', + ], + result: [ + 'Zürich', + 'Bern', + '⟦Basel', + '⟧{}₀Chur', + '⟦Davos', + '⟧{1✓}₁Genf', + 'Thun⟦⟧{}₂', + ], }); model.toggleConflict(2, 1); @@ -135,6 +165,61 @@ suite('merge editor model', () => { } ); }); + + test('conflicts are reset', async () => { + await testMergeModel( + { + "languageId": "typescript", + "base": "import { h } from 'vs/base/browser/dom';\nimport { Disposable, IDisposable } from 'vs/base/common/lifecycle';\nimport { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\nimport { autorun, IReader, observableFromEvent, ObservableValue } from 'vs/workbench/contrib/audioCues/browser/observable';\nimport { LineRange } from 'vs/workbench/contrib/mergeEditor/browser/model/lineRange';\n", + "input1": "import { h } from 'vs/base/browser/dom';\nimport { Disposable, IDisposable } from 'vs/base/common/lifecycle';\nimport { observableSignalFromEvent } from 'vs/base/common/observable';\nimport { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';\nimport { autorun, IReader, observableFromEvent } from 'vs/workbench/contrib/audioCues/browser/observable';\nimport { LineRange } from 'vs/workbench/contrib/mergeEditor/browser/model/lineRange';\n", + "input2": "import { h } from 'vs/base/browser/dom';\nimport { Disposable, IDisposable } from 'vs/base/common/lifecycle';\nimport { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';\nimport { autorun, IReader, observableFromEvent, ObservableValue } from 'vs/workbench/contrib/audioCues/browser/observable';\nimport { LineRange } from 'vs/workbench/contrib/mergeEditor/browser/model/lineRange';\n", + "result": "import { h } from 'vs/base/browser/dom';\r\nimport { Disposable, IDisposable } from 'vs/base/common/lifecycle';\r\nimport { observableSignalFromEvent } from 'vs/base/common/observable';\r\nimport { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';\r\n<<<<<<< Updated upstream\r\nimport { autorun, IReader, observableFromEvent, ObservableValue } from 'vs/workbench/contrib/audioCues/browser/observable';\r\n=======\r\nimport { autorun, IReader, observableFromEvent } from 'vs/workbench/contrib/audioCues/browser/observable';\r\n>>>>>>> Stashed changes\r\nimport { LineRange } from 'vs/workbench/contrib/mergeEditor/browser/model/lineRange';\r\n" + }, + model => { + assert.deepStrictEqual(model.getProjections(), { + base: [ + "import { h } from 'vs/base/browser/dom';", + "import { Disposable, IDisposable } from 'vs/base/common/lifecycle';", + "⟦⟧₀import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';", + "⟦import { EditorOption } from 'vs/editor/common/config/editorOptions';", + "import { autorun, IReader, observableFromEvent, ObservableValue } from 'vs/workbench/contrib/audioCues/browser/observable';", + "⟧₁import { LineRange } from 'vs/workbench/contrib/mergeEditor/browser/model/lineRange';", + '', + ], + input1: [ + "import { h } from 'vs/base/browser/dom';", + "import { Disposable, IDisposable } from 'vs/base/common/lifecycle';", + "⟦import { observableSignalFromEvent } from 'vs/base/common/observable';", + "⟧₀import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';", + "⟦import { autorun, IReader, observableFromEvent } from 'vs/workbench/contrib/audioCues/browser/observable';", + "⟧₁import { LineRange } from 'vs/workbench/contrib/mergeEditor/browser/model/lineRange';", + '', + ], + input2: [ + "import { h } from 'vs/base/browser/dom';", + "import { Disposable, IDisposable } from 'vs/base/common/lifecycle';", + "⟦⟧₀import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';", + "⟦import { autorun, IReader, observableFromEvent, ObservableValue } from 'vs/workbench/contrib/audioCues/browser/observable';", + "⟧₁import { LineRange } from 'vs/workbench/contrib/mergeEditor/browser/model/lineRange';", + '', + ], + result: [ + "import { h } from 'vs/base/browser/dom';", + "import { Disposable, IDisposable } from 'vs/base/common/lifecycle';", + "⟦import { observableSignalFromEvent } from 'vs/base/common/observable';", + "⟧{1✓}₀import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';", + '⟦<<<<<<< Updated upstream', + "import { autorun, IReader, observableFromEvent, ObservableValue } from 'vs/workbench/contrib/audioCues/browser/observable';", + '=======', + "import { autorun, IReader, observableFromEvent } from 'vs/workbench/contrib/audioCues/browser/observable';", + '>>>>>>> Stashed changes', + "⟧{conflicting}₁import { LineRange } from 'vs/workbench/contrib/mergeEditor/browser/model/lineRange';", + '', + ], + }); + } + ); + }); }); async function testMergeModel( @@ -197,7 +282,9 @@ class MergeModelInterface extends Disposable { ), }; }, - } + }, { + resetUnknownOnInitialization: false + } )); } @@ -241,14 +328,25 @@ class MergeModelInterface extends Disposable { })) ); + const resultTextModel = createTextModel(this.mergeModel.result.getValue()); + applyRanges( + resultTextModel, + baseRanges.map((r, idx) => ({ + range: this.mergeModel.getRangeInResult(r.baseRange).toRange(), + label: `{${this.mergeModel.getState(r).get()}}${toSmallNumbersDec(idx)}`, + })) + ); + const result = { - base: baseTextModel.getValue(), - input1: input1TextModel.getValue(), - input2: input2TextModel.getValue(), + base: baseTextModel.getValue(EndOfLinePreference.LF).split('\n'), + input1: input1TextModel.getValue(EndOfLinePreference.LF).split('\n'), + input2: input2TextModel.getValue(EndOfLinePreference.LF).split('\n'), + result: resultTextModel.getValue(EndOfLinePreference.LF).split('\n'), }; baseTextModel.dispose(); input1TextModel.dispose(); input2TextModel.dispose(); + resultTextModel.dispose(); return result; } From 1c5723822a33d7c40913f98d8a2f639b40e7f8ad Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Tue, 5 Jul 2022 14:51:34 +0200 Subject: [PATCH 239/347] Comments editor should respect autoClosingBrackets (#154154) Fixes #150003 --- src/vs/workbench/contrib/comments/browser/commentNode.ts | 2 +- src/vs/workbench/contrib/comments/browser/commentReply.ts | 4 +++- .../workbench/contrib/comments/browser/simpleCommentEditor.ts | 4 +++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/comments/browser/commentNode.ts b/src/vs/workbench/contrib/comments/browser/commentNode.ts index d1d118f5c15..450c76ae8ad 100644 --- a/src/vs/workbench/contrib/comments/browser/commentNode.ts +++ b/src/vs/workbench/contrib/comments/browser/commentNode.ts @@ -382,7 +382,7 @@ export class CommentNode extends Disposable { private createCommentEditor(editContainer: HTMLElement): void { const container = dom.append(editContainer, dom.$('.edit-textarea')); - this._commentEditor = this.instantiationService.createInstance(SimpleCommentEditor, container, SimpleCommentEditor.getEditorOptions(), this.parentThread); + this._commentEditor = this.instantiationService.createInstance(SimpleCommentEditor, container, SimpleCommentEditor.getEditorOptions(this.configurationService), this.parentThread); const resource = URI.parse(`comment:commentinput-${this.comment.uniqueIdInThread}-${Date.now()}.md`); this._commentEditorModel = this.modelService.createModel('', this.languageService.createByFilepathOrFirstLine(resource), resource, false); diff --git a/src/vs/workbench/contrib/comments/browser/commentReply.ts b/src/vs/workbench/contrib/comments/browser/commentReply.ts index 0905db307c3..8fe2a07420e 100644 --- a/src/vs/workbench/contrib/comments/browser/commentReply.ts +++ b/src/vs/workbench/contrib/comments/browser/commentReply.ts @@ -17,6 +17,7 @@ import { ILanguageService } from 'vs/editor/common/languages/language'; import { ITextModel } from 'vs/editor/common/model'; import { IModelService } from 'vs/editor/common/services/model'; import * as nls from 'vs/nls'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { editorForeground, resolveColorValue } from 'vs/platform/theme/common/colorRegistry'; @@ -58,11 +59,12 @@ export class CommentReply extends Disposable { @ILanguageService private languageService: ILanguageService, @IModelService private modelService: IModelService, @IThemeService private themeService: IThemeService, + @IConfigurationService configurationService: IConfigurationService ) { super(); this.form = dom.append(container, dom.$('.comment-form')); - this.commentEditor = this._register(this._scopedInstatiationService.createInstance(SimpleCommentEditor, this.form, SimpleCommentEditor.getEditorOptions(), this._parentThread)); + this.commentEditor = this._register(this._scopedInstatiationService.createInstance(SimpleCommentEditor, this.form, SimpleCommentEditor.getEditorOptions(configurationService), this._parentThread)); this.commentEditorIsEmpty = CommentContextKeys.commentIsEmpty.bindTo(this._contextKeyService); this.commentEditorIsEmpty.set(!this._pendingComment); diff --git a/src/vs/workbench/contrib/comments/browser/simpleCommentEditor.ts b/src/vs/workbench/contrib/comments/browser/simpleCommentEditor.ts index 4a69955fd4a..c4ec1bbf5e3 100644 --- a/src/vs/workbench/contrib/comments/browser/simpleCommentEditor.ts +++ b/src/vs/workbench/contrib/comments/browser/simpleCommentEditor.ts @@ -24,6 +24,7 @@ import { ICommentThreadWidget } from 'vs/workbench/contrib/comments/common/comme import { CommentContextKeys } from 'vs/workbench/contrib/comments/common/commentContextKeys'; import { ILanguageConfigurationService } from 'vs/editor/common/languages/languageConfigurationRegistry'; import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; export const ctxCommentEditorFocused = new RawContextKey('commentEditorFocused', false); @@ -79,7 +80,7 @@ export class SimpleCommentEditor extends CodeEditorWidget { return EditorExtensionsRegistry.getEditorActions(); } - public static getEditorOptions(): IEditorOptions { + public static getEditorOptions(configurationService: IConfigurationService): IEditorOptions { return { wordWrap: 'on', glyphMargin: false, @@ -103,6 +104,7 @@ export class SimpleCommentEditor extends CodeEditorWidget { minimap: { enabled: false }, + autoClosingBrackets: configurationService.getValue('editor.autoClosingBrackets'), quickSuggestions: false }; } From 25cf08709abc75b73db7732ff03800189ca9cff9 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Tue, 5 Jul 2022 06:38:02 -0700 Subject: [PATCH 240/347] Add ellipsis to recent command/dir commands Fixes #153905 --- src/vs/workbench/contrib/terminal/browser/terminalActions.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index ed78d4a79e8..0c70784c0e3 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -307,7 +307,7 @@ export function registerTerminalActions() { constructor() { super({ id: TerminalCommandId.RunRecentCommand, - title: { value: localize('workbench.action.terminal.runRecentCommand', "Run Recent Command"), original: 'Run Recent Command' }, + title: { value: localize('workbench.action.terminal.runRecentCommand', "Run Recent Command..."), original: 'Run Recent Command...' }, f1: true, category, precondition: ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated) @@ -331,7 +331,7 @@ export function registerTerminalActions() { constructor() { super({ id: TerminalCommandId.GoToRecentDirectory, - title: { value: localize('workbench.action.terminal.goToRecentDirectory', "Go to Recent Directory"), original: 'Go to Recent Directory' }, + title: { value: localize('workbench.action.terminal.goToRecentDirectory', "Go to Recent Directory..."), original: 'Go to Recent Directory...' }, f1: true, category, precondition: ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated) From 406aa3e7e6a63f68e7ecd68d6ea628b8b0e740d9 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Tue, 5 Jul 2022 07:40:36 -0700 Subject: [PATCH 241/347] Enable auto shell integration by default Fixes #154161 --- .../workbench/contrib/terminal/common/terminalConfiguration.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts b/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts index efe3aa79bd3..83a67239048 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts @@ -536,7 +536,7 @@ const terminalConfiguration: IConfigurationNode = { restricted: true, markdownDescription: localize('terminal.integrated.shellIntegration.enabled', "Enable features like enhanced command tracking and current working directory detection. \n\nShell integration works by injecting the shell with a startup script. The script gives VS Code insight into what is happening within the terminal.\n\nSupported shells:\n\n- Linux/macOS: bash, pwsh, zsh\n - Windows: pwsh\n\nThis setting applies only when terminals are created, so you will need to restart your terminals for it to take effect.\n\n Note that the script injection may not work if you have custom arguments defined in the terminal profile, a [complex bash `PROMPT_COMMAND`](https://code.visualstudio.com/docs/editor/integrated-terminal#_complex-bash-promptcommand), or other unsupported setup."), type: 'boolean', - default: false + default: true }, [TerminalSettingId.ShellIntegrationDecorationsEnabled]: { restricted: true, From 3fc3965c15b5e22014636a5be08f2cbdb7e05bec Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Tue, 5 Jul 2022 07:54:19 -0700 Subject: [PATCH 242/347] Support detecting eslint compact link format in term Fixes #154165 --- .../contrib/terminal/browser/links/terminalLocalLinkDetector.ts | 2 +- .../test/browser/links/terminalLocalLinkDetector.test.ts | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/browser/links/terminalLocalLinkDetector.ts b/src/vs/workbench/contrib/terminal/browser/links/terminalLocalLinkDetector.ts index 48e5c0659bc..19cab952add 100644 --- a/src/vs/workbench/contrib/terminal/browser/links/terminalLocalLinkDetector.ts +++ b/src/vs/workbench/contrib/terminal/browser/links/terminalLocalLinkDetector.ts @@ -52,7 +52,7 @@ export const lineAndColumnClause = [ '((\\S*)[\'"], line ((\\d+)( column (\\d+))?))', // "(file path)", line 45 [see #40468] '((\\S*)[\'"],((\\d+)(:(\\d+))?))', // "(file path)",45 [see #78205] '((\\S*) on line ((\\d+)(, column (\\d+))?))', // (file path) on line 8, column 13 - '((\\S*):line ((\\d+)(, column (\\d+))?))', // (file path):line 8, column 13 + '((\\S*):\\s?line ((\\d+)(, col(umn)? (\\d+))?))', // (file path):line 8, column 13, (file path): line 8, col 13 '(([^\\s\\(\\)]*)(\\s?[\\(\\[](\\d+)(,\\s?(\\d+))?)[\\)\\]])', // (file path)(45), (file path) (45), (file path)(45,18), (file path) (45,18), (file path)(45, 18), (file path) (45, 18), also with [] '(([^:\\s\\(\\)<>\'\"\\[\\]]*)(:(\\d+))?(:(\\d+))?)' // (file path):336, (file path):336:9 ].join('|').replace(/ /g, `[${'\u00A0'} ]`); diff --git a/src/vs/workbench/contrib/terminal/test/browser/links/terminalLocalLinkDetector.test.ts b/src/vs/workbench/contrib/terminal/test/browser/links/terminalLocalLinkDetector.test.ts index 8ac3607d6e8..9f72ece8c18 100644 --- a/src/vs/workbench/contrib/terminal/test/browser/links/terminalLocalLinkDetector.test.ts +++ b/src/vs/workbench/contrib/terminal/test/browser/links/terminalLocalLinkDetector.test.ts @@ -58,6 +58,8 @@ const supportedLinkFormats: LinkFormatInfo[] = [ { urlFormat: '{0} on line {1}, column {2}', line: '5', column: '3' }, { urlFormat: '{0}:line {1}', line: '5' }, { urlFormat: '{0}:line {1}, column {2}', line: '5', column: '3' }, + { urlFormat: '{0}: line {1}', line: '5' }, + { urlFormat: '{0}: line {1}, col {2}', line: '5', column: '3' }, { urlFormat: '{0}({1})', line: '5' }, { urlFormat: '{0} ({1})', line: '5' }, { urlFormat: '{0}({1},{2})', line: '5', column: '3' }, From 62a2b0509aa29d06f7220d8f3527e67d2b974f2b Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 5 Jul 2022 20:42:05 +0200 Subject: [PATCH 243/347] Clean up in profiles land (#154188) Clean up: - Move preserving data from existing profile to respective components --- .../common/extensionsScannerService.ts | 2 +- .../userDataProfile/common/userDataProfile.ts | 2 +- .../snippets/browser/snippetsService.ts | 7 ++- .../browser/configurationService.ts | 22 ++++++---- .../common/extensionManagement.ts | 3 +- .../extensionManagementServerService.ts | 7 ++- .../common/webExtensionManagementService.ts | 6 +-- .../extensionManagementServerService.ts | 10 +---- .../nativeExtensionManagementService.ts} | 43 +++++++++++-------- .../remoteExtensionManagementService.ts | 15 ++++--- .../keybinding/browser/keybindingService.ts | 15 ++++--- .../browser/userDataProfileManagement.ts | 25 ++--------- 12 files changed, 79 insertions(+), 78 deletions(-) rename src/vs/workbench/services/extensionManagement/{common/profileAwareExtensionManagementService.ts => electron-sandbox/nativeExtensionManagementService.ts} (60%) diff --git a/src/vs/platform/extensionManagement/common/extensionsScannerService.ts b/src/vs/platform/extensionManagement/common/extensionsScannerService.ts index e166e75fd6e..823a0be2541 100644 --- a/src/vs/platform/extensionManagement/common/extensionsScannerService.ts +++ b/src/vs/platform/extensionManagement/common/extensionsScannerService.ts @@ -381,7 +381,7 @@ export abstract class AbstractExtensionsScannerService extends Disposable implem private async createExtensionScannerInput(location: URI, profile: boolean, type: ExtensionType, excludeObsolete: boolean, language: string | undefined, validate: boolean = true): Promise { const translations = await this.getTranslations(language ?? platform.language); const mtime = await this.getMtime(location); - const applicationExtensionsLocation = this.userDataProfilesService.defaultProfile.extensionsResource; + const applicationExtensionsLocation = profile ? this.userDataProfilesService.defaultProfile.extensionsResource : undefined; const applicationExtensionsLocationMtime = applicationExtensionsLocation ? await this.getMtime(applicationExtensionsLocation) : undefined; return new ExtensionScannerInput( location, diff --git a/src/vs/platform/userDataProfile/common/userDataProfile.ts b/src/vs/platform/userDataProfile/common/userDataProfile.ts index 0705d48af4f..949133b32f5 100644 --- a/src/vs/platform/userDataProfile/common/userDataProfile.ts +++ b/src/vs/platform/userDataProfile/common/userDataProfile.ts @@ -104,7 +104,7 @@ export const EXTENSIONS_RESOURCE_NAME = 'extensions.json'; export function toUserDataProfile(name: string, location: URI, useDefaultFlags?: UseDefaultProfileFlags): CustomUserDataProfile { return { - id: hash(location.toString()).toString(16), + id: hash(location.path).toString(16), name: name, location: location, isDefault: false, diff --git a/src/vs/workbench/contrib/snippets/browser/snippetsService.ts b/src/vs/workbench/contrib/snippets/browser/snippetsService.ts index 366ed64536b..abc007e863d 100644 --- a/src/vs/workbench/contrib/snippets/browser/snippetsService.ts +++ b/src/vs/workbench/contrib/snippets/browser/snippetsService.ts @@ -358,7 +358,12 @@ class SnippetsService implements ISnippetsService { await this._initFolderSnippets(SnippetSource.User, userSnippetsFolder, disposables); }; this._disposables.add(disposables); - this._disposables.add(this._userDataProfileService.onDidChangeCurrentProfile(() => this._pendingWork.push(updateUserSnippets()))); + this._disposables.add(this._userDataProfileService.onDidChangeCurrentProfile(e => e.join((async () => { + if (e.preserveData) { + await this._fileService.copy(e.previous.snippetsHome, e.profile.snippetsHome); + } + this._pendingWork.push(updateUserSnippets()); + })()))); await updateUserSnippets(); } diff --git a/src/vs/workbench/services/configuration/browser/configurationService.ts b/src/vs/workbench/services/configuration/browser/configurationService.ts index 72a1946338d..20b7ad38a9a 100644 --- a/src/vs/workbench/services/configuration/browser/configurationService.ts +++ b/src/vs/workbench/services/configuration/browser/configurationService.ts @@ -711,15 +711,21 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat } private onUserDataProfileChanged(e: DidChangeUserDataProfileEvent): void { - const promises: Promise[] = []; - promises.push(this.localUserConfiguration.reset(e.profile.settingsResource, e.profile.tasksResource, getLocalUserConfigurationScopes(e.profile, !!this.remoteUserConfiguration))); - if (e.previous.isDefault !== e.profile.isDefault) { - this.createApplicationConfiguration(); - if (this.applicationConfiguration) { - promises.push(this.reloadApplicationConfiguration(true)); - } - } e.join((async () => { + if (e.preserveData) { + await Promise.all([ + this.fileService.copy(e.previous.settingsResource, e.profile.settingsResource), + this.fileService.copy(e.previous.tasksResource, e.profile.tasksResource) + ]); + } + const promises: Promise[] = []; + promises.push(this.localUserConfiguration.reset(e.profile.settingsResource, e.profile.tasksResource, getLocalUserConfigurationScopes(e.profile, !!this.remoteUserConfiguration))); + if (e.previous.isDefault !== e.profile.isDefault) { + this.createApplicationConfiguration(); + if (this.applicationConfiguration) { + promises.push(this.reloadApplicationConfiguration(true)); + } + } const [localUser, application] = await Promise.all(promises); await this.loadConfiguration(application ?? this._configuration.applicationConfiguration, localUser, this._configuration.remoteUserConfiguration); })()); diff --git a/src/vs/workbench/services/extensionManagement/common/extensionManagement.ts b/src/vs/workbench/services/extensionManagement/common/extensionManagement.ts index 5e3c46b1a5b..9c9683c1c3b 100644 --- a/src/vs/workbench/services/extensionManagement/common/extensionManagement.ts +++ b/src/vs/workbench/services/extensionManagement/common/extensionManagement.ts @@ -13,8 +13,7 @@ import { FileAccess } from 'vs/base/common/network'; export type DidChangeProfileExtensionsEvent = { readonly added: ILocalExtension[]; readonly removed: ILocalExtension[] }; export interface IProfileAwareExtensionManagementService extends IExtensionManagementService { - onDidChangeProfileExtensions: Event; - switchExtensionsProfile(extensionsProfileResource: URI | undefined): Promise; + readonly onDidChangeProfileExtensions: Event; } export interface IExtensionManagementServer { diff --git a/src/vs/workbench/services/extensionManagement/common/extensionManagementServerService.ts b/src/vs/workbench/services/extensionManagement/common/extensionManagementServerService.ts index 233e0bc56c2..b16029ca565 100644 --- a/src/vs/workbench/services/extensionManagement/common/extensionManagementServerService.ts +++ b/src/vs/workbench/services/extensionManagement/common/extensionManagementServerService.ts @@ -7,6 +7,7 @@ import { localize } from 'vs/nls'; import { ExtensionInstallLocation, IExtensionManagementServer, IExtensionManagementServerService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import { Schemas } from 'vs/base/common/network'; +import { Event } from 'vs/base/common/event'; import { IChannel } from 'vs/base/parts/ipc/common/ipc'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ILabelService } from 'vs/platform/label/common/label'; @@ -14,7 +15,7 @@ import { isWeb } from 'vs/base/common/platform'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { WebExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/webExtensionManagementService'; import { IExtension } from 'vs/platform/extensions/common/extensions'; -import { NativeProfileAwareExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/profileAwareExtensionManagementService'; +import { ExtensionManagementChannelClient } from 'vs/platform/extensionManagement/common/extensionManagementIpc'; export class ExtensionManagementServerService implements IExtensionManagementServerService { @@ -31,7 +32,9 @@ export class ExtensionManagementServerService implements IExtensionManagementSer ) { const remoteAgentConnection = remoteAgentService.getConnection(); if (remoteAgentConnection) { - const extensionManagementService = instantiationService.createInstance(NativeProfileAwareExtensionManagementService, remoteAgentConnection.getChannel('extensions'), undefined); + const extensionManagementService = new class extends ExtensionManagementChannelClient { + readonly onDidChangeProfileExtensions = Event.None; + }(remoteAgentConnection.getChannel('extensions')); this.remoteExtensionManagementServer = { id: 'remote', extensionManagementService, diff --git a/src/vs/workbench/services/extensionManagement/common/webExtensionManagementService.ts b/src/vs/workbench/services/extensionManagement/common/webExtensionManagementService.ts index 147936d4468..2c371645082 100644 --- a/src/vs/workbench/services/extensionManagement/common/webExtensionManagementService.ts +++ b/src/vs/workbench/services/extensionManagement/common/webExtensionManagementService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { ExtensionType, IExtension, IExtensionIdentifier, IExtensionManifest, TargetPlatform } from 'vs/platform/extensions/common/extensions'; -import { IExtensionManagementService, ILocalExtension, IGalleryExtension, IGalleryMetadata, InstallOperation, IExtensionGalleryService, InstallOptions, Metadata, UninstallOptions } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { ILocalExtension, IGalleryExtension, IGalleryMetadata, InstallOperation, IExtensionGalleryService, InstallOptions, Metadata, UninstallOptions } from 'vs/platform/extensionManagement/common/extensionManagement'; import { URI } from 'vs/base/common/uri'; import { Event } from 'vs/base/common/event'; import { areSameExtensions, getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; @@ -20,7 +20,7 @@ import { IExtensionsProfileScannerService } from 'vs/platform/extensionManagemen import { IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile'; import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'; -export class WebExtensionManagementService extends AbstractExtensionManagementService implements IExtensionManagementService, IProfileAwareExtensionManagementService { +export class WebExtensionManagementService extends AbstractExtensionManagementService implements IProfileAwareExtensionManagementService { declare readonly _serviceBrand: undefined; @@ -100,8 +100,6 @@ export class WebExtensionManagementService extends AbstractExtensionManagementSe return local; } - async switchExtensionsProfile(extensionsProfileResource: URI | undefined): Promise { } - protected createDefaultInstallExtensionTask(manifest: IExtensionManifest, extension: URI | IGalleryExtension, options: InstallOptions): IInstallExtensionTask { return new InstallExtensionTask(manifest, extension, options, this.webExtensionsScannerService); } diff --git a/src/vs/workbench/services/extensionManagement/electron-sandbox/extensionManagementServerService.ts b/src/vs/workbench/services/extensionManagement/electron-sandbox/extensionManagementServerService.ts index 762987822ee..b6831100888 100644 --- a/src/vs/workbench/services/extensionManagement/electron-sandbox/extensionManagementServerService.ts +++ b/src/vs/workbench/services/extensionManagement/electron-sandbox/extensionManagementServerService.ts @@ -15,7 +15,7 @@ import { ILabelService } from 'vs/platform/label/common/label'; import { IExtension } from 'vs/platform/extensions/common/extensions'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IUserDataProfileService } from 'vs/workbench/services/userDataProfile/common/userDataProfile'; -import { NativeProfileAwareExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/profileAwareExtensionManagementService'; +import { NativeExtensionManagementService } from 'vs/workbench/services/extensionManagement/electron-sandbox/nativeExtensionManagementService'; import { Disposable } from 'vs/base/common/lifecycle'; import { IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile'; @@ -36,14 +36,8 @@ export class ExtensionManagementServerService extends Disposable implements IExt @IInstantiationService instantiationService: IInstantiationService, ) { super(); - const localExtensionManagementService = this._register(instantiationService.createInstance(NativeProfileAwareExtensionManagementService, sharedProcessService.getChannel('extensions'), userDataProfileService.currentProfile.extensionsResource)); + const localExtensionManagementService = this._register(instantiationService.createInstance(NativeExtensionManagementService, sharedProcessService.getChannel('extensions'))); this.localExtensionManagementServer = { extensionManagementService: localExtensionManagementService, id: 'local', label: localize('local', "Local") }; - this._register(userDataProfilesService.onDidChangeProfiles(e => { - if (userDataProfileService.currentProfile.isDefault) { - localExtensionManagementService.extensionsProfileResource = userDataProfilesService.defaultProfile.extensionsResource; - } - })); - this._register(userDataProfileService.onDidChangeCurrentProfile(e => e.join(localExtensionManagementService.switchExtensionsProfile(e.profile.extensionsResource)))); const remoteAgentConnection = remoteAgentService.getConnection(); if (remoteAgentConnection) { const extensionManagementService = instantiationService.createInstance(NativeRemoteExtensionManagementService, remoteAgentConnection.getChannel('extensions'), this.localExtensionManagementServer); diff --git a/src/vs/workbench/services/extensionManagement/common/profileAwareExtensionManagementService.ts b/src/vs/workbench/services/extensionManagement/electron-sandbox/nativeExtensionManagementService.ts similarity index 60% rename from src/vs/workbench/services/extensionManagement/common/profileAwareExtensionManagementService.ts rename to src/vs/workbench/services/extensionManagement/electron-sandbox/nativeExtensionManagementService.ts index b8a639d4e9e..3252281bf30 100644 --- a/src/vs/workbench/services/extensionManagement/common/profileAwareExtensionManagementService.ts +++ b/src/vs/workbench/services/extensionManagement/electron-sandbox/nativeExtensionManagementService.ts @@ -14,8 +14,12 @@ import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity' import { delta } from 'vs/base/common/arrays'; import { compare } from 'vs/base/common/strings'; import { DisposableStore } from 'vs/base/common/lifecycle'; +import { DidChangeUserDataProfileEvent, IUserDataProfileService } from 'vs/workbench/services/userDataProfile/common/userDataProfile'; +import { EXTENSIONS_RESOURCE_NAME } from 'vs/platform/userDataProfile/common/userDataProfile'; +import { joinPath } from 'vs/base/common/resources'; +import { IFileService } from 'vs/platform/files/common/files'; -export class NativeProfileAwareExtensionManagementService extends ExtensionManagementChannelClient implements IProfileAwareExtensionManagementService { +export class NativeExtensionManagementService extends ExtensionManagementChannelClient implements IProfileAwareExtensionManagementService { private readonly disposables = this._register(new DisposableStore()); @@ -31,42 +35,47 @@ export class NativeProfileAwareExtensionManagementService extends ExtensionManag private readonly _onDidChangeProfileExtensions = this._register(new Emitter<{ readonly added: ILocalExtension[]; readonly removed: ILocalExtension[] }>()); readonly onDidChangeProfileExtensions = this._onDidChangeProfileExtensions.event; - constructor(channel: IChannel, public extensionsProfileResource: URI | undefined, + constructor( + channel: IChannel, + @IUserDataProfileService private readonly userDataProfileService: IUserDataProfileService, + @IFileService private readonly fileService: IFileService, @IUriIdentityService private readonly uriIdentityService: IUriIdentityService, ) { super(channel); + this._register(userDataProfileService.onDidChangeCurrentProfile(e => e.join(this.whenProfileChanged(e)))); } private filterEvent({ profileLocation, applicationScoped }: { profileLocation?: URI; applicationScoped?: boolean }): boolean { - return applicationScoped || this.uriIdentityService.extUri.isEqual(this.extensionsProfileResource, profileLocation); + return applicationScoped || this.uriIdentityService.extUri.isEqual(this.userDataProfileService.currentProfile.extensionsResource, profileLocation); } override install(vsix: URI, options?: InstallVSIXOptions): Promise { - return super.install(vsix, { ...options, profileLocation: this.extensionsProfileResource }); + return super.install(vsix, { ...options, profileLocation: this.userDataProfileService.currentProfile.extensionsResource }); } override installFromGallery(extension: IGalleryExtension, installOptions?: InstallOptions): Promise { - return super.installFromGallery(extension, { ...installOptions, profileLocation: this.extensionsProfileResource }); + return super.installFromGallery(extension, { ...installOptions, profileLocation: this.userDataProfileService.currentProfile.extensionsResource }); } override uninstall(extension: ILocalExtension, options?: UninstallOptions): Promise { - return super.uninstall(extension, { ...options, profileLocation: this.extensionsProfileResource }); + return super.uninstall(extension, { ...options, profileLocation: this.userDataProfileService.currentProfile.extensionsResource }); } override getInstalled(type: ExtensionType | null = null): Promise { - return super.getInstalled(type, this.extensionsProfileResource); + return super.getInstalled(type, this.userDataProfileService.currentProfile.extensionsResource); } - async switchExtensionsProfile(extensionsProfileResource: URI | undefined): Promise { - if (this.uriIdentityService.extUri.isEqual(extensionsProfileResource, this.extensionsProfileResource)) { - return; - } - const oldExtensions = await this.getInstalled(ExtensionType.User); - this.extensionsProfileResource = extensionsProfileResource; - const newExtensions = await this.getInstalled(ExtensionType.User); - const { added, removed } = delta(oldExtensions, newExtensions, (a, b) => compare(`${ExtensionIdentifier.toKey(a.identifier.id)}@${a.manifest.version}`, `${ExtensionIdentifier.toKey(b.identifier.id)}@${b.manifest.version}`)); - if (added.length || removed.length) { - this._onDidChangeProfileExtensions.fire({ added, removed }); + private async whenProfileChanged(e: DidChangeUserDataProfileEvent): Promise { + const previousExtensionsResource = e.previous.extensionsResource ?? joinPath(e.previous.location, EXTENSIONS_RESOURCE_NAME); + if (e.preserveData) { + await this.fileService.copy(previousExtensionsResource, e.profile.extensionsResource!); + } else { + const oldExtensions = await super.getInstalled(ExtensionType.User, previousExtensionsResource); + const newExtensions = await this.getInstalled(ExtensionType.User); + const { added, removed } = delta(oldExtensions, newExtensions, (a, b) => compare(`${ExtensionIdentifier.toKey(a.identifier.id)}@${a.manifest.version}`, `${ExtensionIdentifier.toKey(b.identifier.id)}@${b.manifest.version}`)); + if (added.length || removed.length) { + this._onDidChangeProfileExtensions.fire({ added, removed }); + } } } diff --git a/src/vs/workbench/services/extensionManagement/electron-sandbox/remoteExtensionManagementService.ts b/src/vs/workbench/services/extensionManagement/electron-sandbox/remoteExtensionManagementService.ts index 53c178a68f6..b9202112131 100644 --- a/src/vs/workbench/services/extensionManagement/electron-sandbox/remoteExtensionManagementService.ts +++ b/src/vs/workbench/services/extensionManagement/electron-sandbox/remoteExtensionManagementService.ts @@ -4,7 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { IChannel } from 'vs/base/parts/ipc/common/ipc'; -import { IExtensionManagementService, ILocalExtension, IGalleryExtension, IExtensionGalleryService, InstallOperation, InstallOptions, InstallVSIXOptions, ExtensionManagementError, ExtensionManagementErrorCode } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { Event } from 'vs/base/common/event'; +import { ILocalExtension, IGalleryExtension, IExtensionGalleryService, InstallOperation, InstallOptions, InstallVSIXOptions, ExtensionManagementError, ExtensionManagementErrorCode } from 'vs/platform/extensionManagement/common/extensionManagement'; import { URI } from 'vs/base/common/uri'; import { ExtensionType, IExtensionManifest } from 'vs/platform/extensions/common/extensions'; import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; @@ -17,14 +18,15 @@ import { IProductService } from 'vs/platform/product/common/productService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { generateUuid } from 'vs/base/common/uuid'; import { joinPath } from 'vs/base/common/resources'; -import { IExtensionManagementServer } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; +import { IExtensionManagementServer, IProfileAwareExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-sandbox/environmentService'; import { Promises } from 'vs/base/common/async'; import { IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService'; -import { NativeProfileAwareExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/profileAwareExtensionManagementService'; -import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'; +import { ExtensionManagementChannelClient } from 'vs/platform/extensionManagement/common/extensionManagementIpc'; -export class NativeRemoteExtensionManagementService extends NativeProfileAwareExtensionManagementService implements IExtensionManagementService { +export class NativeRemoteExtensionManagementService extends ExtensionManagementChannelClient implements IProfileAwareExtensionManagementService { + + readonly onDidChangeProfileExtensions = Event.None; constructor( channel: IChannel, @@ -35,9 +37,8 @@ export class NativeRemoteExtensionManagementService extends NativeProfileAwareEx @IProductService private readonly productService: IProductService, @INativeWorkbenchEnvironmentService private readonly environmentService: INativeWorkbenchEnvironmentService, @IExtensionManifestPropertiesService private readonly extensionManifestPropertiesService: IExtensionManifestPropertiesService, - @IUriIdentityService uriIdentityService: IUriIdentityService, ) { - super(channel, undefined, uriIdentityService); + super(channel); } override async install(vsix: URI, options?: InstallVSIXOptions): Promise { diff --git a/src/vs/workbench/services/keybinding/browser/keybindingService.ts b/src/vs/workbench/services/keybinding/browser/keybindingService.ts index ccd362686a0..fe4650f771f 100644 --- a/src/vs/workbench/services/keybinding/browser/keybindingService.ts +++ b/src/vs/workbench/services/keybinding/browser/keybindingService.ts @@ -50,7 +50,7 @@ import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { dirname } from 'vs/base/common/resources'; import { getAllUnboundCommands } from 'vs/workbench/services/keybinding/browser/unboundCommands'; import { UserSettingsLabelProvider } from 'vs/base/common/keybindingLabels'; -import { IUserDataProfileService } from 'vs/workbench/services/userDataProfile/common/userDataProfile'; +import { DidChangeUserDataProfileEvent, IUserDataProfileService } from 'vs/workbench/services/userDataProfile/common/userDataProfile'; interface ContributedKeyBinding { command: string; @@ -738,10 +738,15 @@ class UserKeybindings extends Disposable { } })); - this._register(userDataProfileService.onDidChangeCurrentProfile(e => { - this.watch(); - this.reloadConfigurationScheduler.schedule(); - })); + this._register(userDataProfileService.onDidChangeCurrentProfile(e => e.join(this.whenCurrentProfieChanged(e)))); + } + + private async whenCurrentProfieChanged(e: DidChangeUserDataProfileEvent): Promise { + if (e.preserveData) { + await this.fileService.copy(e.previous.keybindingsResource, e.profile.keybindingsResource); + } + this.watch(); + this.reloadConfigurationScheduler.schedule(); } private watch(): void { diff --git a/src/vs/workbench/services/userDataProfile/browser/userDataProfileManagement.ts b/src/vs/workbench/services/userDataProfile/browser/userDataProfileManagement.ts index 2488577017b..ba46d3e24d7 100644 --- a/src/vs/workbench/services/userDataProfile/browser/userDataProfileManagement.ts +++ b/src/vs/workbench/services/userDataProfile/browser/userDataProfileManagement.ts @@ -41,17 +41,6 @@ export class UserDataProfileManagementService extends Disposable implements IUse this._register(userDataProfilesService.onDidChangeProfiles(e => this.onDidChangeProfiles(e))); } - private async checkAndCreateExtensionsProfileResource(): Promise { - if (this.userDataProfileService.currentProfile.extensionsResource) { - return this.userDataProfileService.currentProfile.extensionsResource; - } - if (!this.userDataProfilesService.defaultProfile.extensionsResource) { - // Extensions profile is not yet created for default profile, create it now - return this.createDefaultExtensionsProfile(joinPath(this.userDataProfilesService.defaultProfile.location, EXTENSIONS_RESOURCE_NAME)); - } - throw new Error('Invalid Profile'); - } - private onDidChangeProfiles(e: DidChangeProfilesEvent): void { if (e.removed.some(profile => profile.id === this.userDataProfileService.currentProfile.id)) { this.enterProfile(this.userDataProfilesService.defaultProfile, false, localize('reload message when removed', "The current profile has been removed. Please reload to switch back to default profile")); @@ -65,20 +54,12 @@ export class UserDataProfileManagementService extends Disposable implements IUse async createAndEnterProfile(name: string, useDefaultFlags?: UseDefaultProfileFlags, fromExisting?: boolean): Promise { const workspaceIdentifier = this.getWorkspaceIdentifier(); - const promises: Promise[] = []; const newProfile = this.userDataProfilesService.newProfile(name, useDefaultFlags); await this.fileService.createFolder(newProfile.location); - const extensionsProfileResourcePromise = this.checkAndCreateExtensionsProfileResource(); - promises.push(extensionsProfileResourcePromise); - if (fromExisting) { - // Storage copy is handled by storage service while entering profile - promises.push(this.fileService.copy(this.userDataProfileService.currentProfile.settingsResource, newProfile.settingsResource)); - promises.push((async () => this.fileService.copy(await extensionsProfileResourcePromise, newProfile.extensionsResource))()); - promises.push(this.fileService.copy(this.userDataProfileService.currentProfile.keybindingsResource, newProfile.keybindingsResource)); - promises.push(this.fileService.copy(this.userDataProfileService.currentProfile.tasksResource, newProfile.tasksResource)); - promises.push(this.fileService.copy(this.userDataProfileService.currentProfile.snippetsHome, newProfile.snippetsHome)); + if (!this.userDataProfilesService.defaultProfile.extensionsResource) { + // Extensions profile is not yet created for default profile, create it now + await this.createDefaultExtensionsProfile(joinPath(this.userDataProfilesService.defaultProfile.location, EXTENSIONS_RESOURCE_NAME)); } - await Promise.allSettled(promises); const createdProfile = await this.userDataProfilesService.createProfile(newProfile, workspaceIdentifier); await this.enterProfile(createdProfile, !!fromExisting); return createdProfile; From 510a74fc2cceae1461a26e958699c58c26ee573e Mon Sep 17 00:00:00 2001 From: Logan Ramos Date: Tue, 5 Jul 2022 14:42:46 -0400 Subject: [PATCH 244/347] Update UTC flags properly for 1DS (#154189) Update UTC flags properly for 1DS (#154187) Ensure internal flag isn't applied to non internal data --- .../sharedProcess/sharedProcessMain.ts | 2 +- .../platform/telemetry/browser/1dsAppender.ts | 4 +++- src/vs/platform/telemetry/common/1dsAppender.ts | 17 +++++++++++------ src/vs/platform/telemetry/node/1dsAppender.ts | 4 +++- .../telemetry/browser/telemetryService.ts | 2 +- 5 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts index 11116cc4cce..4d77d394a3a 100644 --- a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts +++ b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts @@ -283,7 +283,7 @@ class SharedProcessMain extends Disposable { const { installSourcePath } = environmentService; const internalTesting = configurationService.getValue('telemetry.internalTesting'); if (internalTesting && productService.aiConfig?.ariaKey) { - const collectorAppender = new OneDataSystemWebAppender('monacoworkbench', null, productService.aiConfig.ariaKey); + const collectorAppender = new OneDataSystemWebAppender(configurationService, 'monacoworkbench', null, productService.aiConfig.ariaKey); this._register(toDisposable(() => collectorAppender.flush())); // Ensure the 1DS appender is disposed so that it flushes remaining data appenders.push(collectorAppender); } else if (productService.aiConfig && productService.aiConfig.asimovKey) { diff --git a/src/vs/platform/telemetry/browser/1dsAppender.ts b/src/vs/platform/telemetry/browser/1dsAppender.ts index 93bf07cdbb6..96db1e7890b 100644 --- a/src/vs/platform/telemetry/browser/1dsAppender.ts +++ b/src/vs/platform/telemetry/browser/1dsAppender.ts @@ -4,16 +4,18 @@ *--------------------------------------------------------------------------------------------*/ import type { AppInsightsCore } from '@microsoft/1ds-core-js'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { AbstractOneDataSystemAppender } from 'vs/platform/telemetry/common/1dsAppender'; export class OneDataSystemWebAppender extends AbstractOneDataSystemAppender { constructor( + configurationService: IConfigurationService, eventPrefix: string, defaultData: { [key: string]: any } | null, iKeyOrClientFactory: string | (() => AppInsightsCore), // allow factory function for testing ) { - super(eventPrefix, defaultData, iKeyOrClientFactory); + super(configurationService, eventPrefix, defaultData, iKeyOrClientFactory); // If we cannot fetch the endpoint it means it is down and we should not send any telemetry. // This is most likely due to ad blockers diff --git a/src/vs/platform/telemetry/common/1dsAppender.ts b/src/vs/platform/telemetry/common/1dsAppender.ts index e2ea5b42fdc..8023931f50f 100644 --- a/src/vs/platform/telemetry/common/1dsAppender.ts +++ b/src/vs/platform/telemetry/common/1dsAppender.ts @@ -7,11 +7,12 @@ import type { AppInsightsCore, IExtendedConfiguration } from '@microsoft/1ds-cor import type { IChannelConfiguration, IXHROverride, PostChannel } from '@microsoft/1ds-post-js'; import { onUnexpectedError } from 'vs/base/common/errors'; import { mixin } from 'vs/base/common/objects'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ITelemetryAppender, validateTelemetryData } from 'vs/platform/telemetry/common/telemetryUtils'; const endpointUrl = 'https://mobile.events.data.microsoft.com/OneCollector/1.0'; -async function getClient(instrumentationKey: string, xhrOverride?: IXHROverride): Promise { +async function getClient(instrumentationKey: string, addInternalFlag?: boolean, xhrOverride?: IXHROverride): Promise { const oneDs = await import('@microsoft/1ds-core-js'); const postPlugin = await import('@microsoft/1ds-post-js'); const appInsightsCore = new oneDs.AppInsightsCore(); @@ -43,10 +44,12 @@ async function getClient(instrumentationKey: string, xhrOverride?: IXHROverride) appInsightsCore.initialize(coreConfig, []); appInsightsCore.addTelemetryInitializer((envelope) => { - envelope['ext'] = envelope['ext'] ?? {}; - envelope['ext']['utc'] = envelope['ext']['utc'] ?? {}; - // Sets it to be internal only based on Windows UTC flagging - envelope['ext']['utc']['flags'] = 0x0000811ECD; + if (addInternalFlag) { + envelope['ext'] = envelope['ext'] ?? {}; + envelope['ext']['utc'] = envelope['ext']['utc'] ?? {}; + // Sets it to be internal only based on Windows UTC flagging + envelope['ext']['utc']['flags'] = 0x0000811ECD; + } }); return appInsightsCore; @@ -60,6 +63,7 @@ export abstract class AbstractOneDataSystemAppender implements ITelemetryAppende protected readonly endPointUrl = endpointUrl; constructor( + private readonly _configurationService: IConfigurationService, private _eventPrefix: string, private _defaultData: { [key: string]: any } | null, iKeyOrClientFactory: string | (() => AppInsightsCore), // allow factory function for testing @@ -88,7 +92,8 @@ export abstract class AbstractOneDataSystemAppender implements ITelemetryAppende } if (!this._asyncAiCore) { - this._asyncAiCore = getClient(this._aiCoreOrKey, this._xhrOverride); + const isInternal = this._configurationService.getValue('telemetry.internalTesting'); + this._asyncAiCore = getClient(this._aiCoreOrKey, isInternal, this._xhrOverride); } this._asyncAiCore.then( diff --git a/src/vs/platform/telemetry/node/1dsAppender.ts b/src/vs/platform/telemetry/node/1dsAppender.ts index 5721843fac1..2e7b1b6f491 100644 --- a/src/vs/platform/telemetry/node/1dsAppender.ts +++ b/src/vs/platform/telemetry/node/1dsAppender.ts @@ -6,12 +6,14 @@ import type { AppInsightsCore } from '@microsoft/1ds-core-js'; import type { IPayloadData, IXHROverride } from '@microsoft/1ds-post-js'; import * as https from 'https'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { AbstractOneDataSystemAppender } from 'vs/platform/telemetry/common/1dsAppender'; export class OneDataSystemAppender extends AbstractOneDataSystemAppender { constructor( + configurationService: IConfigurationService, eventPrefix: string, defaultData: { [key: string]: any } | null, iKeyOrClientFactory: string | (() => AppInsightsCore), // allow factory function for testing @@ -46,6 +48,6 @@ export class OneDataSystemAppender extends AbstractOneDataSystemAppender { } }; - super(eventPrefix, defaultData, iKeyOrClientFactory, customHttpXHROverride); + super(configurationService, eventPrefix, defaultData, iKeyOrClientFactory, customHttpXHROverride); } } diff --git a/src/vs/workbench/services/telemetry/browser/telemetryService.ts b/src/vs/workbench/services/telemetry/browser/telemetryService.ts index 892f318d293..75701e1a088 100644 --- a/src/vs/workbench/services/telemetry/browser/telemetryService.ts +++ b/src/vs/workbench/services/telemetry/browser/telemetryService.ts @@ -43,7 +43,7 @@ export class TelemetryService extends Disposable implements ITelemetryService { const internalTesting = configurationService.getValue('telemetry.internalTesting'); const appenders = []; if (internalTesting || productService.aiConfig?.preferAria) { - const telemetryProvider: ITelemetryAppender = remoteAgentService.getConnection() !== null ? { log: remoteAgentService.logTelemetry.bind(remoteAgentService), flush: remoteAgentService.flushTelemetry.bind(remoteAgentService) } : new OneDataSystemWebAppender('monacoworkbench', null, productService.aiConfig?.ariaKey); + const telemetryProvider: ITelemetryAppender = remoteAgentService.getConnection() !== null ? { log: remoteAgentService.logTelemetry.bind(remoteAgentService), flush: remoteAgentService.flushTelemetry.bind(remoteAgentService) } : new OneDataSystemWebAppender(configurationService, 'monacoworkbench', null, productService.aiConfig?.ariaKey); appenders.push(telemetryProvider); } else { const telemetryProvider: ITelemetryAppender = remoteAgentService.getConnection() !== null ? { log: remoteAgentService.logTelemetry.bind(remoteAgentService), flush: remoteAgentService.flushTelemetry.bind(remoteAgentService) } : new WebAppInsightsAppender('monacoworkbench', productService.aiConfig?.asimovKey); From fc0bd9d3774551259f81c3ae2c01d31c6891b9e2 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 5 Jul 2022 11:52:47 -0700 Subject: [PATCH 245/347] Remove reliance on document.lineAt (#154191) * Remove reliance on document.lineAt This helps aligning more with the LSP types: https://github.com/microsoft/vscode-languageserver-node/issues/146 * Strip newline --- .../src/languageFeatures/documentLinks.ts | 6 +++--- .../src/languageFeatures/folding.ts | 7 ++++--- .../src/languageFeatures/pathCompletions.ts | 4 ++-- .../src/languageFeatures/smartSelect.ts | 17 +++++++++-------- .../src/tableOfContents.ts | 14 +++++++------- .../src/test/documentLinkProvider.test.ts | 2 +- .../src/types/textDocument.ts | 15 +++++---------- .../src/util/inMemoryDocument.ts | 14 +------------- .../src/util/string.ts | 8 ++++++++ 9 files changed, 40 insertions(+), 47 deletions(-) create mode 100644 extensions/markdown-language-features/src/util/string.ts diff --git a/extensions/markdown-language-features/src/languageFeatures/documentLinks.ts b/extensions/markdown-language-features/src/languageFeatures/documentLinks.ts index 4fe6320c6cc..154baf8abcb 100644 --- a/extensions/markdown-language-features/src/languageFeatures/documentLinks.ts +++ b/extensions/markdown-language-features/src/languageFeatures/documentLinks.ts @@ -9,7 +9,7 @@ import * as uri from 'vscode-uri'; import { OpenDocumentLinkCommand } from '../commands/openDocumentLink'; import { ILogger } from '../logging'; import { IMdParser } from '../markdownEngine'; -import { ITextDocument } from '../types/textDocument'; +import { getLine, ITextDocument } from '../types/textDocument'; import { coalesce } from '../util/arrays'; import { noopToken } from '../util/cancellation'; import { Disposable } from '../util/dispose'; @@ -422,9 +422,9 @@ export class MdLinkComputer { reference = match[5]; const offset = ((match.index ?? 0) + match[1].length) + 1; hrefStart = document.positionAt(offset); - const line = document.lineAt(hrefStart.line); + const line = getLine(document, hrefStart.line); // See if link looks like a checkbox - const checkboxMatch = line.text.match(/^\s*[\-\*]\s*\[x\]/i); + const checkboxMatch = line.match(/^\s*[\-\*]\s*\[x\]/i); if (checkboxMatch && hrefStart.character <= checkboxMatch[0].length) { continue; } diff --git a/extensions/markdown-language-features/src/languageFeatures/folding.ts b/extensions/markdown-language-features/src/languageFeatures/folding.ts index f79df449b04..2fef6f67958 100644 --- a/extensions/markdown-language-features/src/languageFeatures/folding.ts +++ b/extensions/markdown-language-features/src/languageFeatures/folding.ts @@ -7,7 +7,8 @@ import type Token = require('markdown-it/lib/token'); import * as vscode from 'vscode'; import { IMdParser } from '../markdownEngine'; import { MdTableOfContentsProvider } from '../tableOfContents'; -import { ITextDocument } from '../types/textDocument'; +import { getLine, ITextDocument } from '../types/textDocument'; +import { isEmptyOrWhitespace } from '../util/string'; const rangeLimit = 5000; @@ -59,7 +60,7 @@ export class MdFoldingProvider implements vscode.FoldingRangeProvider { const toc = await this.tocProvide.getForDocument(document); return toc.entries.map(entry => { let endLine = entry.sectionLocation.range.end.line; - if (document.lineAt(endLine).isEmptyOrWhitespace && endLine >= entry.line + 1) { + if (isEmptyOrWhitespace(getLine(document, endLine)) && endLine >= entry.line + 1) { endLine = endLine - 1; } return new vscode.FoldingRange(entry.line, endLine); @@ -72,7 +73,7 @@ export class MdFoldingProvider implements vscode.FoldingRangeProvider { return multiLineListItems.map(listItem => { const start = listItem.map[0]; let end = listItem.map[1] - 1; - if (document.lineAt(end).isEmptyOrWhitespace && end >= start + 1) { + if (isEmptyOrWhitespace(getLine(document, end)) && end >= start + 1) { end = end - 1; } return new vscode.FoldingRange(start, end, this.getFoldingRangeKind(listItem)); diff --git a/extensions/markdown-language-features/src/languageFeatures/pathCompletions.ts b/extensions/markdown-language-features/src/languageFeatures/pathCompletions.ts index 28f75b57444..65ad060c080 100644 --- a/extensions/markdown-language-features/src/languageFeatures/pathCompletions.ts +++ b/extensions/markdown-language-features/src/languageFeatures/pathCompletions.ts @@ -7,7 +7,7 @@ import { dirname, resolve } from 'path'; import * as vscode from 'vscode'; import { IMdParser } from '../markdownEngine'; import { TableOfContents } from '../tableOfContents'; -import { ITextDocument } from '../types/textDocument'; +import { getLine, ITextDocument } from '../types/textDocument'; import { resolveUriToMarkdownFile } from '../util/openDocumentLink'; import { Schemes } from '../util/schemes'; import { IMdWorkspace } from '../workspace'; @@ -167,7 +167,7 @@ export class MdVsCodePathCompletionProvider implements vscode.CompletionItemProv private readonly definitionPattern = /^\s*\[[\w\-]+\]:\s*([^\s]*)$/m; private getPathCompletionContext(document: ITextDocument, position: vscode.Position): CompletionContext | undefined { - const line = document.lineAt(position.line).text; + const line = getLine(document, position.line); const linePrefixText = line.slice(0, position.character); const lineSuffixText = line.slice(position.character); diff --git a/extensions/markdown-language-features/src/languageFeatures/smartSelect.ts b/extensions/markdown-language-features/src/languageFeatures/smartSelect.ts index 29f0e922559..61fa887073f 100644 --- a/extensions/markdown-language-features/src/languageFeatures/smartSelect.ts +++ b/extensions/markdown-language-features/src/languageFeatures/smartSelect.ts @@ -6,7 +6,8 @@ import Token = require('markdown-it/lib/token'); import * as vscode from 'vscode'; import { IMdParser } from '../markdownEngine'; import { MdTableOfContentsProvider, TocEntry } from '../tableOfContents'; -import { ITextDocument } from '../types/textDocument'; +import { getLine, ITextDocument } from '../types/textDocument'; +import { isEmptyOrWhitespace } from '../util/string'; interface MarkdownItTokenWithMap extends Token { map: [number, number]; @@ -111,14 +112,14 @@ function createBlockRange(block: MarkdownItTokenWithMap, document: ITextDocument if (block.type === 'fence') { return createFencedRange(block, cursorLine, document, parent); } else { - let startLine = document.lineAt(block.map[0]).isEmptyOrWhitespace ? block.map[0] + 1 : block.map[0]; + let startLine = isEmptyOrWhitespace(getLine(document, block.map[0])) ? block.map[0] + 1 : block.map[0]; let endLine = startLine === block.map[1] ? block.map[1] : block.map[1] - 1; if (block.type === 'paragraph_open' && block.map[1] - block.map[0] === 2) { startLine = endLine = cursorLine; - } else if (isList(block) && document.lineAt(endLine).isEmptyOrWhitespace) { + } else if (isList(block) && isEmptyOrWhitespace(getLine(document, endLine))) { endLine = endLine - 1; } - const range = new vscode.Range(startLine, 0, endLine, document.lineAt(endLine).text?.length ?? 0); + const range = new vscode.Range(startLine, 0, endLine, getLine(document, endLine).length); if (parent?.range.contains(range) && !parent.range.isEqual(range)) { return new vscode.SelectionRange(range, parent); } else if (parent?.range.isEqual(range)) { @@ -130,7 +131,7 @@ function createBlockRange(block: MarkdownItTokenWithMap, document: ITextDocument } function createInlineRange(document: ITextDocument, cursorPosition: vscode.Position, parent?: vscode.SelectionRange): vscode.SelectionRange | undefined { - const lineText = document.lineAt(cursorPosition.line).text; + const lineText = getLine(document, cursorPosition.line); const boldSelection = createBoldRange(lineText, cursorPosition.character, cursorPosition.line, parent); const italicSelection = createOtherInlineRange(lineText, cursorPosition.character, cursorPosition.line, true, parent); let comboSelection: vscode.SelectionRange | undefined; @@ -150,8 +151,8 @@ function createFencedRange(token: MarkdownItTokenWithMap, cursorLine: number, do const startLine = token.map[0]; const endLine = token.map[1] - 1; const onFenceLine = cursorLine === startLine || cursorLine === endLine; - const fenceRange = new vscode.Range(startLine, 0, endLine, document.lineAt(endLine).text.length); - const contentRange = endLine - startLine > 2 && !onFenceLine ? new vscode.Range(startLine + 1, 0, endLine - 1, document.lineAt(endLine - 1).text.length) : undefined; + const fenceRange = new vscode.Range(startLine, 0, endLine, getLine(document, endLine).length); + const contentRange = endLine - startLine > 2 && !onFenceLine ? new vscode.Range(startLine + 1, 0, endLine - 1, getLine(document, endLine - 1).length) : undefined; if (contentRange) { return new vscode.SelectionRange(contentRange, new vscode.SelectionRange(fenceRange, parent)); } else { @@ -242,7 +243,7 @@ function getFirstChildHeader(document: ITextDocument, header?: TocEntry, toc?: r const children = toc.filter(t => header.sectionLocation.range.contains(t.sectionLocation.range) && t.sectionLocation.range.start.line > header.sectionLocation.range.start.line).sort((t1, t2) => t1.line - t2.line); if (children.length > 0) { childRange = children[0].sectionLocation.range.start; - const lineText = document.lineAt(childRange.line - 1).text; + const lineText = getLine(document, childRange.line - 1); return childRange ? childRange.translate(-1, lineText.length) : undefined; } } diff --git a/extensions/markdown-language-features/src/tableOfContents.ts b/extensions/markdown-language-features/src/tableOfContents.ts index b1e3e25c8d3..5e0a0cc3684 100644 --- a/extensions/markdown-language-features/src/tableOfContents.ts +++ b/extensions/markdown-language-features/src/tableOfContents.ts @@ -7,7 +7,7 @@ import * as vscode from 'vscode'; import { ILogger } from './logging'; import { IMdParser } from './markdownEngine'; import { githubSlugifier, Slug, Slugifier } from './slugify'; -import { ITextDocument } from './types/textDocument'; +import { getLine, ITextDocument } from './types/textDocument'; import { Disposable } from './util/dispose'; import { isMarkdownFile } from './util/file'; import { Schemes } from './util/schemes'; @@ -108,9 +108,9 @@ export class TableOfContents { } const lineNumber = heading.map[0]; - const line = document.lineAt(lineNumber); + const line = getLine(document, lineNumber); - let slug = parser.slugifier.fromHeading(line.text); + let slug = parser.slugifier.fromHeading(line); const existingSlugEntry = existingSlugEntries.get(slug.value); if (existingSlugEntry) { ++existingSlugEntry.count; @@ -120,14 +120,14 @@ export class TableOfContents { } const headerLocation = new vscode.Location(document.uri, - new vscode.Range(lineNumber, 0, lineNumber, line.text.length)); + new vscode.Range(lineNumber, 0, lineNumber, line.length)); const headerTextLocation = new vscode.Location(document.uri, - new vscode.Range(lineNumber, line.text.match(/^#+\s*/)?.[0].length ?? 0, lineNumber, line.text.length - (line.text.match(/\s*#*$/)?.[0].length ?? 0))); + new vscode.Range(lineNumber, line.match(/^#+\s*/)?.[0].length ?? 0, lineNumber, line.length - (line.match(/\s*#*$/)?.[0].length ?? 0))); toc.push({ slug, - text: TableOfContents.getHeaderText(line.text), + text: TableOfContents.getHeaderText(line), level: TableOfContents.getHeaderLevel(heading.markup), line: lineNumber, sectionLocation: headerLocation, // Populated in next steps @@ -151,7 +151,7 @@ export class TableOfContents { sectionLocation: new vscode.Location(document.uri, new vscode.Range( entry.sectionLocation.range.start, - new vscode.Position(endLine, document.lineAt(endLine).text.length))) + new vscode.Position(endLine, getLine(document, endLine).length))) }; }); } diff --git a/extensions/markdown-language-features/src/test/documentLinkProvider.test.ts b/extensions/markdown-language-features/src/test/documentLinkProvider.test.ts index a96967bafd2..0111980e849 100644 --- a/extensions/markdown-language-features/src/test/documentLinkProvider.test.ts +++ b/extensions/markdown-language-features/src/test/documentLinkProvider.test.ts @@ -15,7 +15,7 @@ import { nulLogger } from './nulLogging'; import { assertRangeEqual, joinLines, workspacePath } from './util'; -suite.only('Markdown: MdLinkComputer', () => { +suite('Markdown: MdLinkComputer', () => { function getLinksForFile(fileContents: string): Promise { const doc = new InMemoryDocument(workspacePath('x.md'), fileContents); diff --git a/extensions/markdown-language-features/src/types/textDocument.ts b/extensions/markdown-language-features/src/types/textDocument.ts index 5c49e065d40..f45614cc0cc 100644 --- a/extensions/markdown-language-features/src/types/textDocument.ts +++ b/extensions/markdown-language-features/src/types/textDocument.ts @@ -3,15 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import type * as vscode from 'vscode'; - -/** - * Minimal version of {@link vscode.TextLine}. - */ -export interface ITextLine { - readonly text: string; - readonly isEmptyOrWhitespace: boolean; -} +import * as vscode from 'vscode'; /** * Minimal version of {@link vscode.TextDocument}. @@ -22,6 +14,9 @@ export interface ITextDocument { readonly lineCount: number; getText(range?: vscode.Range): string; - lineAt(line: number): ITextLine; positionAt(offset: number): vscode.Position; } + +export function getLine(doc: ITextDocument, line: number): string { + return doc.getText(new vscode.Range(line, 0, line, Number.MAX_VALUE)).replace(/\r?\n$/, ''); +} diff --git a/extensions/markdown-language-features/src/util/inMemoryDocument.ts b/extensions/markdown-language-features/src/util/inMemoryDocument.ts index de29de21355..f626878deff 100644 --- a/extensions/markdown-language-features/src/util/inMemoryDocument.ts +++ b/extensions/markdown-language-features/src/util/inMemoryDocument.ts @@ -5,14 +5,12 @@ import * as vscode from 'vscode'; import { TextDocument } from 'vscode-languageserver-textdocument'; -import { ITextDocument, ITextLine } from '../types/textDocument'; +import { ITextDocument } from '../types/textDocument'; export class InMemoryDocument implements ITextDocument { private readonly _doc: TextDocument; - private lines: ITextLine[] | undefined; - constructor( public readonly uri: vscode.Uri, contents: string, public readonly version = 0, @@ -25,16 +23,6 @@ export class InMemoryDocument implements ITextDocument { return this._doc.lineCount; } - lineAt(index: any): ITextLine { - if (!this.lines) { - this.lines = this._doc.getText().split(/\r?\n/).map(text => ({ - text, - get isEmptyOrWhitespace() { return /^\s*$/.test(text); } - })); - } - return this.lines[index]; - } - positionAt(offset: number): vscode.Position { const pos = this._doc.positionAt(offset); return new vscode.Position(pos.line, pos.character); diff --git a/extensions/markdown-language-features/src/util/string.ts b/extensions/markdown-language-features/src/util/string.ts new file mode 100644 index 00000000000..dd9733e9ffd --- /dev/null +++ b/extensions/markdown-language-features/src/util/string.ts @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +export function isEmptyOrWhitespace(str: string): boolean { + return /^\s*$/.test(str); +} From f6271dd82e61d17320edd3df0991c4584aa1e49f Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 5 Jul 2022 11:55:20 -0700 Subject: [PATCH 246/347] Fix angle bracket path completions for link defs (#154182) Fixes #153866 --- .../src/languageFeatures/pathCompletions.ts | 4 +++- .../src/test/pathCompletion.test.ts | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/extensions/markdown-language-features/src/languageFeatures/pathCompletions.ts b/extensions/markdown-language-features/src/languageFeatures/pathCompletions.ts index 65ad060c080..82e28faf3a4 100644 --- a/extensions/markdown-language-features/src/languageFeatures/pathCompletions.ts +++ b/extensions/markdown-language-features/src/languageFeatures/pathCompletions.ts @@ -193,7 +193,8 @@ export class MdVsCodePathCompletionProvider implements vscode.CompletionItemProv const definitionLinkPrefixMatch = linePrefixText.match(this.definitionPattern); if (definitionLinkPrefixMatch) { - const prefix = definitionLinkPrefixMatch[1]; + const isAngleBracketLink = definitionLinkPrefixMatch[1].startsWith('<'); + const prefix = definitionLinkPrefixMatch[1].slice(isAngleBracketLink ? 1 : 0); if (this.refLooksLikeUrl(prefix)) { return undefined; } @@ -205,6 +206,7 @@ export class MdVsCodePathCompletionProvider implements vscode.CompletionItemProv linkTextStartPosition: position.translate({ characterDelta: -prefix.length }), linkSuffix: suffix ? suffix[0] : '', anchorInfo: this.getAnchorContext(prefix), + skipEncoding: isAngleBracketLink, }; } diff --git a/extensions/markdown-language-features/src/test/pathCompletion.test.ts b/extensions/markdown-language-features/src/test/pathCompletion.test.ts index d124461f102..f4ee75f2a74 100644 --- a/extensions/markdown-language-features/src/test/pathCompletion.test.ts +++ b/extensions/markdown-language-features/src/test/pathCompletion.test.ts @@ -292,4 +292,22 @@ suite('Markdown: Path completions', () => { { label: 'file.md', insertText: 'file.md' }, ]); }); + + test('Should support definition path with angle brackets', async () => { + const workspace = new InMemoryMdWorkspace([ + new InMemoryDocument(workspacePath('a.md'), ''), + new InMemoryDocument(workspacePath('b.md'), ''), + new InMemoryDocument(workspacePath('sub with space/file.md'), ''), + ]); + + const completions = await getCompletionsAtCursor(workspacePath('new.md'), joinLines( + `[def]: <./${CURSOR}>` + ), workspace); + + assertCompletionsEqual(completions, [ + { label: 'a.md', insertText: 'a.md' }, + { label: 'b.md', insertText: 'b.md' }, + { label: 'sub with space/', insertText: 'sub with space/' }, + ]); + }); }); From 71c221c532996c9976405f62bb888283c0cf6545 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 5 Jul 2022 21:30:01 +0200 Subject: [PATCH 247/347] joh/theoretical quokka (#154157) * add `SnippetController#apply(ISnippetEdit[])` This replaces the initial ugly trick with a more sound implementation of arbitrary snippet edits. A snippet edit can cover disconnected regions, each will be applied as separate text edit but everything will become a single `OneSnippet` instance * add integration test for SnippetString-text edit inside workspace edit --- extensions/vscode-api-tests/package.json | 1 + .../src/singlefolder-tests/workspace.test.ts | 23 +++ .../snippet/browser/snippetController2.ts | 79 ++++----- .../contrib/snippet/browser/snippetParser.ts | 34 ++-- .../contrib/snippet/browser/snippetSession.ts | 95 ++++++++-- .../test/browser/snippetController2.test.ts | 167 +++++++++++++++++- .../test/browser/snippetSession.test.ts | 32 ++++ .../contrib/bulkEdit/browser/bulkTextEdits.ts | 23 ++- 8 files changed, 368 insertions(+), 86 deletions(-) diff --git a/extensions/vscode-api-tests/package.json b/extensions/vscode-api-tests/package.json index 610dd2590e7..b7ae5707c53 100644 --- a/extensions/vscode-api-tests/package.json +++ b/extensions/vscode-api-tests/package.json @@ -33,6 +33,7 @@ "scmActionButton", "scmSelectedProvider", "scmValidation", + "snippetWorkspaceEdit", "taskPresentationGroup", "terminalDataWriteEvent", "terminalDimensions", diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts index 6e088ce9ee5..9ea22bb3d19 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts @@ -1147,4 +1147,27 @@ suite('vscode API - workspace', () => { assert.strictEqual(document.isDirty, false); } }); + + test('SnippetString in WorkspaceEdit', async function (): Promise { + const file = await createRandomFile('hello\nworld'); + + const document = await vscode.workspace.openTextDocument(file); + const edt = await vscode.window.showTextDocument(document); + + assert.ok(edt === vscode.window.activeTextEditor); + + const we = new vscode.WorkspaceEdit(); + we.set(document.uri, [{ range: new vscode.Range(0, 0, 0, 0), newText: '', newText2: new vscode.SnippetString('${1:foo}${2:bar}') }]); + const success = await vscode.workspace.applyEdit(we); + + + if (edt !== vscode.window.activeTextEditor) { + return this.skip(); + } + + assert.ok(success); + assert.strictEqual(document.getText(), 'foobarhello\nworld'); + assert.deepStrictEqual(edt.selections, [new vscode.Selection(0, 0, 0, 3)]); + + }); }); diff --git a/src/vs/editor/contrib/snippet/browser/snippetController2.ts b/src/vs/editor/contrib/snippet/browser/snippetController2.ts index 43e72f6ce57..862f3a20493 100644 --- a/src/vs/editor/contrib/snippet/browser/snippetController2.ts +++ b/src/vs/editor/contrib/snippet/browser/snippetController2.ts @@ -5,25 +5,26 @@ import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { DisposableStore } from 'vs/base/common/lifecycle'; +import { assertType } from 'vs/base/common/types'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { EditorCommand, registerEditorCommand, registerEditorContribution } from 'vs/editor/browser/editorExtensions'; import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; -import { ISelection } from 'vs/editor/common/core/selection'; +import { ISelection, Selection } from 'vs/editor/common/core/selection'; import { IEditorContribution } from 'vs/editor/common/editorCommon'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { CompletionItem, CompletionItemKind, CompletionItemProvider } from 'vs/editor/common/languages'; import { ILanguageConfigurationService } from 'vs/editor/common/languages/languageConfigurationRegistry'; import { ITextModel } from 'vs/editor/common/model'; import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures'; -import { Choice, SnippetParser } from 'vs/editor/contrib/snippet/browser/snippetParser'; +import { Choice } from 'vs/editor/contrib/snippet/browser/snippetParser'; import { showSimpleSuggestions } from 'vs/editor/contrib/suggest/browser/suggest'; import { OvertypingCapturer } from 'vs/editor/contrib/suggest/browser/suggestOvertypingCapturer'; import { localize } from 'vs/nls'; import { ContextKeyExpr, IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { ILogService } from 'vs/platform/log/common/log'; -import { SnippetSession } from './snippetSession'; +import { ISnippetEdit, SnippetSession } from './snippetSession'; export interface ISnippetInsertOptions { overwriteBefore: number; @@ -88,6 +89,19 @@ export class SnippetController2 implements IEditorContribution { this._snippetListener.dispose(); } + apply(edits: ISnippetEdit[], opts?: Partial) { + try { + this._doInsert(edits, typeof opts === 'undefined' ? _defaultOptions : { ..._defaultOptions, ...opts }); + + } catch (e) { + this.cancel(); + this._logService.error(e); + this._logService.error('snippet_error'); + this._logService.error('insert_edits=', edits); + this._logService.error('existing_template=', this._session ? this._session._logInfo() : ''); + } + } + insert( template: string, opts?: Partial @@ -108,7 +122,7 @@ export class SnippetController2 implements IEditorContribution { } private _doInsert( - template: string, + template: string | ISnippetEdit[], opts: ISnippetInsertOptions ): void { if (!this._editor.hasModel()) { @@ -123,11 +137,17 @@ export class SnippetController2 implements IEditorContribution { this._editor.getModel().pushStackElement(); } + // don't merge + if (this._session && typeof template !== 'string') { + this.cancel(); + } + if (!this._session) { this._modelVersionId = this._editor.getModel().getAlternativeVersionId(); this._session = new SnippetSession(this._editor, template, opts, this._languageConfigurationService); this._session.insert(); } else { + assertType(typeof template === 'string'); this._session.merge(template, opts); } @@ -342,50 +362,11 @@ export function performSnippetEdit(editor: ICodeEditor, snippet: string, selecti return false; } editor.focus(); - editor.setSelections(selections ?? []); - controller.insert(snippet); - return controller.isInSnippet(); -} - - -export type ISnippetEdit = { - range: Range; - snippet: string; -}; - -// --- - -export function performSnippetEdits(editor: ICodeEditor, edits: ISnippetEdit[]) { - - if (!editor.hasModel()) { - return false; - } - if (edits.length === 0) { - return false; - } - - const model = editor.getModel(); - let newText = ''; - let last: ISnippetEdit | undefined; - edits.sort((a, b) => Range.compareRangesUsingStarts(a.range, b.range)); - - for (const item of edits) { - if (last) { - const between = Range.fromPositions(last.range.getEndPosition(), item.range.getStartPosition()); - const text = model.getValueInRange(between); - newText += SnippetParser.escape(text); - } - newText += item.snippet; - last = item; - } - - const controller = SnippetController2.get(editor); - if (!controller) { - return false; - } - model.pushStackElement(); - const range = Range.plusRange(edits[0].range, edits[edits.length - 1].range); - editor.setSelection(range); - controller.insert(newText, { undoStopBefore: false }); + controller.apply(selections.map(selection => { + return { + range: Selection.liftSelection(selection), + template: snippet + }; + })); return controller.isInSnippet(); } diff --git a/src/vs/editor/contrib/snippet/browser/snippetParser.ts b/src/vs/editor/contrib/snippet/browser/snippetParser.ts index 6faf65e0d4d..f68dcbfa953 100644 --- a/src/vs/editor/contrib/snippet/browser/snippetParser.ts +++ b/src/vs/editor/contrib/snippet/browser/snippetParser.ts @@ -613,11 +613,17 @@ export class SnippetParser { } parse(value: string, insertFinalTabstop?: boolean, enforceFinalTabstop?: boolean): TextmateSnippet { + const snippet = new TextmateSnippet(); + this.parseFragment(value, snippet); + this.ensureFinalTabstop(snippet, enforceFinalTabstop ?? false, insertFinalTabstop ?? false); + return snippet; + } + parseFragment(value: string, snippet: TextmateSnippet): readonly Marker[] { + + const offset = snippet.children.length; this._scanner.text(value); this._token = this._scanner.next(); - - const snippet = new TextmateSnippet(); while (this._parse(snippet)) { // nothing } @@ -626,10 +632,8 @@ export class SnippetParser { // that has a value defines the value for all placeholders with that index const placeholderDefaultValues = new Map(); const incompletePlaceholders: Placeholder[] = []; - let placeholderCount = 0; snippet.walk(marker => { if (marker instanceof Placeholder) { - placeholderCount += 1; if (marker.isFinalTabstop) { placeholderDefaultValues.set(0, undefined); } else if (!placeholderDefaultValues.has(marker.index) && marker.children.length > 0) { @@ -640,6 +644,7 @@ export class SnippetParser { } return true; }); + for (const placeholder of incompletePlaceholders) { const defaultValues = placeholderDefaultValues.get(placeholder.index); if (defaultValues) { @@ -652,17 +657,20 @@ export class SnippetParser { } } - if (!enforceFinalTabstop) { - enforceFinalTabstop = placeholderCount > 0 && insertFinalTabstop; + return snippet.children.slice(offset); + } + + ensureFinalTabstop(snippet: TextmateSnippet, enforceFinalTabstop: boolean, insertFinalTabstop: boolean) { + + if (enforceFinalTabstop || insertFinalTabstop && snippet.placeholders.length > 0) { + const finalTabstop = snippet.placeholders.find(p => p.index === 0); + if (!finalTabstop) { + // the snippet uses placeholders but has no + // final tabstop defined -> insert at the end + snippet.appendChild(new Placeholder(0)); + } } - if (!placeholderDefaultValues.has(0) && enforceFinalTabstop) { - // the snippet uses placeholders but has no - // final tabstop defined -> insert at the end - snippet.appendChild(new Placeholder(0)); - } - - return snippet; } private _accept(type?: TokenType): boolean; diff --git a/src/vs/editor/contrib/snippet/browser/snippetSession.ts b/src/vs/editor/contrib/snippet/browser/snippetSession.ts index 00e8268b0b6..74eaa5847f7 100644 --- a/src/vs/editor/contrib/snippet/browser/snippetSession.ts +++ b/src/vs/editor/contrib/snippet/browser/snippetSession.ts @@ -359,6 +359,11 @@ const _defaultOptions: ISnippetSessionInsertOptions = { overtypingCapturer: undefined }; +export interface ISnippetEdit { + range: Range; + template: string; +} + export class SnippetSession { static adjustWhitespace(model: ITextModel, position: IPosition, snippet: TextmateSnippet, adjustIndentation: boolean, adjustNewlines: boolean): string { @@ -434,7 +439,7 @@ export class SnippetSession { return selection; } - static createEditsAndSnippets(editor: IActiveCodeEditor, template: string, overwriteBefore: number, overwriteAfter: number, enforceFinalTabstop: boolean, adjustWhitespace: boolean, clipboardText: string | undefined, overtypingCapturer: OvertypingCapturer | undefined, languageConfigurationService: ILanguageConfigurationService): { edits: IIdentifiedSingleEditOperation[]; snippets: OneSnippet[] } { + static createEditsAndSnippetsFromSelections(editor: IActiveCodeEditor, template: string, overwriteBefore: number, overwriteAfter: number, enforceFinalTabstop: boolean, adjustWhitespace: boolean, clipboardText: string | undefined, overtypingCapturer: OvertypingCapturer | undefined, languageConfigurationService: ILanguageConfigurationService): { edits: IIdentifiedSingleEditOperation[]; snippets: OneSnippet[] } { const edits: IIdentifiedSingleEditOperation[] = []; const snippets: OneSnippet[] = []; @@ -518,22 +523,79 @@ export class SnippetSession { return { edits, snippets }; } - private readonly _editor: IActiveCodeEditor; - private readonly _template: string; - private readonly _templateMerges: [number, number, string][] = []; - private readonly _options: ISnippetSessionInsertOptions; + static createEditsAndSnippetsFromEdits(editor: IActiveCodeEditor, snippetEdits: ISnippetEdit[], enforceFinalTabstop: boolean, adjustWhitespace: boolean, clipboardText: string | undefined, overtypingCapturer: OvertypingCapturer | undefined, languageConfigurationService: ILanguageConfigurationService): { edits: IIdentifiedSingleEditOperation[]; snippets: OneSnippet[] } { + + if (!editor.hasModel() || snippetEdits.length === 0) { + return { edits: [], snippets: [] }; + } + + const edits: IIdentifiedSingleEditOperation[] = []; + const model = editor.getModel(); + + const parser = new SnippetParser(); + const snippet = new TextmateSnippet(); + + // + snippetEdits = snippetEdits.sort((a, b) => Range.compareRangesUsingStarts(a.range, b.range)); + let offset = 0; + for (let i = 0; i < snippetEdits.length; i++) { + + const { range, template } = snippetEdits[i]; + + // gaps between snippet edits are appended as text nodes. this + // ensures placeholder-offsets are later correct + if (i > 0) { + const lastRange = snippetEdits[i - 1].range; + const textRange = Range.fromPositions(lastRange.getEndPosition(), range.getStartPosition()); + const textNode = new Text(model.getValueInRange(textRange)); + snippet.appendChild(textNode); + offset += textNode.value.length; + } + + parser.parseFragment(template, snippet); + + const snippetText = snippet.toString(); + const snippetFragmentText = snippetText.slice(offset); + offset = snippetText.length; + + // make edit + const edit: IIdentifiedSingleEditOperation = EditOperation.replace(range, snippetFragmentText); + edit.identifier = { major: i, minor: 0 }; // mark the edit so only our undo edits will be used to generate end cursors + edit._isTracked = true; + edits.push(edit); + } + + // + parser.ensureFinalTabstop(snippet, enforceFinalTabstop, true); + + // snippet variables resolver + const resolver = new CompositeSnippetVariableResolver([ + editor.invokeWithinContext(accessor => new ModelBasedVariableResolver(accessor.get(ILabelService), model)), + new ClipboardBasedVariableResolver(() => clipboardText, 0, editor.getSelections().length, editor.getOption(EditorOption.multiCursorPaste) === 'spread'), + new SelectionBasedVariableResolver(model, editor.getSelection(), 0, overtypingCapturer), + new CommentBasedVariableResolver(model, editor.getSelection(), languageConfigurationService), + new TimeBasedVariableResolver, + new WorkspaceBasedVariableResolver(editor.invokeWithinContext(accessor => accessor.get(IWorkspaceContextService))), + new RandomBasedVariableResolver, + ]); + snippet.resolveVariables(resolver); + + + return { + edits, + snippets: [new OneSnippet(editor, snippet, '')] + }; + } + + private readonly _templateMerges: [number, number, string | ISnippetEdit[]][] = []; private _snippets: OneSnippet[] = []; constructor( - editor: IActiveCodeEditor, - template: string, - options: ISnippetSessionInsertOptions = _defaultOptions, + private readonly _editor: IActiveCodeEditor, + private readonly _template: string | ISnippetEdit[], + private readonly _options: ISnippetSessionInsertOptions = _defaultOptions, @ILanguageConfigurationService private readonly _languageConfigurationService: ILanguageConfigurationService - ) { - this._editor = editor; - this._template = template; - this._options = options; - } + ) { } dispose(): void { dispose(this._snippets); @@ -549,7 +611,10 @@ export class SnippetSession { } // make insert edit and start with first selections - const { edits, snippets } = SnippetSession.createEditsAndSnippets(this._editor, this._template, this._options.overwriteBefore, this._options.overwriteAfter, false, this._options.adjustWhitespace, this._options.clipboardText, this._options.overtypingCapturer, this._languageConfigurationService); + const { edits, snippets } = typeof this._template === 'string' + ? SnippetSession.createEditsAndSnippetsFromSelections(this._editor, this._template, this._options.overwriteBefore, this._options.overwriteAfter, false, this._options.adjustWhitespace, this._options.clipboardText, this._options.overtypingCapturer, this._languageConfigurationService) + : SnippetSession.createEditsAndSnippetsFromEdits(this._editor, this._template, false, this._options.adjustWhitespace, this._options.clipboardText, this._options.overtypingCapturer, this._languageConfigurationService); + this._snippets = snippets; this._editor.executeEdits('snippet', edits, _undoEdits => { @@ -576,7 +641,7 @@ export class SnippetSession { return; } this._templateMerges.push([this._snippets[0]._nestingLevel, this._snippets[0]._placeholderGroupsIdx, template]); - const { edits, snippets } = SnippetSession.createEditsAndSnippets(this._editor, template, options.overwriteBefore, options.overwriteAfter, true, options.adjustWhitespace, options.clipboardText, options.overtypingCapturer, this._languageConfigurationService); + const { edits, snippets } = SnippetSession.createEditsAndSnippetsFromSelections(this._editor, template, options.overwriteBefore, options.overwriteAfter, true, options.adjustWhitespace, options.clipboardText, options.overtypingCapturer, this._languageConfigurationService); this._editor.executeEdits('snippet', edits, _undoEdits => { // Sometimes, the text buffer will remove automatic whitespace when doing any edits, diff --git a/src/vs/editor/contrib/snippet/test/browser/snippetController2.test.ts b/src/vs/editor/contrib/snippet/test/browser/snippetController2.test.ts index 3560a2c2be4..fce4d2c432b 100644 --- a/src/vs/editor/contrib/snippet/test/browser/snippetController2.test.ts +++ b/src/vs/editor/contrib/snippet/test/browser/snippetController2.test.ts @@ -7,6 +7,7 @@ import { mock } from 'vs/base/test/common/mock'; import { CoreEditingCommands } from 'vs/editor/browser/coreCommands'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { Selection } from 'vs/editor/common/core/selection'; +import { Range } from 'vs/editor/common/core/range'; import { Handler } from 'vs/editor/common/editorCommon'; import { TextModel } from 'vs/editor/common/model/textModel'; import { SnippetController2 } from 'vs/editor/contrib/snippet/browser/snippetController2'; @@ -23,6 +24,7 @@ import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace suite('SnippetController2', function () { + /** @deprecated */ function assertSelections(editor: ICodeEditor, ...s: Selection[]) { for (const selection of editor.getSelections()!) { const actual = s.shift()!; @@ -31,10 +33,20 @@ suite('SnippetController2', function () { assert.strictEqual(s.length, 0); } + /** @deprecated */ function assertContextKeys(service: MockContextKeyService, inSnippet: boolean, hasPrev: boolean, hasNext: boolean): void { - assert.strictEqual(SnippetController2.InSnippetMode.getValue(service), inSnippet, `inSnippetMode`); - assert.strictEqual(SnippetController2.HasPrevTabstop.getValue(service), hasPrev, `HasPrevTabstop`); - assert.strictEqual(SnippetController2.HasNextTabstop.getValue(service), hasNext, `HasNextTabstop`); + const state = getContextState(service); + assert.strictEqual(state.inSnippet, inSnippet, `inSnippetMode`); + assert.strictEqual(state.hasPrev, hasPrev, `HasPrevTabstop`); + assert.strictEqual(state.hasNext, hasNext, `HasNextTabstop`); + } + + function getContextState(service: MockContextKeyService = contextKeys) { + return { + inSnippet: SnippetController2.InSnippetMode.getValue(service), + hasPrev: SnippetController2.HasPrevTabstop.getValue(service), + hasNext: SnippetController2.HasNextTabstop.getValue(service), + }; } let editor: ICodeEditor; @@ -531,4 +543,153 @@ suite('SnippetController2', function () { assert.strictEqual(model.getValue(), `foo: number;\n\nfoo: 'number',`); // editor.trigger('test', 'type', { text: ';' }); }); + + suite('createEditsAndSnippetsFromEdits', function () { + + test('apply, tab, done', function () { + + const ctrl = instaService.createInstance(SnippetController2, editor); + + model.setValue('foo("bar")'); + + ctrl.apply([ + { range: new Range(1, 5, 1, 10), template: '$1' }, + { range: new Range(1, 1, 1, 1), template: 'const ${1:new_const} = "bar";\n' } + ]); + + assert.strictEqual(model.getValue(), "const new_const = \"bar\";\nfoo(new_const)"); + assertContextKeys(contextKeys, true, false, true); + assert.deepStrictEqual(editor.getSelections(), [new Selection(1, 7, 1, 16), new Selection(2, 5, 2, 14)]); + + ctrl.next(); + assertContextKeys(contextKeys, false, false, false); + assert.deepStrictEqual(editor.getSelections(), [new Selection(2, 14, 2, 14)]); + }); + + test('apply, tab, done with special final tabstop', function () { + + model.setValue('foo("bar")'); + + const ctrl = instaService.createInstance(SnippetController2, editor); + ctrl.apply([ + { range: new Range(1, 5, 1, 10), template: '$1' }, + { range: new Range(1, 1, 1, 1), template: 'const ${1:new_const}$0 = "bar";\n' } + ]); + + assert.strictEqual(model.getValue(), "const new_const = \"bar\";\nfoo(new_const)"); + assertContextKeys(contextKeys, true, false, true); + assert.deepStrictEqual(editor.getSelections(), [new Selection(1, 7, 1, 16), new Selection(2, 5, 2, 14)]); + + ctrl.next(); + assertContextKeys(contextKeys, false, false, false); + assert.deepStrictEqual(editor.getSelections(), [new Selection(1, 16, 1, 16)]); + }); + + test('apply, tab, tab, done', function () { + + model.setValue('foo\nbar'); + + const ctrl = instaService.createInstance(SnippetController2, editor); + ctrl.apply([ + { range: new Range(1, 4, 1, 4), template: '${3}' }, + { range: new Range(2, 4, 2, 4), template: '$3' }, + { range: new Range(1, 1, 1, 1), template: '### ${2:Header}\n' } + ]); + + assert.strictEqual(model.getValue(), "### Header\nfoo\nbar"); + assert.deepStrictEqual(getContextState(), { inSnippet: true, hasPrev: false, hasNext: true }); + assert.deepStrictEqual(editor.getSelections(), [new Selection(1, 5, 1, 11)]); + + ctrl.next(); + assert.deepStrictEqual(getContextState(), { inSnippet: true, hasPrev: true, hasNext: true }); + assert.deepStrictEqual(editor.getSelections(), [new Selection(2, 4, 2, 4), new Selection(3, 4, 3, 4)]); + + ctrl.next(); + assert.deepStrictEqual(getContextState(), { inSnippet: false, hasPrev: false, hasNext: false }); + assert.deepStrictEqual(editor.getSelections(), [new Selection(3, 4, 3, 4)]); + }); + + test('nested into apply works', function () { + + const ctrl = instaService.createInstance(SnippetController2, editor); + model.setValue('onetwo'); + + editor.setSelections([new Selection(1, 1, 1, 1), new Selection(2, 1, 2, 1)]); + + ctrl.apply([{ + range: new Range(1, 7, 1, 7), + template: '$0${1:three}' + }]); + + assert.strictEqual(model.getValue(), 'onetwothree'); + assert.deepStrictEqual(getContextState(), { inSnippet: true, hasPrev: false, hasNext: true }); + assert.deepStrictEqual(editor.getSelections(), [new Selection(1, 7, 1, 12)]); + + ctrl.insert('foo$1bar$1'); + assert.strictEqual(model.getValue(), 'onetwofoobar'); + assert.deepStrictEqual(editor.getSelections(), [new Selection(1, 10, 1, 10), new Selection(1, 13, 1, 13)]); + assert.deepStrictEqual(getContextState(), ({ inSnippet: true, hasPrev: false, hasNext: true })); + + ctrl.next(); + assert.deepStrictEqual(getContextState(), ({ inSnippet: true, hasPrev: true, hasNext: true })); + assert.deepStrictEqual(editor.getSelections(), [new Selection(1, 13, 1, 13)]); + + ctrl.next(); + assert.deepStrictEqual(getContextState(), { inSnippet: false, hasPrev: false, hasNext: false }); + assert.deepStrictEqual(editor.getSelections(), [new Selection(1, 7, 1, 7)]); + + }); + + test('nested into insert abort "outer" snippet', function () { + + const ctrl = instaService.createInstance(SnippetController2, editor); + model.setValue('one\ntwo'); + + editor.setSelections([new Selection(1, 1, 1, 1), new Selection(2, 1, 2, 1)]); + + ctrl.insert('foo${1:bar}bazz${1:bang}'); + assert.deepStrictEqual(editor.getSelections(), [new Selection(1, 4, 1, 7), new Selection(1, 11, 1, 14), new Selection(2, 4, 2, 7), new Selection(2, 11, 2, 14)]); + assert.deepStrictEqual(getContextState(), { inSnippet: true, hasPrev: false, hasNext: true }); + + ctrl.apply([{ + range: new Range(1, 4, 1, 7), + template: '$0A' + }]); + + assert.strictEqual(model.getValue(), 'fooAbazzbarone\nfoobarbazzbartwo'); + assert.deepStrictEqual(getContextState(), { inSnippet: false, hasPrev: false, hasNext: false }); + assert.deepStrictEqual(editor.getSelections(), [new Selection(1, 4, 1, 4)]); + }); + + test('nested into "insert" abort "outer" snippet (2)', function () { + + const ctrl = instaService.createInstance(SnippetController2, editor); + model.setValue('one\ntwo'); + + editor.setSelections([new Selection(1, 1, 1, 1), new Selection(2, 1, 2, 1)]); + + ctrl.insert('foo${1:bar}bazz${1:bang}'); + assert.deepStrictEqual(editor.getSelections(), [new Selection(1, 4, 1, 7), new Selection(1, 11, 1, 14), new Selection(2, 4, 2, 7), new Selection(2, 11, 2, 14)]); + assert.deepStrictEqual(getContextState(), { inSnippet: true, hasPrev: false, hasNext: true }); + + const edits = [{ + range: new Range(1, 4, 1, 7), + template: 'A' + }, { + range: new Range(1, 11, 1, 14), + template: 'B' + }, { + range: new Range(2, 4, 2, 7), + template: 'C' + }, { + range: new Range(2, 11, 2, 14), + template: 'D' + }]; + ctrl.apply(edits); + + assert.strictEqual(model.getValue(), "fooAbazzBone\nfooCbazzDtwo"); + assert.deepStrictEqual(getContextState(), { inSnippet: false, hasPrev: false, hasNext: false }); + assert.deepStrictEqual(editor.getSelections(), [new Selection(1, 5, 1, 5), new Selection(1, 10, 1, 10), new Selection(2, 5, 2, 5), new Selection(2, 10, 2, 10)]); + }); + }); }); diff --git a/src/vs/editor/contrib/snippet/test/browser/snippetSession.test.ts b/src/vs/editor/contrib/snippet/test/browser/snippetSession.test.ts index 7ce812e34ee..c9b7d0f2aa1 100644 --- a/src/vs/editor/contrib/snippet/test/browser/snippetSession.test.ts +++ b/src/vs/editor/contrib/snippet/test/browser/snippetSession.test.ts @@ -743,4 +743,36 @@ suite('SnippetSession', function () { '}', ].join('\n')); }); + + + suite('createEditsAndSnippetsFromEdits', function () { + + test('empty', function () { + + const result = SnippetSession.createEditsAndSnippetsFromEdits(editor, [], true, true, undefined, undefined, languageConfigurationService); + + assert.deepStrictEqual(result.edits, []); + assert.deepStrictEqual(result.snippets, []); + }); + + test('basic', function () { + + editor.getModel().setValue('foo("bar")'); + + const result = SnippetSession.createEditsAndSnippetsFromEdits( + editor, + [{ range: new Range(1, 5, 1, 9), template: '$1' }, { range: new Range(1, 1, 1, 1), template: 'const ${1:new_const} = "bar"' }], + true, true, undefined, undefined, languageConfigurationService + ); + + assert.strictEqual(result.edits.length, 2); + assert.deepStrictEqual(result.edits[0].range, new Range(1, 1, 1, 1)); + assert.deepStrictEqual(result.edits[0].text, 'const new_const = "bar"'); + assert.deepStrictEqual(result.edits[1].range, new Range(1, 5, 1, 9)); + assert.deepStrictEqual(result.edits[1].text, 'new_const'); + + assert.strictEqual(result.snippets.length, 1); + assert.strictEqual(result.snippets[0].isTrivialSnippet, false); + }); + }); }); diff --git a/src/vs/workbench/contrib/bulkEdit/browser/bulkTextEdits.ts b/src/vs/workbench/contrib/bulkEdit/browser/bulkTextEdits.ts index f69e60201f2..b07897a513a 100644 --- a/src/vs/workbench/contrib/bulkEdit/browser/bulkTextEdits.ts +++ b/src/vs/workbench/contrib/bulkEdit/browser/bulkTextEdits.ts @@ -19,8 +19,9 @@ import { ResourceMap } from 'vs/base/common/map'; import { IModelService } from 'vs/editor/common/services/model'; import { ResourceTextEdit } from 'vs/editor/browser/services/bulkEditService'; import { CancellationToken } from 'vs/base/common/cancellation'; -import { performSnippetEdits } from 'vs/editor/contrib/snippet/browser/snippetController2'; +import { SnippetController2 } from 'vs/editor/contrib/snippet/browser/snippetController2'; import { SnippetParser } from 'vs/editor/contrib/snippet/browser/snippetParser'; +import { ISnippetEdit } from 'vs/editor/contrib/snippet/browser/snippetSession'; type ValidationResult = { canApply: true } | { canApply: false; reason: URI }; @@ -141,14 +142,24 @@ class EditorEditTask extends ModelEditTask { super.apply(); return; } - if (this._edits.length > 0) { - const insertAsSnippet = this._edits.every(edit => edit.insertAsSnippet); - if (insertAsSnippet) { - // todo@jrieken what ABOUT EOL? - performSnippetEdits(this._editor, this._edits.map(edit => ({ range: Range.lift(edit.range!), snippet: edit.text! }))); + if (this._edits.length > 0) { + const snippetCtrl = SnippetController2.get(this._editor); + if (snippetCtrl && this._edits.some(edit => edit.insertAsSnippet)) { + // some edit is a snippet edit -> use snippet controller and ISnippetEdits + const snippetEdits: ISnippetEdit[] = []; + for (const edit of this._edits) { + if (edit.range && edit.text !== null) { + snippetEdits.push({ + range: Range.lift(edit.range), + template: edit.insertAsSnippet ? edit.text : SnippetParser.escape(edit.text) + }); + } + } + snippetCtrl.apply(snippetEdits); } else { + // normal edit this._edits = this._edits .map(this._transformSnippetStringToInsertText, this) // mixed edits (snippet and normal) -> no snippet mode .sort((a, b) => Range.compareRangesUsingStarts(a.range, b.range)); From 2c7201670f8bb71c43b3e448a0df6ac7b3720d61 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Tue, 5 Jul 2022 12:51:28 -0700 Subject: [PATCH 248/347] Remove use of forEach (#154196) For #154195 --- .../api/test/browser/extHostTypeConverter.test.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/api/test/browser/extHostTypeConverter.test.ts b/src/vs/workbench/api/test/browser/extHostTypeConverter.test.ts index a7a0b914279..650c28eb667 100644 --- a/src/vs/workbench/api/test/browser/extHostTypeConverter.test.ts +++ b/src/vs/workbench/api/test/browser/extHostTypeConverter.test.ts @@ -8,7 +8,6 @@ import * as assert from 'assert'; import * as extHostTypes from 'vs/workbench/api/common/extHostTypes'; import { MarkdownString, NotebookCellOutputItem, NotebookData, LanguageSelector } from 'vs/workbench/api/common/extHostTypeConverters'; import { isEmptyObject } from 'vs/base/common/types'; -import { forEach } from 'vs/base/common/collections'; import { LogLevel as _MainLogLevel } from 'vs/platform/log/common/log'; import { URI } from 'vs/base/common/uri'; @@ -74,13 +73,13 @@ suite('ExtHostTypeConverter', function () { const data = MarkdownString.from('*hello* [click](command:npm.runScriptFromHover?%7B%22documentUri%22%3A%7B%22%24mid%22%3A1%2C%22external%22%3A%22file%3A%2F%2F%2Fc%253A%2Ffoo%2Fbaz.ex%22%2C%22path%22%3A%22%2Fc%3A%2Ffoo%2Fbaz.ex%22%2C%22scheme%22%3A%22file%22%7D%2C%22script%22%3A%22dev%22%7D)'); // assert that both uri get extracted but that the latter is only decoded once... assert.strictEqual(size(data.uris!), 2); - forEach(data.uris!, entry => { - if (entry.value.scheme === 'file') { - assert.ok(URI.revive(entry.value).toString().indexOf('file:///c%3A') === 0); + for (const value of Object.values(data.uris!)) { + if (value.scheme === 'file') { + assert.ok(URI.revive(value).toString().indexOf('file:///c%3A') === 0); } else { - assert.strictEqual(entry.value.scheme, 'command'); + assert.strictEqual(value.scheme, 'command'); } - }); + } }); test('Notebook metadata is ignored when using Notebook Serializer #125716', function () { From 3e59037fa15db36fd2dca02b1546f8e8ac2e6d80 Mon Sep 17 00:00:00 2001 From: Joyce Er Date: Tue, 5 Jul 2022 12:54:14 -0700 Subject: [PATCH 249/347] Debt - Add dedicated Edit Sessions output channel (#154190) * Create a separate log channel for edit sessions * Move edit sessions services into contrib since they are not accessed from outside the contrib * Remove redundant log message prefix * Update test --- .../environment/common/environment.ts | 1 + .../environment/common/environmentService.ts | 3 ++ .../contrib/logs/common/logConstants.ts | 1 + .../contrib/logs/common/logs.contribution.ts | 1 + .../browser/sessionSync.contribution.ts | 41 ++++++++------- .../browser/sessionSyncWorkbenchService.ts | 15 +++--- .../common/editSessionsLogService.ts | 50 +++++++++++++++++++ .../sessionSync/common/sessionSync.ts | 4 ++ .../test/browser/sessionSync.test.ts | 6 +-- .../environment/browser/environmentService.ts | 3 ++ 10 files changed, 95 insertions(+), 30 deletions(-) rename src/vs/workbench/{services => contrib}/sessionSync/browser/sessionSyncWorkbenchService.ts (94%) create mode 100644 src/vs/workbench/contrib/sessionSync/common/editSessionsLogService.ts rename src/vs/workbench/{services => contrib}/sessionSync/common/sessionSync.ts (89%) diff --git a/src/vs/platform/environment/common/environment.ts b/src/vs/platform/environment/common/environment.ts index 5ed69a092ef..32fcb903d4c 100644 --- a/src/vs/platform/environment/common/environment.ts +++ b/src/vs/platform/environment/common/environment.ts @@ -66,6 +66,7 @@ export interface IEnvironmentService { // --- continue edit session editSessionId?: string; + editSessionsLogResource: URI; // --- extension development debugExtensionHost: IExtensionHostDebugParams; diff --git a/src/vs/platform/environment/common/environmentService.ts b/src/vs/platform/environment/common/environmentService.ts index 992c7ed9a96..90b24b9c924 100644 --- a/src/vs/platform/environment/common/environmentService.ts +++ b/src/vs/platform/environment/common/environmentService.ts @@ -80,6 +80,9 @@ export abstract class AbstractNativeEnvironmentService implements INativeEnviron @memoize get userDataSyncLogResource(): URI { return URI.file(join(this.logsPath, 'userDataSync.log')); } + @memoize + get editSessionsLogResource(): URI { return URI.file(join(this.logsPath, 'editSessions.log')); } + @memoize get sync(): 'on' | 'off' | undefined { return this.args.sync; } diff --git a/src/vs/workbench/contrib/logs/common/logConstants.ts b/src/vs/workbench/contrib/logs/common/logConstants.ts index 9ba3e7aa0ee..4342dd4a740 100644 --- a/src/vs/workbench/contrib/logs/common/logConstants.ts +++ b/src/vs/workbench/contrib/logs/common/logConstants.ts @@ -9,5 +9,6 @@ export const rendererLogChannelId = 'rendererLog'; export const extHostLogChannelId = 'extHostLog'; export const telemetryLogChannelId = 'telemetryLog'; export const userDataSyncLogChannelId = 'userDataSyncLog'; +export const editSessionsLogChannelId = 'editSessionsSyncLog'; export const showWindowLogActionId = 'workbench.action.showWindowLog'; diff --git a/src/vs/workbench/contrib/logs/common/logs.contribution.ts b/src/vs/workbench/contrib/logs/common/logs.contribution.ts index 5e533149305..f45fe793b09 100644 --- a/src/vs/workbench/contrib/logs/common/logs.contribution.ts +++ b/src/vs/workbench/contrib/logs/common/logs.contribution.ts @@ -38,6 +38,7 @@ class LogOutputChannels extends Disposable implements IWorkbenchContribution { private registerCommonContributions(): void { this.registerLogChannel(Constants.userDataSyncLogChannelId, nls.localize('userDataSyncLog', "Settings Sync"), this.environmentService.userDataSyncLogResource); + this.registerLogChannel(Constants.editSessionsLogChannelId, nls.localize('editSessionsLog', "Edit Sessions"), this.environmentService.editSessionsLogResource); this.registerLogChannel(Constants.rendererLogChannelId, nls.localize('rendererLog', "Window"), this.environmentService.logFile); const registerTelemetryChannel = () => { diff --git a/src/vs/workbench/contrib/sessionSync/browser/sessionSync.contribution.ts b/src/vs/workbench/contrib/sessionSync/browser/sessionSync.contribution.ts index 08381fc3d9c..642ab0ce273 100644 --- a/src/vs/workbench/contrib/sessionSync/browser/sessionSync.contribution.ts +++ b/src/vs/workbench/contrib/sessionSync/browser/sessionSync.contribution.ts @@ -10,7 +10,7 @@ import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/actions'; import { ServicesAccessor } from 'vs/editor/browser/editorExtensions'; import { localize } from 'vs/nls'; -import { ISessionSyncWorkbenchService, Change, ChangeType, Folder, EditSession, FileType, EDIT_SESSION_SYNC_CATEGORY, EditSessionSchemaVersion } from 'vs/workbench/services/sessionSync/common/sessionSync'; +import { ISessionSyncWorkbenchService, Change, ChangeType, Folder, EditSession, FileType, EDIT_SESSION_SYNC_CATEGORY, EditSessionSchemaVersion, IEditSessionsLogService } from 'vs/workbench/contrib/sessionSync/common/sessionSync'; import { ISCMRepository, ISCMService } from 'vs/workbench/contrib/scm/common/scm'; import { IFileService } from 'vs/platform/files/common/files'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; @@ -19,13 +19,12 @@ import { joinPath, relativePath } from 'vs/base/common/resources'; import { VSBuffer } from 'vs/base/common/buffer'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress'; -import { SessionSyncWorkbenchService } from 'vs/workbench/services/sessionSync/browser/sessionSyncWorkbenchService'; +import { SessionSyncWorkbenchService } from 'vs/workbench/contrib/sessionSync/browser/sessionSyncWorkbenchService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { UserDataSyncErrorCode, UserDataSyncStoreError } from 'vs/platform/userDataSync/common/userDataSync'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { IDialogService, IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; -import { ILogService } from 'vs/platform/log/common/log'; import { IProductService } from 'vs/platform/product/common/productService'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; @@ -39,7 +38,9 @@ import { getVirtualWorkspaceLocation } from 'vs/platform/workspace/common/virtua import { Schemas } from 'vs/base/common/network'; import { IsWebContext } from 'vs/platform/contextkey/common/contextkeys'; import { isProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions'; +import { EditSessionsLogService } from 'vs/workbench/contrib/sessionSync/common/editSessionsLogService'; +registerSingleton(IEditSessionsLogService, EditSessionsLogService); registerSingleton(ISessionSyncWorkbenchService, SessionSyncWorkbenchService); const resumeLatestCommand = { @@ -61,6 +62,7 @@ const openLocalFolderCommand = { title: { value: localize('continue edit session in local folder', "Open In Local Folder"), original: 'Open In Local Folder' }, }; const queryParamName = 'editSessionId'; +const experimentalSettingName = 'workbench.experimental.editSessions.enabled'; export class SessionSyncContribution extends Disposable implements IWorkbenchContribution { @@ -76,7 +78,7 @@ export class SessionSyncContribution extends Disposable implements IWorkbenchCon @ISCMService private readonly scmService: ISCMService, @INotificationService private readonly notificationService: INotificationService, @IDialogService private readonly dialogService: IDialogService, - @ILogService private readonly logService: ILogService, + @IEditSessionsLogService private readonly logService: IEditSessionsLogService, @IEnvironmentService private readonly environmentService: IEnvironmentService, @IProductService private readonly productService: IProductService, @IConfigurationService private configurationService: IConfigurationService, @@ -93,7 +95,7 @@ export class SessionSyncContribution extends Disposable implements IWorkbenchCon } this.configurationService.onDidChangeConfiguration((e) => { - if (e.affectsConfiguration('workbench.experimental.editSessions.enabled')) { + if (e.affectsConfiguration(experimentalSettingName)) { this.registerActions(); } }); @@ -129,7 +131,8 @@ export class SessionSyncContribution extends Disposable implements IWorkbenchCon } private registerActions() { - if (this.registered || this.configurationService.getValue('workbench.experimental.editSessions.enabled') !== true) { + if (this.registered || this.configurationService.getValue(experimentalSettingName) !== true) { + this.logService.info(`Skipping registering edit sessions actions as edit sessions are currently disabled. Set ${experimentalSettingName} to enable edit sessions.`); return; } @@ -167,11 +170,11 @@ export class SessionSyncContribution extends Disposable implements IWorkbenchCon query: uri.query.length > 0 ? (uri + `&${queryParamName}=${encodedRef}`) : `${queryParamName}=${encodedRef}` }); } else { - that.logService.warn(`Edit Sessions: Failed to store edit session when invoking ${continueEditSessionCommand.id}.`); + that.logService.warn(`Failed to store edit session when invoking ${continueEditSessionCommand.id}.`); } // Open the URI - that.logService.info(`Edit Sessions: opening ${uri.toString()}`); + that.logService.info(`Opening ${uri.toString()}`); await that.openerService.open(uri, { openExternal: true }); } })); @@ -221,7 +224,7 @@ export class SessionSyncContribution extends Disposable implements IWorkbenchCon async applyEditSession(ref?: string): Promise { if (ref !== undefined) { - this.logService.info(`Edit Sessions: Applying edit session with ref ${ref}.`); + this.logService.info(`Applying edit session with ref ${ref}.`); } const data = await this.sessionSyncWorkbenchService.read(ref); @@ -231,7 +234,7 @@ export class SessionSyncContribution extends Disposable implements IWorkbenchCon } else { this.notificationService.warn(localize('no edit session content for ref', 'Could not apply edit session contents for ID {0}.', ref)); } - this.logService.info(`Edit Sessions: Aborting applying edit session as no edit session content is available to be applied from ref ${ref}.`); + this.logService.info(`Aborting applying edit session as no edit session content is available to be applied from ref ${ref}.`); return; } const editSession = data.editSession; @@ -249,7 +252,7 @@ export class SessionSyncContribution extends Disposable implements IWorkbenchCon for (const folder of editSession.folders) { const folderRoot = this.contextService.getWorkspace().folders.find((f) => f.name === folder.name); if (!folderRoot) { - this.logService.info(`Edit Sessions: Skipping applying ${folder.workingChanges.length} changes from edit session with ref ${ref} as no corresponding workspace folder named ${folder.name} is currently open.`); + this.logService.info(`Skipping applying ${folder.workingChanges.length} changes from edit session with ref ${ref} as no corresponding workspace folder named ${folder.name} is currently open.`); continue; } @@ -289,11 +292,11 @@ export class SessionSyncContribution extends Disposable implements IWorkbenchCon } } - this.logService.info(`Edit Sessions: Deleting edit session with ref ${ref} after successfully applying it to current workspace...`); + this.logService.info(`Deleting edit session with ref ${ref} after successfully applying it to current workspace...`); await this.sessionSyncWorkbenchService.delete(ref); - this.logService.info(`Edit Sessions: Deleted edit session with ref ${ref}.`); + this.logService.info(`Deleted edit session with ref ${ref}.`); } catch (ex) { - this.logService.error('Edit Sessions: Failed to apply edit session, reason: ', (ex as Error).toString()); + this.logService.error('Failed to apply edit session, reason: ', (ex as Error).toString()); this.notificationService.error(localize('apply failed', "Failed to apply your edit session.")); } } @@ -312,7 +315,7 @@ export class SessionSyncContribution extends Disposable implements IWorkbenchCon for (const uri of trackedUris) { const workspaceFolder = this.contextService.getWorkspaceFolder(uri); if (!workspaceFolder) { - this.logService.info(`Edit Sessions: Skipping working change ${uri.toString()} as no associated workspace folder was found.`); + this.logService.info(`Skipping working change ${uri.toString()} as no associated workspace folder was found.`); continue; } @@ -341,7 +344,7 @@ export class SessionSyncContribution extends Disposable implements IWorkbenchCon } if (!hasEdits) { - this.logService.info('Edit Sessions: Skipping storing edit session as there are no edits to store.'); + this.logService.info('Skipping storing edit session as there are no edits to store.'); if (fromStoreCommand) { this.notificationService.info(localize('no edits to store', 'Skipped storing edit session as there are no edits to store.')); } @@ -351,12 +354,12 @@ export class SessionSyncContribution extends Disposable implements IWorkbenchCon const data: EditSession = { folders, version: 1 }; try { - this.logService.info(`Edit Sessions: Storing edit session...`); + this.logService.info(`Storing edit session...`); const ref = await this.sessionSyncWorkbenchService.write(data); - this.logService.info(`Edit Sessions: Stored edit session with ref ${ref}.`); + this.logService.info(`Stored edit session with ref ${ref}.`); return ref; } catch (ex) { - this.logService.error(`Edit Sessions: Failed to store edit session, reason: `, (ex as Error).toString()); + this.logService.error(`Failed to store edit session, reason: `, (ex as Error).toString()); type UploadFailedEvent = { reason: string }; type UploadFailedClassification = { diff --git a/src/vs/workbench/services/sessionSync/browser/sessionSyncWorkbenchService.ts b/src/vs/workbench/contrib/sessionSync/browser/sessionSyncWorkbenchService.ts similarity index 94% rename from src/vs/workbench/services/sessionSync/browser/sessionSyncWorkbenchService.ts rename to src/vs/workbench/contrib/sessionSync/browser/sessionSyncWorkbenchService.ts index 4274c62031d..1df0ecc3d28 100644 --- a/src/vs/workbench/services/sessionSync/browser/sessionSyncWorkbenchService.ts +++ b/src/vs/workbench/contrib/sessionSync/browser/sessionSyncWorkbenchService.ts @@ -10,7 +10,6 @@ import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/act import { ContextKeyExpr, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IFileService } from 'vs/platform/files/common/files'; -import { ILogService } from 'vs/platform/log/common/log'; import { IProductService } from 'vs/platform/product/common/productService'; import { IQuickInputService, IQuickPickItem, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput'; import { IRequestService } from 'vs/platform/request/common/request'; @@ -19,7 +18,7 @@ import { IAuthenticationProvider } from 'vs/platform/userDataSync/common/userDat import { UserDataSyncStoreClient } from 'vs/platform/userDataSync/common/userDataSyncStoreService'; import { AuthenticationSession, AuthenticationSessionsChangeEvent, IAuthenticationService } from 'vs/workbench/services/authentication/common/authentication'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; -import { EDIT_SESSIONS_SIGNED_IN, EditSession, EDIT_SESSION_SYNC_CATEGORY, ISessionSyncWorkbenchService, EDIT_SESSIONS_SIGNED_IN_KEY } from 'vs/workbench/services/sessionSync/common/sessionSync'; +import { EDIT_SESSIONS_SIGNED_IN, EditSession, EDIT_SESSION_SYNC_CATEGORY, ISessionSyncWorkbenchService, EDIT_SESSIONS_SIGNED_IN_KEY, IEditSessionsLogService } from 'vs/workbench/contrib/sessionSync/common/sessionSync'; type ExistingSession = IQuickPickItem & { session: AuthenticationSession & { providerId: string } }; type AuthenticationProviderOption = IQuickPickItem & { provider: IAuthenticationProvider }; @@ -44,7 +43,7 @@ export class SessionSyncWorkbenchService extends Disposable implements ISessionS @IAuthenticationService private readonly authenticationService: IAuthenticationService, @IExtensionService private readonly extensionService: IExtensionService, @IEnvironmentService private readonly environmentService: IEnvironmentService, - @ILogService private readonly logService: ILogService, + @IEditSessionsLogService private readonly logService: IEditSessionsLogService, @IProductService private readonly productService: IProductService, @IContextKeyService private readonly contextKeyService: IContextKeyService, @IRequestService private readonly requestService: IRequestService, @@ -144,7 +143,7 @@ export class SessionSyncWorkbenchService extends Disposable implements ISessionS if (!this.storeClient) { this.storeClient = new UserDataSyncStoreClient(URI.parse(this.serverConfiguration.url), this.productService, this.requestService, this.logService, this.environmentService, this.fileService, this.storageService); this._register(this.storeClient.onTokenFailed(() => { - this.logService.info('Edit Sessions: clearing edit sessions authentication preference because of successive token failures.'); + this.logService.info('Clearing edit sessions authentication preference because of successive token failures.'); this.clearAuthenticationPreference(); })); } @@ -157,10 +156,10 @@ export class SessionSyncWorkbenchService extends Disposable implements ISessionS // If the user signed in previously and the session is still available, reuse that without prompting the user again const existingSessionId = this.existingSessionId; if (existingSessionId) { - this.logService.trace(`Edit Sessions: Searching for existing authentication session with ID ${existingSessionId}`); + this.logService.trace(`Searching for existing authentication session with ID ${existingSessionId}`); const existing = await this.getExistingSession(); if (existing !== undefined) { - this.logService.trace(`Edit Sessions: Found existing authentication session with ID ${existingSessionId}`); + this.logService.trace(`Found existing authentication session with ID ${existingSessionId}`); this.#authenticationInfo = { sessionId: existing.session.id, token: existing.session.accessToken, providerId: existing.session.providerId }; this.storeClient.setAuthToken(this.#authenticationInfo.token, this.#authenticationInfo.providerId); return true; @@ -173,7 +172,7 @@ export class SessionSyncWorkbenchService extends Disposable implements ISessionS this.#authenticationInfo = { sessionId: session.id, token: session.accessToken, providerId: session.providerId }; this.storeClient.setAuthToken(this.#authenticationInfo.token, this.#authenticationInfo.providerId); this.existingSessionId = session.id; - this.logService.trace(`Edit Sessions: Saving authentication session preference for ID ${session.id}.`); + this.logService.trace(`Saving authentication session preference for ID ${session.id}.`); return true; } @@ -311,7 +310,7 @@ export class SessionSyncWorkbenchService extends Disposable implements ISessionS const previousSessionId = this.#authenticationInfo?.sessionId; if (previousSessionId !== newSessionId) { - this.logService.trace(`Edit Sessions: resetting authentication state because authentication session ID preference changed from ${previousSessionId} to ${newSessionId}.`); + this.logService.trace(`Resetting authentication state because authentication session ID preference changed from ${previousSessionId} to ${newSessionId}.`); this.#authenticationInfo = undefined; this.initialized = false; } diff --git a/src/vs/workbench/contrib/sessionSync/common/editSessionsLogService.ts b/src/vs/workbench/contrib/sessionSync/common/editSessionsLogService.ts new file mode 100644 index 00000000000..2b3b6bca671 --- /dev/null +++ b/src/vs/workbench/contrib/sessionSync/common/editSessionsLogService.ts @@ -0,0 +1,50 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { AbstractLogger, ILogger, ILoggerService } from 'vs/platform/log/common/log'; +import { IEditSessionsLogService } from 'vs/workbench/contrib/sessionSync/common/sessionSync'; + +export class EditSessionsLogService extends AbstractLogger implements IEditSessionsLogService { + + declare readonly _serviceBrand: undefined; + private readonly logger: ILogger; + + constructor( + @ILoggerService loggerService: ILoggerService, + @IEnvironmentService environmentService: IEnvironmentService + ) { + super(); + this.logger = this._register(loggerService.createLogger(environmentService.editSessionsLogResource, { name: 'editsessions' })); + } + + trace(message: string, ...args: any[]): void { + this.logger.trace(message, ...args); + } + + debug(message: string, ...args: any[]): void { + this.logger.debug(message, ...args); + } + + info(message: string, ...args: any[]): void { + this.logger.info(message, ...args); + } + + warn(message: string, ...args: any[]): void { + this.logger.warn(message, ...args); + } + + error(message: string | Error, ...args: any[]): void { + this.logger.error(message, ...args); + } + + critical(message: string | Error, ...args: any[]): void { + this.logger.critical(message, ...args); + } + + flush(): void { + this.logger.flush(); + } +} diff --git a/src/vs/workbench/services/sessionSync/common/sessionSync.ts b/src/vs/workbench/contrib/sessionSync/common/sessionSync.ts similarity index 89% rename from src/vs/workbench/services/sessionSync/common/sessionSync.ts rename to src/vs/workbench/contrib/sessionSync/common/sessionSync.ts index c671ae2aeab..538a54a6444 100644 --- a/src/vs/workbench/services/sessionSync/common/sessionSync.ts +++ b/src/vs/workbench/contrib/sessionSync/common/sessionSync.ts @@ -7,6 +7,7 @@ import { localize } from 'vs/nls'; import { ILocalizedString } from 'vs/platform/action/common/action'; import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { ILogService } from 'vs/platform/log/common/log'; export const EDIT_SESSION_SYNC_CATEGORY: ILocalizedString = { original: 'Edit Sessions', @@ -22,6 +23,9 @@ export interface ISessionSyncWorkbenchService { delete(ref: string): Promise; } +export const IEditSessionsLogService = createDecorator('IEditSessionsLogService'); +export interface IEditSessionsLogService extends ILogService { } + export enum ChangeType { Addition = 1, Deletion = 2, diff --git a/src/vs/workbench/contrib/sessionSync/test/browser/sessionSync.test.ts b/src/vs/workbench/contrib/sessionSync/test/browser/sessionSync.test.ts index 5c29394116b..140c068d5d0 100644 --- a/src/vs/workbench/contrib/sessionSync/test/browser/sessionSync.test.ts +++ b/src/vs/workbench/contrib/sessionSync/test/browser/sessionSync.test.ts @@ -9,7 +9,7 @@ import { FileService } from 'vs/platform/files/common/fileService'; import { Schemas } from 'vs/base/common/network'; import { InMemoryFileSystemProvider } from 'vs/platform/files/common/inMemoryFilesystemProvider'; import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; -import { NullLogService, ILogService } from 'vs/platform/log/common/log'; +import { NullLogService } from 'vs/platform/log/common/log'; import { SessionSyncContribution } from 'vs/workbench/contrib/sessionSync/browser/sessionSync.contribution'; import { ProgressService } from 'vs/workbench/services/progress/browser/progressService'; import { IProgressService } from 'vs/platform/progress/common/progress'; @@ -21,7 +21,7 @@ import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace import { mock } from 'vs/base/test/common/mock'; import * as sinon from 'sinon'; import * as assert from 'assert'; -import { ChangeType, FileType, ISessionSyncWorkbenchService } from 'vs/workbench/services/sessionSync/common/sessionSync'; +import { ChangeType, FileType, IEditSessionsLogService, ISessionSyncWorkbenchService } from 'vs/workbench/contrib/sessionSync/common/sessionSync'; import { URI } from 'vs/base/common/uri'; import { joinPath } from 'vs/base/common/resources'; import { INotificationService } from 'vs/platform/notification/common/notification'; @@ -52,7 +52,7 @@ suite('Edit session sync', () => { fileService.registerProvider(Schemas.file, fileSystemProvider); // Stub out all services - instantiationService.stub(ILogService, logService); + instantiationService.stub(IEditSessionsLogService, logService); instantiationService.stub(IFileService, fileService); instantiationService.stub(INotificationService, new TestNotificationService()); instantiationService.stub(ISessionSyncWorkbenchService, new class extends mock() { }); diff --git a/src/vs/workbench/services/environment/browser/environmentService.ts b/src/vs/workbench/services/environment/browser/environmentService.ts index 631b3db439e..82a2541576a 100644 --- a/src/vs/workbench/services/environment/browser/environmentService.ts +++ b/src/vs/workbench/services/environment/browser/environmentService.ts @@ -83,6 +83,9 @@ export class BrowserWorkbenchEnvironmentService implements IBrowserWorkbenchEnvi @memoize get userDataSyncLogResource(): URI { return joinPath(this.logsHome, 'userDataSync.log'); } + @memoize + get editSessionsLogResource(): URI { return joinPath(this.logsHome, 'editSessions.log'); } + @memoize get sync(): 'on' | 'off' | undefined { return undefined; } From 1a621c9b744ebee70a011324a114994300952f6c Mon Sep 17 00:00:00 2001 From: Frank Dana Date: Tue, 5 Jul 2022 17:01:03 -0400 Subject: [PATCH 250/347] Remove fakeroot wrapper, when building .rpm packages (#153249) RPM packaging: Don't use fakeroot to build RPM packages are intended to be built by normal users, they don't require root permissions (even fake ones). Co-authored-by: Raymond Zhao <7199958+rzhao271@users.noreply.github.com> --- build/gulpfile.vscode.linux.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/gulpfile.vscode.linux.js b/build/gulpfile.vscode.linux.js index 7d0f70f9bef..210556eddb6 100644 --- a/build/gulpfile.vscode.linux.js +++ b/build/gulpfile.vscode.linux.js @@ -210,7 +210,7 @@ function buildRpmPackage(arch) { return shell.task([ 'mkdir -p ' + destination, - 'HOME="$(pwd)/' + destination + '" fakeroot rpmbuild -bb ' + rpmBuildPath + '/SPECS/' + product.applicationName + '.spec --target=' + rpmArch, + 'HOME="$(pwd)/' + destination + '" rpmbuild -bb ' + rpmBuildPath + '/SPECS/' + product.applicationName + '.spec --target=' + rpmArch, 'cp "' + rpmOut + '/$(ls ' + rpmOut + ')" ' + destination + '/' ]); } From a08b7bb4d7f0427d515963d71beb50fc493cc0da Mon Sep 17 00:00:00 2001 From: Tomer Chachamu Date: Tue, 5 Jul 2022 22:53:02 +0100 Subject: [PATCH 251/347] Fix test error not showing when expanded (#153994) --- .../testing/browser/explorerProjections/nodeHelper.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/testing/browser/explorerProjections/nodeHelper.ts b/src/vs/workbench/contrib/testing/browser/explorerProjections/nodeHelper.ts index 0f0d26be6b4..6a74365ede4 100644 --- a/src/vs/workbench/contrib/testing/browser/explorerProjections/nodeHelper.ts +++ b/src/vs/workbench/contrib/testing/browser/explorerProjections/nodeHelper.ts @@ -6,11 +6,11 @@ import { IIdentityProvider } from 'vs/base/browser/ui/list/list'; import { ObjectTree } from 'vs/base/browser/ui/tree/objectTree'; import { ITreeElement } from 'vs/base/browser/ui/tree/tree'; -import { IActionableTestTreeElement, TestExplorerTreeElement, TestItemTreeElement } from 'vs/workbench/contrib/testing/browser/explorerProjections/index'; +import { IActionableTestTreeElement, TestExplorerTreeElement, TestItemTreeElement, TestTreeErrorMessage } from 'vs/workbench/contrib/testing/browser/explorerProjections/index'; -export const testIdentityProvider: IIdentityProvider = { +export const testIdentityProvider: IIdentityProvider = { getId(element) { - return element.treeId + '\0' + element.test.expand; + return element.treeId + '\0' + (element instanceof TestTreeErrorMessage ? 'error' : element.test.expand); } }; From 3862aa876e95b4fe76922349e8c440092dc4bf6c Mon Sep 17 00:00:00 2001 From: Joyce Er Date: Tue, 5 Jul 2022 14:57:52 -0700 Subject: [PATCH 252/347] Debt - clean up edit session action option declaration (#154202) Debt - clean up action option declaration --- .../browser/sessionSync.contribution.ts | 46 +++++++------------ 1 file changed, 17 insertions(+), 29 deletions(-) diff --git a/src/vs/workbench/contrib/sessionSync/browser/sessionSync.contribution.ts b/src/vs/workbench/contrib/sessionSync/browser/sessionSync.contribution.ts index 642ab0ce273..a4cf8be1f5f 100644 --- a/src/vs/workbench/contrib/sessionSync/browser/sessionSync.contribution.ts +++ b/src/vs/workbench/contrib/sessionSync/browser/sessionSync.contribution.ts @@ -7,7 +7,7 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { Registry } from 'vs/platform/registry/common/platform'; import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; -import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/actions'; +import { Action2, IAction2Options, registerAction2 } from 'vs/platform/actions/common/actions'; import { ServicesAccessor } from 'vs/editor/browser/editorExtensions'; import { localize } from 'vs/nls'; import { ISessionSyncWorkbenchService, Change, ChangeType, Folder, EditSession, FileType, EDIT_SESSION_SYNC_CATEGORY, EditSessionSchemaVersion, IEditSessionsLogService } from 'vs/workbench/contrib/sessionSync/common/sessionSync'; @@ -43,23 +43,17 @@ import { EditSessionsLogService } from 'vs/workbench/contrib/sessionSync/common/ registerSingleton(IEditSessionsLogService, EditSessionsLogService); registerSingleton(ISessionSyncWorkbenchService, SessionSyncWorkbenchService); -const resumeLatestCommand = { - id: 'workbench.experimental.editSessions.actions.resumeLatest', - title: { value: localize('resume latest', "Resume Latest Edit Session"), original: 'Resume Latest Edit Session' }, - category: EDIT_SESSION_SYNC_CATEGORY, -}; -const storeCurrentCommand = { - id: 'workbench.experimental.editSessions.actions.storeCurrent', - title: { value: localize('store current', "Store Current Edit Session"), original: 'Store Current Edit Session' }, - category: EDIT_SESSION_SYNC_CATEGORY, -}; -const continueEditSessionCommand = { +const continueEditSessionCommand: IAction2Options = { id: '_workbench.experimental.editSessions.actions.continueEditSession', title: { value: localize('continue edit session', "Continue Edit Session..."), original: 'Continue Edit Session...' }, + category: EDIT_SESSION_SYNC_CATEGORY, + f1: true }; -const openLocalFolderCommand = { +const openLocalFolderCommand: IAction2Options = { id: '_workbench.experimental.editSessions.actions.continueEditSession.openLocalFolder', title: { value: localize('continue edit session in local folder', "Open In Local Folder"), original: 'Open In Local Folder' }, + category: EDIT_SESSION_SYNC_CATEGORY, + precondition: IsWebContext }; const queryParamName = 'editSessionId'; const experimentalSettingName = 'workbench.experimental.editSessions.enabled'; @@ -150,10 +144,7 @@ export class SessionSyncContribution extends Disposable implements IWorkbenchCon const that = this; this._register(registerAction2(class ContinueEditSessionAction extends Action2 { constructor() { - super({ - ...continueEditSessionCommand, - f1: true - }); + super(continueEditSessionCommand); } async run(accessor: ServicesAccessor, workspaceUri: URI | undefined): Promise { @@ -185,10 +176,10 @@ export class SessionSyncContribution extends Disposable implements IWorkbenchCon this._register(registerAction2(class ApplyLatestEditSessionAction extends Action2 { constructor() { super({ - ...resumeLatestCommand, - menu: { - id: MenuId.CommandPalette, - } + id: 'workbench.experimental.editSessions.actions.resumeLatest', + title: { value: localize('resume latest.v2', "Resume Latest Edit Session"), original: 'Resume Latest Edit Session' }, + category: EDIT_SESSION_SYNC_CATEGORY, + f1: true, }); } @@ -206,10 +197,10 @@ export class SessionSyncContribution extends Disposable implements IWorkbenchCon this._register(registerAction2(class StoreLatestEditSessionAction extends Action2 { constructor() { super({ - ...storeCurrentCommand, - menu: { - id: MenuId.CommandPalette, - } + id: 'workbench.experimental.editSessions.actions.storeCurrent', + title: { value: localize('store current.v2', "Store Current Edit Session"), original: 'Store Current Edit Session' }, + category: EDIT_SESSION_SYNC_CATEGORY, + f1: true, }); } @@ -400,10 +391,7 @@ export class SessionSyncContribution extends Disposable implements IWorkbenchCon const that = this; this._register(registerAction2(class ContinueInLocalFolderAction extends Action2 { constructor() { - super({ - ...openLocalFolderCommand, - precondition: IsWebContext - }); + super(openLocalFolderCommand); } async run(accessor: ServicesAccessor): Promise { From 9c3b0bb9b44e011b82a3c7f83ac748f716e6604e Mon Sep 17 00:00:00 2001 From: Frank Dana Date: Tue, 5 Jul 2022 20:13:06 -0400 Subject: [PATCH 253/347] RPM: Make /usr/bin/code owned by package (#142907) Create the `/usr/bin/code` symlink during %install so that the package owns and manages it. Also, make it relative (for better relocatability). Co-authored-by: Raymond Zhao <7199958+rzhao271@users.noreply.github.com> --- resources/linux/rpm/code.spec.template | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/resources/linux/rpm/code.spec.template b/resources/linux/rpm/code.spec.template index 7eea9ff555d..00ddb6fdf08 100644 --- a/resources/linux/rpm/code.spec.template +++ b/resources/linux/rpm/code.spec.template @@ -21,6 +21,7 @@ Visual Studio Code is a new choice of tool that combines the simplicity of a cod %define _build_id_links none %install +mkdir -p %{buildroot}/usr/bin mkdir -p %{buildroot}/usr/share/@@NAME@@ mkdir -p %{buildroot}/usr/share/applications mkdir -p %{buildroot}/usr/share/pixmaps @@ -34,6 +35,7 @@ cp -r usr/share/mime/packages/@@NAME@@-workspace.xml %{buildroot}/usr/share/mime cp -r usr/share/pixmaps/@@ICON@@.png %{buildroot}/usr/share/pixmaps cp usr/share/bash-completion/completions/@@NAME@@ %{buildroot}/usr/share/bash-completion/completions/@@NAME@@ cp usr/share/zsh/site-functions/_@@NAME@@ %{buildroot}/usr/share/zsh/site-functions/_@@NAME@@ +ln -s ../share/@@NAME@@/bin/@@NAME@@ %{buildroot}/usr/bin/@@NAME@@ %post # Remove the legacy bin command if this is the stable build @@ -41,9 +43,6 @@ if [ "@@NAME@@" = "code" ]; then rm -f /usr/local/bin/code fi -# Symlink bin command to /usr/bin -ln -sf /usr/share/@@NAME@@/bin/@@NAME@@ %{_bindir}/@@NAME@@ - # Register yum repository # TODO: #229: Enable once the yum repository is signed #if [ "@@NAME@@" != "code-oss" ]; then @@ -58,10 +57,6 @@ ln -sf /usr/share/@@NAME@@/bin/@@NAME@@ %{_bindir}/@@NAME@@ update-mime-database /usr/share/mime &> /dev/null || : %postun -if [ $1 = 0 ]; then - rm -f /usr/bin/@@NAME@@ -fi - # Update mimetype database for removed workspace mimetype update-mime-database /usr/share/mime &> /dev/null || : @@ -69,6 +64,7 @@ update-mime-database /usr/share/mime &> /dev/null || : %defattr(-,root,root) %attr(4755, root, root) /usr/share/@@NAME@@/chrome-sandbox +/usr/bin/@@NAME@@ /usr/share/@@NAME@@/ /usr/share/applications/@@NAME@@.desktop /usr/share/applications/@@NAME@@-url-handler.desktop From 9c5408c04a614e641d7a69680686cb9346e0d7a8 Mon Sep 17 00:00:00 2001 From: Stephen Sigwart Date: Tue, 5 Jul 2022 20:39:22 -0400 Subject: [PATCH 254/347] Detect terminal links with space, then line:col (#153957) --- .../contrib/terminal/browser/links/terminalLocalLinkDetector.ts | 1 + .../test/browser/links/terminalLocalLinkDetector.test.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/src/vs/workbench/contrib/terminal/browser/links/terminalLocalLinkDetector.ts b/src/vs/workbench/contrib/terminal/browser/links/terminalLocalLinkDetector.ts index 19cab952add..cec80cf90b1 100644 --- a/src/vs/workbench/contrib/terminal/browser/links/terminalLocalLinkDetector.ts +++ b/src/vs/workbench/contrib/terminal/browser/links/terminalLocalLinkDetector.ts @@ -49,6 +49,7 @@ export const winLocalLinkClause = '((' + winPathPrefix + '|(' + winExcludedPathC /** As xterm reads from DOM, space in that case is nonbreaking char ASCII code - 160, replacing space with nonBreakningSpace or space ASCII code - 32. */ export const lineAndColumnClause = [ + '(([^:\\s\\(\\)<>\'\"\\[\\]]*) ((\\d+))(:(\\d+)))', // (file path) 336:9 [see #140780] '((\\S*)[\'"], line ((\\d+)( column (\\d+))?))', // "(file path)", line 45 [see #40468] '((\\S*)[\'"],((\\d+)(:(\\d+))?))', // "(file path)",45 [see #78205] '((\\S*) on line ((\\d+)(, column (\\d+))?))', // (file path) on line 8, column 13 diff --git a/src/vs/workbench/contrib/terminal/test/browser/links/terminalLocalLinkDetector.test.ts b/src/vs/workbench/contrib/terminal/test/browser/links/terminalLocalLinkDetector.test.ts index 9f72ece8c18..93ff1ce3687 100644 --- a/src/vs/workbench/contrib/terminal/test/browser/links/terminalLocalLinkDetector.test.ts +++ b/src/vs/workbench/contrib/terminal/test/browser/links/terminalLocalLinkDetector.test.ts @@ -68,6 +68,7 @@ const supportedLinkFormats: LinkFormatInfo[] = [ { urlFormat: '{0} ({1}, {2})', line: '5', column: '3' }, { urlFormat: '{0}:{1}', line: '5' }, { urlFormat: '{0}:{1}:{2}', line: '5', column: '3' }, + { urlFormat: '{0} {1}:{2}', line: '5', column: '3' }, { urlFormat: '{0}[{1}]', line: '5' }, { urlFormat: '{0} [{1}]', line: '5' }, { urlFormat: '{0}[{1},{2}]', line: '5', column: '3' }, From 0b07495a5526a0d30a579bbe873df5fc54454d60 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 6 Jul 2022 07:21:07 +0200 Subject: [PATCH 255/347] electron - log unexpected `setJumpList` result (#154228) --- .../workspaces/electron-main/workspacesHistoryMainService.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/vs/platform/workspaces/electron-main/workspacesHistoryMainService.ts b/src/vs/platform/workspaces/electron-main/workspacesHistoryMainService.ts index 3801775bee0..2f29d96f1ab 100644 --- a/src/vs/platform/workspaces/electron-main/workspacesHistoryMainService.ts +++ b/src/vs/platform/workspaces/electron-main/workspacesHistoryMainService.ts @@ -377,7 +377,10 @@ export class WorkspacesHistoryMainService extends Disposable implements IWorkspa }); try { - app.setJumpList(jumpList); + const res = app.setJumpList(jumpList); + if (res && res !== 'ok') { + this.logService.warn(`updateWindowsJumpList#setJumpList unexpected result: ${res}`); + } } catch (error) { this.logService.warn('updateWindowsJumpList#setJumpList', error); // since setJumpList is relatively new API, make sure to guard for errors } From f89c103f1162e800043182cabf0de6f15e1adc51 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 6 Jul 2022 07:52:24 +0200 Subject: [PATCH 256/347] storage - :lipstick: (#154230) --- .../electron-sandbox/storageService.ts | 24 +++++++------------ .../storage/browser/storageService.ts | 2 +- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/src/vs/platform/storage/electron-sandbox/storageService.ts b/src/vs/platform/storage/electron-sandbox/storageService.ts index 9a27bd23135..d5bf2548f20 100644 --- a/src/vs/platform/storage/electron-sandbox/storageService.ts +++ b/src/vs/platform/storage/electron-sandbox/storageService.ts @@ -16,30 +16,24 @@ import { IAnyWorkspaceIdentifier, IEmptyWorkspaceIdentifier, ISingleFolderWorksp export class NativeStorageService extends AbstractStorageService { - private readonly applicationStorage: IStorage; - private readonly applicationStorageProfile: IUserDataProfile; + private readonly applicationStorageProfile = this.initialProfiles.defaultProfile; + private readonly applicationStorage = this.createApplicationStorage(); - private profileStorage: IStorage; - private profileStorageProfile: IUserDataProfile | undefined = undefined; + private profileStorageProfile = this.initialProfiles.currentProfile; private readonly profileStorageDisposables = this._register(new DisposableStore()); + private profileStorage = this.createProfileStorage(this.profileStorageProfile); - private workspaceStorage: IStorage | undefined = undefined; - private workspaceStorageId: string | undefined = undefined; + private workspaceStorageId = this.initialWorkspace?.id; private readonly workspaceStorageDisposables = this._register(new DisposableStore()); + private workspaceStorage = this.createWorkspaceStorage(this.initialWorkspace); constructor( - workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier | undefined, - { defaultProfile, currentProfile }: { defaultProfile: IUserDataProfile; currentProfile: IUserDataProfile }, + private readonly initialWorkspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier | undefined, + private readonly initialProfiles: { defaultProfile: IUserDataProfile; currentProfile: IUserDataProfile }, private readonly mainProcessService: IMainProcessService, private readonly environmentService: IEnvironmentService ) { super(); - - this.applicationStorageProfile = defaultProfile; - - this.applicationStorage = this.createApplicationStorage(); - this.profileStorage = this.createProfileStorage(currentProfile); - this.workspaceStorage = this.createWorkspaceStorage(workspace); } private createApplicationStorage(): IStorage { @@ -148,7 +142,7 @@ export class NativeStorageService extends AbstractStorageService { } protected async switchToProfile(toProfile: IUserDataProfile, preserveData: boolean): Promise { - if (this.profileStorageProfile && !this.canSwitchProfile(this.profileStorageProfile, toProfile)) { + if (!this.canSwitchProfile(this.profileStorageProfile, toProfile)) { return; } diff --git a/src/vs/workbench/services/storage/browser/storageService.ts b/src/vs/workbench/services/storage/browser/storageService.ts index 694d8317a1f..a939ea7e567 100644 --- a/src/vs/workbench/services/storage/browser/storageService.ts +++ b/src/vs/workbench/services/storage/browser/storageService.ts @@ -166,7 +166,7 @@ export class BrowserStorageService extends AbstractStorageService { } protected async switchToProfile(toProfile: IUserDataProfile, preserveData: boolean): Promise { - if (this.profileStorageProfile && !this.canSwitchProfile(this.profileStorageProfile, toProfile)) { + if (!this.canSwitchProfile(this.profileStorageProfile, toProfile)) { return; } From c7e5301345e3d976f95f231a821e9e67555829cc Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Tue, 5 Jul 2022 22:54:58 -0700 Subject: [PATCH 257/347] fix #151986. Fix interactive window navigation. (#154200) fix #151986 --- .../browser/interactive.contribution.ts | 28 +++++++++++++++---- .../interactive/browser/interactiveEditor.ts | 7 ++++- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/contrib/interactive/browser/interactive.contribution.ts b/src/vs/workbench/contrib/interactive/browser/interactive.contribution.ts index f108213e01b..c49ec5ad519 100644 --- a/src/vs/workbench/contrib/interactive/browser/interactive.contribution.ts +++ b/src/vs/workbench/contrib/interactive/browser/interactive.contribution.ts @@ -9,6 +9,7 @@ import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; import { parse } from 'vs/base/common/marshalling'; import { Schemas } from 'vs/base/common/network'; +import { extname } from 'vs/base/common/resources'; import { isFalsyOrWhitespace } from 'vs/base/common/strings'; import { assertType } from 'vs/base/common/types'; import { URI } from 'vs/base/common/uri'; @@ -25,7 +26,7 @@ import { localize } from 'vs/nls'; import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/actions'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; -import { EditorActivation } from 'vs/platform/editor/common/editor'; +import { EditorActivation, IResourceEditorInput } from 'vs/platform/editor/common/editor'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; @@ -48,9 +49,10 @@ import { InteractiveEditor } from 'vs/workbench/contrib/interactive/browser/inte import { InteractiveEditorInput } from 'vs/workbench/contrib/interactive/browser/interactiveEditorInput'; import { IInteractiveHistoryService, InteractiveHistoryService } from 'vs/workbench/contrib/interactive/browser/interactiveHistoryService'; import { NOTEBOOK_EDITOR_WIDGET_ACTION_WEIGHT } from 'vs/workbench/contrib/notebook/browser/controller/coreActions'; +import { INotebookEditorOptions } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { NotebookEditorWidget } from 'vs/workbench/contrib/notebook/browser/notebookEditorWidget'; import * as icons from 'vs/workbench/contrib/notebook/browser/notebookIcons'; -import { CellEditType, CellKind, ICellOutput, NotebookSetting } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellEditType, CellKind, CellUri, ICellOutput, NotebookSetting } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { INotebookKernelService } from 'vs/workbench/contrib/notebook/common/notebookKernelService'; import { INotebookContentProvider, INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; import { columnToEditorGroup } from 'vs/workbench/services/editor/common/editorGroupColumn'; @@ -214,12 +216,26 @@ export class InteractiveDocumentContribution extends Disposable implements IWork priority: RegisteredEditorPriority.exclusive }, { - canSupportResource: uri => uri.scheme === Schemas.vscodeInteractive, + canSupportResource: uri => uri.scheme === Schemas.vscodeInteractive || (uri.scheme === Schemas.vscodeNotebookCell && extname(uri) === '.interactive'), singlePerResource: true }, - ({ resource }) => { - const editorInput = editorService.getEditors(EditorsOrder.SEQUENTIAL).find(editor => editor.editor instanceof InteractiveEditorInput && editor.editor.resource?.toString() === resource.toString()); - return editorInput!; + ({ resource, options }) => { + const data = CellUri.parse(resource); + let notebookUri: URI = resource; + let cellOptions: IResourceEditorInput | undefined; + + if (data) { + notebookUri = data.notebook; + cellOptions = { resource, options }; + } + + const notebookOptions = { ...options, cellOptions } as INotebookEditorOptions; + + const editorInput = editorService.getEditors(EditorsOrder.SEQUENTIAL).find(editor => editor.editor instanceof InteractiveEditorInput && editor.editor.resource?.toString() === notebookUri.toString()); + return { + editor: editorInput!.editor, + options: notebookOptions + }; } ); } diff --git a/src/vs/workbench/contrib/interactive/browser/interactiveEditor.ts b/src/vs/workbench/contrib/interactive/browser/interactiveEditor.ts index 37d2b4fde50..ca1f164befa 100644 --- a/src/vs/workbench/contrib/interactive/browser/interactiveEditor.ts +++ b/src/vs/workbench/contrib/interactive/browser/interactiveEditor.ts @@ -22,7 +22,7 @@ import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane'; import { EditorPaneSelectionChangeReason, IEditorMemento, IEditorOpenContext, IEditorPaneSelectionChangeEvent } from 'vs/workbench/common/editor'; import { getSimpleEditorOptions } from 'vs/workbench/contrib/codeEditor/browser/simpleEditorOptions'; import { InteractiveEditorInput } from 'vs/workbench/contrib/interactive/browser/interactiveEditorInput'; -import { ICellViewModel, INotebookEditorViewState } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { ICellViewModel, INotebookEditorOptions, INotebookEditorViewState } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { NotebookEditorExtensionsRegistry } from 'vs/workbench/contrib/notebook/browser/notebookEditorExtensions'; import { IBorrowValue, INotebookEditorService } from 'vs/workbench/contrib/notebook/browser/notebookEditorService'; import { cellEditorBackground, NotebookEditorWidget } from 'vs/workbench/contrib/notebook/browser/notebookEditorWidget'; @@ -501,6 +501,11 @@ export class InteractiveEditor extends EditorPane { this.#syncWithKernel(); } + override setOptions(options: INotebookEditorOptions | undefined): void { + this.#notebookWidget.value?.setOptions(options); + super.setOptions(options); + } + #toEditorPaneSelectionChangeReason(e: ICursorPositionChangedEvent): EditorPaneSelectionChangeReason { switch (e.source) { case TextEditorSelectionSource.PROGRAMMATIC: return EditorPaneSelectionChangeReason.PROGRAMMATIC; From 2d0d5b28a6d9c9233d46d27252f79a728a25d30c Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 6 Jul 2022 08:14:02 +0200 Subject: [PATCH 258/347] File watcher stops working with malformed workspace file (fix #153881) (#154231) --- .../node/watcher/parcel/parcelWatcher.ts | 27 ++++++++++++++++--- .../node/parcelWatcher.integrationTest.ts | 14 ++++++++-- 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/src/vs/platform/files/node/watcher/parcel/parcelWatcher.ts b/src/vs/platform/files/node/watcher/parcel/parcelWatcher.ts index 56509eb740f..66b0bc116eb 100644 --- a/src/vs/platform/files/node/watcher/parcel/parcelWatcher.ts +++ b/src/vs/platform/files/node/watcher/parcel/parcelWatcher.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as parcelWatcher from '@parcel/watcher'; -import { existsSync, unlinkSync } from 'fs'; +import { existsSync, statSync, unlinkSync } from 'fs'; import { tmpdir } from 'os'; import { DeferredPromise, RunOnceScheduler, ThrottledWorker } from 'vs/base/common/async'; import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; @@ -653,7 +653,7 @@ export class ParcelWatcher extends Disposable implements IRecursiveWatcher { } } - protected normalizeRequests(requests: IRecursiveWatchRequest[]): IRecursiveWatchRequest[] { + protected normalizeRequests(requests: IRecursiveWatchRequest[], validatePaths = true): IRecursiveWatchRequest[] { const requestTrie = TernarySearchTree.forPaths(!isLinux); // Sort requests by path length to have shortest first @@ -674,16 +674,35 @@ export class ParcelWatcher extends Disposable implements IRecursiveWatcher { continue; // path is ignored entirely (via `**` glob exclude) } + // Check for overlapping requests if (requestTrie.findSubstr(request.path)) { try { const realpath = realpathSync(request.path); if (realpath === request.path) { this.trace(`ignoring a path for watching who's parent is already watched: ${request.path}`); - continue; // path is not a symbolic link or similar + continue; } } catch (error) { - continue; // invalid path - ignore from watching + this.trace(`ignoring a path for watching who's realpath failed to resolve: ${request.path} (error: ${error})`); + + continue; + } + } + + // Check for invalid paths + if (validatePaths) { + try { + const stat = statSync(request.path); + if (!stat.isDirectory()) { + this.trace(`ignoring a path for watching that is a file and not a folder: ${request.path}`); + + continue; + } + } catch (error) { + this.trace(`ignoring a path for watching who's stat info failed to resolve: ${request.path} (error: ${error})`); + + continue; } } diff --git a/src/vs/platform/files/test/node/parcelWatcher.integrationTest.ts b/src/vs/platform/files/test/node/parcelWatcher.integrationTest.ts index 052e2ffb603..3196a4b6271 100644 --- a/src/vs/platform/files/test/node/parcelWatcher.integrationTest.ts +++ b/src/vs/platform/files/test/node/parcelWatcher.integrationTest.ts @@ -33,7 +33,7 @@ import { ltrim } from 'vs/base/common/strings'; return { path, excludes, recursive: true }; }); - return this.normalizeRequests(requests).map(request => request.path); + return this.normalizeRequests(requests, false /* validate paths skipped for tests */).map(request => request.path); } override async watch(requests: IRecursiveWatchRequest[]): Promise { @@ -155,7 +155,7 @@ import { ltrim } from 'vs/base/common/strings'; } test('basics', async function () { - await watcher.watch([{ path: testDir, excludes: [], recursive: true }]); // + await watcher.watch([{ path: testDir, excludes: [], recursive: true }]); // New file const newFilePath = join(testDir, 'deep', 'newFile.txt'); @@ -430,6 +430,16 @@ import { ltrim } from 'vs/base/common/strings'; await changeFuture; }); + test('invalid path does not crash watcher', async function () { + await watcher.watch([ + { path: testDir, excludes: [], recursive: true }, + { path: join(testDir, 'invalid-folder'), excludes: [], recursive: true }, + { path: __filename, excludes: [], recursive: true } + ]); + + return basicCrudTest(join(testDir, 'deep', 'newFile.txt')); + }); + test('subsequent watch updates watchers (excludes)', async function () { await watcher.watch([{ path: testDir, excludes: [realpathSync(testDir)], recursive: true }]); await watcher.watch([{ path: testDir, excludes: [], recursive: true }]); From 3ecb7fe9996f0863dab796edfc55f12d9c82cdcc Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 6 Jul 2022 10:34:24 +0200 Subject: [PATCH 259/347] move reset default profile to UserDataProfilesService --- src/vs/workbench/browser/web.main.ts | 2 +- .../electron-sandbox/desktop.main.ts | 2 +- .../configurationEditingService.test.ts | 2 +- .../test/browser/configurationService.test.ts | 20 +++++++++---------- .../browser/extensionStorageMigration.test.ts | 2 +- .../test/browser/keybindingEditing.test.ts | 3 ++- .../test/browser/storageService.test.ts | 5 +++-- .../browser/userDataProfileManagement.ts | 4 ---- .../common/userDataProfileService.ts | 19 +++++++++++++----- .../test/browser/workbenchTestServices.ts | 2 +- .../electron-browser/workbenchTestServices.ts | 2 +- 11 files changed, 35 insertions(+), 28 deletions(-) diff --git a/src/vs/workbench/browser/web.main.ts b/src/vs/workbench/browser/web.main.ts index e83eb19ce63..e9b7f4fc8b0 100644 --- a/src/vs/workbench/browser/web.main.ts +++ b/src/vs/workbench/browser/web.main.ts @@ -263,7 +263,7 @@ export class BrowserMain extends Disposable { const userDataProfilesService = new UserDataProfilesService(environmentService, fileService, logService); serviceCollection.set(IUserDataProfilesService, userDataProfilesService); - const userDataProfileService = new UserDataProfileService(userDataProfilesService.defaultProfile); + const userDataProfileService = new UserDataProfileService(userDataProfilesService.defaultProfile, userDataProfilesService); serviceCollection.set(IUserDataProfileService, userDataProfileService); // URI Identity diff --git a/src/vs/workbench/electron-sandbox/desktop.main.ts b/src/vs/workbench/electron-sandbox/desktop.main.ts index 706079b5ea7..38363be6614 100644 --- a/src/vs/workbench/electron-sandbox/desktop.main.ts +++ b/src/vs/workbench/electron-sandbox/desktop.main.ts @@ -237,7 +237,7 @@ export class DesktopMain extends Disposable { // User Data Profiles const userDataProfilesService = new UserDataProfilesNativeService(this.configuration.profiles.all, mainProcessService, environmentService, fileService, logService); serviceCollection.set(IUserDataProfilesService, userDataProfilesService); - const userDataProfileService = new UserDataProfileService(reviveProfile(this.configuration.profiles.current, userDataProfilesService.profilesHome.scheme)); + const userDataProfileService = new UserDataProfileService(reviveProfile(this.configuration.profiles.current, userDataProfilesService.profilesHome.scheme), userDataProfilesService); serviceCollection.set(IUserDataProfileService, userDataProfileService); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! diff --git a/src/vs/workbench/services/configuration/test/browser/configurationEditingService.test.ts b/src/vs/workbench/services/configuration/test/browser/configurationEditingService.test.ts index 243add76058..6412bd0e4c3 100644 --- a/src/vs/workbench/services/configuration/test/browser/configurationEditingService.test.ts +++ b/src/vs/workbench/services/configuration/test/browser/configurationEditingService.test.ts @@ -111,7 +111,7 @@ suite('ConfigurationEditingService', () => { environmentService.policyFile = joinPath(workspaceFolder, 'policies.json'); instantiationService.stub(IEnvironmentService, environmentService); const userDataProfilesService = instantiationService.stub(IUserDataProfilesService, new UserDataProfilesService(environmentService, fileService, logService)); - userDataProfileService = new UserDataProfileService(userDataProfilesService.defaultProfile); + userDataProfileService = new UserDataProfileService(userDataProfilesService.defaultProfile, userDataProfilesService); const remoteAgentService = disposables.add(instantiationService.createInstance(RemoteAgentService, null)); disposables.add(fileService.registerProvider(Schemas.vscodeUserData, disposables.add(new FileUserDataProvider(ROOT.scheme, fileSystemProvider, Schemas.vscodeUserData, logService)))); instantiationService.stub(IFileService, fileService); diff --git a/src/vs/workbench/services/configuration/test/browser/configurationService.test.ts b/src/vs/workbench/services/configuration/test/browser/configurationService.test.ts index 3a1d3a6ca2b..1254e1a9b0b 100644 --- a/src/vs/workbench/services/configuration/test/browser/configurationService.test.ts +++ b/src/vs/workbench/services/configuration/test/browser/configurationService.test.ts @@ -86,7 +86,7 @@ suite('WorkspaceContextService - Folder', () => { const environmentService = TestEnvironmentService; fileService.registerProvider(Schemas.vscodeUserData, disposables.add(new FileUserDataProvider(ROOT.scheme, fileSystemProvider, Schemas.vscodeUserData, new NullLogService()))); const userDataProfilesService = new UserDataProfilesService(environmentService, fileService, logService); - testObject = disposables.add(new WorkspaceService({ configurationCache: new ConfigurationCache() }, environmentService, new UserDataProfileService(userDataProfilesService.defaultProfile), userDataProfilesService, fileService, new RemoteAgentService(null, environmentService, TestProductService, new RemoteAuthorityResolverService(TestProductService, undefined, undefined), new SignService(undefined), new NullLogService()), new UriIdentityService(fileService), new NullLogService(), new NullPolicyService())); + testObject = disposables.add(new WorkspaceService({ configurationCache: new ConfigurationCache() }, environmentService, new UserDataProfileService(userDataProfilesService.defaultProfile, userDataProfilesService), userDataProfilesService, fileService, new RemoteAgentService(null, environmentService, TestProductService, new RemoteAuthorityResolverService(TestProductService, undefined, undefined), new SignService(undefined), new NullLogService()), new UriIdentityService(fileService), new NullLogService(), new NullPolicyService())); await (testObject).initialize(convertToWorkspacePayload(folder)); }); @@ -127,7 +127,7 @@ suite('WorkspaceContextService - Folder', () => { const environmentService = TestEnvironmentService; fileService.registerProvider(Schemas.vscodeUserData, disposables.add(new FileUserDataProvider(ROOT.scheme, fileSystemProvider, Schemas.vscodeUserData, new NullLogService()))); const userDataProfilesService = new UserDataProfilesService(environmentService, fileService, logService); - const testObject = disposables.add(new WorkspaceService({ configurationCache: new ConfigurationCache() }, environmentService, new UserDataProfileService(userDataProfilesService.defaultProfile), userDataProfilesService, fileService, new RemoteAgentService(null, environmentService, TestProductService, new RemoteAuthorityResolverService(TestProductService, undefined, undefined), new SignService(undefined), new NullLogService()), new UriIdentityService(fileService), new NullLogService(), new NullPolicyService())); + const testObject = disposables.add(new WorkspaceService({ configurationCache: new ConfigurationCache() }, environmentService, new UserDataProfileService(userDataProfilesService.defaultProfile, userDataProfilesService), userDataProfilesService, fileService, new RemoteAgentService(null, environmentService, TestProductService, new RemoteAuthorityResolverService(TestProductService, undefined, undefined), new SignService(undefined), new NullLogService()), new UriIdentityService(fileService), new NullLogService(), new NullPolicyService())); await (testObject).initialize(convertToWorkspacePayload(folder)); const actual = testObject.getWorkspaceFolder(joinPath(folder, 'a')); @@ -148,7 +148,7 @@ suite('WorkspaceContextService - Folder', () => { const environmentService = TestEnvironmentService; fileService.registerProvider(Schemas.vscodeUserData, disposables.add(new FileUserDataProvider(ROOT.scheme, fileSystemProvider, Schemas.vscodeUserData, new NullLogService()))); const userDataProfilesService = new UserDataProfilesService(environmentService, fileService, logService); - const testObject = disposables.add(new WorkspaceService({ configurationCache: new ConfigurationCache() }, environmentService, new UserDataProfileService(userDataProfilesService.defaultProfile), userDataProfilesService, fileService, new RemoteAgentService(null, environmentService, TestProductService, new RemoteAuthorityResolverService(TestProductService, undefined, undefined), new SignService(undefined), new NullLogService()), new UriIdentityService(fileService), new NullLogService(), new NullPolicyService())); + const testObject = disposables.add(new WorkspaceService({ configurationCache: new ConfigurationCache() }, environmentService, new UserDataProfileService(userDataProfilesService.defaultProfile, userDataProfilesService), userDataProfilesService, fileService, new RemoteAgentService(null, environmentService, TestProductService, new RemoteAuthorityResolverService(TestProductService, undefined, undefined), new SignService(undefined), new NullLogService()), new UriIdentityService(fileService), new NullLogService(), new NullPolicyService())); await (testObject).initialize(convertToWorkspacePayload(folder)); @@ -196,7 +196,7 @@ suite('WorkspaceContextService - Workspace', () => { instantiationService.stub(IRemoteAgentService, remoteAgentService); fileService.registerProvider(Schemas.vscodeUserData, disposables.add(new FileUserDataProvider(ROOT.scheme, fileSystemProvider, Schemas.vscodeUserData, new NullLogService()))); const userDataProfilesService = instantiationService.stub(IUserDataProfilesService, new UserDataProfilesService(environmentService, fileService, logService)); - testObject = disposables.add(new WorkspaceService({ configurationCache: new ConfigurationCache() }, environmentService, new UserDataProfileService(userDataProfilesService.defaultProfile), userDataProfilesService, fileService, remoteAgentService, new UriIdentityService(fileService), new NullLogService(), new NullPolicyService())); + testObject = disposables.add(new WorkspaceService({ configurationCache: new ConfigurationCache() }, environmentService, new UserDataProfileService(userDataProfilesService.defaultProfile, userDataProfilesService), userDataProfilesService, fileService, remoteAgentService, new UriIdentityService(fileService), new NullLogService(), new NullPolicyService())); instantiationService.stub(IWorkspaceContextService, testObject); instantiationService.stub(IConfigurationService, testObject); @@ -255,7 +255,7 @@ suite('WorkspaceContextService - Workspace Editing', () => { instantiationService.stub(IRemoteAgentService, remoteAgentService); fileService.registerProvider(Schemas.vscodeUserData, disposables.add(new FileUserDataProvider(ROOT.scheme, fileSystemProvider, Schemas.vscodeUserData, new NullLogService()))); const userDataProfilesService = instantiationService.stub(IUserDataProfilesService, new UserDataProfilesService(environmentService, fileService, logService)); - testObject = disposables.add(new WorkspaceService({ configurationCache: new ConfigurationCache() }, environmentService, new UserDataProfileService(userDataProfilesService.defaultProfile), userDataProfilesService, fileService, remoteAgentService, new UriIdentityService(fileService), new NullLogService(), new NullPolicyService())); + testObject = disposables.add(new WorkspaceService({ configurationCache: new ConfigurationCache() }, environmentService, new UserDataProfileService(userDataProfilesService.defaultProfile, userDataProfilesService), userDataProfilesService, fileService, remoteAgentService, new UriIdentityService(fileService), new NullLogService(), new NullPolicyService())); instantiationService.stub(IFileService, fileService); instantiationService.stub(IWorkspaceContextService, testObject); @@ -499,7 +499,7 @@ suite('WorkspaceService - Initialization', () => { instantiationService.stub(IRemoteAgentService, remoteAgentService); fileService.registerProvider(Schemas.vscodeUserData, disposables.add(new FileUserDataProvider(ROOT.scheme, fileSystemProvider, Schemas.vscodeUserData, new NullLogService()))); const userDataProfilesService = instantiationService.stub(IUserDataProfilesService, new UserDataProfilesService(environmentService, fileService, logService)); - userDataProfileService = instantiationService.stub(IUserDataProfileService, new UserDataProfileService(userDataProfilesService.defaultProfile)); + userDataProfileService = instantiationService.stub(IUserDataProfileService, new UserDataProfileService(userDataProfilesService.defaultProfile, userDataProfilesService)); testObject = disposables.add(new WorkspaceService({ configurationCache: new ConfigurationCache() }, environmentService, userDataProfileService, userDataProfilesService, fileService, remoteAgentService, new UriIdentityService(fileService), new NullLogService(), new NullPolicyService())); instantiationService.stub(IFileService, fileService); instantiationService.stub(IWorkspaceContextService, testObject); @@ -759,7 +759,7 @@ suite('WorkspaceConfigurationService - Folder', () => { instantiationService.stub(IRemoteAgentService, remoteAgentService); fileService.registerProvider(Schemas.vscodeUserData, disposables.add(new FileUserDataProvider(ROOT.scheme, fileSystemProvider, Schemas.vscodeUserData, new NullLogService()))); const userDataProfilesService = instantiationService.stub(IUserDataProfilesService, new UserDataProfilesService(environmentService, fileService, logService)); - userDataProfileService = instantiationService.stub(IUserDataProfileService, new UserDataProfileService(userDataProfilesService.defaultProfile)); + userDataProfileService = instantiationService.stub(IUserDataProfileService, new UserDataProfileService(userDataProfilesService.defaultProfile, userDataProfilesService)); workspaceService = testObject = disposables.add(new WorkspaceService({ configurationCache: new ConfigurationCache() }, environmentService, userDataProfileService, userDataProfilesService, fileService, remoteAgentService, new UriIdentityService(fileService), new NullLogService(), new FilePolicyService(environmentService.policyFile, fileService, logService))); instantiationService.stub(IFileService, fileService); instantiationService.stub(IWorkspaceContextService, testObject); @@ -1425,7 +1425,7 @@ suite('WorkspaceConfigurationService - Profiles', () => { instantiationService.stub(IRemoteAgentService, remoteAgentService); fileService.registerProvider(Schemas.vscodeUserData, disposables.add(new FileUserDataProvider(ROOT.scheme, fileSystemProvider, Schemas.vscodeUserData, new NullLogService()))); const userDataProfilesService = instantiationService.stub(IUserDataProfilesService, new UserDataProfilesService(environmentService, fileService, logService)); - userDataProfileService = instantiationService.stub(IUserDataProfileService, new UserDataProfileService(toUserDataProfile('custom', joinPath(environmentService.userRoamingDataHome, 'profiles', 'temp')))); + userDataProfileService = instantiationService.stub(IUserDataProfileService, new UserDataProfileService(toUserDataProfile('custom', joinPath(environmentService.userRoamingDataHome, 'profiles', 'temp')), userDataProfilesService)); workspaceService = testObject = disposables.add(new WorkspaceService({ configurationCache: new ConfigurationCache() }, environmentService, userDataProfileService, userDataProfilesService, fileService, remoteAgentService, new UriIdentityService(fileService), new NullLogService(), new FilePolicyService(environmentService.policyFile, fileService, logService))); instantiationService.stub(IFileService, fileService); instantiationService.stub(IWorkspaceContextService, testObject); @@ -1613,7 +1613,7 @@ suite('WorkspaceConfigurationService-Multiroot', () => { instantiationService.stub(IRemoteAgentService, remoteAgentService); fileService.registerProvider(Schemas.vscodeUserData, disposables.add(new FileUserDataProvider(ROOT.scheme, fileSystemProvider, Schemas.vscodeUserData, new NullLogService()))); const userDataProfilesService = instantiationService.stub(IUserDataProfilesService, new UserDataProfilesService(environmentService, fileService, logService)); - userDataProfileService = instantiationService.stub(IUserDataProfileService, new UserDataProfileService(userDataProfilesService.defaultProfile)); + userDataProfileService = instantiationService.stub(IUserDataProfileService, new UserDataProfileService(userDataProfilesService.defaultProfile, userDataProfilesService)); const workspaceService = disposables.add(new WorkspaceService({ configurationCache: new ConfigurationCache() }, environmentService, userDataProfileService, userDataProfilesService, fileService, remoteAgentService, new UriIdentityService(fileService), new NullLogService(), new NullPolicyService())); instantiationService.stub(IFileService, fileService); @@ -2276,7 +2276,7 @@ suite('WorkspaceConfigurationService - Remote Folder', () => { fileService.registerProvider(Schemas.vscodeUserData, disposables.add(new FileUserDataProvider(ROOT.scheme, fileSystemProvider, Schemas.vscodeUserData, new NullLogService()))); const configurationCache: IConfigurationCache = { read: () => Promise.resolve(''), write: () => Promise.resolve(), remove: () => Promise.resolve(), needsCaching: () => false }; const userDataProfilesService = instantiationService.stub(IUserDataProfilesService, new UserDataProfilesService(environmentService, fileService, logService)); - userDataProfileService = instantiationService.stub(IUserDataProfileService, new UserDataProfileService(userDataProfilesService.defaultProfile)); + userDataProfileService = instantiationService.stub(IUserDataProfileService, new UserDataProfileService(userDataProfilesService.defaultProfile, userDataProfilesService)); testObject = disposables.add(new WorkspaceService({ configurationCache, remoteAuthority }, environmentService, userDataProfileService, userDataProfilesService, fileService, remoteAgentService, new UriIdentityService(fileService), new NullLogService(), new NullPolicyService())); instantiationService.stub(IWorkspaceContextService, testObject); instantiationService.stub(IConfigurationService, testObject); diff --git a/src/vs/workbench/services/extensions/test/browser/extensionStorageMigration.test.ts b/src/vs/workbench/services/extensions/test/browser/extensionStorageMigration.test.ts index bbee18ae82b..d6843185c30 100644 --- a/src/vs/workbench/services/extensions/test/browser/extensionStorageMigration.test.ts +++ b/src/vs/workbench/services/extensions/test/browser/extensionStorageMigration.test.ts @@ -39,7 +39,7 @@ suite('ExtensionStorageMigration', () => { instantiationService.stub(IFileService, fileService); const environmentService = instantiationService.stub(IEnvironmentService, >{ userRoamingDataHome: ROOT, workspaceStorageHome }); const userDataProfilesService = instantiationService.stub(IUserDataProfilesService, new UserDataProfilesService(environmentService, fileService, new NullLogService())); - instantiationService.stub(IUserDataProfileService, new UserDataProfileService(userDataProfilesService.defaultProfile)); + instantiationService.stub(IUserDataProfileService, new UserDataProfileService(userDataProfilesService.defaultProfile, userDataProfilesService)); instantiationService.stub(IExtensionStorageService, instantiationService.createInstance(ExtensionStorageService)); }); diff --git a/src/vs/workbench/services/keybinding/test/browser/keybindingEditing.test.ts b/src/vs/workbench/services/keybinding/test/browser/keybindingEditing.test.ts index 66b5e7fa8a8..a20bd496d4b 100644 --- a/src/vs/workbench/services/keybinding/test/browser/keybindingEditing.test.ts +++ b/src/vs/workbench/services/keybinding/test/browser/keybindingEditing.test.ts @@ -66,7 +66,8 @@ suite('KeybindingsEditing', () => { const configService = new TestConfigurationService(); configService.setUserConfiguration('files', { 'eol': '\n' }); - userDataProfileService = new UserDataProfileService(new UserDataProfilesService(environmentService, fileService, logService).defaultProfile); + const userDataProfilesService = new UserDataProfilesService(environmentService, fileService, logService); + userDataProfileService = new UserDataProfileService(userDataProfilesService.defaultProfile, userDataProfilesService); instantiationService = workbenchInstantiationService({ fileService: () => fileService, diff --git a/src/vs/workbench/services/storage/test/browser/storageService.test.ts b/src/vs/workbench/services/storage/test/browser/storageService.test.ts index 58d1c19d3cb..4205c92d7a8 100644 --- a/src/vs/workbench/services/storage/test/browser/storageService.test.ts +++ b/src/vs/workbench/services/storage/test/browser/storageService.test.ts @@ -16,9 +16,10 @@ import { InMemoryFileSystemProvider } from 'vs/platform/files/common/inMemoryFil import { NullLogService } from 'vs/platform/log/common/log'; import { StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { createSuite } from 'vs/platform/storage/test/common/storageService.test'; -import { IUserDataProfile } from 'vs/platform/userDataProfile/common/userDataProfile'; +import { IUserDataProfile, UserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile'; import { BrowserStorageService, IndexedDBStorageDatabase } from 'vs/workbench/services/storage/browser/storageService'; import { UserDataProfileService } from 'vs/workbench/services/userDataProfile/common/userDataProfileService'; +import { TestEnvironmentService } from 'vs/workbench/test/browser/workbenchTestServices'; async function createStorageService(): Promise<[DisposableStore, BrowserStorageService]> { const disposables = new DisposableStore(); @@ -45,7 +46,7 @@ async function createStorageService(): Promise<[DisposableStore, BrowserStorageS extensionsResource: joinPath(inMemoryExtraProfileRoot, 'extensionsResource') }; - const storageService = disposables.add(new BrowserStorageService({ id: 'workspace-storage-test' }, new UserDataProfileService(inMemoryExtraProfile), logService)); + const storageService = disposables.add(new BrowserStorageService({ id: 'workspace-storage-test' }, new UserDataProfileService(inMemoryExtraProfile, new UserDataProfilesService(TestEnvironmentService, fileService, logService)), logService)); await storageService.initialize(); diff --git a/src/vs/workbench/services/userDataProfile/browser/userDataProfileManagement.ts b/src/vs/workbench/services/userDataProfile/browser/userDataProfileManagement.ts index ba46d3e24d7..798abb97873 100644 --- a/src/vs/workbench/services/userDataProfile/browser/userDataProfileManagement.ts +++ b/src/vs/workbench/services/userDataProfile/browser/userDataProfileManagement.ts @@ -46,10 +46,6 @@ export class UserDataProfileManagementService extends Disposable implements IUse this.enterProfile(this.userDataProfilesService.defaultProfile, false, localize('reload message when removed', "The current profile has been removed. Please reload to switch back to default profile")); return; } - if (this.userDataProfileService.currentProfile.isDefault) { - this.userDataProfileService.updateCurrentProfile(this.userDataProfilesService.defaultProfile, false); - return; - } } async createAndEnterProfile(name: string, useDefaultFlags?: UseDefaultProfileFlags, fromExisting?: boolean): Promise { diff --git a/src/vs/workbench/services/userDataProfile/common/userDataProfileService.ts b/src/vs/workbench/services/userDataProfile/common/userDataProfileService.ts index 96fa879239f..57c6e4161a2 100644 --- a/src/vs/workbench/services/userDataProfile/common/userDataProfileService.ts +++ b/src/vs/workbench/services/userDataProfile/common/userDataProfileService.ts @@ -6,7 +6,7 @@ import { Promises } from 'vs/base/common/async'; import { Emitter } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; -import { IUserDataProfile } from 'vs/platform/userDataProfile/common/userDataProfile'; +import { IUserDataProfile, IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile'; import { DidChangeUserDataProfileEvent, IUserDataProfileService } from 'vs/workbench/services/userDataProfile/common/userDataProfile'; export class UserDataProfileService extends Disposable implements IUserDataProfileService { @@ -19,17 +19,26 @@ export class UserDataProfileService extends Disposable implements IUserDataProfi private _currentProfile: IUserDataProfile; get currentProfile(): IUserDataProfile { return this._currentProfile; } - constructor(currentProfile: IUserDataProfile) { + constructor(currentProfile: IUserDataProfile, userDataProfilesService: IUserDataProfilesService) { super(); this._currentProfile = currentProfile; + this._register(userDataProfilesService.onDidChangeProfiles(() => { + /** + * If the current profile is default profile, then reset it because, + * In Desktop the extensions resource will be set/unset in the default profile when profiles are changed. + */ + if (this._currentProfile.isDefault) { + this._currentProfile = userDataProfilesService.defaultProfile; + } + })); } async updateCurrentProfile(userDataProfile: IUserDataProfile, preserveData: boolean): Promise { - const previous = this._currentProfile; - this._currentProfile = userDataProfile; - if (this._currentProfile.id === previous.id) { + if (this._currentProfile.id === userDataProfile.id) { return; } + const previous = this._currentProfile; + this._currentProfile = userDataProfile; const joiners: Promise[] = []; this._onDidChangeCurrentProfile.fire({ preserveData, diff --git a/src/vs/workbench/test/browser/workbenchTestServices.ts b/src/vs/workbench/test/browser/workbenchTestServices.ts index c45f26e708a..caa62c81497 100644 --- a/src/vs/workbench/test/browser/workbenchTestServices.ts +++ b/src/vs/workbench/test/browser/workbenchTestServices.ts @@ -286,7 +286,7 @@ export function workbenchInstantiationService( const fileService = overrides?.fileService ? overrides.fileService(instantiationService) : new TestFileService(); instantiationService.stub(IFileService, fileService); const userDataProfilesService = instantiationService.stub(IUserDataProfilesService, new UserDataProfilesService(environmentService, fileService, new NullLogService())); - instantiationService.stub(IUserDataProfileService, new UserDataProfileService(userDataProfilesService.defaultProfile)); + instantiationService.stub(IUserDataProfileService, new UserDataProfileService(userDataProfilesService.defaultProfile, userDataProfilesService)); instantiationService.stub(IUriIdentityService, new UriIdentityService(fileService)); instantiationService.stub(IWorkingCopyBackupService, new TestWorkingCopyBackupService()); instantiationService.stub(ITelemetryService, NullTelemetryService); diff --git a/src/vs/workbench/test/electron-browser/workbenchTestServices.ts b/src/vs/workbench/test/electron-browser/workbenchTestServices.ts index ded96d4e010..1880f3377d6 100644 --- a/src/vs/workbench/test/electron-browser/workbenchTestServices.ts +++ b/src/vs/workbench/test/electron-browser/workbenchTestServices.ts @@ -290,7 +290,7 @@ export function workbenchInstantiationService(disposables = new DisposableStore( instantiationService.stub(IWorkbenchEnvironmentService, TestEnvironmentService); instantiationService.stub(INativeWorkbenchEnvironmentService, TestEnvironmentService); const userDataProfilesService = instantiationService.stub(IUserDataProfilesService, new UserDataProfilesService(TestEnvironmentService, new FileService(new NullLogService()), new NullLogService())); - instantiationService.stub(IUserDataProfileService, new UserDataProfileService(userDataProfilesService.defaultProfile)); + instantiationService.stub(IUserDataProfileService, new UserDataProfileService(userDataProfilesService.defaultProfile, userDataProfilesService)); return instantiationService; } From e4069c40f75bd876b9609fb5a291306aa03b062f Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 6 Jul 2022 10:37:18 +0200 Subject: [PATCH 260/347] extract default extensions profile init and uninit invoke it from main --- .../sharedProcess/sharedProcessMain.ts | 7 ++- src/vs/code/electron-main/app.ts | 17 ++++++- .../common/extensionManagement.ts | 7 +++ .../defaultExtensionsProfileInit.ts | 27 +++++++++++ .../defaultExtensionsProfileInit.ts | 45 +++++++++++++++++++ .../browser/userDataProfileManagement.ts | 31 +------------ 6 files changed, 101 insertions(+), 33 deletions(-) create mode 100644 src/vs/platform/extensionManagement/electron-main/defaultExtensionsProfileInit.ts create mode 100644 src/vs/platform/extensionManagement/electron-sandbox/defaultExtensionsProfileInit.ts diff --git a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts index 4d77d394a3a..f166be81aeb 100644 --- a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts +++ b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts @@ -31,7 +31,7 @@ import { INativeEnvironmentService } from 'vs/platform/environment/common/enviro import { SharedProcessEnvironmentService } from 'vs/platform/sharedProcess/node/sharedProcessEnvironmentService'; import { GlobalExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionEnablementService'; import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService'; -import { IExtensionGalleryService, IExtensionManagementService, IExtensionTipsService, IGlobalExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IDefaultExtensionsProfileInitService, IExtensionGalleryService, IExtensionManagementService, IExtensionTipsService, IGlobalExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { ExtensionManagementChannel, ExtensionTipsChannel } from 'vs/platform/extensionManagement/common/extensionManagementIpc'; import { ExtensionTipsService } from 'vs/platform/extensionManagement/electron-sandbox/extensionTipsService'; import { ExtensionManagementService, INativeServerExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService'; @@ -106,6 +106,7 @@ import { PolicyChannelClient } from 'vs/platform/policy/common/policyIpc'; import { IPolicyService, NullPolicyService } from 'vs/platform/policy/common/policy'; import { UserDataProfilesNativeService } from 'vs/platform/userDataProfile/electron-sandbox/userDataProfile'; import { OneDataSystemWebAppender } from 'vs/platform/telemetry/browser/1dsAppender'; +import { DefaultExtensionsProfileInitService } from 'vs/platform/extensionManagement/electron-sandbox/defaultExtensionsProfileInit'; class SharedProcessMain extends Disposable { @@ -316,6 +317,7 @@ class SharedProcessMain extends Disposable { services.set(IExtensionsProfileScannerService, new SyncDescriptor(ExtensionsProfileScannerService)); services.set(IExtensionsScannerService, new SyncDescriptor(ExtensionsScannerService)); services.set(INativeServerExtensionManagementService, new SyncDescriptor(ExtensionManagementService)); + services.set(IDefaultExtensionsProfileInitService, new SyncDescriptor(DefaultExtensionsProfileInitService)); // Extension Gallery services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryService)); @@ -426,6 +428,9 @@ class SharedProcessMain extends Disposable { // Worker const sharedProcessWorkerChannel = ProxyChannel.fromService(accessor.get(ISharedProcessWorkerService)); this.server.registerChannel(ipcSharedProcessWorkerChannelName, sharedProcessWorkerChannel); + + // Default Extensions Profile Init + this.server.registerChannel('IDefaultExtensionsProfileInitService', ProxyChannel.fromService(accessor.get(IDefaultExtensionsProfileInitService))); } private registerErrorHandler(logService: ILogService): void { diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index 7b912a581c3..14346728268 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -102,6 +102,8 @@ import { CredentialsNativeMainService } from 'vs/platform/credentials/electron-m import { IPolicyService } from 'vs/platform/policy/common/policy'; import { PolicyChannel } from 'vs/platform/policy/common/policyIpc'; import { IUserDataProfilesMainService } from 'vs/platform/userDataProfile/electron-main/userDataProfile'; +import { IDefaultExtensionsProfileInitService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { DefaultExtensionsProfileInitHandler } from 'vs/platform/extensionManagement/electron-main/defaultExtensionsProfileInit'; /** * The main VS Code application. There will only ever be one instance, @@ -525,8 +527,8 @@ export class CodeApplication extends Disposable { // Services const appInstantiationService = await this.initServices(machineId, sharedProcess, sharedProcessReady); - // Setup Auth Handler - this._register(appInstantiationService.createInstance(ProxyAuthHandler)); + // Setup Handlers + this.setUpHandlers(appInstantiationService); // Init Channels appInstantiationService.invokeFunction(accessor => this.initChannels(accessor, mainProcessElectronServer, sharedProcessClient)); @@ -543,6 +545,14 @@ export class CodeApplication extends Disposable { } } + private setUpHandlers(instantiationService: IInstantiationService): void { + // Auth Handler + this._register(instantiationService.createInstance(ProxyAuthHandler)); + + // Default Extensions Profile Init Handler + this._register(instantiationService.createInstance(DefaultExtensionsProfileInitHandler)); + } + private async resolveMachineId(): Promise { // We cache the machineId for faster lookups on startup @@ -679,6 +689,9 @@ export class CodeApplication extends Disposable { services.set(ITelemetryService, NullTelemetryService); } + // Default Extensions Profile Init + services.set(IDefaultExtensionsProfileInitService, ProxyChannel.toService(getDelayedChannel(sharedProcessReady.then(client => client.getChannel('IDefaultExtensionsProfileInitService'))))); + // Init services that require it await backupMainService.initialize(); diff --git a/src/vs/platform/extensionManagement/common/extensionManagement.ts b/src/vs/platform/extensionManagement/common/extensionManagement.ts index 3c5ec520512..9302da87da0 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagement.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagement.ts @@ -528,3 +528,10 @@ export interface IExtensionManagementCLIService { uninstallExtensions(extensions: (string | URI)[], force: boolean, output?: CLIOutput): Promise; locateExtension(extensions: string[], output?: CLIOutput): Promise; } + +export const IDefaultExtensionsProfileInitService = createDecorator('IDefaultExtensionsProfileInitService'); +export interface IDefaultExtensionsProfileInitService { + readonly _serviceBrand: undefined; + initialize(): Promise; + uninitialize(): Promise; +} diff --git a/src/vs/platform/extensionManagement/electron-main/defaultExtensionsProfileInit.ts b/src/vs/platform/extensionManagement/electron-main/defaultExtensionsProfileInit.ts new file mode 100644 index 00000000000..2db8dfaa0d8 --- /dev/null +++ b/src/vs/platform/extensionManagement/electron-main/defaultExtensionsProfileInit.ts @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Disposable } from 'vs/base/common/lifecycle'; +import { IDefaultExtensionsProfileInitService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IUserDataProfilesMainService } from 'vs/platform/userDataProfile/electron-main/userDataProfile'; + +export class DefaultExtensionsProfileInitHandler extends Disposable { + constructor( + @IDefaultExtensionsProfileInitService private readonly defaultExtensionsProfileInitService: IDefaultExtensionsProfileInitService, + @IUserDataProfilesMainService userDataProfilesService: IUserDataProfilesMainService, + ) { + super(); + this._register(userDataProfilesService.onWillCreateProfile(e => { + if (userDataProfilesService.profiles.length === 0) { + e.join(this.defaultExtensionsProfileInitService.initialize()); + } + })); + this._register(userDataProfilesService.onDidChangeProfiles(e => { + if (userDataProfilesService.profiles.length === 0) { + this.defaultExtensionsProfileInitService.uninitialize(); + } + })); + } +} diff --git a/src/vs/platform/extensionManagement/electron-sandbox/defaultExtensionsProfileInit.ts b/src/vs/platform/extensionManagement/electron-sandbox/defaultExtensionsProfileInit.ts new file mode 100644 index 00000000000..d353dc77727 --- /dev/null +++ b/src/vs/platform/extensionManagement/electron-sandbox/defaultExtensionsProfileInit.ts @@ -0,0 +1,45 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Disposable } from 'vs/base/common/lifecycle'; +import { joinPath } from 'vs/base/common/resources'; +import { URI } from 'vs/base/common/uri'; +import { IDefaultExtensionsProfileInitService, IExtensionManagementService, ILocalExtension, Metadata } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionsProfileScannerService } from 'vs/platform/extensionManagement/common/extensionsProfileScannerService'; +import { ExtensionType } from 'vs/platform/extensions/common/extensions'; +import { IFileService } from 'vs/platform/files/common/files'; +import { EXTENSIONS_RESOURCE_NAME, IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile'; + +export class DefaultExtensionsProfileInitService extends Disposable implements IDefaultExtensionsProfileInitService { + + readonly _serviceBrand: undefined; + + constructor( + @IUserDataProfilesService private readonly userDataProfilesService: IUserDataProfilesService, + @IFileService private readonly fileService: IFileService, + @IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService, + @IExtensionsProfileScannerService private readonly extensionsProfileScannerService: IExtensionsProfileScannerService, + ) { + super(); + } + + async initialize(): Promise { + /* Create and populate the default extensions profile resource */ + const extensionsProfileResource = this.getDefaultExtensionsProfileResource(); + try { await this.fileService.del(extensionsProfileResource); } catch (error) { /* ignore */ } + const userExtensions = await this.extensionManagementService.getInstalled(ExtensionType.User); + const extensions: [ILocalExtension, Metadata | undefined][] = await Promise.all(userExtensions.map(async e => ([e, await this.extensionManagementService.getMetadata(e)]))); + await this.extensionsProfileScannerService.addExtensionsToProfile(extensions, extensionsProfileResource); + } + + async uninitialize(): Promise { + /* Remove the default extensions profile resource */ + try { await this.fileService.del(this.getDefaultExtensionsProfileResource()); } catch (error) { /* ignore */ } + } + + private getDefaultExtensionsProfileResource(): URI { + return this.userDataProfilesService.defaultProfile.extensionsResource ?? joinPath(this.userDataProfilesService.defaultProfile.location, EXTENSIONS_RESOURCE_NAME); + } +} diff --git a/src/vs/workbench/services/userDataProfile/browser/userDataProfileManagement.ts b/src/vs/workbench/services/userDataProfile/browser/userDataProfileManagement.ts index 798abb97873..6cc49e7a131 100644 --- a/src/vs/workbench/services/userDataProfile/browser/userDataProfileManagement.ts +++ b/src/vs/workbench/services/userDataProfile/browser/userDataProfileManagement.ts @@ -4,19 +4,12 @@ *--------------------------------------------------------------------------------------------*/ import { Disposable } from 'vs/base/common/lifecycle'; -import { joinPath } from 'vs/base/common/resources'; -import { URI } from 'vs/base/common/uri'; import { localize } from 'vs/nls'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; -import { ILocalExtension, Metadata } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { IExtensionsProfileScannerService } from 'vs/platform/extensionManagement/common/extensionsProfileScannerService'; -import { ExtensionType } from 'vs/platform/extensions/common/extensions'; -import { IFileService } from 'vs/platform/files/common/files'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { DidChangeProfilesEvent, EXTENSIONS_RESOURCE_NAME, IUserDataProfile, IUserDataProfilesService, UseDefaultProfileFlags, WorkspaceIdentifier } from 'vs/platform/userDataProfile/common/userDataProfile'; +import { DidChangeProfilesEvent, IUserDataProfile, IUserDataProfilesService, UseDefaultProfileFlags, WorkspaceIdentifier } from 'vs/platform/userDataProfile/common/userDataProfile'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { IExtensionManagementServerService, IWorkbenchExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { IUserDataProfileManagementService, IUserDataProfileService } from 'vs/workbench/services/userDataProfile/common/userDataProfile'; @@ -27,10 +20,6 @@ export class UserDataProfileManagementService extends Disposable implements IUse constructor( @IUserDataProfilesService private readonly userDataProfilesService: IUserDataProfilesService, @IUserDataProfileService private readonly userDataProfileService: IUserDataProfileService, - @IFileService private readonly fileService: IFileService, - @IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService, - @IWorkbenchExtensionManagementService private readonly extensionManagementService: IWorkbenchExtensionManagementService, - @IExtensionsProfileScannerService private readonly extensionsProfileScannerService: IExtensionsProfileScannerService, @IHostService private readonly hostService: IHostService, @IDialogService private readonly dialogService: IDialogService, @IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService, @@ -51,11 +40,6 @@ export class UserDataProfileManagementService extends Disposable implements IUse async createAndEnterProfile(name: string, useDefaultFlags?: UseDefaultProfileFlags, fromExisting?: boolean): Promise { const workspaceIdentifier = this.getWorkspaceIdentifier(); const newProfile = this.userDataProfilesService.newProfile(name, useDefaultFlags); - await this.fileService.createFolder(newProfile.location); - if (!this.userDataProfilesService.defaultProfile.extensionsResource) { - // Extensions profile is not yet created for default profile, create it now - await this.createDefaultExtensionsProfile(joinPath(this.userDataProfilesService.defaultProfile.location, EXTENSIONS_RESOURCE_NAME)); - } const createdProfile = await this.userDataProfilesService.createProfile(newProfile, workspaceIdentifier); await this.enterProfile(createdProfile, !!fromExisting); return createdProfile; @@ -71,11 +55,7 @@ export class UserDataProfileManagementService extends Disposable implements IUse if (profile.id === this.userDataProfileService.currentProfile.id) { throw new Error(localize('cannotDeleteCurrentProfile', "Cannot delete the current profile")); } - const defaultExtensionsResourceToDelete = this.userDataProfilesService.profiles.length === 2 ? this.userDataProfilesService.defaultProfile.extensionsResource : undefined; await this.userDataProfilesService.removeProfile(profile); - if (defaultExtensionsResourceToDelete) { - try { await this.fileService.del(defaultExtensionsResourceToDelete); } catch (error) { /* ignore */ } - } } async switchProfile(profile: IUserDataProfile): Promise { @@ -118,15 +98,6 @@ export class UserDataProfileManagementService extends Disposable implements IUse await this.userDataProfileService.updateCurrentProfile(profile, preserveData); await this.extensionService.startExtensionHosts(); } - - private async createDefaultExtensionsProfile(extensionsProfileResource: URI): Promise { - try { await this.fileService.del(extensionsProfileResource); } catch (error) { /* ignore */ } - const extensionManagementService = this.extensionManagementServerService.localExtensionManagementServer?.extensionManagementService ?? this.extensionManagementService; - const userExtensions = await extensionManagementService.getInstalled(ExtensionType.User); - const extensions: [ILocalExtension, Metadata | undefined][] = await Promise.all(userExtensions.map(async e => ([e, await this.extensionManagementService.getMetadata(e)]))); - await this.extensionsProfileScannerService.addExtensionsToProfile(extensions, extensionsProfileResource); - return extensionsProfileResource; - } } registerSingleton(IUserDataProfileManagementService, UserDataProfileManagementService); From b3d6ef63a72e5f388a86265aae79c238ffd1f4ee Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 6 Jul 2022 10:58:19 +0200 Subject: [PATCH 261/347] show error when action fails --- .../userDataProfile/common/userDataProfileActions.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/userDataProfile/common/userDataProfileActions.ts b/src/vs/workbench/contrib/userDataProfile/common/userDataProfileActions.ts index cda5ca4d8fe..01a3ef3d346 100644 --- a/src/vs/workbench/contrib/userDataProfile/common/userDataProfileActions.ts +++ b/src/vs/workbench/contrib/userDataProfile/common/userDataProfileActions.ts @@ -117,12 +117,17 @@ registerAction2(class RemoveProfileAction extends Action2 { const userDataProfileService = accessor.get(IUserDataProfileService); const userDataProfilesService = accessor.get(IUserDataProfilesService); const userDataProfileManagementService = accessor.get(IUserDataProfileManagementService); + const notificationService = accessor.get(INotificationService); const profiles = userDataProfilesService.profiles.filter(p => p.id !== userDataProfileService.currentProfile.id && !p.isDefault); if (profiles.length) { const pick = await quickInputService.pick(profiles.map(profile => ({ label: profile.name, profile })), { placeHolder: localize('pick profile', "Select Settings Profile") }); if (pick) { - await userDataProfileManagementService.removeProfile(pick.profile); + try { + await userDataProfileManagementService.removeProfile(pick.profile); + } catch (error) { + notificationService.error(error); + } } } } From 0f52e4b9c12e1750c7ec53f8484472d7fa7f205f Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 6 Jul 2022 11:06:56 +0200 Subject: [PATCH 262/347] merge newProfile with createProfile --- .../userDataProfile/common/userDataProfile.ts | 9 ++------- .../electron-main/userDataProfile.ts | 16 ++++++++-------- .../electron-sandbox/userDataProfile.ts | 6 +++--- .../userDataProfileMainService.test.ts | 4 ++-- .../browser/userDataProfileManagement.ts | 8 +++----- 5 files changed, 18 insertions(+), 25 deletions(-) diff --git a/src/vs/platform/userDataProfile/common/userDataProfile.ts b/src/vs/platform/userDataProfile/common/userDataProfile.ts index 949133b32f5..e4027d99812 100644 --- a/src/vs/platform/userDataProfile/common/userDataProfile.ts +++ b/src/vs/platform/userDataProfile/common/userDataProfile.ts @@ -78,8 +78,7 @@ export interface IUserDataProfilesService { readonly onDidChangeProfiles: Event; readonly profiles: IUserDataProfile[]; - newProfile(name: string, useDefaultFlags?: UseDefaultProfileFlags): CustomUserDataProfile; - createProfile(profile: IUserDataProfile, workspaceIdentifier?: WorkspaceIdentifier): Promise; + createProfile(name: string, useDefaultFlags?: UseDefaultProfileFlags, workspaceIdentifier?: WorkspaceIdentifier): Promise; setProfileForWorkspace(profile: IUserDataProfile, workspaceIdentifier: WorkspaceIdentifier): Promise; getProfile(workspaceIdentifier: WorkspaceIdentifier): IUserDataProfile; removeProfile(profile: IUserDataProfile): Promise; @@ -139,16 +138,12 @@ export class UserDataProfilesService extends Disposable implements IUserDataProf this.profilesHome = joinPath(this.environmentService.userRoamingDataHome, 'profiles'); } - newProfile(name: string, useDefaultFlags?: UseDefaultProfileFlags): CustomUserDataProfile { - return toUserDataProfile(name, joinPath(this.profilesHome, hash(name).toString(16)), useDefaultFlags); - } - protected createDefaultUserDataProfile(extensions: boolean): IUserDataProfile { const profile = toUserDataProfile(localize('defaultProfile', "Default"), this.environmentService.userRoamingDataHome); return { ...profile, isDefault: true, extensionsResource: extensions ? profile.extensionsResource : undefined }; } - createProfile(profile: IUserDataProfile, workspaceIdentifier?: WorkspaceIdentifier): Promise { throw new Error('Not implemented'); } + createProfile(name: string, useDefaultFlags?: UseDefaultProfileFlags, workspaceIdentifier?: WorkspaceIdentifier): Promise { throw new Error('Not implemented'); } setProfileForWorkspace(profile: IUserDataProfile, workspaceIdentifier: WorkspaceIdentifier): Promise { throw new Error('Not implemented'); } getProfile(workspaceIdentifier: WorkspaceIdentifier): IUserDataProfile { throw new Error('Not implemented'); } removeProfile(profile: IUserDataProfile): Promise { throw new Error('Not implemented'); } diff --git a/src/vs/platform/userDataProfile/electron-main/userDataProfile.ts b/src/vs/platform/userDataProfile/electron-main/userDataProfile.ts index 7073ead9cda..f890a1e2fcf 100644 --- a/src/vs/platform/userDataProfile/electron-main/userDataProfile.ts +++ b/src/vs/platform/userDataProfile/electron-main/userDataProfile.ts @@ -11,10 +11,12 @@ import { refineServiceDecorator } from 'vs/platform/instantiation/common/instant import { ILogService } from 'vs/platform/log/common/log'; import { IStateMainService } from 'vs/platform/state/electron-main/state'; import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'; -import { IUserDataProfile, IUserDataProfilesService, reviveProfile, PROFILES_ENABLEMENT_CONFIG, WorkspaceIdentifier } from 'vs/platform/userDataProfile/common/userDataProfile'; +import { IUserDataProfile, IUserDataProfilesService, reviveProfile, PROFILES_ENABLEMENT_CONFIG, WorkspaceIdentifier, UseDefaultProfileFlags, toUserDataProfile } from 'vs/platform/userDataProfile/common/userDataProfile'; import { Promises } from 'vs/base/common/async'; import { StoredProfileAssociations, StoredUserDataProfile, UserDataProfilesService } from 'vs/platform/userDataProfile/node/userDataProfile'; import { IStringDictionary } from 'vs/base/common/collections'; +import { joinPath } from 'vs/base/common/resources'; +import { hash } from 'vs/base/common/hash'; export type WillCreateProfileEvent = { profile: IUserDataProfile; @@ -51,18 +53,16 @@ export class UserDataProfilesMainService extends UserDataProfilesService impleme super(stateMainService, uriIdentityService, environmentService, fileService, logService); } - override async createProfile(profile: IUserDataProfile, workspaceIdentifier?: WorkspaceIdentifier): Promise { + override async createProfile(name: string, useDefaultFlags?: UseDefaultProfileFlags, workspaceIdentifier?: WorkspaceIdentifier): Promise { if (!this.enabled) { throw new Error(`Settings Profiles are disabled. Enable them via the '${PROFILES_ENABLEMENT_CONFIG}' setting.`); } - profile = reviveProfile(profile, this.profilesHome.scheme); - if (this.getStoredProfiles().some(p => p.name === profile.name)) { - throw new Error(`Profile with name ${profile.name} already exists`); + if (this.getStoredProfiles().some(p => p.name === name)) { + throw new Error(`Profile with name ${name} already exists`); } - if (!(await this.fileService.exists(this.profilesHome))) { - await this.fileService.createFolder(this.profilesHome); - } + const profile = toUserDataProfile(name, joinPath(this.profilesHome, hash(name).toString(16)), useDefaultFlags); + await this.fileService.createFolder(profile.location); const joiners: Promise[] = []; this._onWillCreateProfile.fire({ diff --git a/src/vs/platform/userDataProfile/electron-sandbox/userDataProfile.ts b/src/vs/platform/userDataProfile/electron-sandbox/userDataProfile.ts index 210bd2288b9..417dc0bf5c8 100644 --- a/src/vs/platform/userDataProfile/electron-sandbox/userDataProfile.ts +++ b/src/vs/platform/userDataProfile/electron-sandbox/userDataProfile.ts @@ -9,7 +9,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import { IFileService } from 'vs/platform/files/common/files'; import { IMainProcessService } from 'vs/platform/ipc/electron-sandbox/services'; import { ILogService } from 'vs/platform/log/common/log'; -import { DidChangeProfilesEvent, IUserDataProfile, IUserDataProfilesService, reviveProfile, UserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile'; +import { DidChangeProfilesEvent, IUserDataProfile, IUserDataProfilesService, reviveProfile, UseDefaultProfileFlags, UserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile'; import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspace/common/workspace'; export class UserDataProfilesNativeService extends UserDataProfilesService implements IUserDataProfilesService { @@ -37,8 +37,8 @@ export class UserDataProfilesNativeService extends UserDataProfilesService imple })); } - override async createProfile(profile: IUserDataProfile, workspaceIdentifier?: ISingleFolderWorkspaceIdentifier | IWorkspaceIdentifier): Promise { - const result = await this.channel.call>('createProfile', [profile, workspaceIdentifier]); + override async createProfile(name: string, useDefaultFlags?: UseDefaultProfileFlags, workspaceIdentifier?: ISingleFolderWorkspaceIdentifier | IWorkspaceIdentifier): Promise { + const result = await this.channel.call>('createProfile', [name, useDefaultFlags, workspaceIdentifier]); return reviveProfile(result, this.profilesHome.scheme); } diff --git a/src/vs/platform/userDataProfile/test/electron-main/userDataProfileMainService.test.ts b/src/vs/platform/userDataProfile/test/electron-main/userDataProfileMainService.test.ts index b5592746149..ec861ab96f4 100644 --- a/src/vs/platform/userDataProfile/test/electron-main/userDataProfileMainService.test.ts +++ b/src/vs/platform/userDataProfile/test/electron-main/userDataProfileMainService.test.ts @@ -59,13 +59,13 @@ suite('UserDataProfileMainService', () => { }); test('default profile when there are profiles', async () => { - await testObject.createProfile(testObject.newProfile('test')); + await testObject.createProfile('test'); assert.strictEqual(testObject.defaultProfile.isDefault, true); assert.strictEqual(testObject.defaultProfile.extensionsResource?.toString(), joinPath(environmentService.userRoamingDataHome, 'extensions.json').toString()); }); test('default profile when profiles are removed', async () => { - const profile = await testObject.createProfile(testObject.newProfile('test')); + const profile = await testObject.createProfile('test'); await testObject.removeProfile(profile); assert.strictEqual(testObject.defaultProfile.isDefault, true); assert.strictEqual(testObject.defaultProfile.extensionsResource, undefined); diff --git a/src/vs/workbench/services/userDataProfile/browser/userDataProfileManagement.ts b/src/vs/workbench/services/userDataProfile/browser/userDataProfileManagement.ts index 6cc49e7a131..3b1578dc366 100644 --- a/src/vs/workbench/services/userDataProfile/browser/userDataProfileManagement.ts +++ b/src/vs/workbench/services/userDataProfile/browser/userDataProfileManagement.ts @@ -38,11 +38,9 @@ export class UserDataProfileManagementService extends Disposable implements IUse } async createAndEnterProfile(name: string, useDefaultFlags?: UseDefaultProfileFlags, fromExisting?: boolean): Promise { - const workspaceIdentifier = this.getWorkspaceIdentifier(); - const newProfile = this.userDataProfilesService.newProfile(name, useDefaultFlags); - const createdProfile = await this.userDataProfilesService.createProfile(newProfile, workspaceIdentifier); - await this.enterProfile(createdProfile, !!fromExisting); - return createdProfile; + const profile = await this.userDataProfilesService.createProfile(name, useDefaultFlags, this.getWorkspaceIdentifier()); + await this.enterProfile(profile, !!fromExisting); + return profile; } async removeProfile(profile: IUserDataProfile): Promise { From 8ad7d24334f9b7860706b71983c74ec06bfb377e Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 6 Jul 2022 11:09:47 +0200 Subject: [PATCH 263/347] remove migration --- .../common/extensionsProfileScannerService.ts | 37 +------------------ 1 file changed, 1 insertion(+), 36 deletions(-) diff --git a/src/vs/platform/extensionManagement/common/extensionsProfileScannerService.ts b/src/vs/platform/extensionManagement/common/extensionsProfileScannerService.ts index 8acce96e6e1..43c8cfd1e19 100644 --- a/src/vs/platform/extensionManagement/common/extensionsProfileScannerService.ts +++ b/src/vs/platform/extensionManagement/common/extensionsProfileScannerService.ts @@ -10,12 +10,10 @@ import { ResourceMap } from 'vs/base/common/map'; import { URI, UriComponents } from 'vs/base/common/uri'; import { ILocalExtension, Metadata } from 'vs/platform/extensionManagement/common/extensionManagement'; import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; -import { IExtensionIdentifier, IExtensionManifest } from 'vs/platform/extensions/common/extensions'; +import { IExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { FileOperationError, FileOperationResult, IFileService } from 'vs/platform/files/common/files'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { ILogService } from 'vs/platform/log/common/log'; -import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'; -import { IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile'; interface IStoredProfileExtension { identifier: IExtensionIdentifier; @@ -43,45 +41,13 @@ export interface IExtensionsProfileScannerService { export class ExtensionsProfileScannerService extends Disposable implements IExtensionsProfileScannerService { readonly _serviceBrand: undefined; - private readonly migratePromise: Promise; private readonly resourcesAccessQueueMap = new ResourceMap>(); constructor( @IFileService private readonly fileService: IFileService, - @IUriIdentityService private readonly uriIdentityService: IUriIdentityService, - @IUserDataProfilesService private readonly userDataProfilesService: IUserDataProfilesService, @ILogService private readonly logService: ILogService, ) { super(); - this.migratePromise = this.migrate(); - } - - // TODO: @sandy081 remove it in a month - private async migrate(): Promise { - await Promise.all(this.userDataProfilesService.profiles.map(async e => { - if (!e.extensionsResource) { - return; - } - try { - let needsMigrating: boolean = false; - const storedWebExtensions: IStoredProfileExtension[] = JSON.parse((await this.fileService.readFile(e.extensionsResource)).value.toString()); - for (const e of storedWebExtensions) { - if (!e.location) { - continue; - } - if (!e.version) { - try { - const content = (await this.fileService.readFile(this.uriIdentityService.extUri.joinPath(URI.revive(e.location), 'package.json'))).value.toString(); - e.version = (JSON.parse(content)).version; - needsMigrating = true; - } catch (error) { /* ignore */ } - } - } - if (needsMigrating) { - await this.fileService.writeFile(e.extensionsResource, VSBuffer.fromString(JSON.stringify(storedWebExtensions))); - } - } catch (error) { /* Ignore */ } - })); } scanProfileExtensions(profileLocation: URI): Promise { @@ -102,7 +68,6 @@ export class ExtensionsProfileScannerService extends Disposable implements IExte } private async withProfileExtensions(file: URI, updateFn?: (extensions: IScannedProfileExtension[]) => IScannedProfileExtension[]): Promise { - await this.migratePromise; return this.getResourceAccessQueue(file).queue(async () => { let extensions: IScannedProfileExtension[] = []; From 0f3bbc794aa9c0c06a150097f4d61144c329b57d Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 6 Jul 2022 03:58:41 -0700 Subject: [PATCH 264/347] Move resizable to base This is a generally useful component, should be in base --- .../suggest/browser => base/browser/ui/resizable}/resizable.ts | 0 src/vs/editor/contrib/suggest/browser/suggestWidget.ts | 2 +- src/vs/editor/contrib/suggest/browser/suggestWidgetDetails.ts | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename src/vs/{editor/contrib/suggest/browser => base/browser/ui/resizable}/resizable.ts (100%) diff --git a/src/vs/editor/contrib/suggest/browser/resizable.ts b/src/vs/base/browser/ui/resizable/resizable.ts similarity index 100% rename from src/vs/editor/contrib/suggest/browser/resizable.ts rename to src/vs/base/browser/ui/resizable/resizable.ts diff --git a/src/vs/editor/contrib/suggest/browser/suggestWidget.ts b/src/vs/editor/contrib/suggest/browser/suggestWidget.ts index 3a03d2da7dd..74cffe08fe9 100644 --- a/src/vs/editor/contrib/suggest/browser/suggestWidget.ts +++ b/src/vs/editor/contrib/suggest/browser/suggestWidget.ts @@ -30,7 +30,7 @@ import { attachListStyler } from 'vs/platform/theme/common/styler'; import { isHighContrast } from 'vs/platform/theme/common/theme'; import { IColorTheme, IThemeService } from 'vs/platform/theme/common/themeService'; import { CompletionModel } from './completionModel'; -import { ResizableHTMLElement } from './resizable'; +import { ResizableHTMLElement } from '../../../../base/browser/ui/resizable/resizable'; import { CompletionItem, Context as SuggestContext } from './suggest'; import { canExpandCompletionItem, SuggestDetailsOverlay, SuggestDetailsWidget } from './suggestWidgetDetails'; import { getAriaId, ItemRenderer } from './suggestWidgetRenderer'; diff --git a/src/vs/editor/contrib/suggest/browser/suggestWidgetDetails.ts b/src/vs/editor/contrib/suggest/browser/suggestWidgetDetails.ts index e9d6c4c5130..cd6e10771c0 100644 --- a/src/vs/editor/contrib/suggest/browser/suggestWidgetDetails.ts +++ b/src/vs/editor/contrib/suggest/browser/suggestWidgetDetails.ts @@ -12,7 +12,7 @@ import { DisposableStore } from 'vs/base/common/lifecycle'; import { MarkdownRenderer } from 'vs/editor/contrib/markdownRenderer/browser/markdownRenderer'; import { ICodeEditor, IOverlayWidget } from 'vs/editor/browser/editorBrowser'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; -import { ResizableHTMLElement } from 'vs/editor/contrib/suggest/browser/resizable'; +import { ResizableHTMLElement } from 'vs/base/browser/ui/resizable/resizable'; import * as nls from 'vs/nls'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { CompletionItem } from './suggest'; From 01d119a39c9ee60cb834d90b6d8e561b97bb91bb Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 6 Jul 2022 13:06:34 +0200 Subject: [PATCH 265/347] select the symbol under cursor when opening quick pick (#154247) fixes https://github.com/microsoft/vscode/issues/154246 --- .../browser/gotoSymbolQuickAccess.ts | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/vs/editor/contrib/quickAccess/browser/gotoSymbolQuickAccess.ts b/src/vs/editor/contrib/quickAccess/browser/gotoSymbolQuickAccess.ts index 1801ab78538..b1ba09a6133 100644 --- a/src/vs/editor/contrib/quickAccess/browser/gotoSymbolQuickAccess.ts +++ b/src/vs/editor/contrib/quickAccess/browser/gotoSymbolQuickAccess.ts @@ -19,6 +19,7 @@ import { AbstractEditorNavigationQuickAccessProvider, IEditorNavigationQuickAcce import { localize } from 'vs/nls'; import { IQuickPick, IQuickPickItem, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput'; import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures'; +import { Position } from 'vs/editor/common/core/position'; export interface IGotoSymbolQuickPickItem extends IQuickPickItem { kind: SymbolKind; @@ -155,7 +156,7 @@ export abstract class AbstractGotoSymbolQuickAccessProvider extends AbstractEdit // Set initial picks and update on type let picksCts: CancellationTokenSource | undefined = undefined; - const updatePickerItems = async () => { + const updatePickerItems = async (positionToEnclose: Position | undefined) => { // Cancel any previous ask for picks and busy picksCts?.dispose(true); @@ -175,6 +176,13 @@ export abstract class AbstractGotoSymbolQuickAccessProvider extends AbstractEdit if (items.length > 0) { picker.items = items; + if (positionToEnclose && query.original.length === 0) { + const candidate = items.find(item => item.type !== 'separator' && item.range && Range.containsPosition(item.range.decoration, positionToEnclose)); + if (candidate) { + picker.activeItems = [candidate]; + } + } + } else { if (query.original.length > 0) { this.provideLabelPick(picker, localize('noMatchingSymbolResults', "No matching editor symbols")); @@ -188,19 +196,19 @@ export abstract class AbstractGotoSymbolQuickAccessProvider extends AbstractEdit } } }; - disposables.add(picker.onDidChangeValue(() => updatePickerItems())); - updatePickerItems(); + disposables.add(picker.onDidChangeValue(() => updatePickerItems(undefined))); + updatePickerItems(editor.getSelection()?.getPosition()); + // Reveal and decorate when active item changes - // However, ignore the very first event so that + // However, ignore the very first two events so that // opening the picker is not immediately revealing // and decorating the first entry. - let ignoreFirstActiveEvent = true; + let ignoreFirstActiveEvent = 2; disposables.add(picker.onDidChangeActive(() => { const [item] = picker.activeItems; if (item && item.range) { - if (ignoreFirstActiveEvent) { - ignoreFirstActiveEvent = false; + if (ignoreFirstActiveEvent-- > 0) { return; } From b94a4bf43814fb4582a5f5e5cf8c48ecd2b90766 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 6 Jul 2022 13:19:07 +0200 Subject: [PATCH 266/347] always include default profile in the profiles --- .../contrib/extensionsCleaner.ts | 4 +-- .../defaultExtensionsProfileInit.ts | 4 +-- .../node/extensionsScannerService.test.ts | 5 +--- .../userDataProfile/common/userDataProfile.ts | 5 ++-- .../electron-main/userDataProfile.ts | 28 ++++++++++--------- .../userDataProfile/node/userDataProfile.ts | 7 ++--- .../common/userDataProfileService.test.ts | 6 ++-- .../userDataProfileMainService.test.ts | 6 ++-- .../browser/userDataProfile.ts | 2 +- 9 files changed, 33 insertions(+), 34 deletions(-) diff --git a/src/vs/code/electron-browser/sharedProcess/contrib/extensionsCleaner.ts b/src/vs/code/electron-browser/sharedProcess/contrib/extensionsCleaner.ts index 221d77ffdfa..0116d6e8aa8 100644 --- a/src/vs/code/electron-browser/sharedProcess/contrib/extensionsCleaner.ts +++ b/src/vs/code/electron-browser/sharedProcess/contrib/extensionsCleaner.ts @@ -34,7 +34,7 @@ export class ExtensionsCleaner extends Disposable { ) { super(); - extensionManagementService.removeUninstalledExtensions(this.userDataProfilesService.profiles.length === 0); + extensionManagementService.removeUninstalledExtensions(this.userDataProfilesService.profiles.length === 1); migrateUnsupportedExtensions(extensionManagementService, extensionGalleryService, extensionStorageService, extensionEnablementService, logService); ExtensionStorageService.removeOutdatedExtensionVersions(extensionManagementService, storageService); this._register(instantiationService.createInstance(ProfileExtensionsCleaner)); @@ -66,7 +66,7 @@ class ProfileExtensionsCleaner extends Disposable { this.logService.error(error); } - if (all.length === 0) { + if (all.length === 1) { // Exit profile mode this.profileModeDisposables.clear(); // Listen for entering into profile mode diff --git a/src/vs/platform/extensionManagement/electron-main/defaultExtensionsProfileInit.ts b/src/vs/platform/extensionManagement/electron-main/defaultExtensionsProfileInit.ts index 2db8dfaa0d8..fd3d1698683 100644 --- a/src/vs/platform/extensionManagement/electron-main/defaultExtensionsProfileInit.ts +++ b/src/vs/platform/extensionManagement/electron-main/defaultExtensionsProfileInit.ts @@ -14,12 +14,12 @@ export class DefaultExtensionsProfileInitHandler extends Disposable { ) { super(); this._register(userDataProfilesService.onWillCreateProfile(e => { - if (userDataProfilesService.profiles.length === 0) { + if (userDataProfilesService.profiles.length === 1) { e.join(this.defaultExtensionsProfileInitService.initialize()); } })); this._register(userDataProfilesService.onDidChangeProfiles(e => { - if (userDataProfilesService.profiles.length === 0) { + if (userDataProfilesService.profiles.length === 1) { this.defaultExtensionsProfileInitService.uninitialize(); } })); diff --git a/src/vs/platform/extensionManagement/test/node/extensionsScannerService.test.ts b/src/vs/platform/extensionManagement/test/node/extensionsScannerService.test.ts index 54a7232c285..cdfaa38b842 100644 --- a/src/vs/platform/extensionManagement/test/node/extensionsScannerService.test.ts +++ b/src/vs/platform/extensionManagement/test/node/extensionsScannerService.test.ts @@ -17,7 +17,6 @@ import { InMemoryFileSystemProvider } from 'vs/platform/files/common/inMemoryFil import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; import { ILogService, NullLogService } from 'vs/platform/log/common/log'; import { IProductService } from 'vs/platform/product/common/productService'; -import { UriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentityService'; import { IUserDataProfilesService, UserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile'; let translations: Translations = Object.create(null); @@ -70,9 +69,7 @@ suite('NativeExtensionsScanerService Test', () => { extensionsPath: userExtensionsLocation.fsPath, }); instantiationService.stub(IProductService, { version: '1.66.0' }); - const uriIdentityService = new UriIdentityService(fileService); - const userDataProfilesService = new UserDataProfilesService(environmentService, fileService, logService); - instantiationService.stub(IExtensionsProfileScannerService, new ExtensionsProfileScannerService(fileService, uriIdentityService, userDataProfilesService, logService)); + instantiationService.stub(IExtensionsProfileScannerService, new ExtensionsProfileScannerService(fileService, logService)); instantiationService.stub(IUserDataProfilesService, new UserDataProfilesService(environmentService, fileService, logService)); await fileService.createFolder(systemExtensionsLocation); await fileService.createFolder(userExtensionsLocation); diff --git a/src/vs/platform/userDataProfile/common/userDataProfile.ts b/src/vs/platform/userDataProfile/common/userDataProfile.ts index e4027d99812..423be13c443 100644 --- a/src/vs/platform/userDataProfile/common/userDataProfile.ts +++ b/src/vs/platform/userDataProfile/common/userDataProfile.ts @@ -122,9 +122,8 @@ export class UserDataProfilesService extends Disposable implements IUserDataProf readonly profilesHome: URI; - private readonly _defaultProfile = this.createDefaultUserDataProfile(false); - get defaultProfile(): IUserDataProfile { return this.profiles[0] ?? this._defaultProfile; } - get profiles(): IUserDataProfile[] { return []; } + get defaultProfile(): IUserDataProfile { return this.profiles[0]; } + get profiles(): IUserDataProfile[] { return [this.createDefaultUserDataProfile(false)]; } protected readonly _onDidChangeProfiles = this._register(new Emitter()); readonly onDidChangeProfiles = this._onDidChangeProfiles.event; diff --git a/src/vs/platform/userDataProfile/electron-main/userDataProfile.ts b/src/vs/platform/userDataProfile/electron-main/userDataProfile.ts index f890a1e2fcf..ae1c744da24 100644 --- a/src/vs/platform/userDataProfile/electron-main/userDataProfile.ts +++ b/src/vs/platform/userDataProfile/electron-main/userDataProfile.ts @@ -11,7 +11,7 @@ import { refineServiceDecorator } from 'vs/platform/instantiation/common/instant import { ILogService } from 'vs/platform/log/common/log'; import { IStateMainService } from 'vs/platform/state/electron-main/state'; import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'; -import { IUserDataProfile, IUserDataProfilesService, reviveProfile, PROFILES_ENABLEMENT_CONFIG, WorkspaceIdentifier, UseDefaultProfileFlags, toUserDataProfile } from 'vs/platform/userDataProfile/common/userDataProfile'; +import { IUserDataProfile, IUserDataProfilesService, PROFILES_ENABLEMENT_CONFIG, WorkspaceIdentifier, UseDefaultProfileFlags, toUserDataProfile } from 'vs/platform/userDataProfile/common/userDataProfile'; import { Promises } from 'vs/base/common/async'; import { StoredProfileAssociations, StoredUserDataProfile, UserDataProfilesService } from 'vs/platform/userDataProfile/node/userDataProfile'; import { IStringDictionary } from 'vs/base/common/collections'; @@ -79,38 +79,40 @@ export class UserDataProfilesMainService extends UserDataProfilesService impleme await this.setProfileForWorkspace(profile, workspaceIdentifier); } - return this.profiles.find(p => this.uriIdentityService.extUri.isEqual(p.location, profile.location))!; + return profile; } - override async setProfileForWorkspace(profile: IUserDataProfile, workspaceIdentifier: WorkspaceIdentifier): Promise { + override async setProfileForWorkspace(profileToSet: IUserDataProfile, workspaceIdentifier: WorkspaceIdentifier): Promise { if (!this.enabled) { throw new Error(`Settings Profiles are disabled. Enable them via the '${PROFILES_ENABLEMENT_CONFIG}' setting.`); } - profile = reviveProfile(profile, this.profilesHome.scheme); - this.updateWorkspaceAssociation(workspaceIdentifier, profile); + const profile = this.profiles.find(p => p.id === profileToSet.id); + if (!profile) { + throw new Error(`Profile '${profileToSet.name}' does not exist`); + } - return this.profiles.find(p => this.uriIdentityService.extUri.isEqual(p.location, profile.location))!; + this.updateWorkspaceAssociation(workspaceIdentifier, profile); + return profile; } async unsetWorkspace(workspaceIdentifier: WorkspaceIdentifier): Promise { if (!this.enabled) { throw new Error(`Settings Profiles are disabled. Enable them via the '${PROFILES_ENABLEMENT_CONFIG}' setting.`); } - this.updateWorkspaceAssociation(workspaceIdentifier); } - override async removeProfile(profile: IUserDataProfile): Promise { + override async removeProfile(profileToRemove: IUserDataProfile): Promise { if (!this.enabled) { throw new Error(`Settings Profiles are disabled. Enable them via the '${PROFILES_ENABLEMENT_CONFIG}' setting.`); } - if (profile.isDefault) { + if (profileToRemove.isDefault) { throw new Error('Cannot remove default profile'); } - profile = reviveProfile(profile, this.profilesHome.scheme); - if (!this.getStoredProfiles().some(p => this.uriIdentityService.extUri.isEqual(p.location, profile.location))) { - throw new Error(`Profile with name ${profile.name} does not exist`); + const profile = this.profiles.find(p => p.id === profileToRemove.id); + if (!profile) { + throw new Error(`Profile '${profileToRemove.name}' does not exist`); } const joiners: Promise[] = []; @@ -135,7 +137,7 @@ export class UserDataProfilesMainService extends UserDataProfilesService impleme this.updateProfiles([], [profile]); try { - if (this.profiles.length === 2) { + if (this.profiles.length === 1) { await this.fileService.del(this.profilesHome, { recursive: true }); } else { await this.fileService.del(profile.location, { recursive: true }); diff --git a/src/vs/platform/userDataProfile/node/userDataProfile.ts b/src/vs/platform/userDataProfile/node/userDataProfile.ts index a7b7c247891..34428dd9689 100644 --- a/src/vs/platform/userDataProfile/node/userDataProfile.ts +++ b/src/vs/platform/userDataProfile/node/userDataProfile.ts @@ -57,15 +57,11 @@ export class UserDataProfilesService extends BaseUserDataProfilesService impleme protected _profilesObject: UserDataProfilesObject | undefined; protected get profilesObject(): UserDataProfilesObject { - if (!this.enabled) { - return { profiles: [], workspaces: new ResourceMap() }; - } if (!this._profilesObject) { - const profiles = this.getStoredProfiles().map(storedProfile => toUserDataProfile(storedProfile.name, storedProfile.location, storedProfile.useDefaultFlags)); + const profiles = this.enabled ? this.getStoredProfiles().map(storedProfile => toUserDataProfile(storedProfile.name, storedProfile.location, storedProfile.useDefaultFlags)) : []; let emptyWindow: IUserDataProfile | undefined; const workspaces = new ResourceMap(); if (profiles.length) { - profiles.unshift(this.createDefaultUserDataProfile(true)); const profileAssicaitions = this.getStoredProfileAssociations(); if (profileAssicaitions.workspaces) { for (const [workspacePath, profilePath] of Object.entries(profileAssicaitions.workspaces)) { @@ -82,6 +78,7 @@ export class UserDataProfilesService extends BaseUserDataProfilesService impleme emptyWindow = profiles.find(p => this.uriIdentityService.extUri.isEqual(p.location, emptyWindowProfileLocation)); } } + profiles.unshift(this.createDefaultUserDataProfile(profiles.length > 0)); this._profilesObject = { profiles, workspaces, emptyWindow }; } return this._profilesObject; diff --git a/src/vs/platform/userDataProfile/test/common/userDataProfileService.test.ts b/src/vs/platform/userDataProfile/test/common/userDataProfileService.test.ts index b284dd6fd70..549c686644c 100644 --- a/src/vs/platform/userDataProfile/test/common/userDataProfileService.test.ts +++ b/src/vs/platform/userDataProfile/test/common/userDataProfileService.test.ts @@ -54,8 +54,10 @@ suite('UserDataProfileService (Common)', () => { assert.strictEqual(testObject.defaultProfile.extensionsResource, undefined); }); - test('profiles are empty', () => { - assert.deepStrictEqual(testObject.profiles, []); + test('profiles always include default profile', () => { + assert.deepStrictEqual(testObject.profiles.length, 1); + assert.deepStrictEqual(testObject.profiles[0].isDefault, true); + assert.deepStrictEqual(testObject.profiles[0].extensionsResource, undefined); }); diff --git a/src/vs/platform/userDataProfile/test/electron-main/userDataProfileMainService.test.ts b/src/vs/platform/userDataProfile/test/electron-main/userDataProfileMainService.test.ts index ec861ab96f4..23e7656a1ad 100644 --- a/src/vs/platform/userDataProfile/test/electron-main/userDataProfileMainService.test.ts +++ b/src/vs/platform/userDataProfile/test/electron-main/userDataProfileMainService.test.ts @@ -54,8 +54,10 @@ suite('UserDataProfileMainService', () => { assert.strictEqual(testObject.defaultProfile.extensionsResource, undefined); }); - test('profiles are empty', () => { - assert.deepStrictEqual(testObject.profiles, []); + test('profiles always include default profile', () => { + assert.deepStrictEqual(testObject.profiles.length, 1); + assert.deepStrictEqual(testObject.profiles[0].isDefault, true); + assert.deepStrictEqual(testObject.profiles[0].extensionsResource, undefined); }); test('default profile when there are profiles', async () => { diff --git a/src/vs/workbench/contrib/userDataProfile/browser/userDataProfile.ts b/src/vs/workbench/contrib/userDataProfile/browser/userDataProfile.ts index 8a75af540d3..44aa262be18 100644 --- a/src/vs/workbench/contrib/userDataProfile/browser/userDataProfile.ts +++ b/src/vs/workbench/contrib/userDataProfile/browser/userDataProfile.ts @@ -133,7 +133,7 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements private profileStatusAccessor: IStatusbarEntryAccessor | undefined; private updateStatus(): void { - if (this.userDataProfilesService.profiles.length) { + if (this.userDataProfilesService.profiles.length > 1) { const statusBarEntry: IStatusbarEntry = { name: PROFILES_CATEGORY, command: 'workbench.profiles.actions.switchProfile', From 2f5975cb43b72e6795d0ee75788151a6f7b087e3 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 6 Jul 2022 04:27:56 -0700 Subject: [PATCH 267/347] Relative -> absolute path --- src/vs/editor/contrib/suggest/browser/suggestWidget.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/suggest/browser/suggestWidget.ts b/src/vs/editor/contrib/suggest/browser/suggestWidget.ts index 74cffe08fe9..987961a013c 100644 --- a/src/vs/editor/contrib/suggest/browser/suggestWidget.ts +++ b/src/vs/editor/contrib/suggest/browser/suggestWidget.ts @@ -30,7 +30,7 @@ import { attachListStyler } from 'vs/platform/theme/common/styler'; import { isHighContrast } from 'vs/platform/theme/common/theme'; import { IColorTheme, IThemeService } from 'vs/platform/theme/common/themeService'; import { CompletionModel } from './completionModel'; -import { ResizableHTMLElement } from '../../../../base/browser/ui/resizable/resizable'; +import { ResizableHTMLElement } from 'vs/base/browser/ui/resizable/resizable'; import { CompletionItem, Context as SuggestContext } from './suggest'; import { canExpandCompletionItem, SuggestDetailsOverlay, SuggestDetailsWidget } from './suggestWidgetDetails'; import { getAriaId, ItemRenderer } from './suggestWidgetRenderer'; From d2b2d407621e23b5886c69e3987977b06aafdd64 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 6 Jul 2022 13:29:38 +0200 Subject: [PATCH 268/347] remove return type for setProfileForWorkspace --- src/vs/platform/userDataProfile/common/userDataProfile.ts | 4 ++-- .../userDataProfile/electron-main/userDataProfile.ts | 3 +-- .../userDataProfile/electron-sandbox/userDataProfile.ts | 5 ++--- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/vs/platform/userDataProfile/common/userDataProfile.ts b/src/vs/platform/userDataProfile/common/userDataProfile.ts index 423be13c443..375166c4ce5 100644 --- a/src/vs/platform/userDataProfile/common/userDataProfile.ts +++ b/src/vs/platform/userDataProfile/common/userDataProfile.ts @@ -79,7 +79,7 @@ export interface IUserDataProfilesService { readonly profiles: IUserDataProfile[]; createProfile(name: string, useDefaultFlags?: UseDefaultProfileFlags, workspaceIdentifier?: WorkspaceIdentifier): Promise; - setProfileForWorkspace(profile: IUserDataProfile, workspaceIdentifier: WorkspaceIdentifier): Promise; + setProfileForWorkspace(profile: IUserDataProfile, workspaceIdentifier: WorkspaceIdentifier): Promise; getProfile(workspaceIdentifier: WorkspaceIdentifier): IUserDataProfile; removeProfile(profile: IUserDataProfile): Promise; } @@ -143,7 +143,7 @@ export class UserDataProfilesService extends Disposable implements IUserDataProf } createProfile(name: string, useDefaultFlags?: UseDefaultProfileFlags, workspaceIdentifier?: WorkspaceIdentifier): Promise { throw new Error('Not implemented'); } - setProfileForWorkspace(profile: IUserDataProfile, workspaceIdentifier: WorkspaceIdentifier): Promise { throw new Error('Not implemented'); } + setProfileForWorkspace(profile: IUserDataProfile, workspaceIdentifier: WorkspaceIdentifier): Promise { throw new Error('Not implemented'); } getProfile(workspaceIdentifier: WorkspaceIdentifier): IUserDataProfile { throw new Error('Not implemented'); } removeProfile(profile: IUserDataProfile): Promise { throw new Error('Not implemented'); } } diff --git a/src/vs/platform/userDataProfile/electron-main/userDataProfile.ts b/src/vs/platform/userDataProfile/electron-main/userDataProfile.ts index ae1c744da24..e52855d4867 100644 --- a/src/vs/platform/userDataProfile/electron-main/userDataProfile.ts +++ b/src/vs/platform/userDataProfile/electron-main/userDataProfile.ts @@ -82,7 +82,7 @@ export class UserDataProfilesMainService extends UserDataProfilesService impleme return profile; } - override async setProfileForWorkspace(profileToSet: IUserDataProfile, workspaceIdentifier: WorkspaceIdentifier): Promise { + override async setProfileForWorkspace(profileToSet: IUserDataProfile, workspaceIdentifier: WorkspaceIdentifier): Promise { if (!this.enabled) { throw new Error(`Settings Profiles are disabled. Enable them via the '${PROFILES_ENABLEMENT_CONFIG}' setting.`); } @@ -93,7 +93,6 @@ export class UserDataProfilesMainService extends UserDataProfilesService impleme } this.updateWorkspaceAssociation(workspaceIdentifier, profile); - return profile; } async unsetWorkspace(workspaceIdentifier: WorkspaceIdentifier): Promise { diff --git a/src/vs/platform/userDataProfile/electron-sandbox/userDataProfile.ts b/src/vs/platform/userDataProfile/electron-sandbox/userDataProfile.ts index 417dc0bf5c8..9d999933058 100644 --- a/src/vs/platform/userDataProfile/electron-sandbox/userDataProfile.ts +++ b/src/vs/platform/userDataProfile/electron-sandbox/userDataProfile.ts @@ -42,9 +42,8 @@ export class UserDataProfilesNativeService extends UserDataProfilesService imple return reviveProfile(result, this.profilesHome.scheme); } - override async setProfileForWorkspace(profile: IUserDataProfile, workspaceIdentifier: ISingleFolderWorkspaceIdentifier | IWorkspaceIdentifier): Promise { - const result = await this.channel.call>('setProfileForWorkspace', [profile, workspaceIdentifier]); - return reviveProfile(result, this.profilesHome.scheme); + override async setProfileForWorkspace(profile: IUserDataProfile, workspaceIdentifier: ISingleFolderWorkspaceIdentifier | IWorkspaceIdentifier): Promise { + await this.channel.call>('setProfileForWorkspace', [profile, workspaceIdentifier]); } override removeProfile(profile: IUserDataProfile): Promise { From 92b276d6d095d33e638a95a7a03fa5b8d3894e4e Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 6 Jul 2022 13:37:21 +0200 Subject: [PATCH 269/347] support `noSelect` for the `editor.action.triggerSuggest` command (#154251) This allows to trigger suggest (as normal) but not select an item, https://github.com/microsoft/vscode/issues/151336 --- .../editor/contrib/suggest/browser/suggest.ts | 1 + .../suggest/browser/suggestController.ts | 29 +++++++++------ .../contrib/suggest/browser/suggestModel.ts | 27 ++++++++------ .../contrib/suggest/browser/suggestWidget.ts | 12 ++++-- .../suggest/test/browser/suggestModel.test.ts | 37 +++++++++++++------ 5 files changed, 70 insertions(+), 36 deletions(-) diff --git a/src/vs/editor/contrib/suggest/browser/suggest.ts b/src/vs/editor/contrib/suggest/browser/suggest.ts index 59e61786894..805c58df531 100644 --- a/src/vs/editor/contrib/suggest/browser/suggest.ts +++ b/src/vs/editor/contrib/suggest/browser/suggest.ts @@ -31,6 +31,7 @@ import { StandardTokenType } from 'vs/editor/common/encodedTokenAttributes'; export const Context = { Visible: historyNavigationVisible, + HasFocusedSuggestion: new RawContextKey('suggestWidgetHasFocusedSuggestion', false, localize('suggestWidgetHasSelection', "Whether any suggestion is focused")), DetailsVisible: new RawContextKey('suggestWidgetDetailsVisible', false, localize('suggestWidgetDetailsVisible', "Whether suggestion details are visible")), MultipleSuggestions: new RawContextKey('suggestWidgetMultipleSuggestions', false, localize('suggestWidgetMultipleSuggestions', "Whether there are multiple suggestions to pick from")), MakesTextEdit: new RawContextKey('suggestionMakesTextEdit', true, localize('suggestionMakesTextEdit', "Whether inserting the current suggestion yields in a change or has everything already been typed")), diff --git a/src/vs/editor/contrib/suggest/browser/suggestController.ts b/src/vs/editor/contrib/suggest/browser/suggestController.ts index c3b80a8c5e9..14045fe6bec 100644 --- a/src/vs/editor/contrib/suggest/browser/suggestController.ts +++ b/src/vs/editor/contrib/suggest/browser/suggestController.ts @@ -226,8 +226,11 @@ export class SuggestController implements IEditorContribution { this._lineSuffix.value = new LineSuffix(this.editor.getModel()!, e.position); })); this._toDispose.add(this.model.onDidSuggest(e => { - if (!e.shy) { - let index = -1; + if (e.shy) { + return; + } + let index = -1; + if (!e.noSelect) { for (const selector of this._selectors.itemsOrderedByPriorityDesc) { index = selector.select(this.editor.getModel()!, this.editor.getPosition()!, e.completionModel.items); if (index !== -1) { @@ -237,8 +240,8 @@ export class SuggestController implements IEditorContribution { if (index === -1) { index = this._memoryService.select(this.editor.getModel()!, this.editor.getPosition()!, e.completionModel.items); } - this.widget.value.showSuggestions(e.completionModel, index, e.isFrozen, e.auto); } + this.widget.value.showSuggestions(e.completionModel, index, e.isFrozen, e.auto); })); this._toDispose.add(this.model.onDidCancel(e => { if (!e.retrigger) { @@ -400,7 +403,7 @@ export class SuggestController implements IEditorContribution { } else if (item.completion.command.id === TriggerSuggestAction.id) { // retigger - this.model.trigger({ auto: true, shy: false }, true); + this.model.trigger({ auto: true, shy: false, noSelect: false }, true); } else { // exec command, done @@ -494,9 +497,9 @@ export class SuggestController implements IEditorContribution { } } - triggerSuggest(onlyFrom?: Set, auto?: boolean, noFilter?: boolean): void { + triggerSuggest(onlyFrom?: Set, auto?: boolean, noFilter?: boolean, noSelect?: boolean): void { if (this.editor.hasModel()) { - this.model.trigger({ auto: auto ?? false, shy: false }, false, onlyFrom, undefined, noFilter); + this.model.trigger({ auto: auto ?? false, shy: false, noSelect: noSelect ?? false }, false, onlyFrom, undefined, noFilter); this.editor.revealPosition(this.editor.getPosition(), ScrollType.Smooth); this.editor.focus(); } @@ -565,7 +568,7 @@ export class SuggestController implements IEditorContribution { }, undefined, listener); }); - this.model.trigger({ auto: false, shy: true }); + this.model.trigger({ auto: false, shy: true, noSelect: false }); this.editor.revealPosition(positionNow, ScrollType.Smooth); this.editor.focus(); } @@ -706,15 +709,19 @@ export class TriggerSuggestAction extends EditorAction { return; } - type TriggerArgs = { auto: boolean }; + type TriggerArgs = { auto: boolean; noSelection: boolean }; let auto: boolean | undefined; + let noSelect: boolean | undefined; if (args && typeof args === 'object') { if ((args).auto === true) { auto = true; } + if ((args).noSelection === true) { + noSelect = true; + } } - controller.triggerSuggest(undefined, auto); + controller.triggerSuggest(undefined, auto, undefined, noSelect); } } @@ -728,7 +735,7 @@ const SuggestCommand = EditorCommand.bindToContribution(Sugge registerEditorCommand(new SuggestCommand({ id: 'acceptSelectedSuggestion', - precondition: SuggestContext.Visible, + precondition: ContextKeyExpr.and(SuggestContext.Visible, SuggestContext.HasFocusedSuggestion), handler(x) { x.acceptSelectedSuggestion(true, false); }, @@ -766,7 +773,7 @@ registerEditorCommand(new SuggestCommand({ registerEditorCommand(new SuggestCommand({ id: 'acceptAlternativeSelectedSuggestion', - precondition: ContextKeyExpr.and(SuggestContext.Visible, EditorContextKeys.textInputFocus), + precondition: ContextKeyExpr.and(SuggestContext.Visible, EditorContextKeys.textInputFocus, SuggestContext.HasFocusedSuggestion), kbOpts: { weight: weight, kbExpr: EditorContextKeys.textInputFocus, diff --git a/src/vs/editor/contrib/suggest/browser/suggestModel.ts b/src/vs/editor/contrib/suggest/browser/suggestModel.ts index 62f7bebafe1..7159e6a10ec 100644 --- a/src/vs/editor/contrib/suggest/browser/suggestModel.ts +++ b/src/vs/editor/contrib/suggest/browser/suggestModel.ts @@ -44,11 +44,13 @@ export interface ISuggestEvent { readonly isFrozen: boolean; readonly auto: boolean; readonly shy: boolean; + readonly noSelect: boolean; } export interface SuggestTriggerContext { readonly auto: boolean; readonly shy: boolean; + readonly noSelect: boolean; readonly triggerKind?: CompletionTriggerKind; readonly triggerCharacter?: string; } @@ -82,14 +84,16 @@ export class LineContext { readonly leadingWord: IWordAtPosition; readonly auto: boolean; readonly shy: boolean; + readonly noSelect: boolean; - constructor(model: ITextModel, position: Position, auto: boolean, shy: boolean) { + constructor(model: ITextModel, position: Position, auto: boolean, shy: boolean, noSelect: boolean) { this.leadingLineContent = model.getLineContent(position.lineNumber).substr(0, position.column - 1); this.leadingWord = model.getWordUntilPosition(position); this.lineNumber = position.lineNumber; this.column = position.column; this.auto = auto; this.shy = shy; + this.noSelect = noSelect; } } @@ -279,7 +283,7 @@ export class SuggestModel implements IDisposable { const existing = this._completionModel ? { items: this._completionModel.adopt(supports), clipboardText: this._completionModel.clipboardText } : undefined; - this.trigger({ auto: true, shy: false, triggerCharacter: lastChar }, Boolean(this._completionModel), supports, existing); + this.trigger({ auto: true, shy: false, noSelect: false, triggerCharacter: lastChar }, Boolean(this._completionModel), supports, existing); } }; @@ -314,7 +318,7 @@ export class SuggestModel implements IDisposable { if (!this._editor.hasModel() || !this._languageFeaturesService.completionProvider.has(this._editor.getModel())) { this.cancel(); } else { - this.trigger({ auto: this._state === State.Auto, shy: false }, true); + this.trigger({ auto: this._state === State.Auto, shy: false, noSelect: false }, true); } } } @@ -413,7 +417,7 @@ export class SuggestModel implements IDisposable { } // we made it till here -> trigger now - this.trigger({ auto: true, shy: false }); + this.trigger({ auto: true, shy: false, noSelect: false }); }, this._editor.getOption(EditorOption.quickSuggestionsDelay)); } @@ -433,7 +437,7 @@ export class SuggestModel implements IDisposable { } const model = this._editor.getModel(); const position = this._editor.getPosition(); - const ctx = new LineContext(model, position, this._state === State.Auto, false); + const ctx = new LineContext(model, position, this._state === State.Auto, false, false); this._onNewContext(ctx); }); } @@ -445,7 +449,7 @@ export class SuggestModel implements IDisposable { const model = this._editor.getModel(); const auto = context.auto; - const ctx = new LineContext(model, this._editor.getPosition(), auto, context.shy); + const ctx = new LineContext(model, this._editor.getPosition(), auto, context.shy, context.noSelect); // Cancel previous requests, change state & update UI this.cancel(retrigger); @@ -520,7 +524,7 @@ export class SuggestModel implements IDisposable { items = items.concat(existing.items).sort(cmpFn); } - const ctx = new LineContext(model, this._editor.getPosition(), auto, context.shy); + const ctx = new LineContext(model, this._editor.getPosition(), auto, context.shy, context.noSelect); this._completionModel = new CompletionModel(items, this._context!.column, { leadingLineContent: ctx.leadingLineContent, characterCountDelta: ctx.column - this._context!.column @@ -630,7 +634,7 @@ export class SuggestModel implements IDisposable { if (ctx.column < this._context.column) { // typed -> moved cursor LEFT -> retrigger if still on a word if (ctx.leadingWord.word) { - this.trigger({ auto: this._context.auto, shy: false }, true); + this.trigger({ auto: this._context.auto, shy: false, noSelect: false }, true); } else { this.cancel(); } @@ -652,7 +656,7 @@ export class SuggestModel implements IDisposable { inactiveProvider.delete(provider); } const items = this._completionModel.adopt(new Set()); - this.trigger({ auto: this._context.auto, shy: false }, true, inactiveProvider, { items, clipboardText: this._completionModel.clipboardText }); + this.trigger({ auto: this._context.auto, shy: false, noSelect: false }, true, inactiveProvider, { items, clipboardText: this._completionModel.clipboardText }); return; } @@ -660,7 +664,7 @@ export class SuggestModel implements IDisposable { // typed -> moved cursor RIGHT & incomple model & still on a word -> retrigger const { incomplete } = this._completionModel; const items = this._completionModel.adopt(incomplete); - this.trigger({ auto: this._state === State.Auto, shy: false, triggerKind: CompletionTriggerKind.TriggerForIncompleteCompletions }, true, incomplete, { items, clipboardText: this._completionModel.clipboardText }); + this.trigger({ auto: this._state === State.Auto, shy: false, noSelect: false, triggerKind: CompletionTriggerKind.TriggerForIncompleteCompletions }, true, incomplete, { items, clipboardText: this._completionModel.clipboardText }); } else { // typed -> moved cursor RIGHT -> update UI @@ -676,7 +680,7 @@ export class SuggestModel implements IDisposable { if (LineContext.shouldAutoTrigger(this._editor) && this._context.leadingWord.endColumn < ctx.leadingWord.startColumn) { // retrigger when heading into a new word - this.trigger({ auto: this._context.auto, shy: false }, true); + this.trigger({ auto: this._context.auto, shy: false, noSelect: false }, true); return; } @@ -703,6 +707,7 @@ export class SuggestModel implements IDisposable { completionModel: this._completionModel, auto: this._context.auto, shy: this._context.shy, + noSelect: this._context.noSelect, isFrozen, }); } diff --git a/src/vs/editor/contrib/suggest/browser/suggestWidget.ts b/src/vs/editor/contrib/suggest/browser/suggestWidget.ts index 3a03d2da7dd..afdf48a801a 100644 --- a/src/vs/editor/contrib/suggest/browser/suggestWidget.ts +++ b/src/vs/editor/contrib/suggest/browser/suggestWidget.ts @@ -124,6 +124,7 @@ export class SuggestWidget implements IDisposable { private readonly _ctxSuggestWidgetVisible: IContextKey; private readonly _ctxSuggestWidgetDetailsVisible: IContextKey; private readonly _ctxSuggestWidgetMultipleSuggestions: IContextKey; + private readonly _ctxSuggestWidgetHasFocusedSuggestion: IContextKey; private readonly _showTimeout = new TimeoutTimer(); private readonly _disposables = new DisposableStore(); @@ -283,7 +284,7 @@ export class SuggestWidget implements IDisposable { this._ctxSuggestWidgetVisible = SuggestContext.Visible.bindTo(_contextKeyService); this._ctxSuggestWidgetDetailsVisible = SuggestContext.DetailsVisible.bindTo(_contextKeyService); this._ctxSuggestWidgetMultipleSuggestions = SuggestContext.MultipleSuggestions.bindTo(_contextKeyService); - + this._ctxSuggestWidgetHasFocusedSuggestion = SuggestContext.HasFocusedSuggestion.bindTo(_contextKeyService); this._disposables.add(dom.addStandardDisposableListener(this._details.widget.domNode, 'keydown', e => { this._onDetailsKeydown.fire(e); @@ -365,6 +366,7 @@ export class SuggestWidget implements IDisposable { } this.editor.setAriaOptions({ activeDescendant: undefined }); + this._ctxSuggestWidgetHasFocusedSuggestion.set(false); return; } @@ -372,6 +374,7 @@ export class SuggestWidget implements IDisposable { return; } + this._ctxSuggestWidgetHasFocusedSuggestion.set(true); const item = e.elements[0]; const index = e.indexes[0]; @@ -440,6 +443,7 @@ export class SuggestWidget implements IDisposable { this._contentWidget.hide(); this._ctxSuggestWidgetVisible.reset(); this._ctxSuggestWidgetMultipleSuggestions.reset(); + this._ctxSuggestWidgetHasFocusedSuggestion.reset(); this._showTimeout.cancel(); this.element.domNode.classList.remove('visible'); this._list.splice(0, this._list.length); @@ -538,8 +542,10 @@ export class SuggestWidget implements IDisposable { this._focusedItem = undefined; this._list.splice(0, this._list.length, this._completionModel.items); this._setState(isFrozen ? State.Frozen : State.Open); - this._list.reveal(selectionIndex, 0); - this._list.setFocus([selectionIndex]); + if (selectionIndex >= 0) { + this._list.reveal(selectionIndex, 0); + this._list.setFocus([selectionIndex]); + } this._layout(this.element.size); // Reset focus border diff --git a/src/vs/editor/contrib/suggest/test/browser/suggestModel.test.ts b/src/vs/editor/contrib/suggest/test/browser/suggestModel.test.ts index f25e0b22040..0a1b3dda2de 100644 --- a/src/vs/editor/contrib/suggest/test/browser/suggestModel.test.ts +++ b/src/vs/editor/contrib/suggest/test/browser/suggestModel.test.ts @@ -253,7 +253,7 @@ suite('SuggestModel - TriggerAndCancelOracle', function () { return Promise.all([ assertEvent(model.onDidTrigger, function () { - model.trigger({ auto: true, shy: false }); + model.trigger({ auto: true, shy: false, noSelect: false }); }, function (event) { assert.strictEqual(event.auto, true); @@ -265,13 +265,13 @@ suite('SuggestModel - TriggerAndCancelOracle', function () { }), assertEvent(model.onDidTrigger, function () { - model.trigger({ auto: true, shy: false }); + model.trigger({ auto: true, shy: false, noSelect: false }); }, function (event) { assert.strictEqual(event.auto, true); }), assertEvent(model.onDidTrigger, function () { - model.trigger({ auto: false, shy: false }); + model.trigger({ auto: false, shy: false, noSelect: false }); }, function (event) { assert.strictEqual(event.auto, false); }) @@ -287,12 +287,12 @@ suite('SuggestModel - TriggerAndCancelOracle', function () { return withOracle(model => { return Promise.all([ assertEvent(model.onDidCancel, function () { - model.trigger({ auto: true, shy: false }); + model.trigger({ auto: true, shy: false, noSelect: false }); }, function (event) { assert.strictEqual(event.retrigger, false); }), assertEvent(model.onDidSuggest, function () { - model.trigger({ auto: false, shy: false }); + model.trigger({ auto: false, shy: false, noSelect: false }); }, function (event) { assert.strictEqual(event.auto, false); assert.strictEqual(event.isFrozen, false); @@ -343,7 +343,7 @@ suite('SuggestModel - TriggerAndCancelOracle', function () { return assertEvent(model.onDidSuggest, () => { // make sure completionModel starts here! - model.trigger({ auto: true, shy: false }); + model.trigger({ auto: true, shy: false, noSelect: false }); }, event => { return assertEvent(model.onDidSuggest, () => { @@ -443,7 +443,7 @@ suite('SuggestModel - TriggerAndCancelOracle', function () { editor.setPosition({ lineNumber: 1, column: 3 }); return assertEvent(model.onDidSuggest, () => { - model.trigger({ auto: false, shy: false }); + model.trigger({ auto: false, shy: false, noSelect: false }); }, event => { assert.strictEqual(event.auto, false); assert.strictEqual(event.isFrozen, false); @@ -468,7 +468,7 @@ suite('SuggestModel - TriggerAndCancelOracle', function () { editor.setPosition({ lineNumber: 1, column: 3 }); return assertEvent(model.onDidSuggest, () => { - model.trigger({ auto: false, shy: false }); + model.trigger({ auto: false, shy: false, noSelect: false }); }, event => { assert.strictEqual(event.auto, false); assert.strictEqual(event.isFrozen, false); @@ -505,7 +505,7 @@ suite('SuggestModel - TriggerAndCancelOracle', function () { editor.setPosition({ lineNumber: 1, column: 4 }); return assertEvent(model.onDidSuggest, () => { - model.trigger({ auto: false, shy: false }); + model.trigger({ auto: false, shy: false, noSelect: false }); }, event => { assert.strictEqual(event.auto, false); assert.strictEqual(event.completionModel.incomplete.size, 1); @@ -542,7 +542,7 @@ suite('SuggestModel - TriggerAndCancelOracle', function () { editor.setPosition({ lineNumber: 1, column: 4 }); return assertEvent(model.onDidSuggest, () => { - model.trigger({ auto: false, shy: false }); + model.trigger({ auto: false, shy: false, noSelect: false }); }, event => { assert.strictEqual(event.auto, false); assert.strictEqual(event.completionModel.incomplete.size, 1); @@ -701,7 +701,7 @@ suite('SuggestModel - TriggerAndCancelOracle', function () { await assertEvent(sugget.onDidSuggest, () => { editor.setPosition({ lineNumber: 1, column: 3 }); - sugget.trigger({ auto: false, shy: false }); + sugget.trigger({ auto: false, shy: false, noSelect: false }); }, event => { assert.strictEqual(event.completionModel.items.length, 1); @@ -928,4 +928,19 @@ suite('SuggestModel - TriggerAndCancelOracle', function () { }); }); }); + + test('noSelect-flag makes it from request to suggest event', function () { + + disposables.add(registry.register({ scheme: 'test' }, alwaysSomethingSupport)); + + return withOracle((model, editor) => { + return assertEvent(model.onDidSuggest, () => { + model.trigger({ auto: false, noSelect: true, shy: false }); + }, event => { + assert.strictEqual(event.noSelect, true); + assert.strictEqual(event.auto, false); + assert.strictEqual(event.shy, false); + }); + }); + }); }); From b1eab983e40dfdca90d0f9833b00afe4233c12c3 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 6 Jul 2022 13:41:24 +0200 Subject: [PATCH 270/347] remove `forEach` usage in my and some other places (#154252) https://github.com/microsoft/vscode/issues/154195 --- .../editor/browser/config/migrateOptions.ts | 11 +++--- .../api/browser/mainThreadDialogs.ts | 9 +++-- .../contrib/snippets/browser/snippetsFile.ts | 11 +++--- .../actions/common/menusExtensionPoint.ts | 35 ++++++++++--------- 4 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/vs/editor/browser/config/migrateOptions.ts b/src/vs/editor/browser/config/migrateOptions.ts index 49d6a503a84..42f1bc526a8 100644 --- a/src/vs/editor/browser/config/migrateOptions.ts +++ b/src/vs/editor/browser/config/migrateOptions.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { forEach } from 'vs/base/common/collections'; import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; export interface ISettingsReader { @@ -152,14 +151,14 @@ const suggestFilteredTypesMapping: Record = { registerEditorSettingMigration('suggest.filteredTypes', (value, read, write) => { if (value && typeof value === 'object') { - forEach(suggestFilteredTypesMapping, entry => { - const v = value[entry.key]; + for (const entry of Object.entries(suggestFilteredTypesMapping)) { + const v = value[entry[0]]; if (v === false) { - if (typeof read(`suggest.${entry.value}`) === 'undefined') { - write(`suggest.${entry.value}`, false); + if (typeof read(`suggest.${entry[1]}`) === 'undefined') { + write(`suggest.${entry[1]}`, false); } } - }); + } write('suggest.filteredTypes', undefined); } }); diff --git a/src/vs/workbench/api/browser/mainThreadDialogs.ts b/src/vs/workbench/api/browser/mainThreadDialogs.ts index 1f8066b2c0d..e9ca6d75502 100644 --- a/src/vs/workbench/api/browser/mainThreadDialogs.ts +++ b/src/vs/workbench/api/browser/mainThreadDialogs.ts @@ -6,7 +6,6 @@ import { URI } from 'vs/base/common/uri'; import { MainThreadDiaglogsShape, MainContext, MainThreadDialogOpenOptions, MainThreadDialogSaveOptions } from '../common/extHost.protocol'; import { extHostNamedCustomer, IExtHostContext } from 'vs/workbench/services/extensions/common/extHostCustomers'; -import { forEach } from 'vs/base/common/collections'; import { IFileDialogService, IOpenDialogOptions, ISaveDialogOptions } from 'vs/platform/dialogs/common/dialogs'; @extHostNamedCustomer(MainContext.MainThreadDialogs) @@ -51,7 +50,9 @@ export class MainThreadDialogs implements MainThreadDiaglogsShape { }; if (options?.filters) { result.filters = []; - forEach(options.filters, entry => result.filters!.push({ name: entry.key, extensions: entry.value })); + for (const [key, value] of Object.entries(options.filters)) { + result.filters!.push({ name: key, extensions: value }); + } } return result; } @@ -64,7 +65,9 @@ export class MainThreadDialogs implements MainThreadDiaglogsShape { }; if (options?.filters) { result.filters = []; - forEach(options.filters, entry => result.filters!.push({ name: entry.key, extensions: entry.value })); + for (const [key, value] of Object.entries(options.filters)) { + result.filters.push({ name: key, extensions: value }); + } } return result; } diff --git a/src/vs/workbench/contrib/snippets/browser/snippetsFile.ts b/src/vs/workbench/contrib/snippets/browser/snippetsFile.ts index eb1497201da..784296b70de 100644 --- a/src/vs/workbench/contrib/snippets/browser/snippetsFile.ts +++ b/src/vs/workbench/contrib/snippets/browser/snippetsFile.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import { parse as jsonParse, getNodeType } from 'vs/base/common/json'; -import { forEach } from 'vs/base/common/collections'; import { localize } from 'vs/nls'; import { extname, basename } from 'vs/base/common/path'; import { SnippetParser, Variable, Placeholder, Text } from 'vs/editor/contrib/snippet/browser/snippetParser'; @@ -256,17 +255,15 @@ export class SnippetFile { this._loadPromise = Promise.resolve(this._load()).then(content => { const data = jsonParse(content); if (getNodeType(data) === 'object') { - forEach(data, entry => { - const { key: name, value: scopeOrTemplate } = entry; + for (const [name, scopeOrTemplate] of Object.entries(data)) { if (isJsonSerializedSnippet(scopeOrTemplate)) { this._parseSnippet(name, scopeOrTemplate, this.data); } else { - forEach(scopeOrTemplate, entry => { - const { key: name, value: template } = entry; + for (const [name, template] of Object.entries(scopeOrTemplate)) { this._parseSnippet(name, template, this.data); - }); + } } - }); + } } return this; }); diff --git a/src/vs/workbench/services/actions/common/menusExtensionPoint.ts b/src/vs/workbench/services/actions/common/menusExtensionPoint.ts index c78225da320..e1b8f018998 100644 --- a/src/vs/workbench/services/actions/common/menusExtensionPoint.ts +++ b/src/vs/workbench/services/actions/common/menusExtensionPoint.ts @@ -686,44 +686,45 @@ submenusExtensionPoint.setHandler(extensions => { for (const extension of extensions) { const { value, collector } = extension; - forEach(value, entry => { - if (!schema.isValidSubmenu(entry.value, collector)) { + for (const [, submenuInfo] of Object.entries(value)) { + + if (!schema.isValidSubmenu(submenuInfo, collector)) { return; } - if (!entry.value.id) { - collector.warn(localize('submenuId.invalid.id', "`{0}` is not a valid submenu identifier", entry.value.id)); + if (!submenuInfo.id) { + collector.warn(localize('submenuId.invalid.id', "`{0}` is not a valid submenu identifier", submenuInfo.id)); return; } - if (_submenus.has(entry.value.id)) { - collector.info(localize('submenuId.duplicate.id', "The `{0}` submenu was already previously registered.", entry.value.id)); + if (_submenus.has(submenuInfo.id)) { + collector.info(localize('submenuId.duplicate.id', "The `{0}` submenu was already previously registered.", submenuInfo.id)); return; } - if (!entry.value.label) { - collector.warn(localize('submenuId.invalid.label', "`{0}` is not a valid submenu label", entry.value.label)); + if (!submenuInfo.label) { + collector.warn(localize('submenuId.invalid.label', "`{0}` is not a valid submenu label", submenuInfo.label)); return; } let absoluteIcon: { dark: URI; light?: URI } | ThemeIcon | undefined; - if (entry.value.icon) { - if (typeof entry.value.icon === 'string') { - absoluteIcon = ThemeIcon.fromString(entry.value.icon) || { dark: resources.joinPath(extension.description.extensionLocation, entry.value.icon) }; + if (submenuInfo.icon) { + if (typeof submenuInfo.icon === 'string') { + absoluteIcon = ThemeIcon.fromString(submenuInfo.icon) || { dark: resources.joinPath(extension.description.extensionLocation, submenuInfo.icon) }; } else { absoluteIcon = { - dark: resources.joinPath(extension.description.extensionLocation, entry.value.icon.dark), - light: resources.joinPath(extension.description.extensionLocation, entry.value.icon.light) + dark: resources.joinPath(extension.description.extensionLocation, submenuInfo.icon.dark), + light: resources.joinPath(extension.description.extensionLocation, submenuInfo.icon.light) }; } } const item: IRegisteredSubmenu = { - id: new MenuId(`api:${entry.value.id}`), - label: entry.value.label, + id: new MenuId(`api:${submenuInfo.id}`), + label: submenuInfo.label, icon: absoluteIcon }; - _submenus.set(entry.value.id, item); - }); + _submenus.set(submenuInfo.id, item); + } } }); From 824671d1fbb16300c8bd4940fa49010f54cd7512 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 6 Jul 2022 13:46:39 +0200 Subject: [PATCH 271/347] remove CustomUserDataProfile type --- src/vs/platform/userDataProfile/common/userDataProfile.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/vs/platform/userDataProfile/common/userDataProfile.ts b/src/vs/platform/userDataProfile/common/userDataProfile.ts index 375166c4ce5..b800cf8b84c 100644 --- a/src/vs/platform/userDataProfile/common/userDataProfile.ts +++ b/src/vs/platform/userDataProfile/common/userDataProfile.ts @@ -42,8 +42,6 @@ export interface IUserDataProfile { readonly useDefaultFlags?: UseDefaultProfileFlags; } -export type CustomUserDataProfile = IUserDataProfile & { readonly extensionsResource: URI; readonly isDefault: false }; - export function isUserDataProfile(thing: unknown): thing is IUserDataProfile { const candidate = thing as IUserDataProfile | undefined; @@ -101,7 +99,7 @@ export function reviveProfile(profile: UriDto, scheme: string) export const EXTENSIONS_RESOURCE_NAME = 'extensions.json'; -export function toUserDataProfile(name: string, location: URI, useDefaultFlags?: UseDefaultProfileFlags): CustomUserDataProfile { +export function toUserDataProfile(name: string, location: URI, useDefaultFlags?: UseDefaultProfileFlags): IUserDataProfile { return { id: hash(location.path).toString(16), name: name, From 835670ed8f05fc116139bfb3b65f3343b978f945 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 6 Jul 2022 13:49:06 +0200 Subject: [PATCH 272/347] fix using extension resource --- .../electron-sandbox/nativeExtensionManagementService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/services/extensionManagement/electron-sandbox/nativeExtensionManagementService.ts b/src/vs/workbench/services/extensionManagement/electron-sandbox/nativeExtensionManagementService.ts index 3252281bf30..6282bc77cf8 100644 --- a/src/vs/workbench/services/extensionManagement/electron-sandbox/nativeExtensionManagementService.ts +++ b/src/vs/workbench/services/extensionManagement/electron-sandbox/nativeExtensionManagementService.ts @@ -68,7 +68,7 @@ export class NativeExtensionManagementService extends ExtensionManagementChannel private async whenProfileChanged(e: DidChangeUserDataProfileEvent): Promise { const previousExtensionsResource = e.previous.extensionsResource ?? joinPath(e.previous.location, EXTENSIONS_RESOURCE_NAME); if (e.preserveData) { - await this.fileService.copy(previousExtensionsResource, e.profile.extensionsResource!); + await this.fileService.copy(previousExtensionsResource, previousExtensionsResource); } else { const oldExtensions = await super.getInstalled(ExtensionType.User, previousExtensionsResource); const newExtensions = await this.getInstalled(ExtensionType.User); From d45ad24af8762cb434a8b5d6094b277efc62e8a3 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 6 Jul 2022 13:55:39 +0200 Subject: [PATCH 273/347] remove totally unneeded hack that slipped through... (#154254) --- src/vs/workbench/contrib/bulkEdit/browser/bulkTextEdits.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/bulkEdit/browser/bulkTextEdits.ts b/src/vs/workbench/contrib/bulkEdit/browser/bulkTextEdits.ts index b07897a513a..6906a0b4fb7 100644 --- a/src/vs/workbench/contrib/bulkEdit/browser/bulkTextEdits.ts +++ b/src/vs/workbench/contrib/bulkEdit/browser/bulkTextEdits.ts @@ -116,7 +116,7 @@ class ModelEditTask implements IDisposable { if (!edit.text) { return edit; } - const text = new SnippetParser().parse(edit.text, false, false).toString(); + const text = new SnippetParser().text(edit.text); return { ...edit, insertAsSnippet: false, text }; } } @@ -233,13 +233,13 @@ export class BulkTextEdits { let makeMinimal = false; if (this._editor?.getModel()?.uri.toString() === ref.object.textEditorModel.uri.toString()) { task = new EditorEditTask(ref, this._editor); - makeMinimal = true && false; // todo@jrieken HACK + makeMinimal = true; } else { task = new ModelEditTask(ref); } for (const edit of value) { - if (makeMinimal) { + if (makeMinimal && !edit.textEdit.insertAsSnippet) { const newEdits = await this._editorWorker.computeMoreMinimalEdits(edit.resource, [edit.textEdit]); if (!newEdits) { task.addEdit(edit); From 9c6d42b1390c1e56c29f04543eaa57f97140e9f9 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 6 Jul 2022 14:18:20 +0200 Subject: [PATCH 274/347] do not compute profiles always --- src/vs/platform/userDataProfile/common/userDataProfile.ts | 3 ++- .../userDataProfile/electron-sandbox/userDataProfile.ts | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/platform/userDataProfile/common/userDataProfile.ts b/src/vs/platform/userDataProfile/common/userDataProfile.ts index b800cf8b84c..89a181cda49 100644 --- a/src/vs/platform/userDataProfile/common/userDataProfile.ts +++ b/src/vs/platform/userDataProfile/common/userDataProfile.ts @@ -121,7 +121,8 @@ export class UserDataProfilesService extends Disposable implements IUserDataProf readonly profilesHome: URI; get defaultProfile(): IUserDataProfile { return this.profiles[0]; } - get profiles(): IUserDataProfile[] { return [this.createDefaultUserDataProfile(false)]; } + protected _profiles: IUserDataProfile[] = [this.createDefaultUserDataProfile(false)]; + get profiles(): IUserDataProfile[] { return this._profiles; } protected readonly _onDidChangeProfiles = this._register(new Emitter()); readonly onDidChangeProfiles = this._onDidChangeProfiles.event; diff --git a/src/vs/platform/userDataProfile/electron-sandbox/userDataProfile.ts b/src/vs/platform/userDataProfile/electron-sandbox/userDataProfile.ts index 9d999933058..1666539da3e 100644 --- a/src/vs/platform/userDataProfile/electron-sandbox/userDataProfile.ts +++ b/src/vs/platform/userDataProfile/electron-sandbox/userDataProfile.ts @@ -16,7 +16,6 @@ export class UserDataProfilesNativeService extends UserDataProfilesService imple private readonly channel: IChannel; - private _profiles: IUserDataProfile[] = []; override get profiles(): IUserDataProfile[] { return this._profiles; } constructor( From 8b475a06d9884ef3ce3f54f236124e4543d6f466 Mon Sep 17 00:00:00 2001 From: Tyler James Leonhardt Date: Wed, 6 Jul 2022 05:35:37 -0700 Subject: [PATCH 275/347] Include if client is in unsupported mode & include restricted mode in copy (#154209) --- .../issue/issueReporterMain.ts | 5 +++ .../issue/issueReporterModel.ts | 12 +++++- .../issue/testReporterModel.test.ts | 42 +++++++++++++------ src/vs/platform/issue/common/issue.ts | 1 + .../issue/electron-sandbox/issueService.ts | 13 +++++- 5 files changed, 58 insertions(+), 15 deletions(-) diff --git a/src/vs/code/electron-sandbox/issue/issueReporterMain.ts b/src/vs/code/electron-sandbox/issue/issueReporterMain.ts index 4037fbb3441..046cb3929ff 100644 --- a/src/vs/code/electron-sandbox/issue/issueReporterMain.ts +++ b/src/vs/code/electron-sandbox/issue/issueReporterMain.ts @@ -140,6 +140,7 @@ export class IssueReporter extends Disposable { this.handleExtensionData(configuration.data.enabledExtensions); this.updateExperimentsInfo(configuration.data.experiments); this.updateRestrictedMode(configuration.data.restrictedMode); + this.updateUnsupportedMode(configuration.data.isUnsupported); } render(): void { @@ -1154,6 +1155,10 @@ export class IssueReporter extends Disposable { this.issueReporterModel.update({ restrictedMode }); } + private updateUnsupportedMode(isUnsupported: boolean) { + this.issueReporterModel.update({ isUnsupported }); + } + private updateExperimentsInfo(experimentInfo: string | undefined) { this.issueReporterModel.update({ experimentInfo }); const target = document.querySelector('.block-experiments .block-info'); diff --git a/src/vs/code/electron-sandbox/issue/issueReporterModel.ts b/src/vs/code/electron-sandbox/issue/issueReporterModel.ts index 37a1a40beb0..b0cc736e46e 100644 --- a/src/vs/code/electron-sandbox/issue/issueReporterModel.ts +++ b/src/vs/code/electron-sandbox/issue/issueReporterModel.ts @@ -33,6 +33,7 @@ export interface IssueReporterData { filterResultCount?: number; experimentInfo?: string; restrictedMode?: boolean; + isUnsupported?: boolean; } export class IssueReporterModel { @@ -61,14 +62,21 @@ export class IssueReporterModel { } serialize(): string { + const modes = []; + if (this._data.restrictedMode) { + modes.push('Restricted'); + } + if (this._data.isUnsupported) { + modes.push('Unsupported'); + } return ` -Issue Type: ${this.getIssueTypeTitle()} +Type: ${this.getIssueTypeTitle()} ${this._data.issueDescription} ${this.getExtensionVersion()} VS Code version: ${this._data.versionInfo && this._data.versionInfo.vscodeVersion} OS version: ${this._data.versionInfo && this._data.versionInfo.os} -Restricted Mode: ${this._data.restrictedMode ? 'Yes' : 'No'} +Modes:${modes.length ? ' ' + modes.join(', ') : ''} ${this.getRemoteOSes()} ${this.getInfos()} `; diff --git a/src/vs/code/test/electron-sandbox/issue/testReporterModel.test.ts b/src/vs/code/test/electron-sandbox/issue/testReporterModel.test.ts index 87bca75fedf..e2280b2338e 100644 --- a/src/vs/code/test/electron-sandbox/issue/testReporterModel.test.ts +++ b/src/vs/code/test/electron-sandbox/issue/testReporterModel.test.ts @@ -27,13 +27,13 @@ suite('IssueReporter', () => { const issueReporterModel = new IssueReporterModel({}); assert.strictEqual(issueReporterModel.serialize(), ` -Issue Type: Bug +Type: Bug undefined VS Code version: undefined OS version: undefined -Restricted Mode: No +Modes: Extensions: none `); @@ -58,13 +58,13 @@ Extensions: none }); assert.strictEqual(issueReporterModel.serialize(), ` -Issue Type: Bug +Type: Bug undefined VS Code version: undefined OS version: undefined -Restricted Mode: No +Modes:
System Info @@ -102,13 +102,13 @@ Restricted Mode: No }); assert.strictEqual(issueReporterModel.serialize(), ` -Issue Type: Bug +Type: Bug undefined VS Code version: undefined OS version: undefined -Restricted Mode: No +Modes:
System Info @@ -157,13 +157,13 @@ vsins829:30139715 }); assert.strictEqual(issueReporterModel.serialize(), ` -Issue Type: Bug +Type: Bug undefined VS Code version: undefined OS version: undefined -Restricted Mode: No +Modes:
System Info @@ -214,13 +214,13 @@ Restricted Mode: No }); assert.strictEqual(issueReporterModel.serialize(), ` -Issue Type: Bug +Type: Bug undefined VS Code version: undefined OS version: undefined -Restricted Mode: No +Modes: Remote OS version: Linux x64 4.18.0
@@ -263,13 +263,13 @@ Remote OS version: Linux x64 4.18.0 }); assert.strictEqual(issueReporterModel.serialize(), ` -Issue Type: Bug +Type: Bug undefined VS Code version: undefined OS version: undefined -Restricted Mode: No +Modes:
System Info @@ -287,6 +287,24 @@ Restricted Mode: No `); }); + test('should supply mode if applicable', () => { + const issueReporterModel = new IssueReporterModel({ + isUnsupported: true, + restrictedMode: true + }); + assert.strictEqual(issueReporterModel.serialize(), + ` +Type: Bug + +undefined + +VS Code version: undefined +OS version: undefined +Modes: Restricted, Unsupported + +Extensions: none +`); + }); test('should normalize GitHub urls', () => { [ 'https://github.com/repo', diff --git a/src/vs/platform/issue/common/issue.ts b/src/vs/platform/issue/common/issue.ts index 550c83be0d9..cbc4d251934 100644 --- a/src/vs/platform/issue/common/issue.ts +++ b/src/vs/platform/issue/common/issue.ts @@ -59,6 +59,7 @@ export interface IssueReporterData extends WindowData { extensionId?: string; experiments?: string; restrictedMode: boolean; + isUnsupported: boolean; githubAccessToken: string; readonly issueTitle?: string; readonly issueBody?: string; diff --git a/src/vs/workbench/services/issue/electron-sandbox/issueService.ts b/src/vs/workbench/services/issue/electron-sandbox/issueService.ts index 40f41611139..a72466b917a 100644 --- a/src/vs/workbench/services/issue/electron-sandbox/issueService.ts +++ b/src/vs/workbench/services/issue/electron-sandbox/issueService.ts @@ -20,6 +20,7 @@ import { IWorkbenchAssignmentService } from 'vs/workbench/services/assignment/co import { IAuthenticationService } from 'vs/workbench/services/authentication/common/authentication'; import { registerMainProcessRemoteService } from 'vs/platform/ipc/electron-sandbox/services'; import { IWorkspaceTrustManagementService } from 'vs/platform/workspace/common/workspaceTrust'; +import { IIntegrityService } from 'vs/workbench/services/integrity/common/integrity'; export class WorkbenchIssueService implements IWorkbenchIssueService { declare readonly _serviceBrand: undefined; @@ -33,7 +34,8 @@ export class WorkbenchIssueService implements IWorkbenchIssueService { @IWorkspaceTrustManagementService private readonly workspaceTrustManagementService: IWorkspaceTrustManagementService, @IProductService private readonly productService: IProductService, @IWorkbenchAssignmentService private readonly experimentService: IWorkbenchAssignmentService, - @IAuthenticationService private readonly authenticationService: IAuthenticationService + @IAuthenticationService private readonly authenticationService: IAuthenticationService, + @IIntegrityService private readonly integrityService: IIntegrityService ) { } async openReporter(dataOverrides: Partial = {}): Promise { @@ -82,6 +84,14 @@ export class WorkbenchIssueService implements IWorkbenchIssueService { // Ignore } + // air on the side of caution and have false be the default + let isUnsupported = false; + try { + isUnsupported = !(await this.integrityService.isPure()).isPure; + } catch (e) { + // Ignore + } + const theme = this.themeService.getColorTheme(); const issueReporterData: IssueReporterData = Object.assign({ styles: getIssueReporterStyles(theme), @@ -89,6 +99,7 @@ export class WorkbenchIssueService implements IWorkbenchIssueService { enabledExtensions: extensionData, experiments: experiments?.join('\n'), restrictedMode: !this.workspaceTrustManagementService.isWorkspaceTrusted(), + isUnsupported, githubAccessToken, }, dataOverrides); return this.issueService.openReporter(issueReporterData); From 5e1a19f4d439cd4a0ac23e0169df94a5646aa0a2 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 6 Jul 2022 05:50:54 -0700 Subject: [PATCH 276/347] Ensure exact match links are only checked on absolute paths Fixes #153832 --- .../contrib/terminal/browser/links/terminalLinkOpeners.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/vs/workbench/contrib/terminal/browser/links/terminalLinkOpeners.ts b/src/vs/workbench/contrib/terminal/browser/links/terminalLinkOpeners.ts index bfc044ba133..0d07ef46dfd 100644 --- a/src/vs/workbench/contrib/terminal/browser/links/terminalLinkOpeners.ts +++ b/src/vs/workbench/contrib/terminal/browser/links/terminalLinkOpeners.ts @@ -218,6 +218,9 @@ export class TerminalSearchLinkOpener implements ITerminalLinkOpener { private async _tryOpenExactLink(text: string, link: ITerminalSimpleLink): Promise { const sanitizedLink = text.replace(/:\d+(:\d+)?$/, ''); + if (!osPathModule(this._os).isAbsolute(sanitizedLink)) { + return false; + } try { const result = await this._getExactMatch(sanitizedLink); if (result) { From 6df57ad27f21eae9aedb2316c96cb7c07632f1cb Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 6 Jul 2022 06:02:39 -0700 Subject: [PATCH 277/347] Fix test and only avoid exact match when a separator does not exist --- .../browser/links/terminalLinkOpeners.ts | 8 ++- .../browser/links/terminalLinkOpeners.test.ts | 51 ++++++++++++++++++- 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/links/terminalLinkOpeners.ts b/src/vs/workbench/contrib/terminal/browser/links/terminalLinkOpeners.ts index 0d07ef46dfd..fda9a67bd29 100644 --- a/src/vs/workbench/contrib/terminal/browser/links/terminalLinkOpeners.ts +++ b/src/vs/workbench/contrib/terminal/browser/links/terminalLinkOpeners.ts @@ -218,7 +218,13 @@ export class TerminalSearchLinkOpener implements ITerminalLinkOpener { private async _tryOpenExactLink(text: string, link: ITerminalSimpleLink): Promise { const sanitizedLink = text.replace(/:\d+(:\d+)?$/, ''); - if (!osPathModule(this._os).isAbsolute(sanitizedLink)) { + // For only file links disallow exact link matching, for example searching for `foo.txt` + // when no cwd information is available should search when only the initial cwd is available + // as it's ambiguous if there are multiple matches. + // + // However, for `src/foo.txt`, if there's an exact match for `src/foo.txt` in any folder we + // want to take it, even if there are partial matches like `src2/foo.txt` available. + if (!sanitizedLink.match(/[\\/]/)) { return false; } try { diff --git a/src/vs/workbench/contrib/terminal/test/browser/links/terminalLinkOpeners.test.ts b/src/vs/workbench/contrib/terminal/test/browser/links/terminalLinkOpeners.test.ts index dcbdef59e2c..e7eea1e62fc 100644 --- a/src/vs/workbench/contrib/terminal/test/browser/links/terminalLinkOpeners.test.ts +++ b/src/vs/workbench/contrib/terminal/test/browser/links/terminalLinkOpeners.test.ts @@ -97,7 +97,37 @@ suite('Workbench - TerminalLinkOpeners', () => { capabilities.add(TerminalCapability.CommandDetection, commandDetection); }); - test('should open single exact match against cwd when searching if it exists', async () => { + test('should open single exact match against cwd when searching if it exists when command detection cwd is available', async () => { + localFileOpener = instantiationService.createInstance(TerminalLocalFileLinkOpener, OperatingSystem.Linux); + const localFolderOpener = instantiationService.createInstance(TerminalLocalFolderInWorkspaceLinkOpener); + opener = instantiationService.createInstance(TerminalSearchLinkOpener, capabilities, Promise.resolve('/initial/cwd'), localFileOpener, localFolderOpener, OperatingSystem.Linux); + // Set a fake detected command starting as line 0 to establish the cwd + commandDetection.setCommands([{ + command: '', + cwd: '/initial/cwd', + timestamp: 0, + getOutput() { return undefined; }, + marker: { + line: 0 + } as Partial as any, + hasOutput: true + }]); + fileService.setFiles([ + URI.from({ scheme: Schemas.file, path: '/initial/cwd/foo/bar.txt' }), + URI.from({ scheme: Schemas.file, path: '/initial/cwd/foo2/bar.txt' }) + ]); + await opener.open({ + text: 'foo/bar.txt', + bufferRange: { start: { x: 1, y: 1 }, end: { x: 8, y: 1 } }, + type: TerminalBuiltinLinkType.Search + }); + deepStrictEqual(activationResult, { + link: 'file:///initial/cwd/foo/bar.txt', + source: 'editor' + }); + }); + + test('should open single exact match against cwd for paths containing a separator when searching if it exists, even when command detection isn\'t available', async () => { localFileOpener = instantiationService.createInstance(TerminalLocalFileLinkOpener, OperatingSystem.Linux); const localFolderOpener = instantiationService.createInstance(TerminalLocalFolderInWorkspaceLinkOpener); opener = instantiationService.createInstance(TerminalSearchLinkOpener, capabilities, Promise.resolve('/initial/cwd'), localFileOpener, localFolderOpener, OperatingSystem.Linux); @@ -116,6 +146,25 @@ suite('Workbench - TerminalLinkOpeners', () => { }); }); + test('should not open single exact match for paths not containing a when command detection isn\'t available', async () => { + localFileOpener = instantiationService.createInstance(TerminalLocalFileLinkOpener, OperatingSystem.Linux); + const localFolderOpener = instantiationService.createInstance(TerminalLocalFolderInWorkspaceLinkOpener); + opener = instantiationService.createInstance(TerminalSearchLinkOpener, capabilities, Promise.resolve('/initial/cwd'), localFileOpener, localFolderOpener, OperatingSystem.Linux); + fileService.setFiles([ + URI.from({ scheme: Schemas.file, path: '/initial/cwd/foo/bar.txt' }), + URI.from({ scheme: Schemas.file, path: '/initial/cwd/foo2/bar.txt' }) + ]); + await opener.open({ + text: 'bar.txt', + bufferRange: { start: { x: 1, y: 1 }, end: { x: 8, y: 1 } }, + type: TerminalBuiltinLinkType.Search + }); + deepStrictEqual(activationResult, { + link: 'bar.txt', + source: 'search' + }); + }); + suite('macOS/Linux', () => { setup(() => { localFileOpener = instantiationService.createInstance(TerminalLocalFileLinkOpener, OperatingSystem.Linux); From 585b6685dda19344ec0304331f294f1c5f9efe24 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 6 Jul 2022 15:08:38 +0200 Subject: [PATCH 278/347] remove forEach usage (#154259) * remove forEach usage * remove extra line --- .../common/extensionTipsService.ts | 5 ++-- .../electron-sandbox/extensionTipsService.ts | 6 ++--- .../api/browser/viewsExtensionPoint.ts | 27 +++++++++---------- .../browser/fileBasedRecommendations.ts | 10 +++---- .../browser/configurationService.ts | 4 +-- .../browser/webExtensionsScannerService.ts | 4 +-- 6 files changed, 27 insertions(+), 29 deletions(-) diff --git a/src/vs/platform/extensionManagement/common/extensionTipsService.ts b/src/vs/platform/extensionManagement/common/extensionTipsService.ts index 4e59c5a3b47..c9c4aaf97dd 100644 --- a/src/vs/platform/extensionManagement/common/extensionTipsService.ts +++ b/src/vs/platform/extensionManagement/common/extensionTipsService.ts @@ -5,7 +5,6 @@ import { isNonEmptyArray } from 'vs/base/common/arrays'; import { CancellationToken } from 'vs/base/common/cancellation'; -import { forEach } from 'vs/base/common/collections'; import { Disposable } from 'vs/base/common/lifecycle'; import { IConfigBasedExtensionTip as IRawConfigBasedExtensionTip } from 'vs/base/common/product'; import { joinPath } from 'vs/base/common/resources'; @@ -31,7 +30,7 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe ) { super(); if (this.productService.configBasedExtensionTips) { - forEach(this.productService.configBasedExtensionTips, ({ value }) => this.allConfigBasedTips.set(value.configPath, value)); + Object.entries(this.productService.configBasedExtensionTips).forEach(([, value]) => this.allConfigBasedTips.set(value.configPath, value)); } } @@ -60,7 +59,7 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe try { const content = await this.fileService.readFile(joinPath(folder, configPath)); const recommendationByRemote: Map = new Map(); - forEach(tip.recommendations, ({ key, value }) => { + Object.entries(tip.recommendations).forEach(([key, value]) => { if (isNonEmptyArray(value.remotes)) { for (const remote of value.remotes) { recommendationByRemote.set(remote, { diff --git a/src/vs/platform/extensionManagement/electron-sandbox/extensionTipsService.ts b/src/vs/platform/extensionManagement/electron-sandbox/extensionTipsService.ts index c6e03e0bf5f..fdfb6721b9a 100644 --- a/src/vs/platform/extensionManagement/electron-sandbox/extensionTipsService.ts +++ b/src/vs/platform/extensionManagement/electron-sandbox/extensionTipsService.ts @@ -5,7 +5,7 @@ import { isNonEmptyArray } from 'vs/base/common/arrays'; import { disposableTimeout, timeout } from 'vs/base/common/async'; -import { forEach, IStringDictionary } from 'vs/base/common/collections'; +import { IStringDictionary } from 'vs/base/common/collections'; import { Event } from 'vs/base/common/event'; import { join } from 'vs/base/common/path'; import { isWindows } from 'vs/base/common/platform'; @@ -67,11 +67,11 @@ export class ExtensionTipsService extends BaseExtensionTipsService { ) { super(fileService, productService, requestService, logService); if (productService.exeBasedExtensionTips) { - forEach(productService.exeBasedExtensionTips, ({ key, value: exeBasedExtensionTip }) => { + Object.entries(productService.exeBasedExtensionTips).forEach(([key, exeBasedExtensionTip]) => { const highImportanceRecommendations: { extensionId: string; extensionName: string; isExtensionPack: boolean }[] = []; const mediumImportanceRecommendations: { extensionId: string; extensionName: string; isExtensionPack: boolean }[] = []; const otherRecommendations: { extensionId: string; extensionName: string; isExtensionPack: boolean }[] = []; - forEach(exeBasedExtensionTip.recommendations, ({ key: extensionId, value }) => { + Object.entries(exeBasedExtensionTip.recommendations).forEach(([extensionId, value]) => { if (value.important) { if (exeBasedExtensionTip.important) { highImportanceRecommendations.push({ extensionId, extensionName: value.name, isExtensionPack: !!value.isExtensionPack }); diff --git a/src/vs/workbench/api/browser/viewsExtensionPoint.ts b/src/vs/workbench/api/browser/viewsExtensionPoint.ts index 1932e2ce93d..b94fab104e1 100644 --- a/src/vs/workbench/api/browser/viewsExtensionPoint.ts +++ b/src/vs/workbench/api/browser/viewsExtensionPoint.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import { coalesce } from 'vs/base/common/arrays'; -import { forEach } from 'vs/base/common/collections'; import { IJSONSchema } from 'vs/base/common/jsonSchema'; import * as resources from 'vs/base/common/resources'; import { isFalsyOrWhitespace } from 'vs/base/common/strings'; @@ -322,16 +321,16 @@ class ViewsExtensionHandler implements IWorkbenchContribution { let activityBarOrder = CUSTOM_VIEWS_START_ORDER + viewContainersRegistry.all.filter(v => !!v.extensionId && viewContainersRegistry.getViewContainerLocation(v) === ViewContainerLocation.Sidebar).length; let panelOrder = 5 + viewContainersRegistry.all.filter(v => !!v.extensionId && viewContainersRegistry.getViewContainerLocation(v) === ViewContainerLocation.Panel).length + 1; for (const { value, collector, description } of extensionPoints) { - forEach(value, entry => { - if (!this.isValidViewsContainer(entry.value, collector)) { + Object.entries(value).forEach(([key, value]) => { + if (!this.isValidViewsContainer(value, collector)) { return; } - switch (entry.key) { + switch (key) { case 'activitybar': - activityBarOrder = this.registerCustomViewContainers(entry.value, description, activityBarOrder, existingViewContainers, ViewContainerLocation.Sidebar); + activityBarOrder = this.registerCustomViewContainers(value, description, activityBarOrder, existingViewContainers, ViewContainerLocation.Sidebar); break; case 'panel': - panelOrder = this.registerCustomViewContainers(entry.value, description, panelOrder, existingViewContainers, ViewContainerLocation.Panel); + panelOrder = this.registerCustomViewContainers(value, description, panelOrder, existingViewContainers, ViewContainerLocation.Panel); break; } }); @@ -455,22 +454,22 @@ class ViewsExtensionHandler implements IWorkbenchContribution { for (const extension of extensions) { const { value, collector } = extension; - forEach(value, entry => { - if (!this.isValidViewDescriptors(entry.value, collector)) { + Object.entries(value).forEach(([key, value]) => { + if (!this.isValidViewDescriptors(value, collector)) { return; } - if (entry.key === 'remote' && !isProposedApiEnabled(extension.description, 'contribViewsRemote')) { - collector.warn(localize('ViewContainerRequiresProposedAPI', "View container '{0}' requires 'enabledApiProposals: [\"contribViewsRemote\"]' to be added to 'Remote'.", entry.key)); + if (key === 'remote' && !isProposedApiEnabled(extension.description, 'contribViewsRemote')) { + collector.warn(localize('ViewContainerRequiresProposedAPI', "View container '{0}' requires 'enabledApiProposals: [\"contribViewsRemote\"]' to be added to 'Remote'.", key)); return; } - const viewContainer = this.getViewContainer(entry.key); + const viewContainer = this.getViewContainer(key); if (!viewContainer) { - collector.warn(localize('ViewContainerDoesnotExist', "View container '{0}' does not exist and all views registered to it will be added to 'Explorer'.", entry.key)); + collector.warn(localize('ViewContainerDoesnotExist', "View container '{0}' does not exist and all views registered to it will be added to 'Explorer'.", key)); } const container = viewContainer || this.getDefaultViewContainer(); - const viewDescriptors = coalesce(entry.value.map((item, index) => { + const viewDescriptors = coalesce(value.map((item, index) => { // validate if (viewIds.has(item.id)) { collector.error(localize('duplicateView1', "Cannot register multiple views with same id `{0}`", item.id)); @@ -514,7 +513,7 @@ class ViewsExtensionHandler implements IWorkbenchContribution { collapsed: this.showCollapsed(container) || initialVisibility === InitialVisibility.Collapsed, order: order, extensionId: extension.description.identifier, - originalContainerId: entry.key, + originalContainerId: key, group: item.group, remoteAuthority: item.remoteName || (item).remoteAuthority, // TODO@roblou - delete after remote extensions are updated hideByDefault: initialVisibility === InitialVisibility.Hidden, diff --git a/src/vs/workbench/contrib/extensions/browser/fileBasedRecommendations.ts b/src/vs/workbench/contrib/extensions/browser/fileBasedRecommendations.ts index d1b91197ff4..57b4387c1c7 100644 --- a/src/vs/workbench/contrib/extensions/browser/fileBasedRecommendations.ts +++ b/src/vs/workbench/contrib/extensions/browser/fileBasedRecommendations.ts @@ -14,7 +14,7 @@ import { localize } from 'vs/nls'; import { StorageScope, IStorageService, StorageTarget } from 'vs/platform/storage/common/storage'; import { IProductService } from 'vs/platform/product/common/productService'; import { ImportantExtensionTip } from 'vs/base/common/product'; -import { forEach, IStringDictionary } from 'vs/base/common/collections'; +import { IStringDictionary } from 'vs/base/common/collections'; import { ITextModel } from 'vs/editor/common/model'; import { Schemas } from 'vs/base/common/network'; import { basename, extname } from 'vs/base/common/resources'; @@ -115,10 +115,10 @@ export class FileBasedRecommendations extends ExtensionRecommendations { this.tasExperimentService = tasExperimentService; if (productService.extensionTips) { - forEach(productService.extensionTips, ({ key, value }) => this.extensionTips.set(key.toLowerCase(), value)); + Object.entries(productService.extensionTips).forEach(([key, value]) => this.extensionTips.set(key.toLowerCase(), value)); } if (productService.extensionImportantTips) { - forEach(productService.extensionImportantTips, ({ key, value }) => this.importantExtensionTips.set(key.toLowerCase(), value)); + Object.entries(productService.extensionImportantTips).forEach(([key, value]) => this.importantExtensionTips.set(key.toLowerCase(), value)); } } @@ -153,7 +153,7 @@ export class FileBasedRecommendations extends ExtensionRecommendations { const cachedRecommendations = this.getCachedRecommendations(); const now = Date.now(); // Retire existing recommendations if they are older than a week or are not part of this.productService.extensionTips anymore - forEach(cachedRecommendations, ({ key, value }) => { + Object.entries(cachedRecommendations).forEach(([key, value]) => { const diff = (now - value) / milliSecondsInADay; if (diff <= 7 && allRecommendations.indexOf(key) > -1) { this.fileBasedRecommendations.set(key.toLowerCase(), { recommendedTime: value }); @@ -400,7 +400,7 @@ export class FileBasedRecommendations extends ExtensionRecommendations { storedRecommendations = storedRecommendations.reduce((result, id) => { result[id] = Date.now(); return result; }, >{}); } const result: IStringDictionary = {}; - forEach(storedRecommendations, ({ key, value }) => { + Object.entries(storedRecommendations).forEach(([key, value]) => { if (typeof value === 'number') { result[key.toLowerCase()] = value; } diff --git a/src/vs/workbench/services/configuration/browser/configurationService.ts b/src/vs/workbench/services/configuration/browser/configurationService.ts index 20b7ad38a9a..10ef3ab6d99 100644 --- a/src/vs/workbench/services/configuration/browser/configurationService.ts +++ b/src/vs/workbench/services/configuration/browser/configurationService.ts @@ -35,7 +35,7 @@ import { toErrorMessage } from 'vs/base/common/errorMessage'; import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'; import { IWorkspaceTrustManagementService } from 'vs/platform/workspace/common/workspaceTrust'; import { delta, distinct } from 'vs/base/common/arrays'; -import { forEach, IStringDictionary } from 'vs/base/common/collections'; +import { IStringDictionary } from 'vs/base/common/collections'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { IWorkbenchAssignmentService } from 'vs/workbench/services/assignment/common/assignmentService'; import { isUndefined } from 'vs/base/common/types'; @@ -1218,7 +1218,7 @@ class RegisterConfigurationSchemasContribution extends Disposable implements IWo } const result: IStringDictionary = {}; - forEach(properties, ({ key, value }) => { + Object.entries(properties).forEach(([key, value]) => { if (!value.restricted) { result[key] = value; } diff --git a/src/vs/workbench/services/extensionManagement/browser/webExtensionsScannerService.ts b/src/vs/workbench/services/extensionManagement/browser/webExtensionsScannerService.ts index faf1645bb6d..fb5c4babf4a 100644 --- a/src/vs/workbench/services/extensionManagement/browser/webExtensionsScannerService.ts +++ b/src/vs/workbench/services/extensionManagement/browser/webExtensionsScannerService.ts @@ -39,7 +39,7 @@ import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storag import { IProductService } from 'vs/platform/product/common/productService'; import { validateExtensionManifest } from 'vs/platform/extensions/common/extensionValidator'; import Severity from 'vs/base/common/severity'; -import { IStringDictionary, forEach } from 'vs/base/common/collections'; +import { IStringDictionary } from 'vs/base/common/collections'; type GalleryExtensionInfo = { readonly id: string; preRelease?: boolean; migrateStorageFrom?: string }; type ExtensionInfo = { readonly id: string; preRelease: boolean }; @@ -737,7 +737,7 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten let packageNLSUris: Map | undefined; if (e.packageNLSUris) { packageNLSUris = new Map(); - forEach(e.packageNLSUris, (entry) => packageNLSUris!.set(entry.key, URI.revive(entry.value))); + Object.entries(e.packageNLSUris).forEach(([key, value]) => packageNLSUris!.set(key, URI.revive(value))); } webExtensions.push({ From ac74e9d093436886b0fbcf955a5917234853926b Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Wed, 6 Jul 2022 15:09:06 +0200 Subject: [PATCH 279/347] [html] unresolved import error in embedded JavaScript (#154261) [html] unresolved import error in embedded JavaScript #154002 --- .../server/src/modes/javascriptMode.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/extensions/html-language-features/server/src/modes/javascriptMode.ts b/extensions/html-language-features/server/src/modes/javascriptMode.ts index 10a70dbe99a..0c199571dd7 100644 --- a/extensions/html-language-features/server/src/modes/javascriptMode.ts +++ b/extensions/html-language-features/server/src/modes/javascriptMode.ts @@ -93,13 +93,16 @@ function getLanguageServiceHost(scriptKind: ts.ScriptKind) { }; } +const ignoredErrors = [ + 1108, /* A_return_statement_can_only_be_used_within_a_function_body_1108 */ + 2792, /* Cannot_find_module_0_Did_you_mean_to_set_the_moduleResolution_option_to_node_or_to_add_aliases_to_the_paths_option */ +]; export function getJavaScriptMode(documentRegions: LanguageModelCache, languageId: 'javascript' | 'typescript', workspace: Workspace): LanguageMode { const jsDocuments = getLanguageModelCache(10, 60, document => documentRegions.get(document).getEmbeddedDocument(languageId)); const host = getLanguageServiceHost(languageId === 'javascript' ? ts.ScriptKind.JS : ts.ScriptKind.TS); const globalSettings: Settings = {}; - return { getId() { return languageId; @@ -110,7 +113,7 @@ export function getJavaScriptMode(documentRegions: LanguageModelCache d.code !== 1108).map((diag: ts.Diagnostic): Diagnostic => { + return syntaxDiagnostics.concat(semanticDiagnostics).filter(d => !ignoredErrors.includes(d.code)).map((diag: ts.Diagnostic): Diagnostic => { return { range: convertRange(jsDocument, diag), severity: DiagnosticSeverity.Error, From 12710c6cfe64785140be33880c1be86290ede0ea Mon Sep 17 00:00:00 2001 From: Leonardo Montini Date: Wed, 6 Jul 2022 15:34:01 +0200 Subject: [PATCH 280/347] Properly display the warning message --- src/vs/platform/instantiation/common/instantiationService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/platform/instantiation/common/instantiationService.ts b/src/vs/platform/instantiation/common/instantiationService.ts index b4253b7765c..1f6bba77e24 100644 --- a/src/vs/platform/instantiation/common/instantiationService.ts +++ b/src/vs/platform/instantiation/common/instantiationService.ts @@ -258,7 +258,7 @@ export class InstantiationService implements IInstantiationService { private _throwIfStrict(msg: string, printWarning: boolean): void { if (printWarning) { - console.warn(printWarning); + console.warn(msg); } if (this._strict) { throw new Error(msg); From d89ea128eca64497fe46bfb36891a8b421f31c30 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 6 Jul 2022 06:39:41 -0700 Subject: [PATCH 281/347] Fix remote Windows terminal link URI Fixes #154265 Fixes #144534 --- .../browser/links/terminalLinkOpeners.ts | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/links/terminalLinkOpeners.ts b/src/vs/workbench/contrib/terminal/browser/links/terminalLinkOpeners.ts index bfc044ba133..52951ddd36c 100644 --- a/src/vs/workbench/contrib/terminal/browser/links/terminalLinkOpeners.ts +++ b/src/vs/workbench/contrib/terminal/browser/links/terminalLinkOpeners.ts @@ -189,9 +189,23 @@ export class TerminalSearchLinkOpener implements ITerminalLinkOpener { // Try open as an absolute link let resourceMatch: IResourceMatch | undefined; if (absolutePath) { - const slashNormalizedPath = this._os === OperatingSystem.Windows ? absolutePath.replace(/\\/g, '/') : absolutePath; - const scheme = this._workbenchEnvironmentService.remoteAuthority ? Schemas.vscodeRemote : Schemas.file; - const uri = URI.from({ scheme, path: slashNormalizedPath }); + let normalizedAbsolutePath: string = absolutePath; + if (this._os === OperatingSystem.Windows) { + normalizedAbsolutePath = absolutePath.replace(/\\/g, '/'); + if (normalizedAbsolutePath.match(/[a-z]:/i)) { + normalizedAbsolutePath = `/${normalizedAbsolutePath}`; + } + } + let uri: URI; + if (this._workbenchEnvironmentService.remoteAuthority) { + uri = URI.from({ + scheme: Schemas.vscodeRemote, + authority: this._workbenchEnvironmentService.remoteAuthority, + path: normalizedAbsolutePath + }); + } else { + uri = URI.file(normalizedAbsolutePath); + } try { const fileStat = await this._fileService.stat(uri); resourceMatch = { uri, isDirectory: fileStat.isDirectory }; From 94e4ee8e4902b332aa4290adfdb806a8414b6065 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 6 Jul 2022 07:05:27 -0700 Subject: [PATCH 282/347] Prevent unicode11 addon from loading in unit tests It's not clear what caused the flake in #153757 but this should fix the suspicious unicode warning. We can reinvestigate if it happens again after this fix. Fixes #153757 --- .../contrib/terminal/test/browser/xterm/xtermTerminal.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/test/browser/xterm/xtermTerminal.test.ts b/src/vs/workbench/contrib/terminal/test/browser/xterm/xtermTerminal.test.ts index a35b293a2a9..99bc8e0b095 100644 --- a/src/vs/workbench/contrib/terminal/test/browser/xterm/xtermTerminal.test.ts +++ b/src/vs/workbench/contrib/terminal/test/browser/xterm/xtermTerminal.test.ts @@ -80,7 +80,7 @@ const defaultTerminalConfig: Partial = { scrollback: 1000, fastScrollSensitivity: 2, mouseWheelScrollSensitivity: 1, - unicodeVersion: '11' + unicodeVersion: '6' }; suite('XtermTerminal', () => { From 2e0e882ac5997526583fd4e9e204ee77bdd534d8 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 6 Jul 2022 07:37:31 -0700 Subject: [PATCH 283/347] Improve comment --- .../terminal/browser/links/terminalLinkOpeners.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/links/terminalLinkOpeners.ts b/src/vs/workbench/contrib/terminal/browser/links/terminalLinkOpeners.ts index fda9a67bd29..3041efab208 100644 --- a/src/vs/workbench/contrib/terminal/browser/links/terminalLinkOpeners.ts +++ b/src/vs/workbench/contrib/terminal/browser/links/terminalLinkOpeners.ts @@ -218,12 +218,13 @@ export class TerminalSearchLinkOpener implements ITerminalLinkOpener { private async _tryOpenExactLink(text: string, link: ITerminalSimpleLink): Promise { const sanitizedLink = text.replace(/:\d+(:\d+)?$/, ''); - // For only file links disallow exact link matching, for example searching for `foo.txt` - // when no cwd information is available should search when only the initial cwd is available - // as it's ambiguous if there are multiple matches. + // For links made up of only a file name (no folder), disallow exact link matching. For + // example searching for `foo.txt` when there is no cwd information available (ie. only the + // initial cwd) should NOT search as it's ambiguous if there are multiple matches. // - // However, for `src/foo.txt`, if there's an exact match for `src/foo.txt` in any folder we - // want to take it, even if there are partial matches like `src2/foo.txt` available. + // However, for a link like `src/foo.txt`, if there's an exact match for `src/foo.txt` in + // any folder we want to take it, even if there are partial matches like `src2/foo.txt` + // available. if (!sanitizedLink.match(/[\\/]/)) { return false; } From 1aaff9ef3d1f779e0ff2322c1d5b4c4a03f6d8cb Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 6 Jul 2022 17:10:43 +0200 Subject: [PATCH 284/347] stub `activationEventIsDone` function, (#154276) fixes https://github.com/microsoft/vscode/issues/154268 --- src/vs/workbench/api/test/browser/extHostApiCommands.test.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/api/test/browser/extHostApiCommands.test.ts b/src/vs/workbench/api/test/browser/extHostApiCommands.test.ts index b3fd49e72b2..2ceac7fde44 100644 --- a/src/vs/workbench/api/test/browser/extHostApiCommands.test.ts +++ b/src/vs/workbench/api/test/browser/extHostApiCommands.test.ts @@ -100,7 +100,9 @@ suite('ExtHostLanguageFeatureCommands', function () { override async activateByEvent() { } - + override activationEventIsDone(activationEvent: string): boolean { + return true; + } }); services.set(ICommandService, new SyncDescriptor(class extends mock() { From 6624aea0d02c14d99442e5067339650bf5904643 Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com> Date: Wed, 6 Jul 2022 17:11:44 +0200 Subject: [PATCH 285/347] GitHub - Add translation comment not to translate the $(github) codicon (#154269) * Add translation comment not to translate the $(github) codicon * Add an additional comment --- extensions/github/package.nls.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/extensions/github/package.nls.json b/extensions/github/package.nls.json index b43271a87a0..4e9bdab9dfa 100644 --- a/extensions/github/package.nls.json +++ b/extensions/github/package.nls.json @@ -6,6 +6,8 @@ "welcome.publishFolder": { "message": "You can also directly publish this folder to a GitHub repository. Once published, you'll have access to source control features powered by git and GitHub.\n[$(github) Publish to GitHub](command:github.publish)", "comment": [ + "{Locked='$(github)'}", + "Do not translate '$(github)'. It will be rendered as an icon", "{Locked='](command:github.publish'}", "Do not translate the 'command:*' part inside of the '(..)'. It is an internal command syntax for VS Code", "Please make sure there is no space between the right bracket and left parenthesis: ]( this is an internal syntax for links" @@ -14,6 +16,8 @@ "welcome.publishWorkspaceFolder": { "message": "You can also directly publish a workspace folder to a GitHub repository. Once published, you'll have access to source control features powered by git and GitHub.\n[$(github) Publish to GitHub](command:github.publish)", "comment": [ + "{Locked='$(github)'}", + "Do not translate '$(github)'. It will be rendered as an icon", "{Locked='](command:github.publish'}", "Do not translate the 'command:*' part inside of the '(..)'. It is an internal command syntax for VS Code", "Please make sure there is no space between the right bracket and left parenthesis: ]( this is an internal syntax for links" From f9f353c90becae9610fc28f5b47078ce859eaa00 Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Wed, 6 Jul 2022 08:53:12 -0700 Subject: [PATCH 286/347] support vscode.dev link generation in notebook editor (#154183) * support vscode.dev link generation in notebook editor * Update comments. --- extensions/github/src/links.ts | 69 +++++++++++++++++-- .../browser/controller/coreActions.ts | 9 ++- 2 files changed, 72 insertions(+), 6 deletions(-) diff --git a/extensions/github/src/links.ts b/extensions/github/src/links.ts index a025c79a804..22ede57ccbd 100644 --- a/extensions/github/src/links.ts +++ b/extensions/github/src/links.ts @@ -22,14 +22,50 @@ export function getRepositoryForFile(gitAPI: GitAPI, file: vscode.Uri): Reposito return undefined; } -function getFileAndPosition(): { uri: vscode.Uri | undefined; range: vscode.Range | undefined } { +enum LinkType { + File = 1, + Notebook = 2 +} + +interface IFilePosition { + type: LinkType.File; + uri: vscode.Uri; + range: vscode.Range | undefined; +} + +interface INotebookPosition { + type: LinkType.Notebook; + uri: vscode.Uri; + cellIndex: number; + range: vscode.Range | undefined; +} + +function getFileAndPosition(): IFilePosition | INotebookPosition | undefined { let uri: vscode.Uri | undefined; let range: vscode.Range | undefined; if (vscode.window.activeTextEditor) { uri = vscode.window.activeTextEditor.document.uri; - range = vscode.window.activeTextEditor.selection; + + if (uri.scheme === 'vscode-notebook-cell' && vscode.window.activeNotebookEditor?.notebook.uri.fsPath === uri.fsPath) { + // if the active editor is a notebook editor and the focus is inside any a cell text editor + // generate deep link for text selection for the notebook cell. + const cell = vscode.window.activeNotebookEditor.notebook.getCells().find(cell => cell.document.uri.fragment === uri?.fragment); + const cellIndex = cell?.index ?? vscode.window.activeNotebookEditor.selection.start; + const range = cell !== undefined ? vscode.window.activeTextEditor.selection : undefined; + return { type: LinkType.Notebook, uri, cellIndex, range }; + } else { + // the active editor is a text editor + range = vscode.window.activeTextEditor.selection; + return { type: LinkType.File, uri, range }; + } } - return { uri, range }; + + if (vscode.window.activeNotebookEditor) { + // if the active editor is a notebook editor but the focus is not inside any cell text editor, generate deep link for the cell selection in the notebook document. + return { type: LinkType.Notebook, uri: vscode.window.activeNotebookEditor.notebook.uri, cellIndex: vscode.window.activeNotebookEditor.selection.start, range: undefined }; + } + + return undefined; } function rangeString(range: vscode.Range | undefined) { @@ -43,9 +79,30 @@ function rangeString(range: vscode.Range | undefined) { return hash; } +export function notebookCellRangeString(index: number | undefined, range: vscode.Range | undefined) { + if (index === undefined) { + return ''; + } + + if (!range) { + return `#C${index + 1}`; + } + + let hash = `#C${index + 1}:L${range.start.line + 1}`; + if (range.start.line !== range.end.line) { + hash += `-L${range.end.line + 1}`; + } + return hash; +} + export function getPermalink(gitAPI: GitAPI, useSelection: boolean, hostPrefix?: string): string | undefined { hostPrefix = hostPrefix ?? 'https://github.com'; - const { uri, range } = getFileAndPosition(); + const fileAndPosition = getFileAndPosition(); + if (!fileAndPosition) { + return; + } + const uri = fileAndPosition.uri; + // Use the first repo if we cannot determine a repo from the uri. const gitRepo = (uri ? getRepositoryForFile(gitAPI, uri) : gitAPI.repositories[0]) ?? gitAPI.repositories[0]; if (!gitRepo) { @@ -69,7 +126,9 @@ export function getPermalink(gitAPI: GitAPI, useSelection: boolean, hostPrefix?: } const commitHash = gitRepo.state.HEAD?.commit; - const fileSegments = (useSelection && uri) ? `${uri.path.substring(gitRepo.rootUri.path.length)}${rangeString(range)}` : ''; + const fileSegments = fileAndPosition.type === LinkType.File + ? (useSelection ? `${uri.path.substring(gitRepo.rootUri.path.length)}${rangeString(fileAndPosition.range)}` : '') + : (useSelection ? `${uri.path.substring(gitRepo.rootUri.path.length)}${notebookCellRangeString(fileAndPosition.cellIndex, fileAndPosition.range)}` : ''); return `${hostPrefix}/${repo.owner}/${repo.repo}/blob/${commitHash }${fileSegments}`; diff --git a/src/vs/workbench/contrib/notebook/browser/controller/coreActions.ts b/src/vs/workbench/contrib/notebook/browser/controller/coreActions.ts index f7b01782aa0..9a42a89b378 100644 --- a/src/vs/workbench/contrib/notebook/browser/controller/coreActions.ts +++ b/src/vs/workbench/contrib/notebook/browser/controller/coreActions.ts @@ -42,7 +42,8 @@ export const enum CellToolbarOrder { export const enum CellOverflowToolbarGroups { Copy = '1_copy', Insert = '2_insert', - Edit = '3_edit' + Edit = '3_edit', + Share = '4_share' } export interface INotebookActionContext { @@ -427,3 +428,9 @@ MenuRegistry.appendMenuItem(MenuId.EditorContext, { group: CellOverflowToolbarGroups.Insert, when: NOTEBOOK_EDITOR_FOCUSED }); + +MenuRegistry.appendMenuItem(MenuId.NotebookCellTitle, { + title: localize('miShare', "Share"), + submenu: MenuId.EditorContextShare, + group: CellOverflowToolbarGroups.Share +}); From 0df86c37b602d08bab3e8def45dd445d36f55fc2 Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Wed, 6 Jul 2022 11:54:37 -0400 Subject: [PATCH 287/347] add `hide` property to configure which tasks appear in the `Tasks: run task` quickpick (#154166) --- .../workbench/api/browser/mainThreadTask.ts | 7 +++--- src/vs/workbench/api/common/shared/tasks.ts | 1 + .../tasks/browser/abstractTaskService.ts | 2 +- .../contrib/tasks/browser/taskQuickPick.ts | 15 ++++++++----- .../tasks/browser/terminalTaskSystem.ts | 22 ++++++++++++++----- .../contrib/tasks/common/jsonSchema_v2.ts | 9 ++++++++ .../contrib/tasks/common/taskConfiguration.ts | 17 +++++++++----- .../workbench/contrib/tasks/common/tasks.ts | 11 ++++++++++ 8 files changed, 64 insertions(+), 20 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadTask.ts b/src/vs/workbench/api/browser/mainThreadTask.ts index 69e679cc5b4..d6193015b85 100644 --- a/src/vs/workbench/api/browser/mainThreadTask.ts +++ b/src/vs/workbench/api/browser/mainThreadTask.ts @@ -342,7 +342,7 @@ namespace TaskDTO { return result; } - export function to(task: ITaskDTO | undefined, workspace: IWorkspaceContextService, executeOnly: boolean, icon?: { id?: string; color?: string }): ContributedTask | undefined { + export function to(task: ITaskDTO | undefined, workspace: IWorkspaceContextService, executeOnly: boolean, icon?: { id?: string; color?: string }, hide?: boolean): ContributedTask | undefined { if (!task || (typeof task.name !== 'string')) { return undefined; } @@ -383,7 +383,8 @@ namespace TaskDTO { isBackground: !!task.isBackground, problemMatchers: task.problemMatchers.slice(), detail: task.detail, - icon + icon, + hide } ); return result; @@ -492,7 +493,7 @@ export class MainThreadTask implements MainThreadTaskShape { dto.name = ((dto.name === undefined) ? '' : dto.name); // Using an empty name causes the name to default to the one given by the provider. return Promise.resolve(this._proxy.$resolveTask(handle, dto)).then(resolvedTask => { if (resolvedTask) { - return TaskDTO.to(resolvedTask, this._workspaceContextServer, true, task.configurationProperties.icon); + return TaskDTO.to(resolvedTask, this._workspaceContextServer, true, task.configurationProperties.icon, task.configurationProperties.hide); } return undefined; diff --git a/src/vs/workbench/api/common/shared/tasks.ts b/src/vs/workbench/api/common/shared/tasks.ts index f7f206f0649..6f0445ab393 100644 --- a/src/vs/workbench/api/common/shared/tasks.ts +++ b/src/vs/workbench/api/common/shared/tasks.ts @@ -78,6 +78,7 @@ export interface ITaskSourceDTO { scope?: number | UriComponents; color?: string; icon?: string; + hide?: boolean; } export interface ITaskHandleDTO { diff --git a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts index 9ef8982eebe..da7e0dccf58 100644 --- a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts +++ b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts @@ -1588,7 +1588,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer { identifier: id, dependsOn: extensionTasks.map((extensionTask) => { return { uri: extensionTask.getWorkspaceFolder()!.uri, task: extensionTask._id }; }), - name: id, + name: id } ); return { task, resolver }; diff --git a/src/vs/workbench/contrib/tasks/browser/taskQuickPick.ts b/src/vs/workbench/contrib/tasks/browser/taskQuickPick.ts index 77dc6f60769..a2cc123e381 100644 --- a/src/vs/workbench/contrib/tasks/browser/taskQuickPick.ts +++ b/src/vs/workbench/contrib/tasks/browser/taskQuickPick.ts @@ -24,7 +24,6 @@ import { TaskQuickPickEntryType } from 'vs/workbench/contrib/tasks/browser/abstr export const QUICKOPEN_DETAIL_CONFIG = 'task.quickOpen.detail'; export const QUICKOPEN_SKIP_CONFIG = 'task.quickOpen.skip'; - export function isWorkspaceFolder(folder: IWorkspace | IWorkspaceFolder): folder is IWorkspaceFolder { return 'uri' in folder; } @@ -108,7 +107,9 @@ export class TaskQuickPick extends Disposable { groupLabel: string, extraButtons: IQuickInputButton[] = []) { entries.push({ type: 'separator', label: groupLabel }); tasks.forEach(task => { - entries.push(this._createTaskEntry(task, extraButtons)); + if (!task.configurationProperties.hide) { + entries.push(this._createTaskEntry(task, extraButtons)); + } }); } @@ -304,7 +305,7 @@ export class TaskQuickPick extends Disposable { private async _doPickerSecondLevel(picker: IQuickPick, type: string) { picker.busy = true; if (type === SHOW_ALL) { - const items = (await this._taskService.tasks()).sort((a, b) => this._sorter.compare(a, b)).map(task => this._createTaskEntry(task)); + const items = (await this._taskService.tasks()).filter(t => !t.configurationProperties.hide).sort((a, b) => this._sorter.compare(a, b)).map(task => this._createTaskEntry(task)); items.push(...TaskQuickPick.allSettingEntries(this._configurationService)); picker.items = items; } else { @@ -353,9 +354,13 @@ export class TaskQuickPick extends Disposable { private async _getEntriesForProvider(type: string): Promise[]> { const tasks = (await this._taskService.tasks({ type })).sort((a, b) => this._sorter.compare(a, b)); - let taskQuickPickEntries: QuickPickInput[]; + let taskQuickPickEntries: QuickPickInput[] = []; if (tasks.length > 0) { - taskQuickPickEntries = tasks.map(task => this._createTaskEntry(task)); + for (const task of tasks) { + if (!task.configurationProperties.hide) { + taskQuickPickEntries.push(this._createTaskEntry(task)); + } + } taskQuickPickEntries.push({ type: 'separator' }, { diff --git a/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts b/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts index d1dd693f370..0beaded25b4 100644 --- a/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts +++ b/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts @@ -516,12 +516,7 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { for (const dependency of task.configurationProperties.dependsOn) { const dependencyTask = await resolver.resolve(dependency.uri, dependency.task!); if (dependencyTask) { - if (dependencyTask.configurationProperties.icon) { - dependencyTask.configurationProperties.icon.id ||= task.configurationProperties.icon?.id; - dependencyTask.configurationProperties.icon.color ||= task.configurationProperties.icon?.color; - } else { - dependencyTask.configurationProperties.icon = task.configurationProperties.icon; - } + this._adoptConfigurationForDependencyTask(dependencyTask, task); const key = dependencyTask.getMapKey(); let promise = this._activeTasks[key] ? this._getDependencyPromise(this._activeTasks[key]) : undefined; if (!promise) { @@ -590,6 +585,21 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { }); } + private _adoptConfigurationForDependencyTask(dependencyTask: Task, task: Task): void { + if (dependencyTask.configurationProperties.icon) { + dependencyTask.configurationProperties.icon.id ||= task.configurationProperties.icon?.id; + dependencyTask.configurationProperties.icon.color ||= task.configurationProperties.icon?.color; + } else { + dependencyTask.configurationProperties.icon = task.configurationProperties.icon; + } + + if (dependencyTask.configurationProperties.hide) { + dependencyTask.configurationProperties.hide ||= task.configurationProperties.hide; + } else { + dependencyTask.configurationProperties.hide = task.configurationProperties.hide; + } + } + private async _getDependencyPromise(task: IActiveTerminalData): Promise { if (!task.task.configurationProperties.isBackground) { return task.promise; diff --git a/src/vs/workbench/contrib/tasks/common/jsonSchema_v2.ts b/src/vs/workbench/contrib/tasks/common/jsonSchema_v2.ts index 077bd89a60e..fa67f8ecf65 100644 --- a/src/vs/workbench/contrib/tasks/common/jsonSchema_v2.ts +++ b/src/vs/workbench/contrib/tasks/common/jsonSchema_v2.ts @@ -45,6 +45,13 @@ const shellCommand: IJSONSchema = { deprecationMessage: nls.localize('JsonSchema.tasks.isShellCommand.deprecated', 'The property isShellCommand is deprecated. Use the type property of the task and the shell property in the options instead. See also the 1.14 release notes.') }; + +const hide: IJSONSchema = { + type: 'boolean', + description: nls.localize('JsonSchema.hide', 'Hide this task from the run task quick pick'), + default: true +}; + const taskIdentifier: IJSONSchema = { type: 'object', additionalProperties: true, @@ -407,6 +414,7 @@ const taskConfiguration: IJSONSchema = { }, presentation: Objects.deepClone(presentation), icon: Objects.deepClone(icon), + hide: Objects.deepClone(hide), options: options, problemMatcher: { $ref: '#/definitions/problemMatcherType', @@ -479,6 +487,7 @@ taskDescriptionProperties.command = Objects.deepClone(command); taskDescriptionProperties.args = Objects.deepClone(args); taskDescriptionProperties.isShellCommand = Objects.deepClone(shellCommand); taskDescriptionProperties.dependsOn = dependsOn; +taskDescriptionProperties.hide = Objects.deepClone(hide); taskDescriptionProperties.dependsOrder = dependsOrder; taskDescriptionProperties.identifier = Objects.deepClone(identifier); taskDescriptionProperties.type = Objects.deepClone(taskType); diff --git a/src/vs/workbench/contrib/tasks/common/taskConfiguration.ts b/src/vs/workbench/contrib/tasks/common/taskConfiguration.ts index c5d4058bcb0..0bb00f57620 100644 --- a/src/vs/workbench/contrib/tasks/common/taskConfiguration.ts +++ b/src/vs/workbench/contrib/tasks/common/taskConfiguration.ts @@ -362,6 +362,11 @@ export interface IConfigurationProperties { * The icon's color in the terminal tabs list */ color?: string; + + /** + * Do not show this task in the run task quickpick + */ + hide?: boolean; } export interface ICustomTask extends ICommandProperties, IConfigurationProperties { @@ -1322,7 +1327,8 @@ namespace ConfigurationProperties { { property: 'presentation', type: CommandConfiguration.PresentationOptions }, { property: 'problemMatchers' }, { property: 'options' }, - { property: 'icon' } + { property: 'icon' }, + { property: 'hide' } ]; export function from(this: void, external: IConfigurationProperties & { [key: string]: any }, context: IParseContext, @@ -1350,7 +1356,7 @@ namespace ConfigurationProperties { result.identifier = external.identifier; } result.icon = external.icon; - + result.hide = external.hide; if (external.isBackground !== undefined) { result.isBackground = !!external.isBackground; } @@ -1483,7 +1489,7 @@ namespace ConfiguringTask { type, taskIdentifier, RunOptions.fromConfiguration(external.runOptions), - {} + { hide: external.hide } ); const configuration = ConfigurationProperties.from(external, context, true, source, typeDeclaration.properties); result.addTaskLoadMessages(configuration.errors); @@ -1635,7 +1641,8 @@ namespace CustomTask { { name: configuredProps.configurationProperties.name || contributedTask.configurationProperties.name, identifier: configuredProps.configurationProperties.identifier || contributedTask.configurationProperties.identifier, - icon: configuredProps.configurationProperties.icon + icon: configuredProps.configurationProperties.icon, + hide: configuredProps.configurationProperties.hide }, ); @@ -2119,7 +2126,7 @@ class ConfigurationParser { identifier: name, group: Tasks.TaskGroup.Build, isBackground: isBackground, - problemMatchers: matchers, + problemMatchers: matchers } ); const taskGroupKind = GroupKind.from(fileConfig.group); diff --git a/src/vs/workbench/contrib/tasks/common/tasks.ts b/src/vs/workbench/contrib/tasks/common/tasks.ts index 1b52c33d02a..f4956cc9aef 100644 --- a/src/vs/workbench/contrib/tasks/common/tasks.ts +++ b/src/vs/workbench/contrib/tasks/common/tasks.ts @@ -549,6 +549,11 @@ export interface IConfigurationProperties { * The icon for this task in the terminal tabs list */ icon?: { id?: string; color?: string }; + + /** + * Do not show this task in the run task quickpick + */ + hide?: boolean; } export enum RunOnOptions { @@ -914,6 +919,11 @@ export class ContributedTask extends CommonTask { */ icon: { id?: string; color?: string } | undefined; + /** + * Don't show the task in the run task quickpick + */ + hide?: boolean; + public constructor(id: string, source: IExtensionTaskSource, label: string, type: string | undefined, defines: KeyedTaskIdentifier, command: ICommandConfiguration, hasDefinedMatchers: boolean, runOptions: IRunOptions, configurationProperties: IConfigurationProperties) { @@ -922,6 +932,7 @@ export class ContributedTask extends CommonTask { this.hasDefinedMatchers = hasDefinedMatchers; this.command = command; this.icon = configurationProperties.icon; + this.hide = configurationProperties.hide; } public override clone(): ContributedTask { From f413297170178f16ab218202153b629d59a98be1 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 6 Jul 2022 18:33:04 +0200 Subject: [PATCH 288/347] joh/plastic fowl (#154275) * * derive workspace dto with util * be strict when defining reference version ids (must be set to a value or undefined) * relax `ResourceNotebookCellEdit` --- .../browser/services/bulkEditService.ts | 64 +++++++++++++------ src/vs/editor/common/languages.ts | 14 ++-- .../test/browser/codeAction.test.ts | 2 +- src/vs/monaco.d.ts | 16 +++-- .../api/browser/mainThreadBulkEdits.ts | 31 +++++---- .../workbench/api/common/extHost.protocol.ts | 47 ++------------ .../common/extHostDocumentSaveParticipant.ts | 8 +-- .../api/common/extHostTypeConverters.ts | 43 ++++++------- .../api/test/browser/extHostBulkEdits.test.ts | 9 +-- .../extHostDocumentSaveParticipant.test.ts | 6 +- .../test/browser/mainThreadEditors.test.ts | 23 +++---- .../contrib/bulkEdit/browser/bulkCellEdits.ts | 26 ++++++-- .../viewModel/notebookViewModelImpl.ts | 7 +- .../contrib/notebook/common/notebookCommon.ts | 10 ++- 14 files changed, 159 insertions(+), 147 deletions(-) diff --git a/src/vs/editor/browser/services/bulkEditService.ts b/src/vs/editor/browser/services/bulkEditService.ts index 1fa168aedb1..1ec6fde3bfb 100644 --- a/src/vs/editor/browser/services/bulkEditService.ts +++ b/src/vs/editor/browser/services/bulkEditService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; -import { TextEdit, WorkspaceEdit, WorkspaceEditMetadata, WorkspaceFileEdit, WorkspaceFileEditOptions, WorkspaceTextEdit } from 'vs/editor/common/languages'; +import { TextEdit, WorkspaceEdit, WorkspaceEditMetadata, IWorkspaceFileEdit, WorkspaceFileEditOptions, IWorkspaceTextEdit } from 'vs/editor/common/languages'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IProgress, IProgressStep } from 'vs/platform/progress/common/progress'; import { IDisposable } from 'vs/base/common/lifecycle'; @@ -15,49 +15,77 @@ import { CancellationToken } from 'vs/base/common/cancellation'; export const IBulkEditService = createDecorator('IWorkspaceEditService'); -function isWorkspaceFileEdit(thing: any): thing is WorkspaceFileEdit { - return isObject(thing) && (Boolean((thing).newUri) || Boolean((thing).oldUri)); -} - -function isWorkspaceTextEdit(thing: any): thing is WorkspaceTextEdit { - return isObject(thing) && URI.isUri((thing).resource) && isObject((thing).edit); -} - export class ResourceEdit { protected constructor(readonly metadata?: WorkspaceEditMetadata) { } static convert(edit: WorkspaceEdit): ResourceEdit[] { - return edit.edits.map(edit => { - if (isWorkspaceTextEdit(edit)) { - return new ResourceTextEdit(edit.resource, edit.edit, edit.modelVersionId, edit.metadata); + if (ResourceTextEdit.is(edit)) { + return ResourceTextEdit.lift(edit); } - if (isWorkspaceFileEdit(edit)) { - return new ResourceFileEdit(edit.oldUri, edit.newUri, edit.options, edit.metadata); + + if (ResourceFileEdit.is(edit)) { + return ResourceFileEdit.lift(edit); } throw new Error('Unsupported edit'); }); } } -export class ResourceTextEdit extends ResourceEdit { +export class ResourceTextEdit extends ResourceEdit implements IWorkspaceTextEdit { + + static is(candidate: any): candidate is IWorkspaceTextEdit { + if (candidate instanceof ResourceTextEdit) { + return true; + } + return isObject(candidate) + && URI.isUri((candidate).resource) + && isObject((candidate).textEdit); + } + + static lift(edit: IWorkspaceTextEdit): ResourceTextEdit { + if (edit instanceof ResourceTextEdit) { + return edit; + } else { + return new ResourceTextEdit(edit.resource, edit.textEdit, edit.versionId, edit.metadata); + } + } + constructor( readonly resource: URI, readonly textEdit: TextEdit & { insertAsSnippet?: boolean }, - readonly versionId?: number, + readonly versionId: number | undefined = undefined, metadata?: WorkspaceEditMetadata, ) { super(metadata); } } -export class ResourceFileEdit extends ResourceEdit { +export class ResourceFileEdit extends ResourceEdit implements IWorkspaceFileEdit { + + static is(candidate: any): candidate is IWorkspaceFileEdit { + if (candidate instanceof ResourceFileEdit) { + return true; + } else { + return isObject(candidate) + && (Boolean((candidate).newResource) || Boolean((candidate).oldResource)); + } + } + + static lift(edit: IWorkspaceFileEdit): ResourceFileEdit { + if (edit instanceof ResourceFileEdit) { + return edit; + } else { + return new ResourceFileEdit(edit.oldResource, edit.newResource, edit.options, edit.metadata); + } + } + constructor( readonly oldResource: URI | undefined, readonly newResource: URI | undefined, - readonly options?: WorkspaceFileEditOptions, + readonly options: WorkspaceFileEditOptions = {}, metadata?: WorkspaceEditMetadata ) { super(metadata); diff --git a/src/vs/editor/common/languages.ts b/src/vs/editor/common/languages.ts index 0d97ad7329e..10baf2667c9 100644 --- a/src/vs/editor/common/languages.ts +++ b/src/vs/editor/common/languages.ts @@ -1412,22 +1412,22 @@ export interface WorkspaceFileEditOptions { maxSize?: number; } -export interface WorkspaceFileEdit { - oldUri?: URI; - newUri?: URI; +export interface IWorkspaceFileEdit { + oldResource?: URI; + newResource?: URI; options?: WorkspaceFileEditOptions; metadata?: WorkspaceEditMetadata; } -export interface WorkspaceTextEdit { +export interface IWorkspaceTextEdit { resource: URI; - edit: TextEdit; - modelVersionId?: number; + textEdit: TextEdit & { insertAsSnippet?: boolean }; + versionId: number | undefined; metadata?: WorkspaceEditMetadata; } export interface WorkspaceEdit { - edits: Array; + edits: Array; } export interface Rejection { diff --git a/src/vs/editor/contrib/codeAction/test/browser/codeAction.test.ts b/src/vs/editor/contrib/codeAction/test/browser/codeAction.test.ts index d1be6b9d645..93005d11387 100644 --- a/src/vs/editor/contrib/codeAction/test/browser/codeAction.test.ts +++ b/src/vs/editor/contrib/codeAction/test/browser/codeAction.test.ts @@ -73,7 +73,7 @@ suite('CodeAction', () => { bcd: { diagnostics: [], edit: new class implements languages.WorkspaceEdit { - edits!: languages.WorkspaceTextEdit[]; + edits!: languages.IWorkspaceTextEdit[]; }, title: 'abc' } diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 713083bfe0c..0ff87c1fdb8 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -7015,22 +7015,24 @@ declare namespace monaco.languages { maxSize?: number; } - export interface WorkspaceFileEdit { - oldUri?: Uri; - newUri?: Uri; + export interface IWorkspaceFileEdit { + oldResource?: Uri; + newResource?: Uri; options?: WorkspaceFileEditOptions; metadata?: WorkspaceEditMetadata; } - export interface WorkspaceTextEdit { + export interface IWorkspaceTextEdit { resource: Uri; - edit: TextEdit; - modelVersionId?: number; + textEdit: TextEdit & { + insertAsSnippet?: boolean; + }; + versionId: number | undefined; metadata?: WorkspaceEditMetadata; } export interface WorkspaceEdit { - edits: Array; + edits: Array; } export interface Rejection { diff --git a/src/vs/workbench/api/browser/mainThreadBulkEdits.ts b/src/vs/workbench/api/browser/mainThreadBulkEdits.ts index e3e5d652a16..b47e47a7286 100644 --- a/src/vs/workbench/api/browser/mainThreadBulkEdits.ts +++ b/src/vs/workbench/api/browser/mainThreadBulkEdits.ts @@ -4,29 +4,28 @@ *--------------------------------------------------------------------------------------------*/ import { IBulkEditService, ResourceEdit, ResourceFileEdit, ResourceTextEdit } from 'vs/editor/browser/services/bulkEditService'; -import { IWorkspaceEditDto, MainThreadBulkEditsShape, MainContext, WorkspaceEditType } from 'vs/workbench/api/common/extHost.protocol'; +import { IWorkspaceEditDto, MainThreadBulkEditsShape, MainContext, reviveWorkspaceEditDto } from 'vs/workbench/api/common/extHost.protocol'; import { extHostNamedCustomer, IExtHostContext } from 'vs/workbench/services/extensions/common/extHostCustomers'; import { ILogService } from 'vs/platform/log/common/log'; -import { revive } from 'vs/base/common/marshalling'; import { ResourceNotebookCellEdit } from 'vs/workbench/contrib/bulkEdit/browser/bulkCellEdits'; -import { NotebookDto } from 'vs/workbench/api/browser/mainThreadNotebookDto'; -export function reviveWorkspaceEditDto2(data: IWorkspaceEditDto | undefined): ResourceEdit[] { - if (!data?.edits) { +export function reviveWorkspaceEditDto2(data: IWorkspaceEditDto): ResourceEdit[] { + const edits = reviveWorkspaceEditDto(data)?.edits; + if (!edits) { return []; } - - const result: ResourceEdit[] = []; - for (const edit of revive(data).edits) { - if (edit._type === WorkspaceEditType.File) { - result.push(new ResourceFileEdit(edit.oldUri, edit.newUri, edit.options, edit.metadata)); - } else if (edit._type === WorkspaceEditType.Text) { - result.push(new ResourceTextEdit(edit.resource, edit.edit, edit.modelVersionId, edit.metadata)); - } else if (edit._type === WorkspaceEditType.Cell) { - result.push(new ResourceNotebookCellEdit(edit.resource, NotebookDto.fromCellEditOperationDto(edit.edit), edit.notebookVersionId, edit.metadata)); + return edits.map(edit => { + if (ResourceTextEdit.is(edit)) { + return ResourceTextEdit.lift(edit); } - } - return result; + if (ResourceFileEdit.is(edit)) { + return ResourceFileEdit.lift(edit); + } + if (ResourceNotebookCellEdit.is(edit)) { + return ResourceNotebookCellEdit.lift(edit); + } + throw new Error('Unsupported edit'); + }); } @extHostNamedCustomer(MainContext.MainThreadBulkEdits) diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index a7b203695df..2d062111195 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -1587,27 +1587,6 @@ export interface IWorkspaceEditEntryMetadataDto { iconPath?: { id: string } | UriComponents | { light: UriComponents; dark: UriComponents }; } -export const enum WorkspaceEditType { - File = 1, - Text = 2, - Cell = 3, -} - -export interface IWorkspaceFileEditDto { - _type: WorkspaceEditType.File; - oldUri?: UriComponents; - newUri?: UriComponents; - options?: languages.WorkspaceFileEditOptions; - metadata?: IWorkspaceEditEntryMetadataDto; -} - -export interface IWorkspaceTextEditDto { - _type: WorkspaceEditType.Text; - resource: UriComponents; - edit: languages.TextEdit & { insertAsSnippet?: boolean }; - modelVersionId?: number; - metadata?: IWorkspaceEditEntryMetadataDto; -} export type ICellEditOperationDto = notebookCommon.ICellPartialMetadataEdit @@ -1619,31 +1598,19 @@ export type ICellEditOperationDto = cells: NotebookCellDataDto[]; }; -export interface IWorkspaceCellEditDto { - _type: WorkspaceEditType.Cell; - resource: UriComponents; - notebookVersionId?: number; - metadata?: IWorkspaceEditEntryMetadataDto; - edit: ICellEditOperationDto; -} +export type IWorkspaceCellEditDto = Dto> & { cellEdit: ICellEditOperationDto }; + +export type IWorkspaceFileEditDto = Dto; + +export type IWorkspaceTextEditDto = Dto; export interface IWorkspaceEditDto { edits: Array; } -export function reviveWorkspaceEditDto(data: IWorkspaceEditDto | undefined): languages.WorkspaceEdit { +export function reviveWorkspaceEditDto(data: IWorkspaceEditDto | undefined): languages.WorkspaceEdit | undefined { if (data && data.edits) { - for (const edit of data.edits) { - if (typeof (edit).resource === 'object') { - (edit).resource = URI.revive((edit).resource); - } else { - (edit).newUri = URI.revive((edit).newUri); - (edit).oldUri = URI.revive((edit).oldUri); - } - if (edit.metadata && edit.metadata.iconPath) { - edit.metadata = revive(edit.metadata); - } - } + revive(data); } return data; } diff --git a/src/vs/workbench/api/common/extHostDocumentSaveParticipant.ts b/src/vs/workbench/api/common/extHostDocumentSaveParticipant.ts index 05f7cb963d6..7a90e5db0f9 100644 --- a/src/vs/workbench/api/common/extHostDocumentSaveParticipant.ts +++ b/src/vs/workbench/api/common/extHostDocumentSaveParticipant.ts @@ -6,7 +6,7 @@ import { Event } from 'vs/base/common/event'; import { URI, UriComponents } from 'vs/base/common/uri'; import { illegalState } from 'vs/base/common/errors'; -import { ExtHostDocumentSaveParticipantShape, IWorkspaceEditDto, WorkspaceEditType, MainThreadBulkEditsShape } from 'vs/workbench/api/common/extHost.protocol'; +import { ExtHostDocumentSaveParticipantShape, IWorkspaceEditDto, MainThreadBulkEditsShape } from 'vs/workbench/api/common/extHost.protocol'; import { TextEdit } from 'vs/workbench/api/common/extHostTypes'; import { Range, TextDocumentSaveReason, EndOfLine } from 'vs/workbench/api/common/extHostTypeConverters'; import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments'; @@ -146,12 +146,12 @@ export class ExtHostDocumentSaveParticipant implements ExtHostDocumentSavePartic if (Array.isArray(value) && (value).every(e => e instanceof TextEdit)) { for (const { newText, newEol, range } of value) { dto.edits.push({ - _type: WorkspaceEditType.Text, resource: document.uri, - edit: { + versionId: undefined, + textEdit: { range: range && Range.from(range), text: newText, - eol: newEol && EndOfLine.from(newEol) + eol: newEol && EndOfLine.from(newEol), } }); } diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index 9b733dc8951..f7917e317d2 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -589,47 +589,44 @@ export namespace WorkspaceEdit { if (entry._type === types.FileEditType.File) { // file operation - result.edits.push({ - _type: extHostProtocol.WorkspaceEditType.File, - oldUri: entry.from, - newUri: entry.to, + result.edits.push({ + oldResource: entry.from, + newResource: entry.to, options: entry.options, metadata: entry.metadata }); } else if (entry._type === types.FileEditType.Text) { - // text edits - const dto = { - _type: extHostProtocol.WorkspaceEditType.Text, + const edit = { resource: entry.uri, - edit: TextEdit.from(entry.edit), - modelVersionId: !toCreate.has(entry.uri) ? versionInfo?.getTextDocumentVersion(entry.uri) : undefined, + textEdit: TextEdit.from(entry.edit), + versionId: !toCreate.has(entry.uri) ? versionInfo?.getTextDocumentVersion(entry.uri) : undefined, metadata: entry.metadata }; if (allowSnippetTextEdit && entry.edit.newText2 instanceof types.SnippetString) { - dto.edit.insertAsSnippet = true; - dto.edit.text = entry.edit.newText2.value; + edit.textEdit.insertAsSnippet = true; + edit.textEdit.text = entry.edit.newText2.value; } - result.edits.push(dto); + result.edits.push(edit); } else if (entry._type === types.FileEditType.Cell) { - result.edits.push({ - _type: extHostProtocol.WorkspaceEditType.Cell, + // cell edit + result.edits.push({ metadata: entry.metadata, resource: entry.uri, - edit: entry.edit, + cellEdit: entry.edit, notebookMetadata: entry.notebookMetadata, notebookVersionId: versionInfo?.getNotebookDocumentVersion(entry.uri) }); } else if (entry._type === types.FileEditType.CellReplace) { - result.edits.push({ - _type: extHostProtocol.WorkspaceEditType.Cell, + // cell replace + result.edits.push({ metadata: entry.metadata, resource: entry.uri, notebookVersionId: versionInfo?.getNotebookDocumentVersion(entry.uri), - edit: { + cellEdit: { editType: notebooks.CellEditType.Replace, index: entry.index, count: entry.count, @@ -645,16 +642,16 @@ export namespace WorkspaceEdit { export function to(value: extHostProtocol.IWorkspaceEditDto) { const result = new types.WorkspaceEdit(); for (const edit of value.edits) { - if ((edit).edit) { + if ((edit).textEdit) { result.replace( URI.revive((edit).resource), - Range.to((edit).edit.range), - (edit).edit.text + Range.to((edit).textEdit.range), + (edit).textEdit.text ); } else { result.renameFile( - URI.revive((edit).oldUri!), - URI.revive((edit).newUri!), + URI.revive((edit).oldResource!), + URI.revive((edit).newResource!), (edit).options ); } diff --git a/src/vs/workbench/api/test/browser/extHostBulkEdits.test.ts b/src/vs/workbench/api/test/browser/extHostBulkEdits.test.ts index 3b393b35347..906405cd6b7 100644 --- a/src/vs/workbench/api/test/browser/extHostBulkEdits.test.ts +++ b/src/vs/workbench/api/test/browser/extHostBulkEdits.test.ts @@ -4,13 +4,12 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; import * as extHostTypes from 'vs/workbench/api/common/extHostTypes'; -import { MainContext, IWorkspaceEditDto, WorkspaceEditType, MainThreadBulkEditsShape } from 'vs/workbench/api/common/extHost.protocol'; +import { MainContext, IWorkspaceEditDto, MainThreadBulkEditsShape, IWorkspaceTextEditDto } from 'vs/workbench/api/common/extHost.protocol'; import { URI } from 'vs/base/common/uri'; import { mock } from 'vs/base/test/common/mock'; import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors'; import { SingleProxyRPCProtocol, TestRPCProtocol } from 'vs/workbench/api/test/common/testRPCProtocol'; import { NullLogService } from 'vs/platform/log/common/log'; -import { assertType } from 'vs/base/common/types'; import { ExtHostBulkEdits } from 'vs/workbench/api/common/extHostBulkEdits'; import { nullExtensionDescription } from 'vs/workbench/services/extensions/common/extensions'; @@ -50,8 +49,7 @@ suite('ExtHostBulkEdits.applyWorkspaceEdit', () => { await bulkEdits.applyWorkspaceEdit(edit, nullExtensionDescription); assert.strictEqual(workspaceResourceEdits.edits.length, 1); const [first] = workspaceResourceEdits.edits; - assertType(first._type === WorkspaceEditType.Text); - assert.strictEqual(first.modelVersionId, 1337); + assert.strictEqual((first).versionId, 1337); }); test('does not use version id if document is not available', async () => { @@ -60,8 +58,7 @@ suite('ExtHostBulkEdits.applyWorkspaceEdit', () => { await bulkEdits.applyWorkspaceEdit(edit, nullExtensionDescription); assert.strictEqual(workspaceResourceEdits.edits.length, 1); const [first] = workspaceResourceEdits.edits; - assertType(first._type === WorkspaceEditType.Text); - assert.ok(typeof first.modelVersionId === 'undefined'); + assert.ok(typeof (first).versionId === 'undefined'); }); }); diff --git a/src/vs/workbench/api/test/browser/extHostDocumentSaveParticipant.test.ts b/src/vs/workbench/api/test/browser/extHostDocumentSaveParticipant.test.ts index 70e338176d7..c50aabb812f 100644 --- a/src/vs/workbench/api/test/browser/extHostDocumentSaveParticipant.test.ts +++ b/src/vs/workbench/api/test/browser/extHostDocumentSaveParticipant.test.ts @@ -266,8 +266,8 @@ suite('ExtHostDocumentSaveParticipant', () => { sub.dispose(); assert.strictEqual(dto.edits.length, 2); - assert.ok((dto.edits[0]).edit); - assert.ok((dto.edits[1]).edit); + assert.ok((dto.edits[0]).textEdit); + assert.ok((dto.edits[1]).textEdit); }); }); @@ -317,7 +317,7 @@ suite('ExtHostDocumentSaveParticipant', () => { for (const edit of dto.edits) { const uri = URI.revive((edit).resource); - const { text, range } = (edit).edit; + const { text, range } = (edit).textEdit; documents.$acceptModelChanged(uri, { changes: [{ range, diff --git a/src/vs/workbench/api/test/browser/mainThreadEditors.test.ts b/src/vs/workbench/api/test/browser/mainThreadEditors.test.ts index dac02ac748e..859c9c28ee8 100644 --- a/src/vs/workbench/api/test/browser/mainThreadEditors.test.ts +++ b/src/vs/workbench/api/test/browser/mainThreadEditors.test.ts @@ -9,7 +9,7 @@ import { TestConfigurationService } from 'vs/platform/configuration/test/common/ import { ModelService } from 'vs/editor/common/services/modelService'; import { TestCodeEditorService } from 'vs/editor/test/browser/editorTestServices'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; -import { IWorkspaceTextEditDto, WorkspaceEditType } from 'vs/workbench/api/common/extHost.protocol'; +import { IWorkspaceTextEditDto } from 'vs/workbench/api/common/extHost.protocol'; import { mock } from 'vs/base/test/common/mock'; import { Event } from 'vs/base/common/event'; import { URI } from 'vs/base/common/uri'; @@ -197,10 +197,9 @@ suite('MainThreadEditors', () => { const model = modelService.createModel('something', null, resource); const workspaceResourceEdit: IWorkspaceTextEditDto = { - _type: WorkspaceEditType.Text, resource: resource, - modelVersionId: model.getVersionId(), - edit: { + versionId: model.getVersionId(), + textEdit: { text: 'asdfg', range: new Range(1, 1, 1, 1) } @@ -219,19 +218,17 @@ suite('MainThreadEditors', () => { const model = modelService.createModel('something', null, resource); const workspaceResourceEdit1: IWorkspaceTextEditDto = { - _type: WorkspaceEditType.Text, resource: resource, - modelVersionId: model.getVersionId(), - edit: { + versionId: model.getVersionId(), + textEdit: { text: 'asdfg', range: new Range(1, 1, 1, 1) } }; const workspaceResourceEdit2: IWorkspaceTextEditDto = { - _type: WorkspaceEditType.Text, resource: resource, - modelVersionId: model.getVersionId(), - edit: { + versionId: model.getVersionId(), + textEdit: { text: 'asdfg', range: new Range(1, 1, 1, 1) } @@ -251,9 +248,9 @@ suite('MainThreadEditors', () => { test(`applyWorkspaceEdit with only resource edit`, () => { return bulkEdits.$tryApplyWorkspaceEdit({ edits: [ - { _type: WorkspaceEditType.File, oldUri: resource, newUri: resource, options: undefined }, - { _type: WorkspaceEditType.File, oldUri: undefined, newUri: resource, options: undefined }, - { _type: WorkspaceEditType.File, oldUri: resource, newUri: undefined, options: undefined } + { oldResource: resource, newResource: resource, options: undefined }, + { oldResource: undefined, newResource: resource, options: undefined }, + { oldResource: resource, newResource: undefined, options: undefined } ] }).then((result) => { assert.strictEqual(result, true); diff --git a/src/vs/workbench/contrib/bulkEdit/browser/bulkCellEdits.ts b/src/vs/workbench/contrib/bulkEdit/browser/bulkCellEdits.ts index 1f533a82ccc..0e870b7b639 100644 --- a/src/vs/workbench/contrib/bulkEdit/browser/bulkCellEdits.ts +++ b/src/vs/workbench/contrib/bulkEdit/browser/bulkCellEdits.ts @@ -6,20 +6,36 @@ import { groupBy } from 'vs/base/common/arrays'; import { CancellationToken } from 'vs/base/common/cancellation'; import { compare } from 'vs/base/common/strings'; +import { isObject } from 'vs/base/common/types'; import { URI } from 'vs/base/common/uri'; import { ResourceEdit } from 'vs/editor/browser/services/bulkEditService'; import { WorkspaceEditMetadata } from 'vs/editor/common/languages'; import { IProgress } from 'vs/platform/progress/common/progress'; import { UndoRedoGroup, UndoRedoSource } from 'vs/platform/undoRedo/common/undoRedo'; -import { ICellEditOperation } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { ICellPartialMetadataEdit, ICellReplaceEdit, IDocumentMetadataEdit, IWorkspaceNotebookCellEdit } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { INotebookEditorModelResolverService } from 'vs/workbench/contrib/notebook/common/notebookEditorModelResolverService'; -export class ResourceNotebookCellEdit extends ResourceEdit { +export class ResourceNotebookCellEdit extends ResourceEdit implements IWorkspaceNotebookCellEdit { + + static is(candidate: any): candidate is IWorkspaceNotebookCellEdit { + if (candidate instanceof ResourceNotebookCellEdit) { + return true; + } + return URI.isUri((candidate).resource) + && isObject((candidate).cellEdit); + } + + static lift(edit: IWorkspaceNotebookCellEdit): ResourceNotebookCellEdit { + if (edit instanceof ResourceNotebookCellEdit) { + return edit; + } + return new ResourceNotebookCellEdit(edit.resource, edit.cellEdit, edit.notebookVersionId, edit.metadata); + } constructor( readonly resource: URI, - readonly cellEdit: ICellEditOperation, - readonly versionId?: number, + readonly cellEdit: ICellPartialMetadataEdit | IDocumentMetadataEdit | ICellReplaceEdit, + readonly notebookVersionId: number | undefined = undefined, metadata?: WorkspaceEditMetadata ) { super(metadata); @@ -49,7 +65,7 @@ export class BulkCellEdits { const ref = await this._notebookModelService.resolve(first.resource); // check state - if (typeof first.versionId === 'number' && ref.object.notebook.versionId !== first.versionId) { + if (typeof first.notebookVersionId === 'number' && ref.object.notebook.versionId !== first.notebookVersionId) { ref.dispose(); throw new Error(`Notebook '${first.resource}' has changed in the meantime`); } diff --git a/src/vs/workbench/contrib/notebook/browser/viewModel/notebookViewModelImpl.ts b/src/vs/workbench/contrib/notebook/browser/viewModel/notebookViewModelImpl.ts index 951fbe0e2e2..a024bbe93a6 100644 --- a/src/vs/workbench/contrib/notebook/browser/viewModel/notebookViewModelImpl.ts +++ b/src/vs/workbench/contrib/notebook/browser/viewModel/notebookViewModelImpl.ts @@ -17,7 +17,7 @@ import { FindMatch, IModelDecorationOptions, IModelDeltaDecoration, TrackedRange import { MultiModelEditStackElement, SingleModelEditStackElement } from 'vs/editor/common/model/editStack'; import { IntervalNode, IntervalTree } from 'vs/editor/common/model/intervalTree'; import { ModelDecorationOptions } from 'vs/editor/common/model/textModel'; -import { WorkspaceTextEdit } from 'vs/editor/common/languages'; +import { IWorkspaceTextEdit } from 'vs/editor/common/languages'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { FoldingRegions } from 'vs/editor/contrib/folding/browser/foldingRanges'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -924,14 +924,15 @@ export class NotebookViewModel extends Disposable implements EditorFoldingStateD return; } - const textEdits: WorkspaceTextEdit[] = []; + const textEdits: IWorkspaceTextEdit[] = []; this._lastNotebookEditResource.push(matches[0].cell.uri); matches.forEach(match => { match.matches.forEach((singleMatch, index) => { if ((singleMatch as OutputFindMatch).index === undefined) { textEdits.push({ - edit: { range: (singleMatch as FindMatch).range, text: texts[index] }, + versionId: undefined, + textEdit: { range: (singleMatch as FindMatch).range, text: texts[index] }, resource: match.cell.uri }); } diff --git a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts index d0ccff06ccd..a95ecc6fb84 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts @@ -17,7 +17,7 @@ import { ISplice } from 'vs/base/common/sequence'; import { URI, UriComponents } from 'vs/base/common/uri'; import { ILineChange } from 'vs/editor/common/diff/diffComputer'; import * as editorCommon from 'vs/editor/common/editorCommon'; -import { Command } from 'vs/editor/common/languages'; +import { Command, WorkspaceEditMetadata } from 'vs/editor/common/languages'; import { IReadonlyTextBuffer } from 'vs/editor/common/model'; import { IAccessibilityInformation } from 'vs/platform/accessibility/common/accessibility'; import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; @@ -497,6 +497,14 @@ export interface ICellMoveEdit { export type IImmediateCellEditOperation = ICellOutputEditByHandle | ICellPartialMetadataEditByHandle | ICellOutputItemEdit | ICellPartialInternalMetadataEdit | ICellPartialInternalMetadataEditByHandle | ICellPartialMetadataEdit; export type ICellEditOperation = IImmediateCellEditOperation | ICellReplaceEdit | ICellOutputEdit | ICellMetadataEdit | ICellPartialMetadataEdit | ICellPartialInternalMetadataEdit | IDocumentMetadataEdit | ICellMoveEdit | ICellOutputItemEdit | ICellLanguageEdit; + +export interface IWorkspaceNotebookCellEdit { + metadata?: WorkspaceEditMetadata; + resource: URI; + notebookVersionId: number | undefined; + cellEdit: ICellPartialMetadataEdit | IDocumentMetadataEdit | ICellReplaceEdit; +} + export interface NotebookData { readonly cells: ICellDto2[]; readonly metadata: NotebookDocumentMetadata; From 09b0f5b54f483b0c3e0bc5bfd70fa6dec437e13e Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 6 Jul 2022 18:44:13 +0200 Subject: [PATCH 289/347] skip application scope settings while copying (#154280) --- .../browser/configurationService.ts | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/services/configuration/browser/configurationService.ts b/src/vs/workbench/services/configuration/browser/configurationService.ts index 10ef3ab6d99..bba9911a158 100644 --- a/src/vs/workbench/services/configuration/browser/configurationService.ts +++ b/src/vs/workbench/services/configuration/browser/configurationService.ts @@ -26,7 +26,7 @@ import { JSONEditingService } from 'vs/workbench/services/configuration/common/j import { IJSONSchema, IJSONSchemaMap } from 'vs/base/common/jsonSchema'; import { mark } from 'vs/base/common/performance'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; -import { IFileService } from 'vs/platform/files/common/files'; +import { FileOperationError, FileOperationResult, IFileService } from 'vs/platform/files/common/files'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; @@ -43,6 +43,8 @@ import { localize } from 'vs/nls'; import { DidChangeUserDataProfileEvent, IUserDataProfileService } from 'vs/workbench/services/userDataProfile/common/userDataProfile'; import { IPolicyService, NullPolicyService } from 'vs/platform/policy/common/policy'; import { IUserDataProfile, IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile'; +import { updateIgnoredSettings } from 'vs/platform/userDataSync/common/settingsMerge'; +import { VSBuffer } from 'vs/base/common/buffer'; function getLocalUserConfigurationScopes(userDataProfile: IUserDataProfile, hasRemote: boolean): ConfigurationScope[] | undefined { return userDataProfile.isDefault @@ -714,7 +716,7 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat e.join((async () => { if (e.preserveData) { await Promise.all([ - this.fileService.copy(e.previous.settingsResource, e.profile.settingsResource), + this.copyProfileSettings(e.previous.settingsResource, e.profile.settingsResource), this.fileService.copy(e.previous.tasksResource, e.profile.tasksResource) ]); } @@ -731,6 +733,24 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat })()); } + private async copyProfileSettings(from: URI, to: URI): Promise { + let fromContent: string | undefined; + try { + fromContent = (await this.fileService.readFile(from)).value.toString(); + } catch (error) { + if ((error).fileOperationResult !== FileOperationResult.FILE_NOT_FOUND) { + throw error; + } + } + if (!fromContent) { + return; + } + const allSettings = Registry.as(Extensions.Configuration).getConfigurationProperties(); + const applicationSettings = Object.keys(allSettings).filter(key => allSettings[key]?.scope === ConfigurationScope.APPLICATION); + const toContent = updateIgnoredSettings(fromContent, '{}', applicationSettings, {}); + await this.fileService.writeFile(to, VSBuffer.fromString(toContent)); + } + private onDefaultConfigurationChanged(configurationModel: ConfigurationModel, properties?: string[]): void { if (this.workspace) { const previousData = this._configuration.toData(); From c133b130bfd88a134e1803d60e6ce5d094af6a03 Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Wed, 6 Jul 2022 12:45:28 -0400 Subject: [PATCH 290/347] remove `forEach` for tasks (#154273) * part of #154195 * Update src/vs/workbench/api/browser/mainThreadTask.ts Co-authored-by: Daniel Imms <2193314+Tyriar@users.noreply.github.com> * Update src/vs/workbench/api/browser/mainThreadTask.ts Co-authored-by: Daniel Imms <2193314+Tyriar@users.noreply.github.com> --- src/vs/workbench/api/browser/mainThreadTask.ts | 8 +++++--- .../contrib/tasks/browser/runAutomaticTasks.ts | 17 ++++++++--------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadTask.ts b/src/vs/workbench/api/browser/mainThreadTask.ts index d6193015b85..e40b95ad866 100644 --- a/src/vs/workbench/api/browser/mainThreadTask.ts +++ b/src/vs/workbench/api/browser/mainThreadTask.ts @@ -434,7 +434,9 @@ export class MainThreadTask implements MainThreadTaskShape { let resolvedDefinition: ITaskDefinitionDTO = execution.task!.definition; if (execution.task?.execution && CustomExecutionDTO.is(execution.task.execution) && event.resolvedVariables) { const dictionary: IStringDictionary = {}; - Array.from(event.resolvedVariables.entries()).forEach(entry => dictionary[entry[0]] = entry[1]); + for (const [key, value] of event.resolvedVariables.entries()) { + dictionary[key] = value; + } resolvedDefinition = await this._configurationResolverService.resolveAnyAsync(task.getWorkspaceFolder(), execution.task.definition, dictionary); } @@ -450,9 +452,9 @@ export class MainThreadTask implements MainThreadTaskShape { } public dispose(): void { - this._providers.forEach((value) => { + for (const value of this._providers.values()) { value.disposable.dispose(); - }); + } this._providers.clear(); } diff --git a/src/vs/workbench/contrib/tasks/browser/runAutomaticTasks.ts b/src/vs/workbench/contrib/tasks/browser/runAutomaticTasks.ts index 3d91091af90..55d63c00125 100644 --- a/src/vs/workbench/contrib/tasks/browser/runAutomaticTasks.ts +++ b/src/vs/workbench/contrib/tasks/browser/runAutomaticTasks.ts @@ -8,7 +8,6 @@ import * as resources from 'vs/base/common/resources'; import { Disposable } from 'vs/base/common/lifecycle'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { ITaskService, IWorkspaceFolderTaskResult } from 'vs/workbench/contrib/tasks/common/taskService'; -import { forEach } from 'vs/base/common/collections'; import { RunOnOptions, Task, TaskRunSource, TaskSource, TaskSourceKind, TASKS_CATEGORY, WorkspaceFileTaskSource, IWorkspaceTaskSource } from 'vs/workbench/contrib/tasks/common/tasks'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; @@ -106,22 +105,22 @@ export class RunAutomaticTasks extends Disposable implements IWorkbenchContribut }); } if (resultElement.configurations) { - forEach(resultElement.configurations.byIdentifier, (configedTask) => { - if (configedTask.value.runOptions.runOn === RunOnOptions.folderOpen) { + for (const configuredTask of Object.values(resultElement.configurations.byIdentifier)) { + if (configuredTask.runOptions.runOn === RunOnOptions.folderOpen) { tasks.push(new Promise(resolve => { - taskService.getTask(resultElement.workspaceFolder, configedTask.value._id, true).then(task => resolve(task)); + taskService.getTask(resultElement.workspaceFolder, configuredTask._id, true).then(task => resolve(task)); })); - if (configedTask.value._label) { - taskNames.push(configedTask.value._label); + if (configuredTask._label) { + taskNames.push(configuredTask._label); } else { - taskNames.push(configedTask.value.configures.task); + taskNames.push(configuredTask.configures.task); } - const location = RunAutomaticTasks._getTaskSource(configedTask.value._source); + const location = RunAutomaticTasks._getTaskSource(configuredTask._source); if (location) { locations.set(location.fsPath, location); } } - }); + } } }); } From cc0dfc9f0e9d398287123013737516298a360e89 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 6 Jul 2022 18:53:03 +0200 Subject: [PATCH 291/347] remove application scoped extensions while copying (#154278) --- .../nativeExtensionManagementService.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/services/extensionManagement/electron-sandbox/nativeExtensionManagementService.ts b/src/vs/workbench/services/extensionManagement/electron-sandbox/nativeExtensionManagementService.ts index 6282bc77cf8..cdd2bdad7db 100644 --- a/src/vs/workbench/services/extensionManagement/electron-sandbox/nativeExtensionManagementService.ts +++ b/src/vs/workbench/services/extensionManagement/electron-sandbox/nativeExtensionManagementService.ts @@ -7,7 +7,7 @@ import { IChannel } from 'vs/base/parts/ipc/common/ipc'; import { IProfileAwareExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { ExtensionManagementChannelClient } from 'vs/platform/extensionManagement/common/extensionManagementIpc'; import { URI } from 'vs/base/common/uri'; -import { IGalleryExtension, ILocalExtension, InstallOptions, InstallVSIXOptions, UninstallOptions } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IGalleryExtension, ILocalExtension, InstallOptions, InstallVSIXOptions, Metadata, UninstallOptions } from 'vs/platform/extensionManagement/common/extensionManagement'; import { ExtensionIdentifier, ExtensionType } from 'vs/platform/extensions/common/extensions'; import { Emitter, Event } from 'vs/base/common/event'; import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'; @@ -17,7 +17,7 @@ import { DisposableStore } from 'vs/base/common/lifecycle'; import { DidChangeUserDataProfileEvent, IUserDataProfileService } from 'vs/workbench/services/userDataProfile/common/userDataProfile'; import { EXTENSIONS_RESOURCE_NAME } from 'vs/platform/userDataProfile/common/userDataProfile'; import { joinPath } from 'vs/base/common/resources'; -import { IFileService } from 'vs/platform/files/common/files'; +import { IExtensionsProfileScannerService } from 'vs/platform/extensionManagement/common/extensionsProfileScannerService'; export class NativeExtensionManagementService extends ExtensionManagementChannelClient implements IProfileAwareExtensionManagementService { @@ -38,7 +38,7 @@ export class NativeExtensionManagementService extends ExtensionManagementChannel constructor( channel: IChannel, @IUserDataProfileService private readonly userDataProfileService: IUserDataProfileService, - @IFileService private readonly fileService: IFileService, + @IExtensionsProfileScannerService private readonly extensionsProfileScannerService: IExtensionsProfileScannerService, @IUriIdentityService private readonly uriIdentityService: IUriIdentityService, ) { super(channel); @@ -67,10 +67,13 @@ export class NativeExtensionManagementService extends ExtensionManagementChannel private async whenProfileChanged(e: DidChangeUserDataProfileEvent): Promise { const previousExtensionsResource = e.previous.extensionsResource ?? joinPath(e.previous.location, EXTENSIONS_RESOURCE_NAME); + const oldExtensions = await super.getInstalled(ExtensionType.User, previousExtensionsResource); if (e.preserveData) { - await this.fileService.copy(previousExtensionsResource, previousExtensionsResource); + const extensions: [ILocalExtension, Metadata | undefined][] = await Promise.all(oldExtensions + .filter(e => !e.isApplicationScoped) /* remove application scoped extensions */ + .map(async e => ([e, await this.getMetadata(e)]))); + await this.extensionsProfileScannerService.addExtensionsToProfile(extensions, e.profile.extensionsResource!); } else { - const oldExtensions = await super.getInstalled(ExtensionType.User, previousExtensionsResource); const newExtensions = await this.getInstalled(ExtensionType.User); const { added, removed } = delta(oldExtensions, newExtensions, (a, b) => compare(`${ExtensionIdentifier.toKey(a.identifier.id)}@${a.manifest.version}`, `${ExtensionIdentifier.toKey(b.identifier.id)}@${b.manifest.version}`)); if (added.length || removed.length) { From 1f0412e3fcb6ace207fe6e4b70349f6e7bc0596d Mon Sep 17 00:00:00 2001 From: Logan Ramos Date: Wed, 6 Jul 2022 13:03:40 -0400 Subject: [PATCH 292/347] Update distro (#154283) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0c567bb015c..360a56bd26f 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.69.0", - "distro": "daf000367ee34d716c5dbdf836b11c06c407ef5f", + "distro": "7b212b70427becfe3691f683d7c7e7225cae9665", "author": { "name": "Microsoft Corporation" }, From 7fb7b795f6ef1f19d57a969b8dc131b1639e2c04 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 6 Jul 2022 10:04:47 -0700 Subject: [PATCH 293/347] Update xterm Fixes #152300 Fixes #151225 --- package.json | 10 +++++----- remote/package.json | 10 +++++----- remote/web/package.json | 6 +++--- remote/web/yarn.lock | 24 ++++++++++++------------ remote/yarn.lock | 40 ++++++++++++++++++++-------------------- yarn.lock | 40 ++++++++++++++++++++-------------------- 6 files changed, 65 insertions(+), 65 deletions(-) diff --git a/package.json b/package.json index 0c567bb015c..03516aa49db 100644 --- a/package.json +++ b/package.json @@ -87,12 +87,12 @@ "vscode-proxy-agent": "^0.12.0", "vscode-regexpp": "^3.1.0", "vscode-textmate": "7.0.1", - "xterm": "4.19.0", - "xterm-addon-search": "0.9.0", - "xterm-addon-serialize": "0.7.0", + "xterm": "4.20.0-beta.5", + "xterm-addon-search": "0.10.0-beta.1", + "xterm-addon-serialize": "0.8.0-beta.1", "xterm-addon-unicode11": "0.4.0-beta.3", - "xterm-addon-webgl": "0.12.0", - "xterm-headless": "4.19.0", + "xterm-addon-webgl": "0.13.0-beta.2", + "xterm-headless": "4.20.0-beta.5", "yauzl": "^2.9.2", "yazl": "^2.4.3" }, diff --git a/remote/package.json b/remote/package.json index d9300a7cb68..6accf3d3154 100644 --- a/remote/package.json +++ b/remote/package.json @@ -26,12 +26,12 @@ "vscode-proxy-agent": "^0.12.0", "vscode-regexpp": "^3.1.0", "vscode-textmate": "7.0.1", - "xterm": "4.19.0", - "xterm-addon-search": "0.9.0", - "xterm-addon-serialize": "0.7.0", + "xterm": "4.20.0-beta.5", + "xterm-addon-search": "0.10.0-beta.1", + "xterm-addon-serialize": "0.8.0-beta.1", "xterm-addon-unicode11": "0.4.0-beta.3", - "xterm-addon-webgl": "0.12.0", - "xterm-headless": "4.19.0", + "xterm-addon-webgl": "0.13.0-beta.2", + "xterm-headless": "4.20.0-beta.5", "yauzl": "^2.9.2", "yazl": "^2.4.3" }, diff --git a/remote/web/package.json b/remote/web/package.json index d73ebade4f4..514de33e21c 100644 --- a/remote/web/package.json +++ b/remote/web/package.json @@ -12,9 +12,9 @@ "tas-client-umd": "0.1.6", "vscode-oniguruma": "1.6.1", "vscode-textmate": "7.0.1", - "xterm": "4.19.0", - "xterm-addon-search": "0.9.0", + "xterm": "4.20.0-beta.5", + "xterm-addon-search": "0.10.0-beta.1", "xterm-addon-unicode11": "0.4.0-beta.3", - "xterm-addon-webgl": "0.12.0" + "xterm-addon-webgl": "0.13.0-beta.2" } } diff --git a/remote/web/yarn.lock b/remote/web/yarn.lock index 3f341e728fa..275fa0853ef 100644 --- a/remote/web/yarn.lock +++ b/remote/web/yarn.lock @@ -131,22 +131,22 @@ vscode-textmate@7.0.1: resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-7.0.1.tgz#8118a32b02735dccd14f893b495fa5389ad7de79" integrity sha512-zQ5U/nuXAAMsh691FtV0wPz89nSkHbs+IQV8FDk+wew9BlSDhf4UmWGlWJfTR2Ti6xZv87Tj5fENzKf6Qk7aLw== -xterm-addon-search@0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.9.0.tgz#95278ebb818cfcf882209ae75be96e0bea5d52a5" - integrity sha512-aoolI8YuHvdGw+Qjg8g2M4kst0v86GtB7WeBm4F0jNXA005/6QbWWy9eCsvnIDLJOFI5JSSrZnD6CaOkvBQYPA== +xterm-addon-search@0.10.0-beta.1: + version "0.10.0-beta.1" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.10.0-beta.1.tgz#ee15b954b6f78585cd3a212ec662018263470266" + integrity sha512-rp68SwoYHIQ1SY4MoILNK+0HcN8OR4hzczHOYCFdeKYZFvH/16vgqg0OJT6t6WlL1cq971rLsEDXT1SKcpoJqA== xterm-addon-unicode11@0.4.0-beta.3: version "0.4.0-beta.3" resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.4.0-beta.3.tgz#f350184155fafd5ad0d6fbf31d13e6ca7dea1efa" integrity sha512-FryZAVwbUjKTmwXnm1trch/2XO60F5JsDvOkZhzobV1hm10sFLVuZpFyHXiUx7TFeeFsvNP+S77LAtWoeT5z+Q== -xterm-addon-webgl@0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.12.0.tgz#2fba8d31890a122adafa1c2fb945482e2ae12973" - integrity sha512-3P5ihdjPnxH6Wrvqjki9UD+duoVrp1fvnO/pSpXP2F1L2GwY6TDNExgj8Yg141vMCNgQbcVqmsTLYEYZxjY92A== +xterm-addon-webgl@0.13.0-beta.2: + version "0.13.0-beta.2" + resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.13.0-beta.2.tgz#f58a7a3641ad7c8ac82dd24cfb0165656ed9ac1c" + integrity sha512-98tX0BkpD402RoCO6SyikUXpzCn9/OQhlXsRmM/kRFCxMWWofStWTXzCPhN0MjIx2IdGueDjCmnShhidwihErg== -xterm@4.19.0: - version "4.19.0" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.19.0.tgz#c0f9d09cd61de1d658f43ca75f992197add9ef6d" - integrity sha512-c3Cp4eOVsYY5Q839dR5IejghRPpxciGmLWWaP9g+ppfMeBChMeLa1DCA+pmX/jyDZ+zxFOmlJL/82qVdayVoGQ== +xterm@4.20.0-beta.5: + version "4.20.0-beta.5" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.20.0-beta.5.tgz#d707b0dcb477a554135fb767b24003fced079866" + integrity sha512-KBWfk9UPBKRy662DVGGTZEcW1becEjYvlyWbn2hLj9h2gy6Q4EEEEbggJh8I7SGwdFizl+apHQGhEOZmFCA70w== diff --git a/remote/yarn.lock b/remote/yarn.lock index 8efe31b7992..3d2078713be 100644 --- a/remote/yarn.lock +++ b/remote/yarn.lock @@ -932,35 +932,35 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= -xterm-addon-search@0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.9.0.tgz#95278ebb818cfcf882209ae75be96e0bea5d52a5" - integrity sha512-aoolI8YuHvdGw+Qjg8g2M4kst0v86GtB7WeBm4F0jNXA005/6QbWWy9eCsvnIDLJOFI5JSSrZnD6CaOkvBQYPA== +xterm-addon-search@0.10.0-beta.1: + version "0.10.0-beta.1" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.10.0-beta.1.tgz#ee15b954b6f78585cd3a212ec662018263470266" + integrity sha512-rp68SwoYHIQ1SY4MoILNK+0HcN8OR4hzczHOYCFdeKYZFvH/16vgqg0OJT6t6WlL1cq971rLsEDXT1SKcpoJqA== -xterm-addon-serialize@0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.7.0.tgz#cc7ef78972c8425b81dd6ae0a76824ce033d1e5f" - integrity sha512-ZfZ4Zj4uTEBFnUA0exipDGZ14jfiWLCov7gIt2OwIjQEz2ey8ic5kL/cxYz5antNz8/hTSA2qZcyA6VyyQASOQ== +xterm-addon-serialize@0.8.0-beta.1: + version "0.8.0-beta.1" + resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.8.0-beta.1.tgz#d1496da20006afa81874a717e3a0f75fc71dc87a" + integrity sha512-CfS0do/GM8e3k0+3O6GNDi4Gbhhkx1ne1nnnkILWQaAmlArLySEL8f0uPR0W72AtlLEFwVF8kABbVTjKc5XUcA== xterm-addon-unicode11@0.4.0-beta.3: version "0.4.0-beta.3" resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.4.0-beta.3.tgz#f350184155fafd5ad0d6fbf31d13e6ca7dea1efa" integrity sha512-FryZAVwbUjKTmwXnm1trch/2XO60F5JsDvOkZhzobV1hm10sFLVuZpFyHXiUx7TFeeFsvNP+S77LAtWoeT5z+Q== -xterm-addon-webgl@0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.12.0.tgz#2fba8d31890a122adafa1c2fb945482e2ae12973" - integrity sha512-3P5ihdjPnxH6Wrvqjki9UD+duoVrp1fvnO/pSpXP2F1L2GwY6TDNExgj8Yg141vMCNgQbcVqmsTLYEYZxjY92A== +xterm-addon-webgl@0.13.0-beta.2: + version "0.13.0-beta.2" + resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.13.0-beta.2.tgz#f58a7a3641ad7c8ac82dd24cfb0165656ed9ac1c" + integrity sha512-98tX0BkpD402RoCO6SyikUXpzCn9/OQhlXsRmM/kRFCxMWWofStWTXzCPhN0MjIx2IdGueDjCmnShhidwihErg== -xterm-headless@4.19.0: - version "4.19.0" - resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-4.19.0.tgz#965eb293fe6258adff5888f24e2a0b778b765e17" - integrity sha512-rYP8I1AGwaztpCoWe9mwxNqmfz7zZCjbzw61QChFqPeiDERjW9CDnqyGhSElvicHAlf47dvA+p4qOuKltxWEkg== +xterm-headless@4.20.0-beta.5: + version "4.20.0-beta.5" + resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-4.20.0-beta.5.tgz#edcff27eb6437d158e6aea2ed7658e783bee5641" + integrity sha512-8SnVUsuNUrQ5P0XU/9Iau3uK7Tf8q/p0KHHwkwJXVxZDIlaDH9XKSs91U9BjJJE3sJgRxH4NSiDYR3vFLSFpxw== -xterm@4.19.0: - version "4.19.0" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.19.0.tgz#c0f9d09cd61de1d658f43ca75f992197add9ef6d" - integrity sha512-c3Cp4eOVsYY5Q839dR5IejghRPpxciGmLWWaP9g+ppfMeBChMeLa1DCA+pmX/jyDZ+zxFOmlJL/82qVdayVoGQ== +xterm@4.20.0-beta.5: + version "4.20.0-beta.5" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.20.0-beta.5.tgz#d707b0dcb477a554135fb767b24003fced079866" + integrity sha512-KBWfk9UPBKRy662DVGGTZEcW1becEjYvlyWbn2hLj9h2gy6Q4EEEEbggJh8I7SGwdFizl+apHQGhEOZmFCA70w== yallist@^4.0.0: version "4.0.0" diff --git a/yarn.lock b/yarn.lock index 714f0424253..919a8b26019 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12256,35 +12256,35 @@ xtend@~2.1.1: dependencies: object-keys "~0.4.0" -xterm-addon-search@0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.9.0.tgz#95278ebb818cfcf882209ae75be96e0bea5d52a5" - integrity sha512-aoolI8YuHvdGw+Qjg8g2M4kst0v86GtB7WeBm4F0jNXA005/6QbWWy9eCsvnIDLJOFI5JSSrZnD6CaOkvBQYPA== +xterm-addon-search@0.10.0-beta.1: + version "0.10.0-beta.1" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.10.0-beta.1.tgz#ee15b954b6f78585cd3a212ec662018263470266" + integrity sha512-rp68SwoYHIQ1SY4MoILNK+0HcN8OR4hzczHOYCFdeKYZFvH/16vgqg0OJT6t6WlL1cq971rLsEDXT1SKcpoJqA== -xterm-addon-serialize@0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.7.0.tgz#cc7ef78972c8425b81dd6ae0a76824ce033d1e5f" - integrity sha512-ZfZ4Zj4uTEBFnUA0exipDGZ14jfiWLCov7gIt2OwIjQEz2ey8ic5kL/cxYz5antNz8/hTSA2qZcyA6VyyQASOQ== +xterm-addon-serialize@0.8.0-beta.1: + version "0.8.0-beta.1" + resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.8.0-beta.1.tgz#d1496da20006afa81874a717e3a0f75fc71dc87a" + integrity sha512-CfS0do/GM8e3k0+3O6GNDi4Gbhhkx1ne1nnnkILWQaAmlArLySEL8f0uPR0W72AtlLEFwVF8kABbVTjKc5XUcA== xterm-addon-unicode11@0.4.0-beta.3: version "0.4.0-beta.3" resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.4.0-beta.3.tgz#f350184155fafd5ad0d6fbf31d13e6ca7dea1efa" integrity sha512-FryZAVwbUjKTmwXnm1trch/2XO60F5JsDvOkZhzobV1hm10sFLVuZpFyHXiUx7TFeeFsvNP+S77LAtWoeT5z+Q== -xterm-addon-webgl@0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.12.0.tgz#2fba8d31890a122adafa1c2fb945482e2ae12973" - integrity sha512-3P5ihdjPnxH6Wrvqjki9UD+duoVrp1fvnO/pSpXP2F1L2GwY6TDNExgj8Yg141vMCNgQbcVqmsTLYEYZxjY92A== +xterm-addon-webgl@0.13.0-beta.2: + version "0.13.0-beta.2" + resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.13.0-beta.2.tgz#f58a7a3641ad7c8ac82dd24cfb0165656ed9ac1c" + integrity sha512-98tX0BkpD402RoCO6SyikUXpzCn9/OQhlXsRmM/kRFCxMWWofStWTXzCPhN0MjIx2IdGueDjCmnShhidwihErg== -xterm-headless@4.19.0: - version "4.19.0" - resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-4.19.0.tgz#965eb293fe6258adff5888f24e2a0b778b765e17" - integrity sha512-rYP8I1AGwaztpCoWe9mwxNqmfz7zZCjbzw61QChFqPeiDERjW9CDnqyGhSElvicHAlf47dvA+p4qOuKltxWEkg== +xterm-headless@4.20.0-beta.5: + version "4.20.0-beta.5" + resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-4.20.0-beta.5.tgz#edcff27eb6437d158e6aea2ed7658e783bee5641" + integrity sha512-8SnVUsuNUrQ5P0XU/9Iau3uK7Tf8q/p0KHHwkwJXVxZDIlaDH9XKSs91U9BjJJE3sJgRxH4NSiDYR3vFLSFpxw== -xterm@4.19.0: - version "4.19.0" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.19.0.tgz#c0f9d09cd61de1d658f43ca75f992197add9ef6d" - integrity sha512-c3Cp4eOVsYY5Q839dR5IejghRPpxciGmLWWaP9g+ppfMeBChMeLa1DCA+pmX/jyDZ+zxFOmlJL/82qVdayVoGQ== +xterm@4.20.0-beta.5: + version "4.20.0-beta.5" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.20.0-beta.5.tgz#d707b0dcb477a554135fb767b24003fced079866" + integrity sha512-KBWfk9UPBKRy662DVGGTZEcW1becEjYvlyWbn2hLj9h2gy6Q4EEEEbggJh8I7SGwdFizl+apHQGhEOZmFCA70w== y18n@^3.2.1: version "3.2.2" From 04d9921d07e1e6145dbbed4303a33479a16d0558 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 6 Jul 2022 10:38:38 -0700 Subject: [PATCH 294/347] Add separators to command decoration menu Part of #153382 --- .../terminal/browser/xterm/decorationAddon.ts | 36 ++++++++++++------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/xterm/decorationAddon.ts b/src/vs/workbench/contrib/terminal/browser/xterm/decorationAddon.ts index 0d033529f59..d3284f43a86 100644 --- a/src/vs/workbench/contrib/terminal/browser/xterm/decorationAddon.ts +++ b/src/vs/workbench/contrib/terminal/browser/xterm/decorationAddon.ts @@ -12,7 +12,7 @@ import { CommandInvalidationReason, ITerminalCapabilityStore, TerminalCapability import { IColorTheme, ICssStyleCollector, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IHoverService } from 'vs/workbench/services/hover/browser/hover'; -import { IAction } from 'vs/base/common/actions'; +import { IAction, Separator } from 'vs/base/common/actions'; import { Emitter } from 'vs/base/common/event'; import { MarkdownString } from 'vs/base/common/htmlContent'; import { localize } from 'vs/nls'; @@ -353,24 +353,34 @@ export class DecorationAddon extends Disposable implements ITerminalAddon { private async _getCommandActions(command: ITerminalCommand): Promise { const actions: IAction[] = []; - if (command.hasOutput) { - actions.push({ - class: 'copy-output', tooltip: 'Copy Output', dispose: () => { }, id: 'terminal.copyOutput', label: localize("terminal.copyOutput", 'Copy Output'), enabled: true, - run: () => this._clipboardService.writeText(command.getOutput()!) - }); - actions.push({ - class: 'copy-output', tooltip: 'Copy Output as HTML', dispose: () => { }, id: 'terminal.copyOutputAsHtml', label: localize("terminal.copyOutputAsHtml", 'Copy Output as HTML'), enabled: true, - run: () => this._onDidRequestRunCommand.fire({ command, copyAsHtml: true }) - }); - } if (command.command !== '') { + const label = localize("terminal.rerunCommand", 'Rerun Command'); actions.push({ - class: 'rerun-command', tooltip: 'Rerun Command', dispose: () => { }, id: 'terminal.rerunCommand', label: localize("terminal.rerunCommand", 'Rerun Command'), enabled: true, + class: undefined, tooltip: label, dispose: () => { }, id: 'terminal.rerunCommand', label, enabled: true, run: () => this._onDidRequestRunCommand.fire({ command }) }); } + if (command.hasOutput) { + if (actions.length > 0) { + actions.push(new Separator()); + } + const labelText = localize("terminal.copyOutput", 'Copy Output'); + actions.push({ + class: undefined, tooltip: labelText, dispose: () => { }, id: 'terminal.copyOutput', label: labelText, enabled: true, + run: () => this._clipboardService.writeText(command.getOutput()!) + }); + const labelHtml = localize("terminal.copyOutputAsHtml", 'Copy Output as HTML'); + actions.push({ + class: undefined, tooltip: labelHtml, dispose: () => { }, id: 'terminal.copyOutputAsHtml', label: labelHtml, enabled: true, + run: () => this._onDidRequestRunCommand.fire({ command, copyAsHtml: true }) + }); + } + if (actions.length > 0) { + actions.push(new Separator()); + } + const label = localize("terminal.learnShellIntegration", 'Learn About Shell Integration'); actions.push({ - class: 'how-does-this-work', tooltip: 'How does this work?', dispose: () => { }, id: 'terminal.howDoesThisWork', label: localize("terminal.howDoesThisWork", 'How does this work?'), enabled: true, + class: undefined, tooltip: label, dispose: () => { }, id: 'terminal.learnShellIntegration', label, enabled: true, run: () => this._openerService.open('https://code.visualstudio.com/docs/editor/integrated-terminal#_shell-integration') }); return actions; From 891fa893646795ec4995dc29f7c8ad76efbca312 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 6 Jul 2022 10:41:54 -0700 Subject: [PATCH 295/347] Add copy command to command decoration menu Fixes #153382 --- .../contrib/terminal/browser/xterm/decorationAddon.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/xterm/decorationAddon.ts b/src/vs/workbench/contrib/terminal/browser/xterm/decorationAddon.ts index d3284f43a86..e7e3137ae30 100644 --- a/src/vs/workbench/contrib/terminal/browser/xterm/decorationAddon.ts +++ b/src/vs/workbench/contrib/terminal/browser/xterm/decorationAddon.ts @@ -354,11 +354,16 @@ export class DecorationAddon extends Disposable implements ITerminalAddon { private async _getCommandActions(command: ITerminalCommand): Promise { const actions: IAction[] = []; if (command.command !== '') { - const label = localize("terminal.rerunCommand", 'Rerun Command'); + const labelRun = localize("terminal.rerunCommand", 'Rerun Command'); actions.push({ - class: undefined, tooltip: label, dispose: () => { }, id: 'terminal.rerunCommand', label, enabled: true, + class: undefined, tooltip: labelRun, dispose: () => { }, id: 'terminal.rerunCommand', label: labelRun, enabled: true, run: () => this._onDidRequestRunCommand.fire({ command }) }); + const labelCopy = localize("terminal.copyCommand", 'Copy Command'); + actions.push({ + class: undefined, tooltip: labelCopy, dispose: () => { }, id: 'terminal.copyCommand', label: labelCopy, enabled: true, + run: () => this._clipboardService.writeText(command.command) + }); } if (command.hasOutput) { if (actions.length > 0) { From 877f2c3bd0fbc29c701813f57e529e947a1b4d28 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Tue, 5 Jul 2022 11:32:21 -0700 Subject: [PATCH 296/347] testing: don't make testing a workspace view For #153513 --- src/vs/workbench/contrib/testing/browser/testing.contribution.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/vs/workbench/contrib/testing/browser/testing.contribution.ts b/src/vs/workbench/contrib/testing/browser/testing.contribution.ts index 3605c75ec80..f6580294960 100644 --- a/src/vs/workbench/contrib/testing/browser/testing.contribution.ts +++ b/src/vs/workbench/contrib/testing/browser/testing.contribution.ts @@ -87,7 +87,6 @@ viewsRegistry.registerViews([{ name: localize('testExplorer', "Test Explorer"), ctorDescriptor: new SyncDescriptor(TestingExplorerView), canToggleVisibility: true, - workspace: true, canMoveView: true, weight: 80, order: -999, From d88ab38f1b028f514e0c38a30222014d1a64dd53 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Tue, 5 Jul 2022 11:33:43 -0700 Subject: [PATCH 297/347] npm: remove icon from localization For #153743 --- extensions/npm/src/npmScriptLens.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/npm/src/npmScriptLens.ts b/extensions/npm/src/npmScriptLens.ts index 067209da334..2834d3e7639 100644 --- a/extensions/npm/src/npmScriptLens.ts +++ b/extensions/npm/src/npmScriptLens.ts @@ -71,7 +71,7 @@ export class NpmScriptLensProvider implements CodeLensProvider, Disposable { return []; } - const title = localize('codelens.debug', '{0} Debug', '$(debug-start)'); + const title = '$(debug-start) ' + localize('codelens.debug', 'Debug'); const cwd = path.dirname(document.uri.fsPath); if (this.lensLocation === 'top') { return [ From 87635892d81b2eb255fc412927f0ec48e6aef421 Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Tue, 5 Jul 2022 12:08:42 -0700 Subject: [PATCH 298/347] debug/testing: fixup localized commands For #153865 --- .../contrib/debug/browser/callStackView.ts | 4 +- .../debug/browser/debug.contribution.ts | 29 ++++++------ .../contrib/debug/browser/debugCommands.ts | 37 +++++++-------- .../contrib/debug/browser/debugToolBar.ts | 4 +- .../testing/browser/testExplorerActions.ts | 46 +++++++++---------- .../testing/browser/testingExplorerFilter.ts | 2 +- .../testing/browser/testingOutputPeek.ts | 8 ++-- 7 files changed, 66 insertions(+), 64 deletions(-) diff --git a/src/vs/workbench/contrib/debug/browser/callStackView.ts b/src/vs/workbench/contrib/debug/browser/callStackView.ts index 2eb3d65a818..b97d040674f 100644 --- a/src/vs/workbench/contrib/debug/browser/callStackView.ts +++ b/src/vs/workbench/contrib/debug/browser/callStackView.ts @@ -21,7 +21,7 @@ import { DisposableStore, dispose, IDisposable } from 'vs/base/common/lifecycle' import { posix } from 'vs/base/common/path'; import { commonSuffixLength } from 'vs/base/common/strings'; import { localize } from 'vs/nls'; -import { Icon } from 'vs/platform/action/common/action'; +import { ICommandActionTitle, Icon } from 'vs/platform/action/common/action'; import { createAndFillInActionBarActions, createAndFillInContextMenuActions, MenuEntryActionViewItem, SubmenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem'; import { IMenuService, MenuId, MenuItemAction, MenuRegistry, registerAction2, SubmenuItemAction } from 'vs/platform/actions/common/actions'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -1120,7 +1120,7 @@ registerAction2(class Collapse extends ViewAction { } }); -function registerCallStackInlineMenuItem(id: string, title: string, icon: Icon, when: ContextKeyExpression, order: number, precondition?: ContextKeyExpression): void { +function registerCallStackInlineMenuItem(id: string, title: string | ICommandActionTitle, icon: Icon, when: ContextKeyExpression, order: number, precondition?: ContextKeyExpression): void { MenuRegistry.appendMenuItem(MenuId.DebugCallStackContext, { group: 'inline', order, diff --git a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts index 11584519c47..bebcecd9455 100644 --- a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts +++ b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts @@ -20,7 +20,7 @@ import { } from 'vs/workbench/contrib/debug/common/debug'; import { DebugToolBar } from 'vs/workbench/contrib/debug/browser/debugToolBar'; import { DebugService } from 'vs/workbench/contrib/debug/browser/debugService'; -import { ADD_CONFIGURATION_ID, TOGGLE_INLINE_BREAKPOINT_ID, COPY_STACK_TRACE_ID, RESTART_SESSION_ID, TERMINATE_THREAD_ID, STEP_OVER_ID, STEP_INTO_ID, STEP_OUT_ID, PAUSE_ID, DISCONNECT_ID, STOP_ID, RESTART_FRAME_ID, CONTINUE_ID, FOCUS_REPL_ID, JUMP_TO_CURSOR_ID, RESTART_LABEL, STEP_INTO_LABEL, STEP_OVER_LABEL, STEP_OUT_LABEL, PAUSE_LABEL, DISCONNECT_LABEL, STOP_LABEL, CONTINUE_LABEL, DEBUG_START_LABEL, DEBUG_START_COMMAND_ID, DEBUG_RUN_LABEL, DEBUG_RUN_COMMAND_ID, EDIT_EXPRESSION_COMMAND_ID, REMOVE_EXPRESSION_COMMAND_ID, SELECT_AND_START_ID, SELECT_AND_START_LABEL, SET_EXPRESSION_COMMAND_ID, DISCONNECT_AND_SUSPEND_ID, DISCONNECT_AND_SUSPEND_LABEL, NEXT_DEBUG_CONSOLE_ID, NEXT_DEBUG_CONSOLE_LABEL, PREV_DEBUG_CONSOLE_ID, PREV_DEBUG_CONSOLE_LABEL, OPEN_LOADED_SCRIPTS_LABEL, SHOW_LOADED_SCRIPTS_ID, DEBUG_QUICK_ACCESS_PREFIX, DEBUG_CONSOLE_QUICK_ACCESS_PREFIX, SELECT_DEBUG_CONSOLE_ID, SELECT_DEBUG_CONSOLE_LABEL, STEP_INTO_TARGET_LABEL, STEP_INTO_TARGET_ID } from 'vs/workbench/contrib/debug/browser/debugCommands'; +import { ADD_CONFIGURATION_ID, TOGGLE_INLINE_BREAKPOINT_ID, COPY_STACK_TRACE_ID, RESTART_SESSION_ID, TERMINATE_THREAD_ID, STEP_OVER_ID, STEP_INTO_ID, STEP_OUT_ID, PAUSE_ID, DISCONNECT_ID, STOP_ID, RESTART_FRAME_ID, CONTINUE_ID, FOCUS_REPL_ID, JUMP_TO_CURSOR_ID, RESTART_LABEL, STEP_INTO_LABEL, STEP_OVER_LABEL, STEP_OUT_LABEL, PAUSE_LABEL, DISCONNECT_LABEL, STOP_LABEL, CONTINUE_LABEL, DEBUG_START_LABEL, DEBUG_START_COMMAND_ID, DEBUG_RUN_LABEL, DEBUG_RUN_COMMAND_ID, EDIT_EXPRESSION_COMMAND_ID, REMOVE_EXPRESSION_COMMAND_ID, SELECT_AND_START_ID, SELECT_AND_START_LABEL, SET_EXPRESSION_COMMAND_ID, DISCONNECT_AND_SUSPEND_ID, DISCONNECT_AND_SUSPEND_LABEL, NEXT_DEBUG_CONSOLE_ID, NEXT_DEBUG_CONSOLE_LABEL, PREV_DEBUG_CONSOLE_ID, PREV_DEBUG_CONSOLE_LABEL, OPEN_LOADED_SCRIPTS_LABEL, SHOW_LOADED_SCRIPTS_ID, DEBUG_QUICK_ACCESS_PREFIX, DEBUG_CONSOLE_QUICK_ACCESS_PREFIX, SELECT_DEBUG_CONSOLE_ID, SELECT_DEBUG_CONSOLE_LABEL, STEP_INTO_TARGET_LABEL, STEP_INTO_TARGET_ID, DEBUG_COMMAND_CATEGORY } from 'vs/workbench/contrib/debug/browser/debugCommands'; import { StatusBarColorProvider } from 'vs/workbench/contrib/debug/browser/statusbarColorProvider'; import { IViewsRegistry, Extensions as ViewExtensions, IViewContainersRegistry, ViewContainerLocation, ViewContainer } from 'vs/workbench/common/views'; import { isMacintosh, isWeb } from 'vs/base/common/platform'; @@ -55,7 +55,7 @@ import { DisassemblyView, DisassemblyViewContribution } from 'vs/workbench/contr import { EditorPaneDescriptor, IEditorPaneRegistry } from 'vs/workbench/browser/editor'; import { DisassemblyViewInput } from 'vs/workbench/contrib/debug/common/disassemblyViewInput'; import { DebugLifecycle } from 'vs/workbench/contrib/debug/common/debugLifecycle'; -import { Icon } from 'vs/platform/action/common/action'; +import { ICommandActionTitle, Icon } from 'vs/platform/action/common/action'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { DebugConsoleQuickAccess } from 'vs/workbench/contrib/debug/browser/debugConsoleQuickAccess'; @@ -98,20 +98,21 @@ registerEditorContribution('editor.contrib.callStack', CallStackEditorContributi registerEditorContribution(BREAKPOINT_EDITOR_CONTRIBUTION_ID, BreakpointEditorContribution); registerEditorContribution(EDITOR_CONTRIBUTION_ID, DebugEditorContribution); -const registerDebugCommandPaletteItem = (id: string, title: string, when?: ContextKeyExpression, precondition?: ContextKeyExpression) => { +const registerDebugCommandPaletteItem = (id: string, title: ICommandActionTitle, when?: ContextKeyExpression, precondition?: ContextKeyExpression) => { MenuRegistry.appendMenuItem(MenuId.CommandPalette, { when: ContextKeyExpr.and(CONTEXT_DEBUGGERS_AVAILABLE, when), group: debugCategory, command: { id, - title: `Debug: ${title}`, + title, + category: DEBUG_COMMAND_CATEGORY, precondition } }); }; registerDebugCommandPaletteItem(RESTART_SESSION_ID, RESTART_LABEL); -registerDebugCommandPaletteItem(TERMINATE_THREAD_ID, nls.localize('terminateThread', "Terminate Thread"), CONTEXT_IN_DEBUG_MODE); +registerDebugCommandPaletteItem(TERMINATE_THREAD_ID, { value: nls.localize('terminateThread', "Terminate Thread"), original: 'Terminate Thread' }, CONTEXT_IN_DEBUG_MODE); registerDebugCommandPaletteItem(STEP_OVER_ID, STEP_OVER_LABEL, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); registerDebugCommandPaletteItem(STEP_INTO_ID, STEP_INTO_LABEL, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); registerDebugCommandPaletteItem(STEP_INTO_TARGET_ID, STEP_INTO_TARGET_LABEL, CONTEXT_IN_DEBUG_MODE, ContextKeyExpr.and(CONTEXT_STEP_INTO_TARGETS_SUPPORTED, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped'))); @@ -121,13 +122,13 @@ registerDebugCommandPaletteItem(DISCONNECT_ID, DISCONNECT_LABEL, CONTEXT_IN_DEBU registerDebugCommandPaletteItem(DISCONNECT_AND_SUSPEND_ID, DISCONNECT_AND_SUSPEND_LABEL, CONTEXT_IN_DEBUG_MODE, ContextKeyExpr.or(CONTEXT_FOCUSED_SESSION_IS_ATTACH, ContextKeyExpr.and(CONTEXT_SUSPEND_DEBUGGEE_SUPPORTED, CONTEXT_TERMINATE_DEBUGGEE_SUPPORTED))); registerDebugCommandPaletteItem(STOP_ID, STOP_LABEL, CONTEXT_IN_DEBUG_MODE, ContextKeyExpr.or(CONTEXT_FOCUSED_SESSION_IS_ATTACH.toNegated(), CONTEXT_TERMINATE_DEBUGGEE_SUPPORTED)); registerDebugCommandPaletteItem(CONTINUE_ID, CONTINUE_LABEL, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); -registerDebugCommandPaletteItem(FOCUS_REPL_ID, nls.localize({ comment: ['Debug is a noun in this context, not a verb.'], key: 'debugFocusConsole' }, 'Focus on Debug Console View')); -registerDebugCommandPaletteItem(JUMP_TO_CURSOR_ID, nls.localize('jumpToCursor', "Jump to Cursor"), CONTEXT_JUMP_TO_CURSOR_SUPPORTED); -registerDebugCommandPaletteItem(JUMP_TO_CURSOR_ID, nls.localize('SetNextStatement', "Set Next Statement"), CONTEXT_JUMP_TO_CURSOR_SUPPORTED); -registerDebugCommandPaletteItem(RunToCursorAction.ID, RunToCursorAction.LABEL, ContextKeyExpr.and(CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped'))); -registerDebugCommandPaletteItem(SelectionToReplAction.ID, SelectionToReplAction.LABEL, ContextKeyExpr.and(EditorContextKeys.hasNonEmptySelection, CONTEXT_IN_DEBUG_MODE)); -registerDebugCommandPaletteItem(SelectionToWatchExpressionsAction.ID, SelectionToWatchExpressionsAction.LABEL, ContextKeyExpr.and(EditorContextKeys.hasNonEmptySelection, CONTEXT_IN_DEBUG_MODE)); -registerDebugCommandPaletteItem(TOGGLE_INLINE_BREAKPOINT_ID, nls.localize('inlineBreakpoint', "Inline Breakpoint")); +registerDebugCommandPaletteItem(FOCUS_REPL_ID, { value: nls.localize({ comment: ['Debug is a noun in this context, not a verb.'], key: 'debugFocusConsole' }, 'Focus on Debug Console View'), original: 'Focus on Debug Console View' }); +registerDebugCommandPaletteItem(JUMP_TO_CURSOR_ID, { value: nls.localize('jumpToCursor', "Jump to Cursor"), original: 'Jump to Cursor' }, CONTEXT_JUMP_TO_CURSOR_SUPPORTED); +registerDebugCommandPaletteItem(JUMP_TO_CURSOR_ID, { value: nls.localize('SetNextStatement', "Set Next Statement"), original: 'Set Next Statement' }, CONTEXT_JUMP_TO_CURSOR_SUPPORTED); +registerDebugCommandPaletteItem(RunToCursorAction.ID, { value: RunToCursorAction.LABEL, original: 'Run to Cursor' }, ContextKeyExpr.and(CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped'))); +registerDebugCommandPaletteItem(SelectionToReplAction.ID, { value: SelectionToReplAction.LABEL, original: 'Evaluate in Debug Console' }, ContextKeyExpr.and(EditorContextKeys.hasNonEmptySelection, CONTEXT_IN_DEBUG_MODE)); +registerDebugCommandPaletteItem(SelectionToWatchExpressionsAction.ID, { value: SelectionToWatchExpressionsAction.LABEL, original: 'Add to Watch' }, ContextKeyExpr.and(EditorContextKeys.hasNonEmptySelection, CONTEXT_IN_DEBUG_MODE)); +registerDebugCommandPaletteItem(TOGGLE_INLINE_BREAKPOINT_ID, { value: nls.localize('inlineBreakpoint', "Inline Breakpoint"), original: 'Inline Breakpoint' }); registerDebugCommandPaletteItem(DEBUG_START_COMMAND_ID, DEBUG_START_LABEL, ContextKeyExpr.and(CONTEXT_DEBUGGERS_AVAILABLE, CONTEXT_DEBUG_STATE.notEqualsTo(getStateLabel(State.Initializing)))); registerDebugCommandPaletteItem(DEBUG_RUN_COMMAND_ID, DEBUG_RUN_LABEL, ContextKeyExpr.and(CONTEXT_DEBUGGERS_AVAILABLE, CONTEXT_DEBUG_STATE.notEqualsTo(getStateLabel(State.Initializing)))); registerDebugCommandPaletteItem(SELECT_AND_START_ID, SELECT_AND_START_LABEL, ContextKeyExpr.and(CONTEXT_DEBUGGERS_AVAILABLE, CONTEXT_DEBUG_STATE.notEqualsTo(getStateLabel(State.Initializing)))); @@ -138,7 +139,7 @@ registerDebugCommandPaletteItem(SELECT_DEBUG_CONSOLE_ID, SELECT_DEBUG_CONSOLE_LA // Debug callstack context menu -const registerDebugViewMenuItem = (menuId: MenuId, id: string, title: string, order: number, when?: ContextKeyExpression, precondition?: ContextKeyExpression, group = 'navigation', icon?: Icon) => { +const registerDebugViewMenuItem = (menuId: MenuId, id: string, title: string | ICommandActionTitle, order: number, when?: ContextKeyExpression, precondition?: ContextKeyExpression, group = 'navigation', icon?: Icon) => { MenuRegistry.appendMenuItem(menuId, { group, when, @@ -186,7 +187,7 @@ registerDebugViewMenuItem(MenuId.DebugWatchContext, REMOVE_WATCH_EXPRESSIONS_COM // Touch Bar if (isMacintosh) { - const registerTouchBarEntry = (id: string, title: string, order: number, when: ContextKeyExpression | undefined, iconUri: URI) => { + const registerTouchBarEntry = (id: string, title: string | ICommandActionTitle, order: number, when: ContextKeyExpression | undefined, iconUri: URI) => { MenuRegistry.appendMenuItem(MenuId.TouchBarContext, { command: { id, diff --git a/src/vs/workbench/contrib/debug/browser/debugCommands.ts b/src/vs/workbench/contrib/debug/browser/debugCommands.ts index 49eb8197d7a..86fa5b8c01b 100644 --- a/src/vs/workbench/contrib/debug/browser/debugCommands.ts +++ b/src/vs/workbench/contrib/debug/browser/debugCommands.ts @@ -65,26 +65,27 @@ export const NEXT_DEBUG_CONSOLE_ID = 'workbench.action.debug.nextConsole'; export const PREV_DEBUG_CONSOLE_ID = 'workbench.action.debug.prevConsole'; export const SHOW_LOADED_SCRIPTS_ID = 'workbench.action.debug.showLoadedScripts'; -export const RESTART_LABEL = nls.localize('restartDebug', "Restart"); -export const STEP_OVER_LABEL = nls.localize('stepOverDebug', "Step Over"); -export const STEP_INTO_LABEL = nls.localize('stepIntoDebug', "Step Into"); -export const STEP_INTO_TARGET_LABEL = nls.localize('stepIntoTargetDebug', "Step Into Target"); -export const STEP_OUT_LABEL = nls.localize('stepOutDebug', "Step Out"); -export const PAUSE_LABEL = nls.localize('pauseDebug', "Pause"); -export const DISCONNECT_LABEL = nls.localize('disconnect', "Disconnect"); -export const DISCONNECT_AND_SUSPEND_LABEL = nls.localize('disconnectSuspend', "Disconnect and Suspend"); -export const STOP_LABEL = nls.localize('stop', "Stop"); -export const CONTINUE_LABEL = nls.localize('continueDebug', "Continue"); -export const FOCUS_SESSION_LABEL = nls.localize('focusSession', "Focus Session"); -export const SELECT_AND_START_LABEL = nls.localize('selectAndStartDebugging', "Select and Start Debugging"); +export const DEBUG_COMMAND_CATEGORY = 'Debug'; +export const RESTART_LABEL = { value: nls.localize('restartDebug', "Restart"), original: 'Restart' }; +export const STEP_OVER_LABEL = { value: nls.localize('stepOverDebug', "Step Over"), original: 'Step Over' }; +export const STEP_INTO_LABEL = { value: nls.localize('stepIntoDebug', "Step Into"), original: 'Step Into' }; +export const STEP_INTO_TARGET_LABEL = { value: nls.localize('stepIntoTargetDebug', "Step Into Target"), original: 'Step Into Target' }; +export const STEP_OUT_LABEL = { value: nls.localize('stepOutDebug', "Step Out"), original: 'Step Out' }; +export const PAUSE_LABEL = { value: nls.localize('pauseDebug', "Pause"), original: 'Pause' }; +export const DISCONNECT_LABEL = { value: nls.localize('disconnect', "Disconnect"), original: 'Disconnect' }; +export const DISCONNECT_AND_SUSPEND_LABEL = { value: nls.localize('disconnectSuspend', "Disconnect and Suspend"), original: 'Disconnect and Suspend' }; +export const STOP_LABEL = { value: nls.localize('stop', "Stop"), original: 'Stop' }; +export const CONTINUE_LABEL = { value: nls.localize('continueDebug', "Continue"), original: 'Continue' }; +export const FOCUS_SESSION_LABEL = { value: nls.localize('focusSession', "Focus Session"), original: 'Focus Session' }; +export const SELECT_AND_START_LABEL = { value: nls.localize('selectAndStartDebugging', "Select and Start Debugging"), original: 'Select and Start Debugging' }; export const DEBUG_CONFIGURE_LABEL = nls.localize('openLaunchJson', "Open '{0}'", 'launch.json'); -export const DEBUG_START_LABEL = nls.localize('startDebug', "Start Debugging"); -export const DEBUG_RUN_LABEL = nls.localize('startWithoutDebugging', "Start Without Debugging"); -export const NEXT_DEBUG_CONSOLE_LABEL = nls.localize('nextDebugConsole', "Focus Next Debug Console"); -export const PREV_DEBUG_CONSOLE_LABEL = nls.localize('prevDebugConsole', "Focus Previous Debug Console"); -export const OPEN_LOADED_SCRIPTS_LABEL = nls.localize('openLoadedScript', "Open Loaded Script..."); +export const DEBUG_START_LABEL = { value: nls.localize('startDebug', "Start Debugging"), original: 'Start Debugging' }; +export const DEBUG_RUN_LABEL = { value: nls.localize('startWithoutDebugging', "Start Without Debugging"), original: 'Start Without Debugging' }; +export const NEXT_DEBUG_CONSOLE_LABEL = { value: nls.localize('nextDebugConsole', "Focus Next Debug Console"), original: 'Focus Next Debug Console' }; +export const PREV_DEBUG_CONSOLE_LABEL = { value: nls.localize('prevDebugConsole', "Focus Previous Debug Console"), original: 'Focus Previous Debug Console' }; +export const OPEN_LOADED_SCRIPTS_LABEL = { value: nls.localize('openLoadedScript', "Open Loaded Script..."), original: 'Open Loaded Script...' }; -export const SELECT_DEBUG_CONSOLE_LABEL = nls.localize('selectDebugConsole', "Select Debug Console"); +export const SELECT_DEBUG_CONSOLE_LABEL = { value: nls.localize('selectDebugConsole', "Select Debug Console"), original: 'Select Debug Console' }; export const DEBUG_QUICK_ACCESS_PREFIX = 'debug '; export const DEBUG_CONSOLE_QUICK_ACCESS_PREFIX = 'debug consoles '; diff --git a/src/vs/workbench/contrib/debug/browser/debugToolBar.ts b/src/vs/workbench/contrib/debug/browser/debugToolBar.ts index 1f7614bfee7..3fd1c0238b8 100644 --- a/src/vs/workbench/contrib/debug/browser/debugToolBar.ts +++ b/src/vs/workbench/contrib/debug/browser/debugToolBar.ts @@ -16,7 +16,7 @@ import { URI } from 'vs/base/common/uri'; import 'vs/css!./media/debugToolBar'; import { ServicesAccessor } from 'vs/editor/browser/editorExtensions'; import { localize } from 'vs/nls'; -import { ICommandAction } from 'vs/platform/action/common/action'; +import { ICommandAction, ICommandActionTitle } from 'vs/platform/action/common/action'; import { DropdownWithPrimaryActionViewItem } from 'vs/platform/actions/browser/dropdownWithPrimaryActionViewItem'; import { createActionViewItem, createAndFillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; import { IMenu, IMenuService, MenuId, MenuItemAction, MenuRegistry } from 'vs/platform/actions/common/actions'; @@ -296,7 +296,7 @@ export function createDisconnectMenuItemAction(action: MenuItemAction, disposabl // Debug toolbar const debugViewTitleItems: IDisposable[] = []; -const registerDebugToolBarItem = (id: string, title: string, order: number, icon?: { light?: URI; dark?: URI } | ThemeIcon, when?: ContextKeyExpression, precondition?: ContextKeyExpression, alt?: ICommandAction) => { +const registerDebugToolBarItem = (id: string, title: string | ICommandActionTitle, order: number, icon?: { light?: URI; dark?: URI } | ThemeIcon, when?: ContextKeyExpression, precondition?: ContextKeyExpression, alt?: ICommandAction) => { MenuRegistry.appendMenuItem(MenuId.DebugToolBar, { group: 'navigation', when, diff --git a/src/vs/workbench/contrib/testing/browser/testExplorerActions.ts b/src/vs/workbench/contrib/testing/browser/testExplorerActions.ts index db687ec08b6..556f7f4e65d 100644 --- a/src/vs/workbench/contrib/testing/browser/testExplorerActions.ts +++ b/src/vs/workbench/contrib/testing/browser/testExplorerActions.ts @@ -406,7 +406,7 @@ export class CancelTestRunAction extends Action2 { constructor() { super({ id: TestCommandId.CancelTestRunAction, - title: localize('testing.cancelRun', "Cancel Test Run"), + title: { value: localize('testing.cancelRun', "Cancel Test Run"), original: 'Cancel Test Run' }, icon: icons.testingCancelIcon, keybinding: { weight: KeybindingWeight.WorkbenchContrib, @@ -443,7 +443,7 @@ export class TestingViewAsListAction extends ViewAction { super({ id: TestCommandId.TestingViewAsListAction, viewId: Testing.ExplorerViewId, - title: localize('testing.viewAsList', "View as List"), + title: { value: localize('testing.viewAsList', "View as List"), original: 'View as List' }, toggled: TestingContextKeys.viewMode.isEqualTo(TestExplorerViewMode.List), menu: { id: MenuId.ViewTitle, @@ -467,7 +467,7 @@ export class TestingViewAsTreeAction extends ViewAction { super({ id: TestCommandId.TestingViewAsTreeAction, viewId: Testing.ExplorerViewId, - title: localize('testing.viewAsTree', "View as Tree"), + title: { value: localize('testing.viewAsTree', "View as Tree"), original: 'View as Tree' }, toggled: TestingContextKeys.viewMode.isEqualTo(TestExplorerViewMode.Tree), menu: { id: MenuId.ViewTitle, @@ -492,7 +492,7 @@ export class TestingSortByStatusAction extends ViewAction { super({ id: TestCommandId.TestingSortByStatusAction, viewId: Testing.ExplorerViewId, - title: localize('testing.sortByStatus', "Sort by Status"), + title: { value: localize('testing.sortByStatus', "Sort by Status"), original: 'Sort by Status' }, toggled: TestingContextKeys.viewSorting.isEqualTo(TestExplorerViewSorting.ByStatus), menu: { id: MenuId.ViewTitle, @@ -516,7 +516,7 @@ export class TestingSortByLocationAction extends ViewAction super({ id: TestCommandId.TestingSortByLocationAction, viewId: Testing.ExplorerViewId, - title: localize('testing.sortByLocation', "Sort by Location"), + title: { value: localize('testing.sortByLocation', "Sort by Location"), original: 'Sort by Location' }, toggled: TestingContextKeys.viewSorting.isEqualTo(TestExplorerViewSorting.ByLocation), menu: { id: MenuId.ViewTitle, @@ -540,7 +540,7 @@ export class TestingSortByDurationAction extends ViewAction super({ id: TestCommandId.TestingSortByDurationAction, viewId: Testing.ExplorerViewId, - title: localize('testing.sortByDuration', "Sort by Duration"), + title: { value: localize('testing.sortByDuration', "Sort by Duration"), original: 'Sort by Duration' }, toggled: TestingContextKeys.viewSorting.isEqualTo(TestExplorerViewSorting.ByDuration), menu: { id: MenuId.ViewTitle, @@ -563,7 +563,7 @@ export class ShowMostRecentOutputAction extends Action2 { constructor() { super({ id: TestCommandId.ShowMostRecentOutputAction, - title: localize('testing.showMostRecentOutput', "Show Output"), + title: { value: localize('testing.showMostRecentOutput', "Show Output"), original: 'Show Output' }, category, icon: Codicon.terminal, keybinding: { @@ -594,7 +594,7 @@ export class CollapseAllAction extends ViewAction { super({ id: TestCommandId.CollapseAllAction, viewId: Testing.ExplorerViewId, - title: localize('testing.collapseAll', "Collapse All Tests"), + title: { value: localize('testing.collapseAll', "Collapse All Tests"), original: 'Collapse All Tests' }, icon: Codicon.collapseAll, menu: { id: MenuId.ViewTitle, @@ -617,7 +617,7 @@ export class ClearTestResultsAction extends Action2 { constructor() { super({ id: TestCommandId.ClearTestResultsAction, - title: localize('testing.clearResults', "Clear All Results"), + title: { value: localize('testing.clearResults', "Clear All Results"), original: 'Clear All Results' }, category, icon: Codicon.trash, menu: [{ @@ -646,7 +646,7 @@ export class GoToTest extends Action2 { constructor() { super({ id: TestCommandId.GoToTest, - title: localize('testing.editFocusedTest', "Go to Test"), + title: { value: localize('testing.editFocusedTest', "Go to Test"), original: 'Go to Test' }, icon: Codicon.goToFile, menu: testItemInlineAndInContext(ActionOrder.GoToTest, TestingContextKeys.testItemHasUri.isEqualTo(true)), keybinding: { @@ -742,7 +742,7 @@ export class RunAtCursor extends ExecuteTestAtCursor { constructor() { super({ id: TestCommandId.RunAtCursor, - title: localize('testing.runAtCursor', "Run Test at Cursor"), + title: { value: localize('testing.runAtCursor', "Run Test at Cursor"), original: 'Run Test at Cursor' }, category, keybinding: { weight: KeybindingWeight.WorkbenchContrib, @@ -757,7 +757,7 @@ export class DebugAtCursor extends ExecuteTestAtCursor { constructor() { super({ id: TestCommandId.DebugAtCursor, - title: localize('testing.debugAtCursor', "Debug Test at Cursor"), + title: { value: localize('testing.debugAtCursor', "Debug Test at Cursor"), original: 'Debug Test at Cursor' }, category, keybinding: { weight: KeybindingWeight.WorkbenchContrib, @@ -824,7 +824,7 @@ export class RunCurrentFile extends ExecuteTestsInCurrentFile { constructor() { super({ id: TestCommandId.RunCurrentFile, - title: localize('testing.runCurrentFile', "Run Tests in Current File"), + title: { value: localize('testing.runCurrentFile', "Run Tests in Current File"), original: 'Run Tests in Current File' }, category, keybinding: { weight: KeybindingWeight.WorkbenchContrib, @@ -840,7 +840,7 @@ export class DebugCurrentFile extends ExecuteTestsInCurrentFile { constructor() { super({ id: TestCommandId.DebugCurrentFile, - title: localize('testing.debugCurrentFile', "Debug Tests in Current File"), + title: { value: localize('testing.debugCurrentFile', "Debug Tests in Current File"), original: 'Debug Tests in Current File' }, category, keybinding: { weight: KeybindingWeight.WorkbenchContrib, @@ -948,7 +948,7 @@ export class ReRunFailedTests extends RunOrDebugFailedTests { constructor() { super({ id: TestCommandId.ReRunFailedTests, - title: localize('testing.reRunFailTests', "Rerun Failed Tests"), + title: { value: localize('testing.reRunFailTests', "Rerun Failed Tests"), original: 'Rerun Failed Tests' }, category, keybinding: { weight: KeybindingWeight.WorkbenchContrib, @@ -969,7 +969,7 @@ export class DebugFailedTests extends RunOrDebugFailedTests { constructor() { super({ id: TestCommandId.DebugFailedTests, - title: localize('testing.debugFailTests', "Debug Failed Tests"), + title: { value: localize('testing.debugFailTests', "Debug Failed Tests"), original: 'Debug Failed Tests' }, category, keybinding: { weight: KeybindingWeight.WorkbenchContrib, @@ -990,7 +990,7 @@ export class ReRunLastRun extends RunOrDebugLastRun { constructor() { super({ id: TestCommandId.ReRunLastRun, - title: localize('testing.reRunLastRun', "Rerun Last Run"), + title: { value: localize('testing.reRunLastRun', "Rerun Last Run"), original: 'Rerun Last Run' }, category, keybinding: { weight: KeybindingWeight.WorkbenchContrib, @@ -1011,7 +1011,7 @@ export class DebugLastRun extends RunOrDebugLastRun { constructor() { super({ id: TestCommandId.DebugLastRun, - title: localize('testing.debugLastRun', "Debug Last Run"), + title: { value: localize('testing.debugLastRun', "Debug Last Run"), original: 'Debug Last Run' }, category, keybinding: { weight: KeybindingWeight.WorkbenchContrib, @@ -1032,7 +1032,7 @@ export class SearchForTestExtension extends Action2 { constructor() { super({ id: TestCommandId.SearchForTestExtension, - title: localize('testing.searchForTestExtension', "Search for Test Extension"), + title: { value: localize('testing.searchForTestExtension', "Search for Test Extension"), original: 'Search for Test Extension' }, }); } @@ -1048,7 +1048,7 @@ export class OpenOutputPeek extends Action2 { constructor() { super({ id: TestCommandId.OpenOutputPeek, - title: localize('testing.openOutputPeek', "Peek Output"), + title: { value: localize('testing.openOutputPeek', "Peek Output"), original: 'Peek Output' }, category, keybinding: { weight: KeybindingWeight.WorkbenchContrib, @@ -1070,7 +1070,7 @@ export class ToggleInlineTestOutput extends Action2 { constructor() { super({ id: TestCommandId.ToggleInlineTestOutput, - title: localize('testing.toggleInlineTestOutput', "Toggle Inline Test Output"), + title: { value: localize('testing.toggleInlineTestOutput', "Toggle Inline Test Output"), original: 'Toggle Inline Test Output' }, category, keybinding: { weight: KeybindingWeight.WorkbenchContrib, @@ -1119,7 +1119,7 @@ export class RefreshTestsAction extends Action2 { constructor() { super({ id: TestCommandId.RefreshTestsAction, - title: localize('testing.refreshTests', "Refresh Tests"), + title: { value: localize('testing.refreshTests', "Refresh Tests"), original: 'Refresh Tests' }, category, icon: icons.testingRefreshTests, keybinding: { @@ -1155,7 +1155,7 @@ export class CancelTestRefreshAction extends Action2 { constructor() { super({ id: TestCommandId.CancelTestRefreshAction, - title: localize('testing.cancelTestRefresh', "Cancel Test Refresh"), + title: { value: localize('testing.cancelTestRefresh', "Cancel Test Refresh"), original: 'Cancel Test Refresh' }, category, icon: icons.testingCancelRefreshTests, menu: refreshMenus(true), diff --git a/src/vs/workbench/contrib/testing/browser/testingExplorerFilter.ts b/src/vs/workbench/contrib/testing/browser/testingExplorerFilter.ts index 4d1af363aa7..52d57770b21 100644 --- a/src/vs/workbench/contrib/testing/browser/testingExplorerFilter.ts +++ b/src/vs/workbench/contrib/testing/browser/testingExplorerFilter.ts @@ -252,7 +252,7 @@ registerAction2(class extends Action2 { constructor() { super({ id: TestCommandId.FilterAction, - title: localize('filter', "Filter"), + title: { value: localize('filter', "Filter"), original: 'Filter' }, }); } async run(): Promise { } diff --git a/src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts b/src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts index c3452de68dd..988ad294015 100644 --- a/src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts +++ b/src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts @@ -1666,7 +1666,7 @@ export class GoToNextMessageAction extends EditorAction2 { super({ id: GoToNextMessageAction.ID, f1: true, - title: localize('testing.goToNextMessage', "Go to Next Test Failure"), + title: { value: localize('testing.goToNextMessage', "Go to Next Test Failure"), original: 'Go to Next Test Failure' }, icon: Codicon.arrowDown, category: CATEGORIES.Test, keybinding: { @@ -1696,7 +1696,7 @@ export class GoToPreviousMessageAction extends EditorAction2 { super({ id: GoToPreviousMessageAction.ID, f1: true, - title: localize('testing.goToPreviousMessage', "Go to Previous Test Failure"), + title: { value: localize('testing.goToPreviousMessage', "Go to Previous Test Failure"), original: 'Go to Previous Test Failure' }, icon: Codicon.arrowUp, category: CATEGORIES.Test, keybinding: { @@ -1726,7 +1726,7 @@ export class OpenMessageInEditorAction extends EditorAction2 { super({ id: OpenMessageInEditorAction.ID, f1: false, - title: localize('testing.openMessageInEditor', "Open in Editor"), + title: { value: localize('testing.openMessageInEditor', "Open in Editor"), original: 'Open in Editor' }, icon: Codicon.linkExternal, category: CATEGORIES.Test, menu: [{ id: MenuId.TestPeekTitle }], @@ -1744,7 +1744,7 @@ export class ToggleTestingPeekHistory extends EditorAction2 { super({ id: ToggleTestingPeekHistory.ID, f1: true, - title: localize('testing.toggleTestingPeekHistory', "Toggle Test History in Peek"), + title: { value: localize('testing.toggleTestingPeekHistory', "Toggle Test History in Peek"), original: 'Toggle Test History in Peek' }, icon: Codicon.history, category: CATEGORIES.Test, menu: [{ From 934408aea7883601032febd844796f826ca8ecd2 Mon Sep 17 00:00:00 2001 From: Joyce Er Date: Wed, 6 Jul 2022 11:03:38 -0700 Subject: [PATCH 299/347] Debt - `sessionSync` -> `editSessions` (#154289) --- build/lib/i18n.resources.json | 4 ++-- src/vs/base/common/product.ts | 2 +- .../browser/editSessions.contribution.ts} | 24 +++++++++---------- .../browser/editSessionsWorkbenchService.ts} | 18 +++++++------- .../common/editSessions.ts} | 4 ++-- .../common/editSessionsLogService.ts | 2 +- .../test/browser/editSessions.test.ts} | 20 ++++++++-------- src/vs/workbench/workbench.common.main.ts | 2 +- 8 files changed, 38 insertions(+), 38 deletions(-) rename src/vs/workbench/contrib/{sessionSync/browser/sessionSync.contribution.ts => editSessions/browser/editSessions.contribution.ts} (94%) rename src/vs/workbench/contrib/{sessionSync/browser/sessionSyncWorkbenchService.ts => editSessions/browser/editSessionsWorkbenchService.ts} (93%) rename src/vs/workbench/contrib/{sessionSync/common/sessionSync.ts => editSessions/common/editSessions.ts} (91%) rename src/vs/workbench/contrib/{sessionSync => editSessions}/common/editSessionsLogService.ts (94%) rename src/vs/workbench/contrib/{sessionSync/test/browser/sessionSync.test.ts => editSessions/test/browser/editSessions.test.ts} (84%) diff --git a/build/lib/i18n.resources.json b/build/lib/i18n.resources.json index 9f39f658de2..2ab4a471fb6 100644 --- a/build/lib/i18n.resources.json +++ b/build/lib/i18n.resources.json @@ -279,7 +279,7 @@ "project": "vscode-workbench" }, { - "name": "vs/workbench/contrib/sessionSync", + "name": "vs/workbench/contrib/editSessions", "project": "vscode-workbench" }, { @@ -431,7 +431,7 @@ "project": "vscode-workbench" }, { - "name": "vs/workbench/services/sessionSync", + "name": "vs/workbench/services/editSessions", "project": "vscode-workbench" }, { diff --git a/src/vs/base/common/product.ts b/src/vs/base/common/product.ts index 5dcf73fc4a3..0e9dcdcba96 100644 --- a/src/vs/base/common/product.ts +++ b/src/vs/base/common/product.ts @@ -155,7 +155,7 @@ export interface IProductConfiguration { readonly 'configurationSync.store'?: ConfigurationSyncStore; - readonly 'sessionSync.store'?: Omit; + readonly 'editSessions.store'?: Omit; readonly darwinUniversalAssetId?: string; } diff --git a/src/vs/workbench/contrib/sessionSync/browser/sessionSync.contribution.ts b/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts similarity index 94% rename from src/vs/workbench/contrib/sessionSync/browser/sessionSync.contribution.ts rename to src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts index a4cf8be1f5f..deb0cb486bc 100644 --- a/src/vs/workbench/contrib/sessionSync/browser/sessionSync.contribution.ts +++ b/src/vs/workbench/contrib/editSessions/browser/editSessions.contribution.ts @@ -10,7 +10,7 @@ import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle import { Action2, IAction2Options, registerAction2 } from 'vs/platform/actions/common/actions'; import { ServicesAccessor } from 'vs/editor/browser/editorExtensions'; import { localize } from 'vs/nls'; -import { ISessionSyncWorkbenchService, Change, ChangeType, Folder, EditSession, FileType, EDIT_SESSION_SYNC_CATEGORY, EditSessionSchemaVersion, IEditSessionsLogService } from 'vs/workbench/contrib/sessionSync/common/sessionSync'; +import { IEditSessionsWorkbenchService, Change, ChangeType, Folder, EditSession, FileType, EDIT_SESSION_SYNC_CATEGORY, EditSessionSchemaVersion, IEditSessionsLogService } from 'vs/workbench/contrib/editSessions/common/editSessions'; import { ISCMRepository, ISCMService } from 'vs/workbench/contrib/scm/common/scm'; import { IFileService } from 'vs/platform/files/common/files'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; @@ -19,7 +19,7 @@ import { joinPath, relativePath } from 'vs/base/common/resources'; import { VSBuffer } from 'vs/base/common/buffer'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress'; -import { SessionSyncWorkbenchService } from 'vs/workbench/contrib/sessionSync/browser/sessionSyncWorkbenchService'; +import { EditSessionsWorkbenchService } from 'vs/workbench/contrib/editSessions/browser/editSessionsWorkbenchService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { UserDataSyncErrorCode, UserDataSyncStoreError } from 'vs/platform/userDataSync/common/userDataSync'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -38,10 +38,10 @@ import { getVirtualWorkspaceLocation } from 'vs/platform/workspace/common/virtua import { Schemas } from 'vs/base/common/network'; import { IsWebContext } from 'vs/platform/contextkey/common/contextkeys'; import { isProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions'; -import { EditSessionsLogService } from 'vs/workbench/contrib/sessionSync/common/editSessionsLogService'; +import { EditSessionsLogService } from 'vs/workbench/contrib/editSessions/common/editSessionsLogService'; registerSingleton(IEditSessionsLogService, EditSessionsLogService); -registerSingleton(ISessionSyncWorkbenchService, SessionSyncWorkbenchService); +registerSingleton(IEditSessionsWorkbenchService, EditSessionsWorkbenchService); const continueEditSessionCommand: IAction2Options = { id: '_workbench.experimental.editSessions.actions.continueEditSession', @@ -58,13 +58,13 @@ const openLocalFolderCommand: IAction2Options = { const queryParamName = 'editSessionId'; const experimentalSettingName = 'workbench.experimental.editSessions.enabled'; -export class SessionSyncContribution extends Disposable implements IWorkbenchContribution { +export class EditSessionsContribution extends Disposable implements IWorkbenchContribution { private registered = false; private continueEditSessionOptions: ContinueEditSessionItem[] = []; constructor( - @ISessionSyncWorkbenchService private readonly sessionSyncWorkbenchService: ISessionSyncWorkbenchService, + @IEditSessionsWorkbenchService private readonly editSessionsWorkbenchService: IEditSessionsWorkbenchService, @IFileService private readonly fileService: IFileService, @IProgressService private readonly progressService: IProgressService, @IOpenerService private readonly openerService: IOpenerService, @@ -218,7 +218,7 @@ export class SessionSyncContribution extends Disposable implements IWorkbenchCon this.logService.info(`Applying edit session with ref ${ref}.`); } - const data = await this.sessionSyncWorkbenchService.read(ref); + const data = await this.editSessionsWorkbenchService.read(ref); if (!data) { if (ref === undefined) { this.notificationService.info(localize('no edit session', 'There are no edit sessions to apply.')); @@ -284,7 +284,7 @@ export class SessionSyncContribution extends Disposable implements IWorkbenchCon } this.logService.info(`Deleting edit session with ref ${ref} after successfully applying it to current workspace...`); - await this.sessionSyncWorkbenchService.delete(ref); + await this.editSessionsWorkbenchService.delete(ref); this.logService.info(`Deleted edit session with ref ${ref}.`); } catch (ex) { this.logService.error('Failed to apply edit session, reason: ', (ex as Error).toString()); @@ -346,7 +346,7 @@ export class SessionSyncContribution extends Disposable implements IWorkbenchCon try { this.logService.info(`Storing edit session...`); - const ref = await this.sessionSyncWorkbenchService.write(data); + const ref = await this.editSessionsWorkbenchService.write(data); this.logService.info(`Stored edit session with ref ${ref}.`); return ref; } catch (ex) { @@ -362,11 +362,11 @@ export class SessionSyncContribution extends Disposable implements IWorkbenchCon switch (ex.code) { case UserDataSyncErrorCode.TooLarge: // Uploading a payload can fail due to server size limits - this.telemetryService.publicLog2('sessionSync.upload.failed', { reason: 'TooLarge' }); + this.telemetryService.publicLog2('editSessions.upload.failed', { reason: 'TooLarge' }); this.notificationService.error(localize('payload too large', 'Your edit session exceeds the size limit and cannot be stored.')); break; default: - this.telemetryService.publicLog2('sessionSync.upload.failed', { reason: 'unknown' }); + this.telemetryService.publicLog2('editSessions.upload.failed', { reason: 'unknown' }); this.notificationService.error(localize('payload failed', 'Your edit session cannot be stored.')); break; } @@ -502,7 +502,7 @@ const continueEditSessionExtPoint = ExtensionsRegistry.registerExtensionPoint(WorkbenchExtensions.Workbench); -workbenchRegistry.registerWorkbenchContribution(SessionSyncContribution, LifecyclePhase.Restored); +workbenchRegistry.registerWorkbenchContribution(EditSessionsContribution, LifecyclePhase.Restored); Registry.as(Extensions.Configuration).registerConfiguration({ ...workbenchConfigurationNodeBase, diff --git a/src/vs/workbench/contrib/sessionSync/browser/sessionSyncWorkbenchService.ts b/src/vs/workbench/contrib/editSessions/browser/editSessionsWorkbenchService.ts similarity index 93% rename from src/vs/workbench/contrib/sessionSync/browser/sessionSyncWorkbenchService.ts rename to src/vs/workbench/contrib/editSessions/browser/editSessionsWorkbenchService.ts index 1df0ecc3d28..af25b5ee15a 100644 --- a/src/vs/workbench/contrib/sessionSync/browser/sessionSyncWorkbenchService.ts +++ b/src/vs/workbench/contrib/editSessions/browser/editSessionsWorkbenchService.ts @@ -18,20 +18,20 @@ import { IAuthenticationProvider } from 'vs/platform/userDataSync/common/userDat import { UserDataSyncStoreClient } from 'vs/platform/userDataSync/common/userDataSyncStoreService'; import { AuthenticationSession, AuthenticationSessionsChangeEvent, IAuthenticationService } from 'vs/workbench/services/authentication/common/authentication'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; -import { EDIT_SESSIONS_SIGNED_IN, EditSession, EDIT_SESSION_SYNC_CATEGORY, ISessionSyncWorkbenchService, EDIT_SESSIONS_SIGNED_IN_KEY, IEditSessionsLogService } from 'vs/workbench/contrib/sessionSync/common/sessionSync'; +import { EDIT_SESSIONS_SIGNED_IN, EditSession, EDIT_SESSION_SYNC_CATEGORY, IEditSessionsWorkbenchService, EDIT_SESSIONS_SIGNED_IN_KEY, IEditSessionsLogService } from 'vs/workbench/contrib/editSessions/common/editSessions'; type ExistingSession = IQuickPickItem & { session: AuthenticationSession & { providerId: string } }; type AuthenticationProviderOption = IQuickPickItem & { provider: IAuthenticationProvider }; -export class SessionSyncWorkbenchService extends Disposable implements ISessionSyncWorkbenchService { +export class EditSessionsWorkbenchService extends Disposable implements IEditSessionsWorkbenchService { _serviceBrand = undefined; - private serverConfiguration = this.productService['sessionSync.store']; + private serverConfiguration = this.productService['editSessions.store']; private storeClient: UserDataSyncStoreClient | undefined; #authenticationInfo: { sessionId: string; token: string; providerId: string } | undefined; - private static CACHED_SESSION_STORAGE_KEY = 'editSessionSyncAccountPreference'; + private static CACHED_SESSION_STORAGE_KEY = 'editSessionAccountPreference'; private initialized = false; private readonly signedInContext: IContextKey; @@ -286,14 +286,14 @@ export class SessionSyncWorkbenchService extends Disposable implements ISessionS } private get existingSessionId() { - return this.storageService.get(SessionSyncWorkbenchService.CACHED_SESSION_STORAGE_KEY, StorageScope.APPLICATION); + return this.storageService.get(EditSessionsWorkbenchService.CACHED_SESSION_STORAGE_KEY, StorageScope.APPLICATION); } private set existingSessionId(sessionId: string | undefined) { if (sessionId === undefined) { - this.storageService.remove(SessionSyncWorkbenchService.CACHED_SESSION_STORAGE_KEY, StorageScope.APPLICATION); + this.storageService.remove(EditSessionsWorkbenchService.CACHED_SESSION_STORAGE_KEY, StorageScope.APPLICATION); } else { - this.storageService.store(SessionSyncWorkbenchService.CACHED_SESSION_STORAGE_KEY, sessionId, StorageScope.APPLICATION, StorageTarget.MACHINE); + this.storageService.store(EditSessionsWorkbenchService.CACHED_SESSION_STORAGE_KEY, sessionId, StorageScope.APPLICATION, StorageTarget.MACHINE); } } @@ -303,7 +303,7 @@ export class SessionSyncWorkbenchService extends Disposable implements ISessionS } private async onDidChangeStorage(e: IStorageValueChangeEvent): Promise { - if (e.key === SessionSyncWorkbenchService.CACHED_SESSION_STORAGE_KEY + if (e.key === EditSessionsWorkbenchService.CACHED_SESSION_STORAGE_KEY && e.scope === StorageScope.APPLICATION ) { const newSessionId = this.existingSessionId; @@ -335,7 +335,7 @@ export class SessionSyncWorkbenchService extends Disposable implements ISessionS this._register(registerAction2(class ResetEditSessionAuthenticationAction extends Action2 { constructor() { super({ - id: 'workbench.sessionSync.actions.resetAuth', + id: 'workbench.editSessions.actions.resetAuth', title: localize('reset auth', 'Sign Out'), category: EDIT_SESSION_SYNC_CATEGORY, precondition: ContextKeyExpr.equals(EDIT_SESSIONS_SIGNED_IN_KEY, true), diff --git a/src/vs/workbench/contrib/sessionSync/common/sessionSync.ts b/src/vs/workbench/contrib/editSessions/common/editSessions.ts similarity index 91% rename from src/vs/workbench/contrib/sessionSync/common/sessionSync.ts rename to src/vs/workbench/contrib/editSessions/common/editSessions.ts index 538a54a6444..789976a50e5 100644 --- a/src/vs/workbench/contrib/sessionSync/common/sessionSync.ts +++ b/src/vs/workbench/contrib/editSessions/common/editSessions.ts @@ -14,8 +14,8 @@ export const EDIT_SESSION_SYNC_CATEGORY: ILocalizedString = { value: localize('session sync', 'Edit Sessions') }; -export const ISessionSyncWorkbenchService = createDecorator('ISessionSyncWorkbenchService'); -export interface ISessionSyncWorkbenchService { +export const IEditSessionsWorkbenchService = createDecorator('IEditSessionsWorkbenchService'); +export interface IEditSessionsWorkbenchService { _serviceBrand: undefined; read(ref: string | undefined): Promise<{ ref: string; editSession: EditSession } | undefined>; diff --git a/src/vs/workbench/contrib/sessionSync/common/editSessionsLogService.ts b/src/vs/workbench/contrib/editSessions/common/editSessionsLogService.ts similarity index 94% rename from src/vs/workbench/contrib/sessionSync/common/editSessionsLogService.ts rename to src/vs/workbench/contrib/editSessions/common/editSessionsLogService.ts index 2b3b6bca671..a18c9e29304 100644 --- a/src/vs/workbench/contrib/sessionSync/common/editSessionsLogService.ts +++ b/src/vs/workbench/contrib/editSessions/common/editSessionsLogService.ts @@ -5,7 +5,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { AbstractLogger, ILogger, ILoggerService } from 'vs/platform/log/common/log'; -import { IEditSessionsLogService } from 'vs/workbench/contrib/sessionSync/common/sessionSync'; +import { IEditSessionsLogService } from 'vs/workbench/contrib/editSessions/common/editSessions'; export class EditSessionsLogService extends AbstractLogger implements IEditSessionsLogService { diff --git a/src/vs/workbench/contrib/sessionSync/test/browser/sessionSync.test.ts b/src/vs/workbench/contrib/editSessions/test/browser/editSessions.test.ts similarity index 84% rename from src/vs/workbench/contrib/sessionSync/test/browser/sessionSync.test.ts rename to src/vs/workbench/contrib/editSessions/test/browser/editSessions.test.ts index 140c068d5d0..b7caca6f077 100644 --- a/src/vs/workbench/contrib/sessionSync/test/browser/sessionSync.test.ts +++ b/src/vs/workbench/contrib/editSessions/test/browser/editSessions.test.ts @@ -10,7 +10,7 @@ import { Schemas } from 'vs/base/common/network'; import { InMemoryFileSystemProvider } from 'vs/platform/files/common/inMemoryFilesystemProvider'; import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; import { NullLogService } from 'vs/platform/log/common/log'; -import { SessionSyncContribution } from 'vs/workbench/contrib/sessionSync/browser/sessionSync.contribution'; +import { EditSessionsContribution } from 'vs/workbench/contrib/editSessions/browser/editSessions.contribution'; import { ProgressService } from 'vs/workbench/services/progress/browser/progressService'; import { IProgressService } from 'vs/platform/progress/common/progress'; import { ISCMService } from 'vs/workbench/contrib/scm/common/scm'; @@ -21,7 +21,7 @@ import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace import { mock } from 'vs/base/test/common/mock'; import * as sinon from 'sinon'; import * as assert from 'assert'; -import { ChangeType, FileType, IEditSessionsLogService, ISessionSyncWorkbenchService } from 'vs/workbench/contrib/sessionSync/common/sessionSync'; +import { ChangeType, FileType, IEditSessionsLogService, IEditSessionsWorkbenchService } from 'vs/workbench/contrib/editSessions/common/editSessions'; import { URI } from 'vs/base/common/uri'; import { joinPath } from 'vs/base/common/resources'; import { INotificationService } from 'vs/platform/notification/common/notification'; @@ -34,7 +34,7 @@ const folderUri = URI.file(`/${folderName}`); suite('Edit session sync', () => { let instantiationService: TestInstantiationService; - let sessionSyncContribution: SessionSyncContribution; + let editSessionsContribution: EditSessionsContribution; let fileService: FileService; let sandbox: sinon.SinonSandbox; @@ -55,11 +55,11 @@ suite('Edit session sync', () => { instantiationService.stub(IEditSessionsLogService, logService); instantiationService.stub(IFileService, fileService); instantiationService.stub(INotificationService, new TestNotificationService()); - instantiationService.stub(ISessionSyncWorkbenchService, new class extends mock() { }); + instantiationService.stub(IEditSessionsWorkbenchService, new class extends mock() { }); instantiationService.stub(IProgressService, ProgressService); instantiationService.stub(ISCMService, SCMService); instantiationService.stub(IEnvironmentService, TestEnvironmentService); - instantiationService.stub(IConfigurationService, new TestConfigurationService({ workbench: { experimental: { sessionSync: { enabled: true } } } })); + instantiationService.stub(IConfigurationService, new TestConfigurationService({ workbench: { experimental: { editSessions: { enabled: true } } } })); instantiationService.stub(IWorkspaceContextService, new class extends mock() { override getWorkspace() { return { @@ -77,7 +77,7 @@ suite('Edit session sync', () => { // Stub repositories instantiationService.stub(ISCMService, '_repositories', new Map()); - sessionSyncContribution = instantiationService.createInstance(SessionSyncContribution); + editSessionsContribution = instantiationService.createInstance(EditSessionsContribution); }); teardown(() => { @@ -107,13 +107,13 @@ suite('Edit session sync', () => { // Stub sync service to return edit session data const readStub = sandbox.stub().returns({ editSession, ref: '0' }); - instantiationService.stub(ISessionSyncWorkbenchService, 'read', readStub); + instantiationService.stub(IEditSessionsWorkbenchService, 'read', readStub); // Create root folder await fileService.createFolder(folderUri); // Apply edit session - await sessionSyncContribution.applyEditSession(); + await editSessionsContribution.applyEditSession(); // Verify edit session was correctly applied assert.equal((await fileService.readFile(fileUri)).value.toString(), fileContents); @@ -121,12 +121,12 @@ suite('Edit session sync', () => { test('Edit session not stored if there are no edits', async function () { const writeStub = sandbox.stub(); - instantiationService.stub(ISessionSyncWorkbenchService, 'write', writeStub); + instantiationService.stub(IEditSessionsWorkbenchService, 'write', writeStub); // Create root folder await fileService.createFolder(folderUri); - await sessionSyncContribution.storeEditSession(true); + await editSessionsContribution.storeEditSession(true); // Verify that we did not attempt to write the edit session assert.equal(writeStub.called, false); diff --git a/src/vs/workbench/workbench.common.main.ts b/src/vs/workbench/workbench.common.main.ts index 3319bbe6143..14407f52692 100644 --- a/src/vs/workbench/workbench.common.main.ts +++ b/src/vs/workbench/workbench.common.main.ts @@ -329,7 +329,7 @@ import 'vs/workbench/contrib/userDataSync/browser/userDataSync.contribution'; import 'vs/workbench/contrib/userDataProfile/browser/userDataProfile.contribution'; // Continue Edit Session -import 'vs/workbench/contrib/sessionSync/browser/sessionSync.contribution'; +import 'vs/workbench/contrib/editSessions/browser/editSessions.contribution'; // Code Actions import 'vs/workbench/contrib/codeActions/browser/codeActions.contribution'; From c1279baa481f30e5da21d08a56a53693251d6f07 Mon Sep 17 00:00:00 2001 From: Joyce Er Date: Wed, 6 Jul 2022 11:16:43 -0700 Subject: [PATCH 300/347] =?UTF-8?q?=F0=9F=86=99=20distro=20(#154292)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1ea5f8d128b..8f07addce0c 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.69.0", - "distro": "7b212b70427becfe3691f683d7c7e7225cae9665", + "distro": "ed09627fa6e06b81792498a4e72e20becb6164f8", "author": { "name": "Microsoft Corporation" }, From 0586d45c690dab433101b5aa64f6434dd6bd03ba Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Wed, 6 Jul 2022 14:41:26 -0400 Subject: [PATCH 301/347] replace forEach in resolver service (#154286) * part of #154195 * fix test --- .../baseConfigurationResolverService.ts | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/vs/workbench/services/configurationResolver/browser/baseConfigurationResolverService.ts b/src/vs/workbench/services/configurationResolver/browser/baseConfigurationResolverService.ts index 059d8e46456..07053d26b4d 100644 --- a/src/vs/workbench/services/configurationResolver/browser/baseConfigurationResolverService.ts +++ b/src/vs/workbench/services/configurationResolver/browser/baseConfigurationResolverService.ts @@ -7,7 +7,7 @@ import * as nls from 'vs/nls'; import * as Types from 'vs/base/common/types'; import { Schemas } from 'vs/base/common/network'; import { SideBySideEditor, EditorResourceAccessor } from 'vs/workbench/common/editor'; -import { IStringDictionary, forEach } from 'vs/base/common/collections'; +import { IStringDictionary } from 'vs/base/common/collections'; import { IConfigurationService, IConfigurationOverrides, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { IWorkspaceFolder, IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; @@ -157,9 +157,9 @@ export abstract class BaseConfigurationResolverService extends AbstractVariableR if (!newMapping) { return false; } - forEach(newMapping, (entry) => { - fullMapping.set(entry.key, entry.value); - }); + for (const [key, value] of Object.entries(newMapping)) { + fullMapping.set(key, value); + } return true; } @@ -256,20 +256,21 @@ export abstract class BaseConfigurationResolverService extends AbstractVariableR } } } - this._contributedVariables.forEach((value, contributed: string) => { + for (const contributed of this._contributedVariables.keys()) { if ((variables.indexOf(contributed) < 0) && (object.indexOf('${' + contributed + '}') >= 0)) { variables.push(contributed); } - }); + } } else if (Types.isArray(object)) { - object.forEach(value => { + for (const value of object) { this.findVariables(value, variables); - }); + + } } else if (object) { - Object.keys(object).forEach(key => { - const value = object[key]; + for (const value of Object.values(object)) { this.findVariables(value, variables); - }); + + } } } @@ -315,11 +316,11 @@ export abstract class BaseConfigurationResolverService extends AbstractVariableR missingAttribute('description'); } if (Types.isArray(info.options)) { - info.options.forEach(pickOption => { + for (const pickOption of info.options) { if (!Types.isString(pickOption) && !Types.isString(pickOption.value)) { missingAttribute('value'); } - }); + } } else { missingAttribute('options'); } @@ -327,7 +328,7 @@ export abstract class BaseConfigurationResolverService extends AbstractVariableR value: string; } const picks = new Array(); - info.options.forEach(pickOption => { + for (const pickOption of info.options) { const value = Types.isString(pickOption) ? pickOption : pickOption.value; const label = Types.isString(pickOption) ? undefined : pickOption.label; @@ -343,7 +344,7 @@ export abstract class BaseConfigurationResolverService extends AbstractVariableR } else { picks.push(item); } - }); + } const pickOptions: IPickOptions = { placeHolder: info.description, matchOnDetail: true, ignoreFocusLost: true }; return this.quickInputService.pick(picks, pickOptions, undefined).then(resolvedInput => { if (resolvedInput) { From 419a7cc1a0bd6be79b27e80eaf7e0dfbb2dd6543 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Wed, 6 Jul 2022 13:13:57 -0700 Subject: [PATCH 302/347] Register commands correctly with original title, #153865 (#154297) --- .../contrib/cellCommands/cellCommands.ts | 90 +++++++++++++++---- .../search/browser/search.contribution.ts | 25 ++++-- 2 files changed, 92 insertions(+), 23 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/cellCommands/cellCommands.ts b/src/vs/workbench/contrib/notebook/browser/contrib/cellCommands/cellCommands.ts index 2adc303d4e1..5074d759b06 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/cellCommands/cellCommands.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/cellCommands/cellCommands.ts @@ -31,7 +31,10 @@ registerAction2(class extends NotebookCellAction { super( { id: MOVE_CELL_UP_COMMAND_ID, - title: localize('notebookActions.moveCellUp', "Move Cell Up"), + title: { + value: localize('notebookActions.moveCellUp', "Move Cell Up"), + original: 'Move Cell Up' + }, icon: icons.moveUpIcon, keybinding: { primary: KeyMod.Alt | KeyCode.UpArrow, @@ -57,7 +60,10 @@ registerAction2(class extends NotebookCellAction { super( { id: MOVE_CELL_DOWN_COMMAND_ID, - title: localize('notebookActions.moveCellDown', "Move Cell Down"), + title: { + value: localize('notebookActions.moveCellDown', "Move Cell Down"), + original: 'Move Cell Down' + }, icon: icons.moveDownIcon, keybinding: { primary: KeyMod.Alt | KeyCode.DownArrow, @@ -83,7 +89,10 @@ registerAction2(class extends NotebookCellAction { super( { id: COPY_CELL_UP_COMMAND_ID, - title: localize('notebookActions.copyCellUp', "Copy Cell Up"), + title: { + value: localize('notebookActions.copyCellUp', "Copy Cell Up"), + original: 'Copy Cell Up' + }, keybinding: { primary: KeyMod.Alt | KeyMod.Shift | KeyCode.UpArrow, when: ContextKeyExpr.and(NOTEBOOK_EDITOR_FOCUSED, InputFocusedContext.toNegated()), @@ -102,7 +111,10 @@ registerAction2(class extends NotebookCellAction { super( { id: COPY_CELL_DOWN_COMMAND_ID, - title: localize('notebookActions.copyCellDown', "Copy Cell Down"), + title: { + value: localize('notebookActions.copyCellDown', "Copy Cell Down"), + original: 'Copy Cell Down' + }, keybinding: { primary: KeyMod.Alt | KeyMod.Shift | KeyCode.DownArrow, when: ContextKeyExpr.and(NOTEBOOK_EDITOR_FOCUSED, InputFocusedContext.toNegated()), @@ -137,7 +149,10 @@ registerAction2(class extends NotebookCellAction { super( { id: SPLIT_CELL_COMMAND_ID, - title: localize('notebookActions.splitCell', "Split Cell"), + title: { + value: localize('notebookActions.splitCell', "Split Cell"), + original: 'Split Cell' + }, menu: { id: MenuId.NotebookCellTitle, when: ContextKeyExpr.and( @@ -212,7 +227,10 @@ registerAction2(class extends NotebookCellAction { super( { id: JOIN_CELL_ABOVE_COMMAND_ID, - title: localize('notebookActions.joinCellAbove', "Join With Previous Cell"), + title: { + value: localize('notebookActions.joinCellAbove', "Join With Previous Cell"), + original: 'Join With Previous Cell' + }, keybinding: { when: NOTEBOOK_EDITOR_FOCUSED, primary: KeyMod.WinCtrl | KeyMod.Alt | KeyMod.Shift | KeyCode.KeyJ, @@ -238,7 +256,10 @@ registerAction2(class extends NotebookCellAction { super( { id: JOIN_CELL_BELOW_COMMAND_ID, - title: localize('notebookActions.joinCellBelow', "Join With Next Cell"), + title: { + value: localize('notebookActions.joinCellBelow', "Join With Next Cell"), + original: 'Join With Next Cell' + }, keybinding: { when: NOTEBOOK_EDITOR_FOCUSED, primary: KeyMod.WinCtrl | KeyMod.Alt | KeyCode.KeyJ, @@ -270,7 +291,10 @@ registerAction2(class ChangeCellToCodeAction extends NotebookMultiCellAction { constructor() { super({ id: CHANGE_CELL_TO_CODE_COMMAND_ID, - title: localize('notebookActions.changeCellToCode', "Change Cell to Code"), + title: { + value: localize('notebookActions.changeCellToCode', "Change Cell to Code"), + original: 'Change Cell to Code' + }, keybinding: { when: ContextKeyExpr.and(NOTEBOOK_EDITOR_FOCUSED, ContextKeyExpr.not(InputFocusedContextKey)), primary: KeyCode.KeyY, @@ -294,7 +318,10 @@ registerAction2(class ChangeCellToMarkdownAction extends NotebookMultiCellAction constructor() { super({ id: CHANGE_CELL_TO_MARKDOWN_COMMAND_ID, - title: localize('notebookActions.changeCellToMarkdown', "Change Cell to Markdown"), + title: { + value: localize('notebookActions.changeCellToMarkdown', "Change Cell to Markdown"), + original: 'Change Cell to Markdown' + }, keybinding: { when: ContextKeyExpr.and(NOTEBOOK_EDITOR_FOCUSED, ContextKeyExpr.not(InputFocusedContextKey)), primary: KeyCode.KeyM, @@ -330,7 +357,10 @@ registerAction2(class CollapseCellInputAction extends NotebookMultiCellAction { constructor() { super({ id: COLLAPSE_CELL_INPUT_COMMAND_ID, - title: localize('notebookActions.collapseCellInput', "Collapse Cell Input"), + title: { + value: localize('notebookActions.collapseCellInput', "Collapse Cell Input"), + original: 'Collapse Cell Input' + }, keybinding: { when: ContextKeyExpr.and(NOTEBOOK_CELL_LIST_FOCUSED, NOTEBOOK_CELL_INPUT_COLLAPSED.toNegated(), InputFocusedContext.toNegated()), primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.KeyC), @@ -356,7 +386,10 @@ registerAction2(class ExpandCellInputAction extends NotebookMultiCellAction { constructor() { super({ id: EXPAND_CELL_INPUT_COMMAND_ID, - title: localize('notebookActions.expandCellInput', "Expand Cell Input"), + title: { + value: localize('notebookActions.expandCellInput', "Expand Cell Input"), + original: 'Expand Cell Input' + }, keybinding: { when: ContextKeyExpr.and(NOTEBOOK_CELL_LIST_FOCUSED, NOTEBOOK_CELL_INPUT_COLLAPSED), primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.KeyC), @@ -382,7 +415,10 @@ registerAction2(class CollapseCellOutputAction extends NotebookMultiCellAction { constructor() { super({ id: COLLAPSE_CELL_OUTPUT_COMMAND_ID, - title: localize('notebookActions.collapseCellOutput', "Collapse Cell Output"), + title: { + value: localize('notebookActions.collapseCellOutput', "Collapse Cell Output"), + original: 'Collapse Cell Output' + }, keybinding: { when: ContextKeyExpr.and(NOTEBOOK_CELL_LIST_FOCUSED, NOTEBOOK_CELL_OUTPUT_COLLAPSED.toNegated(), InputFocusedContext.toNegated(), NOTEBOOK_CELL_HAS_OUTPUTS), primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyCode.KeyT), @@ -404,7 +440,10 @@ registerAction2(class ExpandCellOuputAction extends NotebookMultiCellAction { constructor() { super({ id: EXPAND_CELL_OUTPUT_COMMAND_ID, - title: localize('notebookActions.expandCellOutput', "Expand Cell Output"), + title: { + value: localize('notebookActions.expandCellOutput', "Expand Cell Output"), + original: 'Expand Cell Output' + }, keybinding: { when: ContextKeyExpr.and(NOTEBOOK_CELL_LIST_FOCUSED, NOTEBOOK_CELL_OUTPUT_COLLAPSED), primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyCode.KeyT), @@ -427,7 +466,10 @@ registerAction2(class extends NotebookMultiCellAction { super({ id: TOGGLE_CELL_OUTPUTS_COMMAND_ID, precondition: NOTEBOOK_CELL_LIST_FOCUSED, - title: localize('notebookActions.toggleOutputs', "Toggle Outputs"), + title: { + value: localize('notebookActions.toggleOutputs', "Toggle Outputs"), + original: 'Toggle Outputs' + }, description: { description: localize('notebookActions.toggleOutputs', "Toggle Outputs"), args: cellExecutionArgs @@ -457,7 +499,10 @@ registerAction2(class CollapseAllCellInputsAction extends NotebookMultiCellActio constructor() { super({ id: COLLAPSE_ALL_CELL_INPUTS_COMMAND_ID, - title: localize('notebookActions.collapseAllCellInput', "Collapse All Cell Inputs"), + title: { + value: localize('notebookActions.collapseAllCellInput', "Collapse All Cell Inputs"), + original: 'Collapse All Cell Inputs' + }, f1: true, }); } @@ -471,7 +516,10 @@ registerAction2(class ExpandAllCellInputsAction extends NotebookMultiCellAction constructor() { super({ id: EXPAND_ALL_CELL_INPUTS_COMMAND_ID, - title: localize('notebookActions.expandAllCellInput', "Expand All Cell Inputs"), + title: { + value: localize('notebookActions.expandAllCellInput', "Expand All Cell Inputs"), + original: 'Expand All Cell Inputs' + }, f1: true }); } @@ -485,7 +533,10 @@ registerAction2(class CollapseAllCellOutputsAction extends NotebookMultiCellActi constructor() { super({ id: COLLAPSE_ALL_CELL_OUTPUTS_COMMAND_ID, - title: localize('notebookActions.collapseAllCellOutput', "Collapse All Cell Outputs"), + title: { + value: localize('notebookActions.collapseAllCellOutput', "Collapse All Cell Outputs"), + original: 'Collapse All Cell Outputs' + }, f1: true, }); } @@ -499,7 +550,10 @@ registerAction2(class ExpandAllCellOutputsAction extends NotebookMultiCellAction constructor() { super({ id: EXPAND_ALL_CELL_OUTPUTS_COMMAND_ID, - title: localize('notebookActions.expandAllCellOutput', "Expand All Cell Outputs"), + title: { + value: localize('notebookActions.expandAllCellOutput', "Expand All Cell Outputs"), + original: 'Expand All Cell Outputs' + }, f1: true }); } diff --git a/src/vs/workbench/contrib/search/browser/search.contribution.ts b/src/vs/workbench/contrib/search/browser/search.contribution.ts index 77782e09059..08f7dc2cf25 100644 --- a/src/vs/workbench/contrib/search/browser/search.contribution.ts +++ b/src/vs/workbench/contrib/search/browser/search.contribution.ts @@ -365,7 +365,10 @@ registerAction2(class CancelSearchAction extends Action2 { constructor() { super({ id: 'search.action.cancel', - title: nls.localize('CancelSearchAction.label', "Cancel Search"), + title: { + value: nls.localize('CancelSearchAction.label', "Cancel Search"), + original: 'Cancel Search' + }, icon: searchStopIcon, category, f1: true, @@ -392,7 +395,10 @@ registerAction2(class RefreshAction extends Action2 { constructor() { super({ id: 'search.action.refreshSearchResults', - title: nls.localize('RefreshAction.label', "Refresh"), + title: { + value: nls.localize('RefreshAction.label', "Refresh"), + original: 'Refresh' + }, icon: searchRefreshIcon, precondition: Constants.ViewHasSearchPatternKey, category, @@ -414,7 +420,10 @@ registerAction2(class CollapseDeepestExpandedLevelAction extends Action2 { constructor() { super({ id: 'search.action.collapseSearchResults', - title: nls.localize('CollapseDeepestExpandedLevelAction.label', "Collapse All"), + title: { + value: nls.localize('CollapseDeepestExpandedLevelAction.label', "Collapse All"), + original: 'Collapse All' + }, category, icon: searchCollapseAllIcon, f1: true, @@ -436,7 +445,10 @@ registerAction2(class ExpandAllAction extends Action2 { constructor() { super({ id: 'search.action.expandSearchResults', - title: nls.localize('ExpandAllAction.label', "Expand All"), + title: { + value: nls.localize('ExpandAllAction.label', "Expand All"), + original: 'Expand All' + }, category, icon: searchExpandAllIcon, f1: true, @@ -458,7 +470,10 @@ registerAction2(class ClearSearchResultsAction extends Action2 { constructor() { super({ id: 'search.action.clearSearchResults', - title: nls.localize('ClearSearchResultsAction.label', "Clear Search Results"), + title: { + value: nls.localize('ClearSearchResultsAction.label', "Clear Search Results"), + original: 'Clear Search Results' + }, category, icon: searchClearIcon, f1: true, From 9c724118aea8f0c4539c745c0474371fdfe21038 Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Wed, 6 Jul 2022 13:50:18 -0700 Subject: [PATCH 303/347] re #153865. ICommandActionTitle for notebook (#154307) --- .../gettingStarted/notebookGettingStarted.ts | 5 ++++- .../browser/contrib/troubleshoot/layout.ts | 16 ++++++++++++--- .../browser/controller/layoutActions.ts | 20 +++++++++++++++---- 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/gettingStarted/notebookGettingStarted.ts b/src/vs/workbench/contrib/notebook/browser/contrib/gettingStarted/notebookGettingStarted.ts index 3e1c47af18a..2165fa94cc2 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/gettingStarted/notebookGettingStarted.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/gettingStarted/notebookGettingStarted.ts @@ -81,7 +81,10 @@ registerAction2(class NotebookClearNotebookLayoutAction extends Action2 { constructor() { super({ id: 'workbench.notebook.layout.gettingStarted', - title: localize('workbench.notebook.layout.gettingStarted.label', "Reset notebook getting started"), + title: { + value: localize('workbench.notebook.layout.gettingStarted.label', "Reset notebook getting started"), + original: 'Reset notebook getting started' + }, f1: true, precondition: ContextKeyExpr.equals(`config.${NotebookSetting.openGettingStarted}`, true), category: CATEGORIES.Developer, diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/troubleshoot/layout.ts b/src/vs/workbench/contrib/notebook/browser/contrib/troubleshoot/layout.ts index b3af4143741..ab714f85b51 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/troubleshoot/layout.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/troubleshoot/layout.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Disposable, DisposableStore, dispose, IDisposable } from 'vs/base/common/lifecycle'; +import { localize } from 'vs/nls'; import { Action2, registerAction2 } from 'vs/platform/actions/common/actions'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { CATEGORIES } from 'vs/workbench/common/actions'; @@ -121,7 +122,10 @@ registerAction2(class extends Action2 { constructor() { super({ id: 'notebook.toggleLayoutTroubleshoot', - title: 'Toggle Notebook Layout Troubleshoot', + title: { + value: localize('workbench.notebook.toggleLayoutTroubleshoot', "Toggle Layout Troubleshoot"), + original: 'Toggle Notebook Layout Troubleshoot' + }, category: CATEGORIES.Developer, f1: true }); @@ -144,7 +148,10 @@ registerAction2(class extends Action2 { constructor() { super({ id: 'notebook.inspectLayout', - title: 'Inspect Notebook Layout', + title: { + value: localize('workbench.notebook.inspectLayout', "Inspect Notebook Layout"), + original: 'Inspect Notebook Layout' + }, category: CATEGORIES.Developer, f1: true }); @@ -169,7 +176,10 @@ registerAction2(class extends Action2 { constructor() { super({ id: 'notebook.clearNotebookEdtitorTypeCache', - title: 'Clear Notebook Editor Cache', + title: { + value: localize('workbench.notebook.clearNotebookEdtitorTypeCache', "Clear Notebook Editor Type Cache"), + original: 'Clear Notebook Editor Cache' + }, category: CATEGORIES.Developer, f1: true }); diff --git a/src/vs/workbench/contrib/notebook/browser/controller/layoutActions.ts b/src/vs/workbench/contrib/notebook/browser/controller/layoutActions.ts index 4f6a3e489c5..7f6ac0a645b 100644 --- a/src/vs/workbench/contrib/notebook/browser/controller/layoutActions.ts +++ b/src/vs/workbench/contrib/notebook/browser/controller/layoutActions.ts @@ -21,7 +21,10 @@ registerAction2(class NotebookConfigureLayoutAction extends Action2 { constructor() { super({ id: 'workbench.notebook.layout.select', - title: localize('workbench.notebook.layout.select.label', "Select between Notebook Layouts"), + title: { + value: localize('workbench.notebook.layout.select.label', "Select between Notebook Layouts"), + original: 'Select between Notebook Layouts' + }, f1: true, precondition: ContextKeyExpr.equals(`config.${NotebookSetting.openGettingStarted}`, true), category: NOTEBOOK_ACTIONS_CATEGORY, @@ -57,7 +60,10 @@ registerAction2(class NotebookConfigureLayoutAction extends Action2 { constructor() { super({ id: 'workbench.notebook.layout.configure', - title: localize('workbench.notebook.layout.configure.label', "Customize Notebook Layout"), + title: { + value: localize('workbench.notebook.layout.configure.label', "Customize Notebook Layout"), + original: 'Customize Notebook Layout' + }, f1: true, category: NOTEBOOK_ACTIONS_CATEGORY, menu: [ @@ -79,7 +85,10 @@ registerAction2(class NotebookConfigureLayoutFromEditorTitle extends Action2 { constructor() { super({ id: 'workbench.notebook.layout.configure.editorTitle', - title: localize('workbench.notebook.layout.configure.label', "Customize Notebook Layout"), + title: { + value: localize('workbench.notebook.layout.configure.label', "Customize Notebook Layout"), + original: 'Customize Notebook Layout' + }, f1: false, category: NOTEBOOK_ACTIONS_CATEGORY, menu: [ @@ -177,7 +186,10 @@ registerAction2(class SaveMimeTypeDisplayOrder extends Action2 { constructor() { super({ id: 'notebook.saveMimeTypeOrder', - title: localize('notebook.saveMimeTypeOrder', 'Save Mimetype Display Order'), + title: { + value: localize('notebook.saveMimeTypeOrder', 'Save Mimetype Display Order'), + original: 'Save Mimetype Display Order' + }, f1: true, category: NOTEBOOK_ACTIONS_CATEGORY, precondition: NOTEBOOK_IS_ACTIVE_EDITOR, From 2a99db38280d48220b1c15d9bfee7d9ec2ec1666 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 6 Jul 2022 15:42:20 -0700 Subject: [PATCH 304/347] Remove collections.forEach (#154314) * Remove collections.forEach Fixes #154195 * return -> continue previously these were in a closure so we need to continue instead of returning --- src/vs/base/common/collections.ts | 14 ---------- src/vs/base/test/common/collections.test.ts | 21 --------------- .../workbench/api/browser/mainThreadTask.ts | 7 ++--- .../actions/common/menusExtensionPoint.ts | 27 +++++++++---------- .../common/abstractExtensionService.ts | 9 +++---- 5 files changed, 19 insertions(+), 59 deletions(-) diff --git a/src/vs/base/common/collections.ts b/src/vs/base/common/collections.ts index 1f16cd438ea..d8ee92f757e 100644 --- a/src/vs/base/common/collections.ts +++ b/src/vs/base/common/collections.ts @@ -15,20 +15,6 @@ export type IStringDictionary = Record; */ export type INumberDictionary = Record; -/** - * Iterates over each entry in the provided dictionary. The iterator will stop when the callback returns `false`. - * - * @deprecated Use `Object.entries(x)` with a `for...of` loop. - */ -export function forEach(from: IStringDictionary | INumberDictionary, callback: (entry: { key: any; value: T }) => any): void { - for (const [key, value] of Object.entries(from)) { - const result = callback({ key, value }); - if (result === false) { - return; - } - } -} - /** * Groups the collection into a dictionary based on the provided * group function. diff --git a/src/vs/base/test/common/collections.test.ts b/src/vs/base/test/common/collections.test.ts index 138d7486390..9dfe59a58fe 100644 --- a/src/vs/base/test/common/collections.test.ts +++ b/src/vs/base/test/common/collections.test.ts @@ -8,27 +8,6 @@ import * as collections from 'vs/base/common/collections'; suite('Collections', () => { - test('forEach', () => { - collections.forEach({}, () => assert(false)); - collections.forEach(Object.create(null), () => assert(false)); - - let count = 0; - collections.forEach({ toString: 123 }, () => count++); - assert.strictEqual(count, 1); - - count = 0; - const dict = Object.create(null); - dict['toString'] = 123; - collections.forEach(dict, () => count++); - assert.strictEqual(count, 1); - - collections.forEach(dict, () => false); - - // don't iterate over properties that are not on the object itself - const test = Object.create({ 'derived': true }); - collections.forEach(test, () => assert(false)); - }); - test('groupBy', () => { const group1 = 'a', group2 = 'b'; diff --git a/src/vs/workbench/api/browser/mainThreadTask.ts b/src/vs/workbench/api/browser/mainThreadTask.ts index e40b95ad866..be081d8e61f 100644 --- a/src/vs/workbench/api/browser/mainThreadTask.ts +++ b/src/vs/workbench/api/browser/mainThreadTask.ts @@ -9,7 +9,7 @@ import { URI, UriComponents } from 'vs/base/common/uri'; import { generateUuid } from 'vs/base/common/uuid'; import * as Types from 'vs/base/common/types'; import * as Platform from 'vs/base/common/platform'; -import { IStringDictionary, forEach } from 'vs/base/common/collections'; +import { IStringDictionary } from 'vs/base/common/collections'; import { IDisposable } from 'vs/base/common/lifecycle'; import { IWorkspace, IWorkspaceContextService, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; @@ -682,10 +682,7 @@ export class MainThreadTask implements MainThreadTaskShape { const vars: string[] = []; toResolve.variables.forEach(item => vars.push(item)); return Promise.resolve(this._proxy.$resolveVariables(workspaceFolder.uri, { process: toResolve.process, variables: vars })).then(values => { - const partiallyResolvedVars = new Array(); - forEach(values.variables, (entry) => { - partiallyResolvedVars.push(entry.value); - }); + const partiallyResolvedVars = Array.from(Object.values(values.variables)); return new Promise((resolve, reject) => { this._configurationResolverService.resolveWithInteraction(workspaceFolder, partiallyResolvedVars, 'tasks', undefined, target).then(resolvedVars => { if (!resolvedVars) { diff --git a/src/vs/workbench/services/actions/common/menusExtensionPoint.ts b/src/vs/workbench/services/actions/common/menusExtensionPoint.ts index e1b8f018998..3d0d3b0206d 100644 --- a/src/vs/workbench/services/actions/common/menusExtensionPoint.ts +++ b/src/vs/workbench/services/actions/common/menusExtensionPoint.ts @@ -7,7 +7,6 @@ import { localize } from 'vs/nls'; import { isFalsyOrWhitespace } from 'vs/base/common/strings'; import * as resources from 'vs/base/common/resources'; import { IJSONSchema } from 'vs/base/common/jsonSchema'; -import { forEach } from 'vs/base/common/collections'; import { IExtensionPointUser, ExtensionMessageCollector, ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { MenuId, MenuRegistry, IMenuItem, ISubmenuItem } from 'vs/platform/actions/common/actions'; @@ -749,19 +748,19 @@ menusExtensionPoint.setHandler(extensions => { for (const extension of extensions) { const { value, collector } = extension; - forEach(value, entry => { - if (!schema.isValidItems(entry.value, collector)) { - return; + for (const entry of Object.entries(value)) { + if (!schema.isValidItems(entry[1], collector)) { + continue; } - let menu = _apiMenusByKey.get(entry.key); + let menu = _apiMenusByKey.get(entry[0]); if (!menu) { - const submenu = _submenus.get(entry.key); + const submenu = _submenus.get(entry[0]); if (submenu) { menu = { - key: entry.key, + key: entry[0], id: submenu.id, description: '' }; @@ -769,16 +768,16 @@ menusExtensionPoint.setHandler(extensions => { } if (!menu) { - collector.info(localize('menuId.invalid', "`{0}` is not a valid menu identifier", entry.key)); - return; + collector.info(localize('menuId.invalid', "`{0}` is not a valid menu identifier", entry[0])); + continue; } if (menu.proposed && !isProposedApiEnabled(extension.description, menu.proposed)) { - collector.error(localize('proposedAPI.invalid', "{0} is a proposed menu identifier. It requires 'package.json#enabledApiProposals: [\"{1}\"]' and is only available when running out of dev or with the following command line switch: --enable-proposed-api {2}", entry.key, menu.proposed, extension.description.identifier.value)); - return; + collector.error(localize('proposedAPI.invalid', "{0} is a proposed menu identifier. It requires 'package.json#enabledApiProposals: [\"{1}\"]' and is only available when running out of dev or with the following command line switch: --enable-proposed-api {2}", entry[0], menu.proposed, extension.description.identifier.value)); + continue; } - for (const menuItem of entry.value) { + for (const menuItem of entry[1]) { let item: IMenuItem | ISubmenuItem; if (schema.isMenuItem(menuItem)) { @@ -818,7 +817,7 @@ menusExtensionPoint.setHandler(extensions => { } if (submenuRegistrations.has(submenu.id.id)) { - collector.warn(localize('submenuItem.duplicate', "The `{0}` submenu was already contributed to the `{1}` menu.", menuItem.submenu, entry.key)); + collector.warn(localize('submenuItem.duplicate', "The `{0}` submenu was already contributed to the `{1}` menu.", menuItem.submenu, entry[0])); continue; } @@ -840,7 +839,7 @@ menusExtensionPoint.setHandler(extensions => { item.when = ContextKeyExpr.deserialize(menuItem.when); items.push({ id: menu.id, item }); } - }); + } } _menuRegistrations.add(MenuRegistry.appendMenuItems(items)); diff --git a/src/vs/workbench/services/extensions/common/abstractExtensionService.ts b/src/vs/workbench/services/extensions/common/abstractExtensionService.ts index 5314122757d..76589d23182 100644 --- a/src/vs/workbench/services/extensions/common/abstractExtensionService.ts +++ b/src/vs/workbench/services/extensions/common/abstractExtensionService.ts @@ -34,7 +34,6 @@ import { URI } from 'vs/base/common/uri'; import { IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService'; import { dedupExtensions } from 'vs/workbench/services/extensions/common/extensionsUtil'; import { ApiProposalName, allApiProposals } from 'vs/workbench/services/extensions/common/extensionsApiProposals'; -import { forEach } from 'vs/base/common/collections'; import { ILogService } from 'vs/platform/log/common/log'; import { IExtensionHostExitInfo, IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import { ILifecycleService } from 'vs/workbench/services/lifecycle/common/lifecycle'; @@ -1479,9 +1478,9 @@ class ProposedApiController { // NEW world - product.json spells out what proposals each extension can use if (productService.extensionEnabledApiProposals) { - forEach(productService.extensionEnabledApiProposals, entry => { - const key = ExtensionIdentifier.toKey(entry.key); - const proposalNames = entry.value.filter(name => { + for (const [k, value] of Object.entries(productService.extensionEnabledApiProposals)) { + const key = ExtensionIdentifier.toKey(k); + const proposalNames = value.filter(name => { if (!allApiProposals[name]) { _logService.warn(`Via 'product.json#extensionEnabledApiProposals' extension '${key}' wants API proposal '${name}' but that proposal DOES NOT EXIST. Likely, the proposal has been finalized (check 'vscode.d.ts') or was abandoned.`); return false; @@ -1489,7 +1488,7 @@ class ProposedApiController { return true; }); this._productEnabledExtensions.set(key, proposalNames); - }); + } } } From f96a4627b13a7c9a00f022ad6d16348cf87e5843 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 6 Jul 2022 15:42:42 -0700 Subject: [PATCH 305/347] Pick up latest TS for building VS Code (#154312) --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 8f07addce0c..5dec1737bc8 100644 --- a/package.json +++ b/package.json @@ -202,7 +202,7 @@ "style-loader": "^1.3.0", "ts-loader": "^9.2.7", "tsec": "0.1.4", - "typescript": "^4.8.0-dev.20220614", + "typescript": "^4.8.0-dev.20220706", "typescript-formatter": "7.1.0", "underscore": "^1.12.1", "util": "^0.12.4", diff --git a/yarn.lock b/yarn.lock index 919a8b26019..4189162c56a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11448,10 +11448,10 @@ typescript@^2.6.2: resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.6.2.tgz#3c5b6fd7f6de0914269027f03c0946758f7673a4" integrity sha1-PFtv1/beCRQmkCfwPAlGdY92c6Q= -typescript@^4.8.0-dev.20220614: - version "4.8.0-dev.20220614" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.0-dev.20220614.tgz#5b3f65db9667b054667f891d79cebb0e2993c162" - integrity sha512-pZVLT8Li6ZCYmyv6F+xEJ+nZ947uRE7el5OloggrPZdhjDJpBBBn/CK5YCgnXcmZFgwO6WMbco1GwfsR23CsxA== +typescript@^4.8.0-dev.20220706: + version "4.8.0-dev.20220706" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.0-dev.20220706.tgz#5f2c703258f08468eac5d1147a8604954681a6b4" + integrity sha512-kQGVsx25I0KFyzMwrZTm+umjHRDA31SUH4WBtJfCaSmr67CH0vKu8XSaPCl84zb39cAnfHpI4S8qLvkgDaAmqQ== typical@^4.0.0: version "4.0.0" From 3d3bfced969d0ffd1fdc7a1938cc26bbd64d9d42 Mon Sep 17 00:00:00 2001 From: Andrea Mah <31675041+andreamah@users.noreply.github.com> Date: Wed, 6 Jul 2022 15:46:56 -0700 Subject: [PATCH 306/347] Commands for Navigating Call Stack (#154117) Commands to navigate the call stack Fixes #149975 --- .../debug/browser/debug.contribution.ts | 7 +- .../contrib/debug/browser/debugCommands.ts | 140 +++++++++++++++++- .../contrib/debug/browser/debugSession.ts | 2 +- .../workbench/contrib/debug/common/debug.ts | 2 + .../contrib/debug/common/debugModel.ts | 26 +++- 5 files changed, 172 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts index bebcecd9455..54d0f0a0e7c 100644 --- a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts +++ b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts @@ -20,7 +20,7 @@ import { } from 'vs/workbench/contrib/debug/common/debug'; import { DebugToolBar } from 'vs/workbench/contrib/debug/browser/debugToolBar'; import { DebugService } from 'vs/workbench/contrib/debug/browser/debugService'; -import { ADD_CONFIGURATION_ID, TOGGLE_INLINE_BREAKPOINT_ID, COPY_STACK_TRACE_ID, RESTART_SESSION_ID, TERMINATE_THREAD_ID, STEP_OVER_ID, STEP_INTO_ID, STEP_OUT_ID, PAUSE_ID, DISCONNECT_ID, STOP_ID, RESTART_FRAME_ID, CONTINUE_ID, FOCUS_REPL_ID, JUMP_TO_CURSOR_ID, RESTART_LABEL, STEP_INTO_LABEL, STEP_OVER_LABEL, STEP_OUT_LABEL, PAUSE_LABEL, DISCONNECT_LABEL, STOP_LABEL, CONTINUE_LABEL, DEBUG_START_LABEL, DEBUG_START_COMMAND_ID, DEBUG_RUN_LABEL, DEBUG_RUN_COMMAND_ID, EDIT_EXPRESSION_COMMAND_ID, REMOVE_EXPRESSION_COMMAND_ID, SELECT_AND_START_ID, SELECT_AND_START_LABEL, SET_EXPRESSION_COMMAND_ID, DISCONNECT_AND_SUSPEND_ID, DISCONNECT_AND_SUSPEND_LABEL, NEXT_DEBUG_CONSOLE_ID, NEXT_DEBUG_CONSOLE_LABEL, PREV_DEBUG_CONSOLE_ID, PREV_DEBUG_CONSOLE_LABEL, OPEN_LOADED_SCRIPTS_LABEL, SHOW_LOADED_SCRIPTS_ID, DEBUG_QUICK_ACCESS_PREFIX, DEBUG_CONSOLE_QUICK_ACCESS_PREFIX, SELECT_DEBUG_CONSOLE_ID, SELECT_DEBUG_CONSOLE_LABEL, STEP_INTO_TARGET_LABEL, STEP_INTO_TARGET_ID, DEBUG_COMMAND_CATEGORY } from 'vs/workbench/contrib/debug/browser/debugCommands'; +import { ADD_CONFIGURATION_ID, TOGGLE_INLINE_BREAKPOINT_ID, COPY_STACK_TRACE_ID, RESTART_SESSION_ID, TERMINATE_THREAD_ID, STEP_OVER_ID, STEP_INTO_ID, STEP_OUT_ID, PAUSE_ID, DISCONNECT_ID, STOP_ID, RESTART_FRAME_ID, CONTINUE_ID, FOCUS_REPL_ID, JUMP_TO_CURSOR_ID, RESTART_LABEL, STEP_INTO_LABEL, STEP_OVER_LABEL, STEP_OUT_LABEL, PAUSE_LABEL, DISCONNECT_LABEL, STOP_LABEL, CONTINUE_LABEL, DEBUG_START_LABEL, DEBUG_START_COMMAND_ID, DEBUG_RUN_LABEL, DEBUG_RUN_COMMAND_ID, EDIT_EXPRESSION_COMMAND_ID, REMOVE_EXPRESSION_COMMAND_ID, SELECT_AND_START_ID, SELECT_AND_START_LABEL, SET_EXPRESSION_COMMAND_ID, DISCONNECT_AND_SUSPEND_ID, DISCONNECT_AND_SUSPEND_LABEL, NEXT_DEBUG_CONSOLE_ID, NEXT_DEBUG_CONSOLE_LABEL, PREV_DEBUG_CONSOLE_ID, PREV_DEBUG_CONSOLE_LABEL, OPEN_LOADED_SCRIPTS_LABEL, SHOW_LOADED_SCRIPTS_ID, DEBUG_QUICK_ACCESS_PREFIX, DEBUG_CONSOLE_QUICK_ACCESS_PREFIX, SELECT_DEBUG_CONSOLE_ID, SELECT_DEBUG_CONSOLE_LABEL, STEP_INTO_TARGET_LABEL, STEP_INTO_TARGET_ID, CALLSTACK_TOP_ID, CALLSTACK_TOP_LABEL, CALLSTACK_BOTTOM_LABEL, CALLSTACK_UP_LABEL, CALLSTACK_BOTTOM_ID, CALLSTACK_UP_ID, CALLSTACK_DOWN_ID, CALLSTACK_DOWN_LABEL, DEBUG_COMMAND_CATEGORY } from 'vs/workbench/contrib/debug/browser/debugCommands'; import { StatusBarColorProvider } from 'vs/workbench/contrib/debug/browser/statusbarColorProvider'; import { IViewsRegistry, Extensions as ViewExtensions, IViewContainersRegistry, ViewContainerLocation, ViewContainer } from 'vs/workbench/common/views'; import { isMacintosh, isWeb } from 'vs/base/common/platform'; @@ -136,7 +136,10 @@ registerDebugCommandPaletteItem(NEXT_DEBUG_CONSOLE_ID, NEXT_DEBUG_CONSOLE_LABEL) registerDebugCommandPaletteItem(PREV_DEBUG_CONSOLE_ID, PREV_DEBUG_CONSOLE_LABEL); registerDebugCommandPaletteItem(SHOW_LOADED_SCRIPTS_ID, OPEN_LOADED_SCRIPTS_LABEL, CONTEXT_IN_DEBUG_MODE); registerDebugCommandPaletteItem(SELECT_DEBUG_CONSOLE_ID, SELECT_DEBUG_CONSOLE_LABEL); - +registerDebugCommandPaletteItem(CALLSTACK_TOP_ID, CALLSTACK_TOP_LABEL, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); +registerDebugCommandPaletteItem(CALLSTACK_BOTTOM_ID, CALLSTACK_BOTTOM_LABEL, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); +registerDebugCommandPaletteItem(CALLSTACK_UP_ID, CALLSTACK_UP_LABEL, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); +registerDebugCommandPaletteItem(CALLSTACK_DOWN_ID, CALLSTACK_DOWN_LABEL, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped')); // Debug callstack context menu const registerDebugViewMenuItem = (menuId: MenuId, id: string, title: string | ICommandActionTitle, order: number, when?: ContextKeyExpression, precondition?: ContextKeyExpression, group = 'navigation', icon?: Icon) => { diff --git a/src/vs/workbench/contrib/debug/browser/debugCommands.ts b/src/vs/workbench/contrib/debug/browser/debugCommands.ts index 86fa5b8c01b..25da3464ac6 100644 --- a/src/vs/workbench/contrib/debug/browser/debugCommands.ts +++ b/src/vs/workbench/contrib/debug/browser/debugCommands.ts @@ -9,7 +9,7 @@ import { List } from 'vs/base/browser/ui/list/listWidget'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { IListService } from 'vs/platform/list/browser/listService'; import { IDebugService, IEnablement, CONTEXT_BREAKPOINTS_FOCUSED, CONTEXT_WATCH_EXPRESSIONS_FOCUSED, CONTEXT_VARIABLES_FOCUSED, EDITOR_CONTRIBUTION_ID, IDebugEditorContribution, CONTEXT_IN_DEBUG_MODE, CONTEXT_EXPRESSION_SELECTED, IConfig, IStackFrame, IThread, IDebugSession, CONTEXT_DEBUG_STATE, IDebugConfiguration, CONTEXT_JUMP_TO_CURSOR_SUPPORTED, REPL_VIEW_ID, CONTEXT_DEBUGGERS_AVAILABLE, State, getStateLabel, CONTEXT_BREAKPOINT_INPUT_FOCUSED, CONTEXT_FOCUSED_SESSION_IS_ATTACH, VIEWLET_ID, CONTEXT_DISASSEMBLY_VIEW_FOCUS, CONTEXT_IN_DEBUG_REPL, CONTEXT_STEP_INTO_TARGETS_SUPPORTED } from 'vs/workbench/contrib/debug/common/debug'; -import { Expression, Variable, Breakpoint, FunctionBreakpoint, DataBreakpoint } from 'vs/workbench/contrib/debug/common/debugModel'; +import { Expression, Variable, Breakpoint, FunctionBreakpoint, DataBreakpoint, Thread } from 'vs/workbench/contrib/debug/common/debugModel'; import { IExtensionsViewPaneContainer, VIEWLET_ID as EXTENSIONS_VIEWLET_ID } from 'vs/workbench/contrib/extensions/common/extensions'; import { ICodeEditor, isCodeEditor } from 'vs/editor/browser/editorBrowser'; import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; @@ -64,6 +64,10 @@ export const REMOVE_EXPRESSION_COMMAND_ID = 'debug.removeWatchExpression'; export const NEXT_DEBUG_CONSOLE_ID = 'workbench.action.debug.nextConsole'; export const PREV_DEBUG_CONSOLE_ID = 'workbench.action.debug.prevConsole'; export const SHOW_LOADED_SCRIPTS_ID = 'workbench.action.debug.showLoadedScripts'; +export const CALLSTACK_TOP_ID = 'workbench.action.debug.callStackTop'; +export const CALLSTACK_BOTTOM_ID = 'workbench.action.debug.callStackBottom'; +export const CALLSTACK_UP_ID = 'workbench.action.debug.callStackUp'; +export const CALLSTACK_DOWN_ID = 'workbench.action.debug.callStackDown'; export const DEBUG_COMMAND_CATEGORY = 'Debug'; export const RESTART_LABEL = { value: nls.localize('restartDebug', "Restart"), original: 'Restart' }; @@ -84,6 +88,10 @@ export const DEBUG_RUN_LABEL = { value: nls.localize('startWithoutDebugging', "S export const NEXT_DEBUG_CONSOLE_LABEL = { value: nls.localize('nextDebugConsole', "Focus Next Debug Console"), original: 'Focus Next Debug Console' }; export const PREV_DEBUG_CONSOLE_LABEL = { value: nls.localize('prevDebugConsole', "Focus Previous Debug Console"), original: 'Focus Previous Debug Console' }; export const OPEN_LOADED_SCRIPTS_LABEL = { value: nls.localize('openLoadedScript', "Open Loaded Script..."), original: 'Open Loaded Script...' }; +export const CALLSTACK_TOP_LABEL = { value: nls.localize('callStackTop', "Navigate to Top of Call Stack"), original: 'Navigate to Top of Call Stack' }; +export const CALLSTACK_BOTTOM_LABEL = { value: nls.localize('callStackBottom', "Navigate to Bottom of Call Stack"), original: 'Navigate to Bottom of Call Stack' }; +export const CALLSTACK_UP_LABEL = { value: nls.localize('callStackUp', "Navigate Up Call Stack"), original: 'Navigate Up Call Stack' }; +export const CALLSTACK_DOWN_LABEL = { value: nls.localize('callStackDown', "Navigate Down Call Stack"), original: 'Navigate Down Call Stack' }; export const SELECT_DEBUG_CONSOLE_LABEL = { value: nls.localize('selectDebugConsole', "Select Debug Console"), original: 'Select Debug Console' }; @@ -180,6 +188,103 @@ async function changeDebugConsoleFocus(accessor: ServicesAccessor, next: boolean } } +async function navigateCallStack(debugService: IDebugService, down: boolean) { + const frame = debugService.getViewModel().focusedStackFrame; + if (frame) { + + let callStack = frame.thread.getCallStack(); + let index = callStack.findIndex(elem => elem.frameId === frame.frameId); + let nextVisibleFrame; + if (down) { + if (index >= callStack.length - 1) { + if ((frame.thread).reachedEndOfCallStack) { + goToTopOfCallStack(debugService); + return; + } else { + await debugService.getModel().fetchCallstack(frame.thread, 20); + callStack = frame.thread.getCallStack(); + index = callStack.findIndex(elem => elem.frameId === frame.frameId); + } + } + nextVisibleFrame = findNextVisibleFrame(true, callStack, index); + } else { + if (index <= 0) { + goToBottomOfCallStack(debugService); + return; + } + nextVisibleFrame = findNextVisibleFrame(false, callStack, index); + } + + if (nextVisibleFrame) { + debugService.focusStackFrame(nextVisibleFrame); + } + } +} + +async function goToBottomOfCallStack(debugService: IDebugService) { + const thread = debugService.getViewModel().focusedThread; + if (thread) { + await debugService.getModel().fetchCallstack(thread); + const callStack = thread.getCallStack(); + if (callStack.length > 0) { + const nextVisibleFrame = findNextVisibleFrame(false, callStack, 0); // must consider the next frame up first, which will be the last frame + if (nextVisibleFrame) { + debugService.focusStackFrame(nextVisibleFrame); + } + } + } +} + +function goToTopOfCallStack(debugService: IDebugService) { + const thread = debugService.getViewModel().focusedThread; + + if (thread) { + debugService.focusStackFrame(thread.getTopStackFrame()); + } +} + +/** + * Finds next frame that is not skipped by SkipFiles. Skips frame at index and starts searching at next. + * Must satisfy `0 <= startIndex <= callStack - 1` + * @param down specifies whether to search downwards if the current file is skipped. + * @param callStack the call stack to search + * @param startIndex the index to start the search at + */ +function findNextVisibleFrame(down: boolean, callStack: readonly IStackFrame[], startIndex: number) { + + if (startIndex >= callStack.length) { + startIndex = callStack.length - 1; + } else if (startIndex < 0) { + startIndex = 0; + } + + let index = startIndex; + + let currFrame; + do { + if (down) { + if (index === callStack.length - 1) { + index = 0; + } else { + index++; + } + } else { + if (index === 0) { + index = callStack.length - 1; + } else { + index--; + } + } + + currFrame = callStack[index]; + if (!(currFrame.source.presentationHint === 'deemphasize' || currFrame.presentationHint === 'deemphasize')) { + return currFrame; + } + } while (index !== startIndex); // end loop when we've just checked the start index, since that should be the last one checked + + return undefined; +} + // These commands are used in call stack context menu, call stack inline actions, command palette, debug toolbar, mac native touch bar // When the command is exectued in the context of a thread(context menu on a thread, inline call stack action) we pass the thread id // Otherwise when it is executed "globaly"(using the touch bar, debug toolbar, command palette) we do not pass any id and just take whatever is the focussed thread @@ -261,6 +366,39 @@ CommandsRegistry.registerCommand({ } }); + +CommandsRegistry.registerCommand({ + id: CALLSTACK_TOP_ID, + handler: async (accessor: ServicesAccessor, _: string, context: CallStackContext | unknown) => { + const debugService = accessor.get(IDebugService); + goToTopOfCallStack(debugService); + } +}); + +CommandsRegistry.registerCommand({ + id: CALLSTACK_BOTTOM_ID, + handler: async (accessor: ServicesAccessor, _: string, context: CallStackContext | unknown) => { + const debugService = accessor.get(IDebugService); + await goToBottomOfCallStack(debugService); + } +}); + +CommandsRegistry.registerCommand({ + id: CALLSTACK_UP_ID, + handler: async (accessor: ServicesAccessor, _: string, context: CallStackContext | unknown) => { + const debugService = accessor.get(IDebugService); + navigateCallStack(debugService, false); + } +}); + +CommandsRegistry.registerCommand({ + id: CALLSTACK_DOWN_ID, + handler: async (accessor: ServicesAccessor, _: string, context: CallStackContext | unknown) => { + const debugService = accessor.get(IDebugService); + navigateCallStack(debugService, true); + } +}); + MenuRegistry.appendMenuItem(MenuId.EditorContext, { command: { id: JUMP_TO_CURSOR_ID, diff --git a/src/vs/workbench/contrib/debug/browser/debugSession.ts b/src/vs/workbench/contrib/debug/browser/debugSession.ts index 4a53a4e0c93..de26f713ef0 100644 --- a/src/vs/workbench/contrib/debug/browser/debugSession.ts +++ b/src/vs/workbench/contrib/debug/browser/debugSession.ts @@ -955,7 +955,7 @@ export class DebugSession implements IDebugSession { if (thread) { // Call fetch call stack twice, the first only return the top stack frame. // Second retrieves the rest of the call stack. For performance reasons #25605 - const promises = this.model.fetchCallStack(thread); + const promises = this.model.refreshTopOfCallstack(thread); const focus = async () => { if (focusedThreadDoesNotExist || (!event.body.preserveFocusHint && thread.getCallStack().length)) { const focusedStackFrame = this.debugService.getViewModel().focusedStackFrame; diff --git a/src/vs/workbench/contrib/debug/common/debug.ts b/src/vs/workbench/contrib/debug/common/debug.ts index baac9206484..a8397f69aef 100644 --- a/src/vs/workbench/contrib/debug/common/debug.ts +++ b/src/vs/workbench/contrib/debug/common/debug.ts @@ -602,6 +602,8 @@ export interface IDebugModel extends ITreeElement { onDidChangeBreakpoints: Event; onDidChangeCallStack: Event; onDidChangeWatchExpressions: Event; + + fetchCallstack(thread: IThread, levels?: number): Promise; } /** diff --git a/src/vs/workbench/contrib/debug/common/debugModel.ts b/src/vs/workbench/contrib/debug/common/debugModel.ts index 4b20e069cd2..1f50eb36368 100644 --- a/src/vs/workbench/contrib/debug/common/debugModel.ts +++ b/src/vs/workbench/contrib/debug/common/debugModel.ts @@ -1244,7 +1244,31 @@ export class DebugModel implements IDebugModel { } } - fetchCallStack(thread: Thread): { topCallStack: Promise; wholeCallStack: Promise } { + /** + * Update the call stack and notify the call stack view that changes have occurred. + */ + async fetchCallstack(thread: IThread, levels?: number): Promise { + + if ((thread).reachedEndOfCallStack) { + return; + } + + const totalFrames = thread.stoppedDetails?.totalFrames; + const remainingFrames = (typeof totalFrames === 'number') ? (totalFrames - thread.getCallStack().length) : undefined; + + if (!levels || (remainingFrames && levels > remainingFrames)) { + levels = remainingFrames; + } + + if (levels && levels > 0) { + await (thread).fetchCallStack(levels); + this._onDidChangeCallStack.fire(); + } + + return; + } + + refreshTopOfCallstack(thread: Thread): { topCallStack: Promise; wholeCallStack: Promise } { if (thread.session.capabilities.supportsDelayedStackTraceLoading) { // For improved performance load the first stack frame and then load the rest async. let topCallStack = Promise.resolve(); From a6238ac59c487435fb5810986771999f1d6ea8bb Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 6 Jul 2022 15:15:03 -0700 Subject: [PATCH 307/347] Add icon in defaultIcon description --- .../workbench/contrib/terminal/common/terminalConfiguration.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts b/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts index c1f9c0af306..acdd4ce698d 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts @@ -58,6 +58,7 @@ const terminalConfiguration: IConfigurationNode = { description: localize('terminal.integrated.tabs.defaultIcon', "Controls the terminal tab's default icon."), type: 'string', enum: Codicon.getAll().map(icon => icon.id), + markdownEnumDescriptions: Array.from(Codicon.getAll(), icon => `$(${icon.id})`), default: undefined, }, [TerminalSettingId.TabsEnabled]: { From ad9675f09956998950de8001d496a8bfe726dab3 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 6 Jul 2022 16:03:24 -0700 Subject: [PATCH 308/347] Scaffold out basic markdown language server (#154293) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Scaffold out basic markdown lsp This scaffolds out a new markdown language server and then uses it to implement document symbols. After the change, the markdown extension will have the following structure: - languageService — Where all the LSP language stuff will eventually land - server — The actual language server. Consumes ` languageService` - src — The current extension that launches the server and implements VS Code specific functions * Adding build scripts * a * Use language service from github * Remove ls build scripts * Bump versions * Only build ext * Enable for web * Fixing for browser --- .../darwin/product-build-darwin-test.yml | 1 + .../linux/product-build-linux-client-test.yml | 1 + .../win32/product-build-win32-test.yml | 1 + build/gulpfile.extensions.js | 1 + build/npm/dirs.js | 1 + .../extension-browser.webpack.config.js | 2 +- .../extension.webpack.config.js | 2 +- .../markdown-language-features/package.json | 7 +- .../server/.vscode/launch.json | 33 +++++ .../server/.vscode/tasks.json | 9 ++ .../extension-browser.webpack.config.js | 24 ++++ .../server/extension.webpack.config.js | 22 +++ .../server/package.json | 27 ++++ .../server/src/browser/main.ts | 16 +++ .../server/src/logging.ts | 42 ++++++ .../server/src/node/main.ts | 19 +++ .../server/src/server.ts | 132 ++++++++++++++++++ .../server/tsconfig.json | 9 ++ .../server/yarn.lock | 60 ++++++++ .../markdown-language-features/src/client.ts | 49 +++++++ .../src/extension.browser.ts | 39 ++++++ .../src/extension.node.ts | 50 +++++++ .../src/{extension.ts => extension.shared.ts} | 29 ++-- .../src/languageFeatures/documentSymbols.ts | 8 -- .../src/test/documentSymbolProvider.test.ts | 121 ---------------- .../markdown-language-features/yarn.lock | 71 ++++++++++ extensions/markdown-math/.gitignore | 1 + 27 files changed, 626 insertions(+), 151 deletions(-) create mode 100644 extensions/markdown-language-features/server/.vscode/launch.json create mode 100644 extensions/markdown-language-features/server/.vscode/tasks.json create mode 100644 extensions/markdown-language-features/server/extension-browser.webpack.config.js create mode 100644 extensions/markdown-language-features/server/extension.webpack.config.js create mode 100644 extensions/markdown-language-features/server/package.json create mode 100644 extensions/markdown-language-features/server/src/browser/main.ts create mode 100644 extensions/markdown-language-features/server/src/logging.ts create mode 100644 extensions/markdown-language-features/server/src/node/main.ts create mode 100644 extensions/markdown-language-features/server/src/server.ts create mode 100644 extensions/markdown-language-features/server/tsconfig.json create mode 100644 extensions/markdown-language-features/server/yarn.lock create mode 100644 extensions/markdown-language-features/src/client.ts create mode 100644 extensions/markdown-language-features/src/extension.browser.ts create mode 100644 extensions/markdown-language-features/src/extension.node.ts rename extensions/markdown-language-features/src/{extension.ts => extension.shared.ts} (87%) delete mode 100644 extensions/markdown-language-features/src/test/documentSymbolProvider.test.ts diff --git a/build/azure-pipelines/darwin/product-build-darwin-test.yml b/build/azure-pipelines/darwin/product-build-darwin-test.yml index c5547cbdcf2..4c30c5e0b31 100644 --- a/build/azure-pipelines/darwin/product-build-darwin-test.yml +++ b/build/azure-pipelines/darwin/product-build-darwin-test.yml @@ -46,6 +46,7 @@ steps: compile-extension:html-language-features-server \ compile-extension:ipynb \ compile-extension:json-language-features-server \ + compile-extension:markdown-language-features-server \ compile-extension:markdown-language-features \ compile-extension-media \ compile-extension:microsoft-authentication \ diff --git a/build/azure-pipelines/linux/product-build-linux-client-test.yml b/build/azure-pipelines/linux/product-build-linux-client-test.yml index ae1e77aaa73..bc9aae42daf 100644 --- a/build/azure-pipelines/linux/product-build-linux-client-test.yml +++ b/build/azure-pipelines/linux/product-build-linux-client-test.yml @@ -58,6 +58,7 @@ steps: compile-extension:html-language-features-server \ compile-extension:ipynb \ compile-extension:json-language-features-server \ + compile-extension:markdown-language-features-server \ compile-extension:markdown-language-features \ compile-extension-media \ compile-extension:microsoft-authentication \ diff --git a/build/azure-pipelines/win32/product-build-win32-test.yml b/build/azure-pipelines/win32/product-build-win32-test.yml index 4b846b1bada..9dc50f8bcc4 100644 --- a/build/azure-pipelines/win32/product-build-win32-test.yml +++ b/build/azure-pipelines/win32/product-build-win32-test.yml @@ -52,6 +52,7 @@ steps: compile-extension:html-language-features-server ` compile-extension:ipynb ` compile-extension:json-language-features-server ` + compile-extension:markdown-language-features-server ` compile-extension:markdown-language-features ` compile-extension-media ` compile-extension:microsoft-authentication ` diff --git a/build/gulpfile.extensions.js b/build/gulpfile.extensions.js index a07071e345d..bb893f02923 100644 --- a/build/gulpfile.extensions.js +++ b/build/gulpfile.extensions.js @@ -53,6 +53,7 @@ const compilations = [ 'json-language-features/client/tsconfig.json', 'json-language-features/server/tsconfig.json', 'markdown-language-features/preview-src/tsconfig.json', + 'markdown-language-features/server/tsconfig.json', 'markdown-language-features/tsconfig.json', 'markdown-math/tsconfig.json', 'merge-conflict/tsconfig.json', diff --git a/build/npm/dirs.js b/build/npm/dirs.js index 35521822dc6..d77e0099290 100644 --- a/build/npm/dirs.js +++ b/build/npm/dirs.js @@ -28,6 +28,7 @@ exports.dirs = [ 'extensions/jake', 'extensions/json-language-features', 'extensions/json-language-features/server', + 'extensions/markdown-language-features/server', 'extensions/markdown-language-features', 'extensions/markdown-math', 'extensions/merge-conflict', diff --git a/extensions/markdown-language-features/extension-browser.webpack.config.js b/extensions/markdown-language-features/extension-browser.webpack.config.js index 1b52e196f91..bad27aab02e 100644 --- a/extensions/markdown-language-features/extension-browser.webpack.config.js +++ b/extensions/markdown-language-features/extension-browser.webpack.config.js @@ -12,7 +12,7 @@ const withBrowserDefaults = require('../shared.webpack.config').browser; module.exports = withBrowserDefaults({ context: __dirname, entry: { - extension: './src/extension.ts' + extension: './src/extension.browser.ts' } }, { configFile: 'tsconfig.browser.json' diff --git a/extensions/markdown-language-features/extension.webpack.config.js b/extensions/markdown-language-features/extension.webpack.config.js index de88398eca0..756d6735a60 100644 --- a/extensions/markdown-language-features/extension.webpack.config.js +++ b/extensions/markdown-language-features/extension.webpack.config.js @@ -15,6 +15,6 @@ module.exports = withDefaults({ mainFields: ['module', 'main'] }, entry: { - extension: './src/extension.ts', + extension: './src/extension.node.ts', } }); diff --git a/extensions/markdown-language-features/package.json b/extensions/markdown-language-features/package.json index 0ce010f6cc3..13a77aa1f42 100644 --- a/extensions/markdown-language-features/package.json +++ b/extensions/markdown-language-features/package.json @@ -10,7 +10,7 @@ "engines": { "vscode": "^1.20.0" }, - "main": "./out/extension", + "main": "./out/extension.node", "browser": "./dist/browser/extension", "categories": [ "Programming Languages" @@ -534,8 +534,8 @@ ] }, "scripts": { - "compile": "gulp compile-extension:markdown-language-features && npm run build-preview && npm run build-notebook", - "watch": "npm run build-preview && gulp watch-extension:markdown-language-features", + "compile": "gulp compile-extension:markdown-language-features-languageService && gulp compile-extension:markdown-language-features-server && gulp compile-extension:markdown-language-features && npm run build-preview && npm run build-notebook", + "watch": "npm run build-preview && gulp watch-extension:markdown-language-features watch-extension:markdown-language-features-languageService watch-extension:markdown-language-features-server", "vscode:prepublish": "npm run build-ext && npm run build-preview", "build-ext": "node ../../node_modules/gulp/bin/gulp.js --gulpfile ../../build/gulpfile.extensions.js compile-extension:markdown-language-features ./tsconfig.json", "build-notebook": "node ./esbuild-notebook", @@ -551,6 +551,7 @@ "markdown-it-front-matter": "^0.2.1", "morphdom": "^2.6.1", "picomatch": "^2.3.1", + "vscode-languageclient": "^8.0.1", "vscode-languageserver-textdocument": "^1.0.4", "vscode-nls": "^5.0.0", "vscode-uri": "^3.0.3" diff --git a/extensions/markdown-language-features/server/.vscode/launch.json b/extensions/markdown-language-features/server/.vscode/launch.json new file mode 100644 index 00000000000..5753befac8b --- /dev/null +++ b/extensions/markdown-language-features/server/.vscode/launch.json @@ -0,0 +1,33 @@ +{ + "version": "0.1.0", + // List of configurations. Add new configurations or edit existing ones. + "configurations": [ + { + "name": "Attach", + "type": "node", + "request": "attach", + "port": 6044, + "protocol": "inspector", + "sourceMaps": true, + "outFiles": ["${workspaceFolder}/out/**/*.js"] + }, + { + "name": "Unit Tests", + "type": "node", + "request": "launch", + "program": "${workspaceFolder}/../../../node_modules/mocha/bin/_mocha", + "stopOnEntry": false, + "args": [ + "--timeout", + "999999", + "--colors" + ], + "cwd": "${workspaceFolder}", + "runtimeExecutable": null, + "runtimeArgs": [], + "env": {}, + "sourceMaps": true, + "outFiles": ["${workspaceFolder}/out/**/*.js"] + } + ] +} \ No newline at end of file diff --git a/extensions/markdown-language-features/server/.vscode/tasks.json b/extensions/markdown-language-features/server/.vscode/tasks.json new file mode 100644 index 00000000000..6a159d6a5fa --- /dev/null +++ b/extensions/markdown-language-features/server/.vscode/tasks.json @@ -0,0 +1,9 @@ +{ + "version": "0.1.0", + "command": "npm", + "isShellCommand": true, + "showOutput": "silent", + "args": ["run", "watch"], + "isWatching": true, + "problemMatcher": "$tsc-watch" +} \ No newline at end of file diff --git a/extensions/markdown-language-features/server/extension-browser.webpack.config.js b/extensions/markdown-language-features/server/extension-browser.webpack.config.js new file mode 100644 index 00000000000..b36d36f936d --- /dev/null +++ b/extensions/markdown-language-features/server/extension-browser.webpack.config.js @@ -0,0 +1,24 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +//@ts-check + +'use strict'; + +const withBrowserDefaults = require('../../shared.webpack.config').browser; +const path = require('path'); + +module.exports = withBrowserDefaults({ + context: __dirname, + entry: { + extension: './src/browser/main.ts', + }, + output: { + filename: 'main.js', + path: path.join(__dirname, 'dist', 'browser'), + libraryTarget: 'var', + library: 'serverExportVar' + } +}); diff --git a/extensions/markdown-language-features/server/extension.webpack.config.js b/extensions/markdown-language-features/server/extension.webpack.config.js new file mode 100644 index 00000000000..a1917b54dc6 --- /dev/null +++ b/extensions/markdown-language-features/server/extension.webpack.config.js @@ -0,0 +1,22 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +//@ts-check + +'use strict'; + +const withDefaults = require('../../shared.webpack.config'); +const path = require('path'); + +module.exports = withDefaults({ + context: path.join(__dirname), + entry: { + extension: './src/node/main.ts', + }, + output: { + filename: 'main.js', + path: path.join(__dirname, 'dist', 'node'), + } +}); diff --git a/extensions/markdown-language-features/server/package.json b/extensions/markdown-language-features/server/package.json new file mode 100644 index 00000000000..2ca66e39347 --- /dev/null +++ b/extensions/markdown-language-features/server/package.json @@ -0,0 +1,27 @@ +{ + "name": "vscode-markdown-languageserver", + "description": "Markdown language server", + "version": "1.0.0", + "author": "Microsoft Corporation", + "license": "MIT", + "engines": { + "node": "*" + }, + "main": "./out/node/main", + "browser": "./dist/browser/main", + "dependencies": { + "vscode-languageserver": "^8.0.2-next.4", + "vscode-uri": "^3.0.3", + "vscode-languageserver-textdocument": "^1.0.5", + "vscode-languageserver-types": "^3.17.1", + "vscode-markdown-languageservice": "mjbvz/vscode-markdown-languageservice" + }, + "devDependencies": { + "@types/node": "16.x" + }, + "scripts": { + "postinstall": "cd node_modules/vscode-markdown-languageservice && yarn run compile-ext", + "compile": "gulp compile-extension:markdown-language-features-server", + "watch": "gulp watch-extension:markdown-language-features-server" + } +} diff --git a/extensions/markdown-language-features/server/src/browser/main.ts b/extensions/markdown-language-features/server/src/browser/main.ts new file mode 100644 index 00000000000..cc5e12e9c19 --- /dev/null +++ b/extensions/markdown-language-features/server/src/browser/main.ts @@ -0,0 +1,16 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { BrowserMessageReader, BrowserMessageWriter, createConnection } from 'vscode-languageserver/browser'; +import { startServer } from '../server'; + +declare let self: any; + +const messageReader = new BrowserMessageReader(self); +const messageWriter = new BrowserMessageWriter(self); + +const connection = createConnection(messageReader, messageWriter); + +startServer(connection); diff --git a/extensions/markdown-language-features/server/src/logging.ts b/extensions/markdown-language-features/server/src/logging.ts new file mode 100644 index 00000000000..2172ef8d1d6 --- /dev/null +++ b/extensions/markdown-language-features/server/src/logging.ts @@ -0,0 +1,42 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { ILogger } from 'vscode-markdown-languageservice'; + +class ConsoleLogger implements ILogger { + + public verbose(title: string, message: string, data?: any): void { + this.appendLine(`[Verbose ${ConsoleLogger.now()}] ${title}: ${message}`); + if (data) { + this.appendLine(ConsoleLogger.data2String(data)); + } + } + + private static now(): string { + const now = new Date(); + return String(now.getUTCHours()).padStart(2, '0') + + ':' + String(now.getMinutes()).padStart(2, '0') + + ':' + String(now.getUTCSeconds()).padStart(2, '0') + '.' + String(now.getMilliseconds()).padStart(3, '0'); + } + + private appendLine(value: string): void { + console.log(value); + } + + private static data2String(data: any): string { + if (data instanceof Error) { + if (typeof data.stack === 'string') { + return data.stack; + } + return data.message; + } + if (typeof data === 'string') { + return data; + } + return JSON.stringify(data, undefined, 2); + } +} + +export const consoleLogger = new ConsoleLogger(); diff --git a/extensions/markdown-language-features/server/src/node/main.ts b/extensions/markdown-language-features/server/src/node/main.ts new file mode 100644 index 00000000000..609948b803d --- /dev/null +++ b/extensions/markdown-language-features/server/src/node/main.ts @@ -0,0 +1,19 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Connection, createConnection } from 'vscode-languageserver/node'; +import { startServer } from '../server'; + +// Create a connection for the server. +const connection: Connection = createConnection(); + +console.log = connection.console.log.bind(connection.console); +console.error = connection.console.error.bind(connection.console); + +process.on('unhandledRejection', (e: any) => { + connection.console.error(`Unhandled exception ${e}`); +}); + +startServer(connection); diff --git a/extensions/markdown-language-features/server/src/server.ts b/extensions/markdown-language-features/server/src/server.ts new file mode 100644 index 00000000000..8a2ec6dbba8 --- /dev/null +++ b/extensions/markdown-language-features/server/src/server.ts @@ -0,0 +1,132 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Connection, Emitter, Event, InitializeParams, InitializeResult, RequestType, TextDocuments } from 'vscode-languageserver'; +import { TextDocument } from 'vscode-languageserver-textdocument'; +import { DocumentSymbol, Position, Range } from 'vscode-languageserver-types'; +import * as md from 'vscode-markdown-languageservice'; +import { URI } from 'vscode-uri'; +import { consoleLogger } from './logging'; + + +const parseRequestType: RequestType<{ uri: string }, md.Token[], any> = new RequestType('markdown/parse'); + +class TextDocumentToITextDocumentAdapter implements md.ITextDocument { + public readonly uri: md.IUri; + + public get version(): number { return this._doc.version; } + + public get lineCount(): number { return this._doc.lineCount; } + + constructor( + private readonly _doc: TextDocument, + ) { + this.uri = URI.parse(this._doc.uri); + } + + getText(range?: md.IRange | undefined): string { + return this._doc.getText(range); + } + + positionAt(offset: number): md.IPosition { + const pos = this._doc.positionAt(offset); + return md.makePosition(pos.line, pos.character); + } +} + +export function startServer(connection: Connection) { + const documents = new TextDocuments(TextDocument); + documents.listen(connection); + + connection.onInitialize((_params: InitializeParams): InitializeResult => { + return { + capabilities: { + documentSymbolProvider: true, + } + }; + }); + + + const parser = new class implements md.IMdParser { + slugifier = md.githubSlugifier; + + async tokenize(document: md.ITextDocument): Promise { + return await connection.sendRequest(parseRequestType, { uri: document.uri.toString() }); + } + }; + + const workspace = new class implements md.IMdWorkspace { + + private readonly _onDidChangeMarkdownDocument = new Emitter(); + onDidChangeMarkdownDocument: Event = this._onDidChangeMarkdownDocument.event; + + private readonly _onDidCreateMarkdownDocument = new Emitter(); + onDidCreateMarkdownDocument: Event = this._onDidCreateMarkdownDocument.event; + + private readonly _onDidDeleteMarkdownDocument = new Emitter(); + onDidDeleteMarkdownDocument: Event = this._onDidDeleteMarkdownDocument.event; + + async getAllMarkdownDocuments(): Promise> { + return documents.all().map(doc => new TextDocumentToITextDocumentAdapter(doc)); + } + hasMarkdownDocument(resource: md.IUri): boolean { + return !!documents.get(resource.toString()); + } + async getOrLoadMarkdownDocument(_resource: md.IUri): Promise { + return undefined; + } + async pathExists(_resource: md.IUri): Promise { + return false; + } + async readDirectory(_resource: md.IUri): Promise<[string, { isDir: boolean }][]> { + return []; + } + }; + + const provider = md.createLanguageService(workspace, parser, consoleLogger); + + connection.onDocumentSymbol(async (documentSymbolParams, _token): Promise => { + try { + const document = documents.get(documentSymbolParams.textDocument.uri) as TextDocument | undefined; + if (document) { + const response = await provider.provideDocumentSymbols(new TextDocumentToITextDocumentAdapter(document)); + // TODO: only required because extra methods returned on positions/ranges + return response.map(symbol => convertDocumentSymbol(symbol)); + } + } catch (e) { + console.error(e.stack); + } + return []; + }); + + connection.listen(); +} + + +function convertDocumentSymbol(sym: DocumentSymbol): DocumentSymbol { + return { + kind: sym.kind, + name: sym.name, + range: convertRange(sym.range), + selectionRange: convertRange(sym.selectionRange), + children: sym.children?.map(convertDocumentSymbol), + detail: sym.detail, + tags: sym.tags, + }; +} + +function convertRange(range: Range): Range { + return { + start: convertPosition(range.start), + end: convertPosition(range.end), + }; +} + +function convertPosition(start: Position): Position { + return { + character: start.character, + line: start.line, + }; +} diff --git a/extensions/markdown-language-features/server/tsconfig.json b/extensions/markdown-language-features/server/tsconfig.json new file mode 100644 index 00000000000..8b4aedde27d --- /dev/null +++ b/extensions/markdown-language-features/server/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "./out" + }, + "include": [ + "src/**/*" + ] +} diff --git a/extensions/markdown-language-features/server/yarn.lock b/extensions/markdown-language-features/server/yarn.lock new file mode 100644 index 00000000000..32cc01c3263 --- /dev/null +++ b/extensions/markdown-language-features/server/yarn.lock @@ -0,0 +1,60 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@types/mocha@^9.1.1": + version "9.1.1" + resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-9.1.1.tgz#e7c4f1001eefa4b8afbd1eee27a237fee3bf29c4" + integrity sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw== + +"@types/node@16.x": + version "16.11.43" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.43.tgz#555e5a743f76b6b897d47f945305b618525ddbe6" + integrity sha512-GqWykok+3uocgfAJM8imbozrqLnPyTrpFlrryURQlw1EesPUCx5XxTiucWDSFF9/NUEXDuD4bnvHm8xfVGWTpQ== + +vscode-jsonrpc@8.0.2-next.1: + version "8.0.2-next.1" + resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-8.0.2-next.1.tgz#6bdc39fd194782032e34047eeefce562941259c6" + integrity sha512-sbbvGSWja7NVBLHPGawtgezc8DHYJaP4qfr/AaJiyDapWcSFtHyPtm18+LnYMLTmB7bhOUW/lf5PeeuLpP6bKA== + +vscode-languageserver-protocol@3.17.2-next.6: + version "3.17.2-next.6" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.2-next.6.tgz#8f1dc0fcb29366b85f623a3f9af726de433b5fcc" + integrity sha512-WtsebNOOkWyNn4oFYoAMPC8Q/ZDoJ/K7Ja53OzTixiitvrl/RpXZETrtzH79R8P5kqCyx6VFBPb6KQILJfkDkA== + dependencies: + vscode-jsonrpc "8.0.2-next.1" + vscode-languageserver-types "3.17.2-next.2" + +vscode-languageserver-textdocument@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.5.tgz#838769940ece626176ec5d5a2aa2d0aa69f5095c" + integrity sha512-1ah7zyQjKBudnMiHbZmxz5bYNM9KKZYz+5VQLj+yr8l+9w3g+WAhCkUkWbhMEdC5u0ub4Ndiye/fDyS8ghIKQg== + +vscode-languageserver-types@3.17.2-next.2: + version "3.17.2-next.2" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2-next.2.tgz#af5d6978eee7682aab87c1419323f5b141ac6596" + integrity sha512-TiAkLABgqkVWdAlC3XlOfdhdjIAdVU4YntPUm9kKGbXr+MGwpVnKz2KZMNBcvG0CFx8Hi8qliL0iq+ndPB720w== + +vscode-languageserver-types@^3.17.1: + version "3.17.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.1.tgz#c2d87fa7784f8cac389deb3ff1e2d9a7bef07e16" + integrity sha512-K3HqVRPElLZVVPtMeKlsyL9aK0GxGQpvtAUTfX4k7+iJ4mc1M+JM+zQwkgGy2LzY0f0IAafe8MKqIkJrxfGGjQ== + +vscode-languageserver@^8.0.2-next.4: + version "8.0.2-next.5" + resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-8.0.2-next.5.tgz#39a2dd4c504fb88042375e7ac706a714bdaab4e5" + integrity sha512-2ZDb7O/4atS9mJKufPPz637z+51kCyZfgnobFW5eSrUdS3c0UB/nMS4Ng1EavYTX84GVaVMKCrmP0f2ceLmR0A== + dependencies: + vscode-languageserver-protocol "3.17.2-next.6" + +vscode-markdown-languageservice@mjbvz/vscode-markdown-languageservice: + version "1.0.0" + resolved "https://codeload.github.com/mjbvz/vscode-markdown-languageservice/tar.gz/e410b5df64659fbc186cf0a7a7c882c451e07b8b" + dependencies: + vscode-languageserver-types "^3.17.1" + vscode-uri "^3.0.3" + +vscode-uri@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.0.3.tgz#a95c1ce2e6f41b7549f86279d19f47951e4f4d84" + integrity sha512-EcswR2S8bpR7fD0YPeS7r2xXExrScVMxg4MedACaWHEtx9ftCF/qHG1xGkolzTPcEmjTavCQgbVzHUIdTMzFGA== diff --git a/extensions/markdown-language-features/src/client.ts b/extensions/markdown-language-features/src/client.ts new file mode 100644 index 00000000000..0bf5588ec38 --- /dev/null +++ b/extensions/markdown-language-features/src/client.ts @@ -0,0 +1,49 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import Token = require('markdown-it/lib/token'); +import * as vscode from 'vscode'; +import { BaseLanguageClient, LanguageClientOptions, RequestType } from 'vscode-languageclient'; +import * as nls from 'vscode-nls'; +import { IMdParser } from './markdownEngine'; +import { IMdWorkspace } from './workspace'; + +const localize = nls.loadMessageBundle(); + +const parseRequestType: RequestType<{ uri: string }, Token[], any> = new RequestType('markdown/parse'); + +export type LanguageClientConstructor = (name: string, description: string, clientOptions: LanguageClientOptions) => BaseLanguageClient; + + +export async function startClient(factory: LanguageClientConstructor, workspace: IMdWorkspace, parser: IMdParser): Promise { + + const documentSelector = ['markdown']; + + const clientOptions: LanguageClientOptions = { + documentSelector, + synchronize: { + configurationSection: ['markdown'] + }, + initializationOptions: {} + }; + + const client = factory('markdown', localize('markdownServer.name', 'Markdown Language Server'), clientOptions); + + client.registerProposedFeatures(); + + client.onRequest(parseRequestType, async (e) => { + const uri = vscode.Uri.parse(e.uri); + const doc = await workspace.getOrLoadMarkdownDocument(uri); + if (doc) { + return parser.tokenize(doc); + } else { + return []; + } + }); + + await client.start(); + + return client; +} diff --git a/extensions/markdown-language-features/src/extension.browser.ts b/extensions/markdown-language-features/src/extension.browser.ts new file mode 100644 index 00000000000..717d1c5ccc9 --- /dev/null +++ b/extensions/markdown-language-features/src/extension.browser.ts @@ -0,0 +1,39 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as vscode from 'vscode'; +import { LanguageClient, LanguageClientOptions } from 'vscode-languageclient/browser'; +import { startClient } from './client'; +import { activateShared } from './extension.shared'; +import { VsCodeOutputLogger } from './logging'; +import { IMdParser, MarkdownItEngine } from './markdownEngine'; +import { getMarkdownExtensionContributions } from './markdownExtensions'; +import { githubSlugifier } from './slugify'; +import { IMdWorkspace, VsCodeMdWorkspace } from './workspace'; + +export function activate(context: vscode.ExtensionContext) { + const contributions = getMarkdownExtensionContributions(context); + context.subscriptions.push(contributions); + + const logger = new VsCodeOutputLogger(); + context.subscriptions.push(logger); + + const engine = new MarkdownItEngine(contributions, githubSlugifier, logger); + + const workspace = new VsCodeMdWorkspace(); + context.subscriptions.push(workspace); + + activateShared(context, workspace, engine, logger, contributions); + startServer(context, workspace, engine); +} + +async function startServer(context: vscode.ExtensionContext, workspace: IMdWorkspace, parser: IMdParser): Promise { + const serverMain = vscode.Uri.joinPath(context.extensionUri, 'server/dist/browser/main.js'); + const worker = new Worker(serverMain.toString()); + + await startClient((id: string, name: string, clientOptions: LanguageClientOptions) => { + return new LanguageClient(id, name, clientOptions, worker); + }, workspace, parser); +} diff --git a/extensions/markdown-language-features/src/extension.node.ts b/extensions/markdown-language-features/src/extension.node.ts new file mode 100644 index 00000000000..ffa76f3fde3 --- /dev/null +++ b/extensions/markdown-language-features/src/extension.node.ts @@ -0,0 +1,50 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as vscode from 'vscode'; +import { LanguageClient, ServerOptions, TransportKind } from 'vscode-languageclient/node'; +import { startClient } from './client'; +import { activateShared } from './extension.shared'; +import { VsCodeOutputLogger } from './logging'; +import { IMdParser, MarkdownItEngine } from './markdownEngine'; +import { getMarkdownExtensionContributions } from './markdownExtensions'; +import { githubSlugifier } from './slugify'; +import { IMdWorkspace, VsCodeMdWorkspace } from './workspace'; + +export function activate(context: vscode.ExtensionContext) { + const contributions = getMarkdownExtensionContributions(context); + context.subscriptions.push(contributions); + + const logger = new VsCodeOutputLogger(); + context.subscriptions.push(logger); + + const engine = new MarkdownItEngine(contributions, githubSlugifier, logger); + + const workspace = new VsCodeMdWorkspace(); + context.subscriptions.push(workspace); + + activateShared(context, workspace, engine, logger, contributions); + startServer(context, workspace, engine); +} + +async function startServer(context: vscode.ExtensionContext, workspace: IMdWorkspace, parser: IMdParser): Promise { + const clientMain = vscode.extensions.getExtension('vscode.css-language-features')?.packageJSON?.main || ''; + + const serverMain = `./server/${clientMain.indexOf('/dist/') !== -1 ? 'dist' : 'out'}/node/main`; + const serverModule = context.asAbsolutePath(serverMain); + + // The debug options for the server + const debugOptions = { execArgv: ['--nolazy', '--inspect=' + (7000 + Math.round(Math.random() * 999))] }; + + // If the extension is launch in debug mode the debug server options are use + // Otherwise the run options are used + const serverOptions: ServerOptions = { + run: { module: serverModule, transport: TransportKind.ipc }, + debug: { module: serverModule, transport: TransportKind.ipc, options: debugOptions } + }; + await startClient((id, name, clientOptions) => { + return new LanguageClient(id, name, serverOptions, clientOptions); + }, workspace, parser); +} diff --git a/extensions/markdown-language-features/src/extension.ts b/extensions/markdown-language-features/src/extension.shared.ts similarity index 87% rename from extensions/markdown-language-features/src/extension.ts rename to extensions/markdown-language-features/src/extension.shared.ts index 32eef08f82e..57f9f9d99d7 100644 --- a/extensions/markdown-language-features/src/extension.ts +++ b/extensions/markdown-language-features/src/extension.shared.ts @@ -10,7 +10,7 @@ import { registerPasteSupport } from './languageFeatures/copyPaste'; import { registerDefinitionSupport } from './languageFeatures/definitions'; import { registerDiagnosticSupport } from './languageFeatures/diagnostics'; import { MdLinkProvider, registerDocumentLinkSupport } from './languageFeatures/documentLinks'; -import { MdDocumentSymbolProvider, registerDocumentSymbolSupport } from './languageFeatures/documentSymbols'; +import { MdDocumentSymbolProvider } from './languageFeatures/documentSymbols'; import { registerDropIntoEditorSupport } from './languageFeatures/dropIntoEditor'; import { registerFindFileReferenceSupport } from './languageFeatures/fileReferences'; import { registerFoldingSupport } from './languageFeatures/folding'; @@ -19,36 +19,32 @@ import { MdReferencesProvider, registerReferencesSupport } from './languageFeatu import { registerRenameSupport } from './languageFeatures/rename'; import { registerSmartSelectSupport } from './languageFeatures/smartSelect'; import { registerWorkspaceSymbolSupport } from './languageFeatures/workspaceSymbols'; -import { ILogger, VsCodeOutputLogger } from './logging'; +import { ILogger } from './logging'; import { IMdParser, MarkdownItEngine, MdParsingProvider } from './markdownEngine'; -import { getMarkdownExtensionContributions } from './markdownExtensions'; +import { MarkdownContributionProvider } from './markdownExtensions'; import { MdDocumentRenderer } from './preview/documentRenderer'; import { MarkdownPreviewManager } from './preview/previewManager'; import { ContentSecurityPolicyArbiter, ExtensionContentSecurityPolicyArbiter, PreviewSecuritySelector } from './preview/security'; -import { githubSlugifier } from './slugify'; import { MdTableOfContentsProvider } from './tableOfContents'; import { loadDefaultTelemetryReporter, TelemetryReporter } from './telemetryReporter'; -import { IMdWorkspace, VsCodeMdWorkspace } from './workspace'; +import { IMdWorkspace } from './workspace'; - -export function activate(context: vscode.ExtensionContext) { +export function activateShared( + context: vscode.ExtensionContext, + workspace: IMdWorkspace, + engine: MarkdownItEngine, + logger: ILogger, + contributions: MarkdownContributionProvider, +) { const telemetryReporter = loadDefaultTelemetryReporter(); context.subscriptions.push(telemetryReporter); - const contributions = getMarkdownExtensionContributions(context); - context.subscriptions.push(contributions); - - const logger = new VsCodeOutputLogger(); - context.subscriptions.push(logger); - const cspArbiter = new ExtensionContentSecurityPolicyArbiter(context.globalState, context.workspaceState); const commandManager = new CommandManager(); - const engine = new MarkdownItEngine(contributions, githubSlugifier, logger); - const workspace = new VsCodeMdWorkspace(); const parser = new MdParsingProvider(engine, workspace); const tocProvider = new MdTableOfContentsProvider(parser, workspace, logger); - context.subscriptions.push(workspace, parser, tocProvider); + context.subscriptions.push(parser, tocProvider); const contentProvider = new MdDocumentRenderer(engine, context, cspArbiter, contributions, logger); const previewManager = new MarkdownPreviewManager(contentProvider, workspace, logger, contributions, tocProvider); @@ -83,7 +79,6 @@ function registerMarkdownLanguageFeatures( registerDefinitionSupport(selector, referencesProvider), registerDiagnosticSupport(selector, workspace, linkProvider, commandManager, referencesProvider, tocProvider, logger), registerDocumentLinkSupport(selector, linkProvider), - registerDocumentSymbolSupport(selector, tocProvider, logger), registerDropIntoEditorSupport(selector), registerFindFileReferenceSupport(commandManager, referencesProvider), registerFoldingSupport(selector, parser, tocProvider), diff --git a/extensions/markdown-language-features/src/languageFeatures/documentSymbols.ts b/extensions/markdown-language-features/src/languageFeatures/documentSymbols.ts index a048180a4c6..2152e7bd46c 100644 --- a/extensions/markdown-language-features/src/languageFeatures/documentSymbols.ts +++ b/extensions/markdown-language-features/src/languageFeatures/documentSymbols.ts @@ -75,11 +75,3 @@ export class MdDocumentSymbolProvider implements vscode.DocumentSymbolProvider { return '#'.repeat(entry.level) + ' ' + entry.text; } } - -export function registerDocumentSymbolSupport( - selector: vscode.DocumentSelector, - tocProvider: MdTableOfContentsProvider, - logger: ILogger, -): vscode.Disposable { - return vscode.languages.registerDocumentSymbolProvider(selector, new MdDocumentSymbolProvider(tocProvider, logger)); -} diff --git a/extensions/markdown-language-features/src/test/documentSymbolProvider.test.ts b/extensions/markdown-language-features/src/test/documentSymbolProvider.test.ts deleted file mode 100644 index c4570303868..00000000000 --- a/extensions/markdown-language-features/src/test/documentSymbolProvider.test.ts +++ /dev/null @@ -1,121 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as assert from 'assert'; -import 'mocha'; -import { MdDocumentSymbolProvider } from '../languageFeatures/documentSymbols'; -import { MdTableOfContentsProvider } from '../tableOfContents'; -import { DisposableStore } from '../util/dispose'; -import { InMemoryDocument } from '../util/inMemoryDocument'; -import { createNewMarkdownEngine } from './engine'; -import { InMemoryMdWorkspace } from './inMemoryWorkspace'; -import { nulLogger } from './nulLogging'; -import { joinLines, withStore, workspacePath } from './util'; - - -function getSymbolsForFile(store: DisposableStore, fileContents: string) { - const doc = new InMemoryDocument(workspacePath('test.md'), fileContents); - const workspace = store.add(new InMemoryMdWorkspace([doc])); - const engine = createNewMarkdownEngine(); - const tocProvider = store.add(new MdTableOfContentsProvider(engine, workspace, nulLogger)); - const provider = new MdDocumentSymbolProvider(tocProvider, nulLogger); - return provider.provideDocumentSymbols(doc); -} - -suite('Markdown: DocumentSymbolProvider', () => { - test('Should not return anything for empty document', withStore(async (store) => { - const symbols = await getSymbolsForFile(store, ''); - assert.strictEqual(symbols.length, 0); - })); - - test('Should not return anything for document with no headers', withStore(async (store) => { - const symbols = await getSymbolsForFile(store, joinLines( - `a`, - `a`, - )); - assert.strictEqual(symbols.length, 0); - })); - - test('Should not return anything for document with # but no real headers', withStore(async (store) => { - const symbols = await getSymbolsForFile(store, joinLines( - `a#a`, - `a#`, - )); - assert.strictEqual(symbols.length, 0); - })); - - test('Should return single symbol for single header', withStore(async (store) => { - const symbols = await getSymbolsForFile(store, '# h'); - assert.strictEqual(symbols.length, 1); - assert.strictEqual(symbols[0].name, '# h'); - })); - - test('Should not care about symbol level for single header', withStore(async (store) => { - const symbols = await getSymbolsForFile(store, '### h'); - assert.strictEqual(symbols.length, 1); - assert.strictEqual(symbols[0].name, '### h'); - })); - - test('Should put symbols of same level in flat list', withStore(async (store) => { - const symbols = await getSymbolsForFile(store, joinLines( - `## h`, - `## h2`, - )); - assert.strictEqual(symbols.length, 2); - assert.strictEqual(symbols[0].name, '## h'); - assert.strictEqual(symbols[1].name, '## h2'); - })); - - test('Should nest symbol of level - 1 under parent', withStore(async (store) => { - const symbols = await getSymbolsForFile(store, joinLines( - `# h`, - `## h2`, - `## h3`, - )); - assert.strictEqual(symbols.length, 1); - assert.strictEqual(symbols[0].name, '# h'); - assert.strictEqual(symbols[0].children.length, 2); - assert.strictEqual(symbols[0].children[0].name, '## h2'); - assert.strictEqual(symbols[0].children[1].name, '## h3'); - })); - - test('Should nest symbol of level - n under parent', withStore(async (store) => { - const symbols = await getSymbolsForFile(store, joinLines( - `# h`, - `#### h2`, - )); - assert.strictEqual(symbols.length, 1); - assert.strictEqual(symbols[0].name, '# h'); - assert.strictEqual(symbols[0].children.length, 1); - assert.strictEqual(symbols[0].children[0].name, '#### h2'); - })); - - test('Should flatten children where lower level occurs first', withStore(async (store) => { - const symbols = await getSymbolsForFile(store, joinLines( - `# h`, - `### h2`, - `## h3`, - )); - assert.strictEqual(symbols.length, 1); - assert.strictEqual(symbols[0].name, '# h'); - assert.strictEqual(symbols[0].children.length, 2); - assert.strictEqual(symbols[0].children[0].name, '### h2'); - assert.strictEqual(symbols[0].children[1].name, '## h3'); - })); - - test('Should handle line separator in file. Issue #63749', withStore(async (store) => { - const symbols = await getSymbolsForFile(store, joinLines( - `# A`, - `- foo`, - ``, - `# B`, - `- bar`, - )); - assert.strictEqual(symbols.length, 2); - assert.strictEqual(symbols[0].name, '# A'); - assert.strictEqual(symbols[1].name, '# B'); - })); -}); - diff --git a/extensions/markdown-language-features/yarn.lock b/extensions/markdown-language-features/yarn.lock index 9052af7c6df..b4ecb4b0303 100644 --- a/extensions/markdown-language-features/yarn.lock +++ b/extensions/markdown-language-features/yarn.lock @@ -69,6 +69,24 @@ argparse@^2.0.1: resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + dompurify@^2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.3.3.tgz#c1af3eb88be47324432964d8abc75cf4b98d634c" @@ -96,6 +114,13 @@ lodash.throttle@^4.1.1: resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4" integrity sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ= +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + markdown-it-front-matter@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/markdown-it-front-matter/-/markdown-it-front-matter-0.2.1.tgz#dca49a827bb3cebb0528452c1d87dff276eb28dc" @@ -117,6 +142,13 @@ mdurl@^1.0.1: resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4= +minimatch@^3.0.4: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + morphdom@^2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/morphdom/-/morphdom-2.6.1.tgz#e868e24f989fa3183004b159aed643e628b4306e" @@ -127,16 +159,50 @@ picomatch@^2.3.1: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== +semver@^7.3.5: + version "7.3.7" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" + integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== + dependencies: + lru-cache "^6.0.0" + uc.micro@^1.0.1, uc.micro@^1.0.5: version "1.0.6" resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac" integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA== +vscode-jsonrpc@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-8.0.1.tgz#f30b0625ebafa0fb3bc53e934ca47b706445e57e" + integrity sha512-N/WKvghIajmEvXpatSzvTvOIz61ZSmOSa4BRA4pTLi+1+jozquQKP/MkaylP9iB68k73Oua1feLQvH3xQuigiQ== + +vscode-languageclient@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-8.0.1.tgz#bf5535c4463a78daeaca0bcb4f5868aec86bb301" + integrity sha512-9XoE+HJfaWvu7Y75H3VmLo5WLCtsbxEgEhrLPqwt7eyoR49lUIyyrjb98Yfa50JCMqF2cePJAEVI6oe2o1sIhw== + dependencies: + minimatch "^3.0.4" + semver "^7.3.5" + vscode-languageserver-protocol "3.17.1" + +vscode-languageserver-protocol@3.17.1: + version "3.17.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.1.tgz#e801762c304f740208b6c804a0cf21f2c87509ed" + integrity sha512-BNlAYgQoYwlSgDLJhSG+DeA8G1JyECqRzM2YO6tMmMji3Ad9Mw6AW7vnZMti90qlAKb0LqAlJfSVGEdqMMNzKg== + dependencies: + vscode-jsonrpc "8.0.1" + vscode-languageserver-types "3.17.1" + vscode-languageserver-textdocument@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.4.tgz#3cd56dd14cec1d09e86c4bb04b09a246cb3df157" integrity sha512-/xhqXP/2A2RSs+J8JNXpiiNVvvNM0oTosNVmQnunlKvq9o4mupHOBAnnzH0lwIPKazXKvAKsVp1kr+H/K4lgoQ== +vscode-languageserver-types@3.17.1: + version "3.17.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.1.tgz#c2d87fa7784f8cac389deb3ff1e2d9a7bef07e16" + integrity sha512-K3HqVRPElLZVVPtMeKlsyL9aK0GxGQpvtAUTfX4k7+iJ4mc1M+JM+zQwkgGy2LzY0f0IAafe8MKqIkJrxfGGjQ== + vscode-nls@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.0.tgz#99f0da0bd9ea7cda44e565a74c54b1f2bc257840" @@ -146,3 +212,8 @@ vscode-uri@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.0.3.tgz#a95c1ce2e6f41b7549f86279d19f47951e4f4d84" integrity sha512-EcswR2S8bpR7fD0YPeS7r2xXExrScVMxg4MedACaWHEtx9ftCF/qHG1xGkolzTPcEmjTavCQgbVzHUIdTMzFGA== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== diff --git a/extensions/markdown-math/.gitignore b/extensions/markdown-math/.gitignore index 67c177886fb..93d9e664eae 100644 --- a/extensions/markdown-math/.gitignore +++ b/extensions/markdown-math/.gitignore @@ -1 +1,2 @@ notebook-out +languageService From 510656a44a5dfa3ad63190f0641018d858e222a9 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 6 Jul 2022 16:02:50 -0700 Subject: [PATCH 309/347] Replace all Terminal codicon references with default icon --- .../common/terminalPlatformConfiguration.ts | 38 +++++++++++-------- .../terminal/browser/terminalActions.ts | 3 +- .../contrib/terminal/browser/terminalIcon.ts | 7 ++-- .../terminal/browser/terminalInstance.ts | 5 ++- .../browser/terminalProfileQuickpick.ts | 5 ++- .../browser/terminalProfileResolverService.ts | 17 +++++++-- .../terminal/browser/terminalQuickAccess.ts | 6 ++- .../terminal/browser/terminalTabsList.ts | 2 +- .../contrib/terminal/browser/terminalView.ts | 10 +++-- .../contrib/terminal/common/terminal.ts | 2 + .../terminal/common/terminalConfiguration.ts | 24 +++--------- .../test/browser/workbenchTestServices.ts | 6 ++- 12 files changed, 72 insertions(+), 53 deletions(-) diff --git a/src/vs/platform/terminal/common/terminalPlatformConfiguration.ts b/src/vs/platform/terminal/common/terminalPlatformConfiguration.ts index 9dc40ebec2c..79db8443a33 100644 --- a/src/vs/platform/terminal/common/terminalPlatformConfiguration.ts +++ b/src/vs/platform/terminal/common/terminalPlatformConfiguration.ts @@ -12,6 +12,27 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { IExtensionTerminalProfile, ITerminalProfile, TerminalSettingId } from 'vs/platform/terminal/common/terminal'; import { createProfileSchemaEnums } from 'vs/platform/terminal/common/terminalProfiles'; +export const terminalColorSchema: IJSONSchema = { + type: ['string', 'null'], + enum: [ + 'terminal.ansiBlack', + 'terminal.ansiRed', + 'terminal.ansiGreen', + 'terminal.ansiYellow', + 'terminal.ansiBlue', + 'terminal.ansiMagenta', + 'terminal.ansiCyan', + 'terminal.ansiWhite' + ], + default: null +}; + +export const terminalIconSchema: IJSONSchema = { + type: 'string', + enum: Array.from(Codicon.getAll(), icon => icon.id), + markdownEnumDescriptions: Array.from(Codicon.getAll(), icon => `$(${icon.id})`), +}; + const terminalProfileBaseProperties: IJSONSchemaMap = { args: { description: localize('terminalProfile.args', 'An optional set of arguments to run the shell executable with.'), @@ -26,24 +47,11 @@ const terminalProfileBaseProperties: IJSONSchemaMap = { }, icon: { description: localize('terminalProfile.icon', 'A codicon ID to associate with this terminal.'), - type: 'string', - enum: Array.from(Codicon.getAll(), icon => icon.id), - markdownEnumDescriptions: Array.from(Codicon.getAll(), icon => `$(${icon.id})`), + ...terminalIconSchema }, color: { description: localize('terminalProfile.color', 'A theme color ID to associate with this terminal.'), - type: ['string', 'null'], - enum: [ - 'terminal.ansiBlack', - 'terminal.ansiRed', - 'terminal.ansiGreen', - 'terminal.ansiYellow', - 'terminal.ansiBlue', - 'terminal.ansiMagenta', - 'terminal.ansiCyan', - 'terminal.ansiWhite' - ], - default: null + ...terminalColorSchema }, env: { markdownDescription: localize('terminalProfile.env', "An object with environment variables that will be added to the terminal profile process. Set to `null` to delete environment variables from the base environment."), diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index 0c70784c0e3..540f153ea32 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -1709,6 +1709,7 @@ export function registerTerminalActions() { const themeService = accessor.get(IThemeService); const groupService = accessor.get(ITerminalGroupService); const notificationService = accessor.get(INotificationService); + const picks: ITerminalQuickPickItem[] = []; if (groupService.instances.length <= 1) { notificationService.warn(localize('workbench.action.terminal.join.insufficientTerminals', 'Insufficient terminals for the join action')); @@ -1718,7 +1719,7 @@ export function registerTerminalActions() { for (const terminal of otherInstances) { const group = groupService.getGroupForInstance(terminal); if (group?.terminalInstances.length === 1) { - const iconId = getIconId(terminal); + const iconId = getIconId(accessor, terminal); const label = `$(${iconId}): ${terminal.title}`; const iconClasses: string[] = []; const colorClass = getColorClass(terminal); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalIcon.ts b/src/vs/workbench/contrib/terminal/browser/terminalIcon.ts index b098cc3ece1..89acbedfa80 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalIcon.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalIcon.ts @@ -3,14 +3,15 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Codicon } from 'vs/base/common/codicons'; import { hash } from 'vs/base/common/hash'; import { URI } from 'vs/base/common/uri'; +import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IExtensionTerminalProfile, ITerminalProfile } from 'vs/platform/terminal/common/terminal'; import { getIconRegistry } from 'vs/platform/theme/common/iconRegistry'; import { ColorScheme } from 'vs/platform/theme/common/theme'; import { IColorTheme, ThemeIcon } from 'vs/platform/theme/common/themeService'; import { ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal'; +import { ITerminalProfileResolverService } from 'vs/workbench/contrib/terminal/common/terminal'; import { ansiColorMap } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry'; @@ -116,9 +117,9 @@ export function getUriClasses(terminal: ITerminalInstance | IExtensionTerminalPr return iconClasses; } -export function getIconId(terminal: ITerminalInstance | IExtensionTerminalProfile | ITerminalProfile): string { +export function getIconId(accessor: ServicesAccessor, terminal: ITerminalInstance | IExtensionTerminalProfile | ITerminalProfile): string { if (!terminal.icon || (terminal.icon instanceof Object && !('id' in terminal.icon))) { - return Codicon.terminal.id; + return accessor.get(ITerminalProfileResolverService).getDefaultIcon().id; } return typeof terminal.icon === 'string' ? terminal.icon : terminal.icon.id; } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index edf4d2b4198..a02e18413dc 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -86,6 +86,7 @@ import type { IMarker, ITerminalAddon, Terminal as XTermTerminal } from 'xterm'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IGenericMarkProperties } from 'vs/platform/terminal/common/terminalProcess'; import { ICommandService } from 'vs/platform/commands/common/commands'; +import { getIconRegistry } from 'vs/platform/theme/common/iconRegistry'; const enum Constants { /** @@ -548,7 +549,9 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { private _getIcon(): TerminalIcon | undefined { if (!this._icon) { - this._icon = this._processManager.processState >= ProcessState.Launching ? Codicon.terminal : undefined; + this._icon = this._processManager.processState >= ProcessState.Launching + ? getIconRegistry().getIcon(this._configurationService.getValue(TerminalSettingId.TabsDefaultIcon)) + : undefined; } return this._icon; } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalProfileQuickpick.ts b/src/vs/workbench/contrib/terminal/browser/terminalProfileQuickpick.ts index e715b730b66..e67654f2c70 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalProfileQuickpick.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalProfileQuickpick.ts @@ -11,7 +11,7 @@ import { getUriClasses, getColorClass, getColorStyleElement } from 'vs/workbench import { configureTerminalProfileIcon } from 'vs/workbench/contrib/terminal/browser/terminalIcons'; import * as nls from 'vs/nls'; import { IThemeService, ThemeIcon } from 'vs/platform/theme/common/themeService'; -import { ITerminalProfileService } from 'vs/workbench/contrib/terminal/common/terminal'; +import { ITerminalProfileResolverService, ITerminalProfileService } from 'vs/workbench/contrib/terminal/common/terminal'; import { IQuickPickTerminalObject, ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal'; import { IPickerQuickAccessItem } from 'vs/platform/quickinput/browser/pickerQuickAccess'; import { getIconRegistry } from 'vs/platform/theme/common/iconRegistry'; @@ -22,6 +22,7 @@ type DefaultProfileName = string; export class TerminalProfileQuickpick { constructor( @ITerminalProfileService private readonly _terminalProfileService: ITerminalProfileService, + @ITerminalProfileResolverService private readonly _terminalProfileResolverService: ITerminalProfileResolverService, @IConfigurationService private readonly _configurationService: IConfigurationService, @IQuickInputService private readonly _quickInputService: IQuickInputService, @IThemeService private readonly _themeService: IThemeService @@ -155,7 +156,7 @@ export class TerminalProfileQuickpick { } } if (!icon || !getIconRegistry().getIcon(icon.id)) { - icon = Codicon.terminal; + icon = this._terminalProfileResolverService.getDefaultIcon(); } const uriClasses = getUriClasses(contributed, this._themeService.getColorTheme().type, true); const colorClass = getColorClass(contributed); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts b/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts index 1554d580f33..2abd550fedc 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts @@ -97,11 +97,11 @@ export abstract class BaseTerminalProfileResolverService implements ITerminalPro resolveIcon(shellLaunchConfig: IShellLaunchConfig, os: OperatingSystem): void { if (shellLaunchConfig.icon) { - shellLaunchConfig.icon = this._getCustomIcon(shellLaunchConfig.icon) || Codicon.terminal; + shellLaunchConfig.icon = this._getCustomIcon(shellLaunchConfig.icon) || this.getDefaultIcon(); return; } if (shellLaunchConfig.customPtyImplementation) { - shellLaunchConfig.icon = Codicon.terminal; + shellLaunchConfig.icon = this.getDefaultIcon(); return; } if (shellLaunchConfig.executable) { @@ -111,6 +111,13 @@ export abstract class BaseTerminalProfileResolverService implements ITerminalPro if (defaultProfile) { shellLaunchConfig.icon = defaultProfile.icon; } + if (!shellLaunchConfig.icon) { + shellLaunchConfig.icon = this.getDefaultIcon(); + } + } + + getDefaultIcon(): TerminalIcon & ThemeIcon { + return this._iconRegistry.getIcon(this._configurationService.getValue(TerminalSettingId.TabsDefaultIcon)) || Codicon.terminal; } async resolveShellLaunchConfig(shellLaunchConfig: IShellLaunchConfig, options: IShellLaunchConfigResolveOptions): Promise { @@ -138,10 +145,11 @@ export abstract class BaseTerminalProfileResolverService implements ITerminalPro // Verify the icon is valid, and fallback correctly to the generic terminal id if there is // an issue + console.log('icon', this._configurationService.getValue(TerminalSettingId.TabsDefaultIcon)); shellLaunchConfig.icon = this._getCustomIcon(shellLaunchConfig.icon) || this._getCustomIcon(resolvedProfile.icon) - || this._iconRegistry.getIcon(this._configurationService.getValue(TerminalSettingId.TabsDefaultIcon)) - || Codicon.terminal; + || this.getDefaultIcon(); + console.log('icon2', shellLaunchConfig.icon); // Override the name if specified if (resolvedProfile.overrideName) { @@ -240,6 +248,7 @@ export abstract class BaseTerminalProfileResolverService implements ITerminalPro if (defaultProfileName && typeof defaultProfileName === 'string') { return this._terminalProfileService.availableProfiles.find(e => e.profileName === defaultProfileName); } + return undefined; } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalQuickAccess.ts b/src/vs/workbench/contrib/terminal/browser/terminalQuickAccess.ts index af7953a3268..71bdeeb5de4 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalQuickAccess.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalQuickAccess.ts @@ -16,6 +16,7 @@ import { getColorClass, getIconId, getUriClasses } from 'vs/workbench/contrib/te import { terminalStrings } from 'vs/workbench/contrib/terminal/common/terminalStrings'; import { TerminalLocation } from 'vs/platform/terminal/common/terminal'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; let terminalPicks: Array = []; export class TerminalQuickAccessProvider extends PickerQuickAccessProvider { @@ -27,7 +28,8 @@ export class TerminalQuickAccessProvider extends PickerQuickAccessProvider 1 ? `${groupInfo.groupIndex + 1}.${terminalIndex + 1}` diff --git a/src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts b/src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts index d9fc17533ed..14890b1b9bf 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalTabsList.ts @@ -309,7 +309,7 @@ class TerminalTabsRenderer implements IListRenderer; getDefaultShell(options: IShellLaunchConfigResolveOptions): Promise; getDefaultShellArgs(options: IShellLaunchConfigResolveOptions): Promise; + getDefaultIcon(): TerminalIcon & ThemeIcon; getEnvironment(remoteAuthority: string | undefined): Promise; createProfileFromShellAndShellArgs(shell?: unknown, shellArgs?: unknown): Promise; } diff --git a/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts b/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts index acdd4ce698d..5c982b8dc56 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts @@ -10,6 +10,7 @@ import { TerminalLocationString, TerminalSettingId } from 'vs/platform/terminal/ import { isMacintosh, isWindows } from 'vs/base/common/platform'; import { Registry } from 'vs/platform/registry/common/platform'; import { Codicon } from 'vs/base/common/codicons'; +import { terminalColorSchema, terminalIconSchema } from 'vs/platform/terminal/common/terminalPlatformConfiguration'; const terminalDescriptors = '\n- ' + [ '`\${cwd}`: ' + localize("cwd", "the terminal's current working directory"), @@ -40,26 +41,13 @@ const terminalConfiguration: IConfigurationNode = { default: false }, [TerminalSettingId.TabsDefaultColor]: { - description: localize('terminal.integrated.tabs.defaultColor', "Controls the terminal tab icon's default color."), - type: 'string', - enum: [ - 'terminal.ansiBlack', - 'terminal.ansiRed', - 'terminal.ansiGreen', - 'terminal.ansiYellow', - 'terminal.ansiBlue', - 'terminal.ansiMagenta', - 'terminal.ansiCyan', - 'terminal.ansiWhite' - ], - default: undefined, + description: localize('terminal.integrated.tabs.defaultColor', "A theme color ID to associate with terminals by default."), + ...terminalColorSchema }, [TerminalSettingId.TabsDefaultIcon]: { - description: localize('terminal.integrated.tabs.defaultIcon', "Controls the terminal tab's default icon."), - type: 'string', - enum: Codicon.getAll().map(icon => icon.id), - markdownEnumDescriptions: Array.from(Codicon.getAll(), icon => `$(${icon.id})`), - default: undefined, + description: localize('terminal.integrated.tabs.defaultIcon', "A codicon ID to associate with terminals by default."), + ...terminalIconSchema, + default: Codicon.terminal.id, }, [TerminalSettingId.TabsEnabled]: { description: localize('terminal.integrated.tabs.enabled', 'Controls whether terminal tabs display as a list to the side of the terminal. When this is disabled a dropdown will display instead.'), diff --git a/src/vs/workbench/test/browser/workbenchTestServices.ts b/src/vs/workbench/test/browser/workbenchTestServices.ts index caa62c81497..f7e9543fb3f 100644 --- a/src/vs/workbench/test/browser/workbenchTestServices.ts +++ b/src/vs/workbench/test/browser/workbenchTestServices.ts @@ -35,7 +35,7 @@ import { TestConfigurationService } from 'vs/platform/configuration/test/common/ import { MenuBarVisibility, IWindowOpenable, IOpenWindowOptions, IOpenEmptyWindowOptions } from 'vs/platform/window/common/window'; import { TestWorkspace } from 'vs/platform/workspace/test/common/testWorkspace'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { IThemeService } from 'vs/platform/theme/common/themeService'; +import { IThemeService, ThemeIcon } from 'vs/platform/theme/common/themeService'; import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService'; import { ITextResourceConfigurationService, ITextResourcePropertiesService } from 'vs/editor/common/services/textResourceConfiguration'; import { IPosition, Position as EditorPosition } from 'vs/editor/common/core/position'; @@ -122,7 +122,7 @@ import { SideBySideEditor } from 'vs/workbench/browser/parts/editor/sideBySideEd import { IEnterWorkspaceResult, IRecent, IRecentlyOpened, IWorkspaceFolderCreationData, IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; import { IWorkspaceTrustManagementService, IWorkspaceTrustRequestService } from 'vs/platform/workspace/common/workspaceTrust'; import { TestWorkspaceTrustManagementService, TestWorkspaceTrustRequestService } from 'vs/workbench/services/workspaces/test/common/testWorkspaceTrustService'; -import { IExtensionTerminalProfile, IShellLaunchConfig, ITerminalProfile, TerminalLocation, TerminalShellType } from 'vs/platform/terminal/common/terminal'; +import { IExtensionTerminalProfile, IShellLaunchConfig, ITerminalProfile, TerminalIcon, TerminalLocation, TerminalShellType } from 'vs/platform/terminal/common/terminal'; import { ICreateTerminalOptions, IDeserializedTerminalEditorInput, ITerminalEditorService, ITerminalGroup, ITerminalGroupService, ITerminalInstance, ITerminalInstanceService, TerminalEditorLocation } from 'vs/workbench/contrib/terminal/browser/terminal'; import { assertIsDefined, isArray } from 'vs/base/common/types'; import { IRegisterContributedProfileArgs, IShellLaunchConfigResolveOptions, ITerminalBackend, ITerminalProfileProvider, ITerminalProfileResolverService, ITerminalProfileService } from 'vs/workbench/contrib/terminal/common/terminal'; @@ -165,6 +165,7 @@ import { UserDataProfileService } from 'vs/workbench/services/userDataProfile/co import { IUserDataProfileService } from 'vs/workbench/services/userDataProfile/common/userDataProfile'; import { EnablementState, IExtensionManagementServer, IScannedExtension, IWebExtensionsScannerService, IWorkbenchExtensionEnablementService, IWorkbenchExtensionManagementService, ScanOptions } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { InstallVSIXOptions, ILocalExtension, IGalleryExtension, InstallOptions, IExtensionIdentifier, UninstallOptions, IExtensionsControlManifest, IGalleryMetadata, IExtensionManagementParticipant } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { Codicon } from 'vs/base/common/codicons'; export function createFileEditorInput(instantiationService: IInstantiationService, resource: URI): FileEditorInput { return instantiationService.createInstance(FileEditorInput, resource, undefined, undefined, undefined, undefined, undefined, undefined); @@ -1863,6 +1864,7 @@ export class TestTerminalProfileResolverService implements ITerminalProfileResol async getDefaultProfile(options: IShellLaunchConfigResolveOptions): Promise { return { path: '/default', profileName: 'Default', isDefault: true }; } async getDefaultShell(options: IShellLaunchConfigResolveOptions): Promise { return '/default'; } async getDefaultShellArgs(options: IShellLaunchConfigResolveOptions): Promise { return []; } + getDefaultIcon(): TerminalIcon & ThemeIcon { return Codicon.terminal; } async getEnvironment(): Promise { return env; } getSafeConfigValue(key: string, os: OperatingSystem): unknown | undefined { return undefined; } getSafeConfigValueFullKey(key: string): unknown | undefined { return undefined; } From 22f3f6064e9fc2cf8247932436e7f910641370af Mon Sep 17 00:00:00 2001 From: Raymond Zhao <7199958+rzhao271@users.noreply.github.com> Date: Wed, 6 Jul 2022 16:29:08 -0700 Subject: [PATCH 310/347] Move some text out of localization string for integrated terminal settings (#154318) Fixes #154317 --- .../terminal/common/terminalConfiguration.ts | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts b/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts index 83a67239048..95fb4b4e3e6 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts @@ -34,7 +34,7 @@ const terminalConfiguration: IConfigurationNode = { type: 'object', properties: { [TerminalSettingId.SendKeybindingsToShell]: { - markdownDescription: localize('terminal.integrated.sendKeybindingsToShell', "Dispatches most keybindings to the terminal instead of the workbench, overriding `#terminal.integrated.commandsToSkipShell#`, which can be used alternatively for fine tuning."), + markdownDescription: localize('terminal.integrated.sendKeybindingsToShell', "Dispatches most keybindings to the terminal instead of the workbench, overriding {0}, which can be used alternatively for fine tuning.", '`#terminal.integrated.commandsToSkipShell#`'), type: 'boolean', default: false }, @@ -106,17 +106,17 @@ const terminalConfiguration: IConfigurationNode = { [TerminalSettingId.ShellIntegrationDecorationIconSuccess]: { type: 'string', default: 'primitive-dot', - markdownDescription: localize('terminal.integrated.shellIntegration.decorationIconSuccess', "Controls the icon that will be used for each command in terminals with shell integration enabled that do not have an associated exit code. Set to `''` to hide the icon or disable decorations with `#terminal.integrated.shellIntegration.decorationsEnabled#`") + markdownDescription: localize('terminal.integrated.shellIntegration.decorationIconSuccess', "Controls the icon that will be used for each command in terminals with shell integration enabled that do not have an associated exit code. Set to {0} to hide the icon or disable decorations with {1}.", '`\'\'`', '`#terminal.integrated.shellIntegration.decorationsEnabled#`') }, [TerminalSettingId.ShellIntegrationDecorationIconError]: { type: 'string', default: 'error-small', - markdownDescription: localize('terminal.integrated.shellIntegration.decorationIconError', "Controls the icon that will be used for each command in terminals with shell integration enabled that do have an associated exit code. Set to `''` to hide the icon or disable decorations with `#terminal.integrated.shellIntegration.decorationsEnabled#`.") + markdownDescription: localize('terminal.integrated.shellIntegration.decorationIconError', "Controls the icon that will be used for each command in terminals with shell integration enabled that do have an associated exit code. Set to {0} to hide the icon or disable decorations with {1}.", '`\'\'`', '`#terminal.integrated.shellIntegration.decorationsEnabled#`') }, [TerminalSettingId.ShellIntegrationDecorationIcon]: { type: 'string', default: 'circle-outline', - markdownDescription: localize('terminal.integrated.shellIntegration.decorationIcon', "Controls the icon that will be used for skipped/empty commands. Set to `''` to hide the icon or disable decorations with `#terminal.integrated.shellIntegration.decorationsEnabled#`") + markdownDescription: localize('terminal.integrated.shellIntegration.decorationIcon', "Controls the icon that will be used for skipped/empty commands. Set to {0} to hide the icon or disable decorations with {1}.", '`\'\'`', '`#terminal.integrated.shellIntegration.decorationsEnabled#`') }, [TerminalSettingId.TabsFocusMode]: { type: 'string', @@ -139,7 +139,7 @@ const terminalConfiguration: IConfigurationNode = { default: false }, [TerminalSettingId.AltClickMovesCursor]: { - markdownDescription: localize('terminal.integrated.altClickMovesCursor', "If enabled, alt/option + click will reposition the prompt cursor to underneath the mouse when `#editor.multiCursorModifier#` is set to `'alt'` (the default value). This may not work reliably depending on your shell."), + markdownDescription: localize('terminal.integrated.altClickMovesCursor', "If enabled, alt/option + click will reposition the prompt cursor to underneath the mouse when {0} is set to {1} (the default value). This may not work reliably depending on your shell.", '`#editor.multiCursorModifier#`', '`\'alt\'`'), type: 'boolean', default: true }, @@ -159,7 +159,7 @@ const terminalConfiguration: IConfigurationNode = { default: true }, [TerminalSettingId.FontFamily]: { - markdownDescription: localize('terminal.integrated.fontFamily', "Controls the font family of the terminal, this defaults to `#editor.fontFamily#`'s value."), + markdownDescription: localize('terminal.integrated.fontFamily', "Controls the font family of the terminal, this defaults to {0}'s value.", '`#editor.fontFamily#`'), type: 'string' }, // TODO: Support font ligatures @@ -254,7 +254,7 @@ const terminalConfiguration: IConfigurationNode = { default: TerminalCursorStyle.BLOCK }, [TerminalSettingId.CursorWidth]: { - markdownDescription: localize('terminal.integrated.cursorWidth', "Controls the width of the cursor when `#terminal.integrated.cursorStyle#` is set to `line`."), + markdownDescription: localize('terminal.integrated.cursorWidth', "Controls the width of the cursor when {0} is set to {1}.", '`#terminal.integrated.cursorStyle#`', '`line`'), type: 'number', default: 1 }, @@ -354,7 +354,8 @@ const terminalConfiguration: IConfigurationNode = { 'terminal.integrated.commandsToSkipShell', "A set of command IDs whose keybindings will not be sent to the shell but instead always be handled by VS Code. This allows keybindings that would normally be consumed by the shell to act instead the same as when the terminal is not focused, for example `Ctrl+P` to launch Quick Open.\n\n \n\nMany commands are skipped by default. To override a default and pass that command's keybinding to the shell instead, add the command prefixed with the `-` character. For example add `-workbench.action.quickOpen` to allow `Ctrl+P` to reach the shell.\n\n \n\nThe following list of default skipped commands is truncated when viewed in Settings Editor. To see the full list, {1} and search for the first command from the list below.\n\n \n\nDefault Skipped Commands:\n\n{0}", DEFAULT_COMMANDS_TO_SKIP_SHELL.sort().map(command => `- ${command}`).join('\n'), - `[${localize('openDefaultSettingsJson', "open the default settings JSON")}](command:workbench.action.openRawDefaultSettings '${localize('openDefaultSettingsJson.capitalized', "Open Default Settings (JSON)")}')` + `[${localize('openDefaultSettingsJson', "open the default settings JSON")}](command:workbench.action.openRawDefaultSettings '${localize('openDefaultSettingsJson.capitalized', "Open Default Settings (JSON)")}')`, + ), type: 'array', items: { @@ -363,7 +364,7 @@ const terminalConfiguration: IConfigurationNode = { default: [] }, [TerminalSettingId.AllowChords]: { - markdownDescription: localize('terminal.integrated.allowChords', "Whether or not to allow chord keybindings in the terminal. Note that when this is true and the keystroke results in a chord it will bypass `#terminal.integrated.commandsToSkipShell#`, setting this to false is particularly useful when you want ctrl+k to go to your shell (not VS Code)."), + markdownDescription: localize('terminal.integrated.allowChords', "Whether or not to allow chord keybindings in the terminal. Note that when this is true and the keystroke results in a chord it will bypass {0}, setting this to false is particularly useful when you want ctrl+k to go to your shell (not VS Code).", '`#terminal.integrated.commandsToSkipShell#`'), type: 'boolean', default: true }, @@ -464,7 +465,7 @@ const terminalConfiguration: IConfigurationNode = { default: 30, }, [TerminalSettingId.LocalEchoEnabled]: { - markdownDescription: localize('terminal.integrated.localEchoEnabled', "When local echo should be enabled. This will override `#terminal.integrated.localEchoLatencyThreshold#`"), + markdownDescription: localize('terminal.integrated.localEchoEnabled', "When local echo should be enabled. This will override {0}", '`#terminal.integrated.localEchoLatencyThreshold#`'), type: 'string', enum: ['on', 'off', 'auto'], enumDescriptions: [ From c4b08408c8e9ed572e29e1d106c8d9d105716e41 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 6 Jul 2022 16:30:46 -0700 Subject: [PATCH 311/347] Fix compile --- src/vs/workbench/contrib/terminal/browser/terminalView.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalView.ts b/src/vs/workbench/contrib/terminal/browser/terminalView.ts index ed41d6eac2a..f3f77734984 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalView.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalView.ts @@ -375,7 +375,7 @@ class SingleTerminalTabActionViewItem extends MenuEntryActionViewItem { @ITerminalGroupService private readonly _terminalGroupService: ITerminalGroupService, @IContextMenuService private readonly _contextMenuService: IContextMenuService, @ICommandService private readonly _commandService: ICommandService, - @IConfigurationService configurationService: IConfigurationService + @IConfigurationService configurationService: IConfigurationService, @IInstantiationService private readonly _instantiationService: IInstantiationService, ) { super(new MenuItemAction( From 2a5d381d162212f47c495eacf2e84a372a74f5ef Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Wed, 6 Jul 2022 20:15:58 -0400 Subject: [PATCH 312/347] only show output button when a command's markers haven't been disposed of (#154220) * fix #154215 * make hasOutput a function * fix test * Update src/vs/workbench/contrib/terminal/browser/terminalProfileService.ts * actually fix tests --- .../platform/terminal/common/capabilities/capabilities.ts | 2 +- .../common/capabilities/commandDetectionCapability.ts | 4 ++-- .../contrib/terminal/browser/terminalInstance.ts | 2 +- .../contrib/terminal/browser/xterm/decorationAddon.ts | 2 +- src/vs/workbench/contrib/terminal/common/terminal.ts | 2 +- .../test/browser/links/terminalLinkOpeners.test.ts | 6 +++--- .../terminal/test/browser/xterm/decorationAddon.test.ts | 8 ++++---- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/vs/platform/terminal/common/capabilities/capabilities.ts b/src/vs/platform/terminal/common/capabilities/capabilities.ts index d398dccd0ac..1cfbab58a30 100644 --- a/src/vs/platform/terminal/common/capabilities/capabilities.ts +++ b/src/vs/platform/terminal/common/capabilities/capabilities.ts @@ -198,7 +198,7 @@ export interface ITerminalCommand { executedMarker?: IXtermMarker; commandStartLineContent?: string; getOutput(): string | undefined; - hasOutput: boolean; + hasOutput(): boolean; genericMarkProperties?: IGenericMarkProperties; } diff --git a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts index 95aa53d305c..7194815abb1 100644 --- a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts +++ b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts @@ -457,7 +457,7 @@ export class CommandDetectionCapability implements ICommandDetectionCapability { cwd: this._cwd, exitCode: this._exitCode, commandStartLineContent: this._currentCommand.commandStartLineContent, - hasOutput: !!(executedMarker && endMarker && executedMarker?.line < endMarker!.line), + hasOutput: () => !executedMarker?.isDisposed && !endMarker?.isDisposed && !!(executedMarker && endMarker && executedMarker?.line < endMarker!.line), getOutput: () => getOutputForCommand(executedMarker, endMarker, buffer), genericMarkProperties: options?.genericMarkProperties }; @@ -579,7 +579,7 @@ export class CommandDetectionCapability implements ICommandDetectionCapability { cwd: e.cwd, commandStartLineContent: e.commandStartLineContent, exitCode: e.exitCode, - hasOutput: !!(executedMarker && endMarker && executedMarker.line < endMarker.line), + hasOutput: () => !executedMarker?.isDisposed && !endMarker?.isDisposed && !!(executedMarker && endMarker && executedMarker.line < endMarker.line), getOutput: () => getOutputForCommand(executedMarker, endMarker, buffer), genericMarkProperties: e.genericMarkProperties }; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index edf4d2b4198..6c3e3c9f25c 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -877,7 +877,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { description, id: entry.timestamp.toString(), command: entry, - buttons: entry.hasOutput ? buttons : undefined + buttons: entry.hasOutput() ? buttons : undefined }); commandMap.add(label); } diff --git a/src/vs/workbench/contrib/terminal/browser/xterm/decorationAddon.ts b/src/vs/workbench/contrib/terminal/browser/xterm/decorationAddon.ts index e7e3137ae30..45b820a935c 100644 --- a/src/vs/workbench/contrib/terminal/browser/xterm/decorationAddon.ts +++ b/src/vs/workbench/contrib/terminal/browser/xterm/decorationAddon.ts @@ -365,7 +365,7 @@ export class DecorationAddon extends Disposable implements ITerminalAddon { run: () => this._clipboardService.writeText(command.command) }); } - if (command.hasOutput) { + if (command.hasOutput()) { if (actions.length > 0) { actions.push(new Separator()); } diff --git a/src/vs/workbench/contrib/terminal/common/terminal.ts b/src/vs/workbench/contrib/terminal/common/terminal.ts index 8346edc1b8e..109988ca671 100644 --- a/src/vs/workbench/contrib/terminal/common/terminal.ts +++ b/src/vs/workbench/contrib/terminal/common/terminal.ts @@ -341,7 +341,7 @@ export interface ITerminalCommand { cwd?: string; exitCode?: number; marker?: IXtermMarker; - hasOutput: boolean; + hasOutput(): boolean; getOutput(): string | undefined; genericMarkProperties?: IGenericMarkProperties; } diff --git a/src/vs/workbench/contrib/terminal/test/browser/links/terminalLinkOpeners.test.ts b/src/vs/workbench/contrib/terminal/test/browser/links/terminalLinkOpeners.test.ts index e7eea1e62fc..225dd72bbdc 100644 --- a/src/vs/workbench/contrib/terminal/test/browser/links/terminalLinkOpeners.test.ts +++ b/src/vs/workbench/contrib/terminal/test/browser/links/terminalLinkOpeners.test.ts @@ -110,7 +110,7 @@ suite('Workbench - TerminalLinkOpeners', () => { marker: { line: 0 } as Partial as any, - hasOutput: true + hasOutput() { return true; } }]); fileService.setFiles([ URI.from({ scheme: Schemas.file, path: '/initial/cwd/foo/bar.txt' }), @@ -188,7 +188,7 @@ suite('Workbench - TerminalLinkOpeners', () => { marker: { line: 0 } as Partial as any, - hasOutput: true + hasOutput() { return true; } }]); await opener.open({ text: 'file.txt', @@ -237,7 +237,7 @@ suite('Workbench - TerminalLinkOpeners', () => { marker: { line: 0 } as Partial as any, - hasOutput: true + hasOutput() { return true; } }]); await opener.open({ text: 'file.txt', diff --git a/src/vs/workbench/contrib/terminal/test/browser/xterm/decorationAddon.test.ts b/src/vs/workbench/contrib/terminal/test/browser/xterm/decorationAddon.test.ts index 80802218586..3ea312e1e1e 100644 --- a/src/vs/workbench/contrib/terminal/test/browser/xterm/decorationAddon.test.ts +++ b/src/vs/workbench/contrib/terminal/test/browser/xterm/decorationAddon.test.ts @@ -56,21 +56,21 @@ suite('DecorationAddon', () => { suite('registerDecoration', async () => { test('should throw when command has no marker', async () => { - throws(() => decorationAddon.registerCommandDecoration({ command: 'cd src', timestamp: Date.now(), hasOutput: false } as ITerminalCommand)); + throws(() => decorationAddon.registerCommandDecoration({ command: 'cd src', timestamp: Date.now(), hasOutput: () => false } as ITerminalCommand)); }); test('should return undefined when marker has been disposed of', async () => { const marker = xterm.registerMarker(1); marker?.dispose(); - strictEqual(decorationAddon.registerCommandDecoration({ command: 'cd src', marker, timestamp: Date.now(), hasOutput: false } as ITerminalCommand), undefined); + strictEqual(decorationAddon.registerCommandDecoration({ command: 'cd src', marker, timestamp: Date.now(), hasOutput: () => false } as ITerminalCommand), undefined); }); test('should return undefined when command is just empty chars', async () => { const marker = xterm.registerMarker(1); marker?.dispose(); - strictEqual(decorationAddon.registerCommandDecoration({ command: ' ', marker, timestamp: Date.now(), hasOutput: false } as ITerminalCommand), undefined); + strictEqual(decorationAddon.registerCommandDecoration({ command: ' ', marker, timestamp: Date.now(), hasOutput: () => false } as ITerminalCommand), undefined); }); test('should return decoration when marker has not been disposed of', async () => { const marker = xterm.registerMarker(2); - notEqual(decorationAddon.registerCommandDecoration({ command: 'cd src', marker, timestamp: Date.now(), hasOutput: false } as ITerminalCommand), undefined); + notEqual(decorationAddon.registerCommandDecoration({ command: 'cd src', marker, timestamp: Date.now(), hasOutput: () => false } as ITerminalCommand), undefined); }); }); }); From d5d6e089978695d51760b35a64510d8d0e999534 Mon Sep 17 00:00:00 2001 From: MonadChains Date: Thu, 7 Jul 2022 02:16:10 +0200 Subject: [PATCH 313/347] Add command to copy output of the last command (#152097) (#153235) * Add command to copy output of the last command (#152097) * Polish changes, casing, wording, etc. Co-authored-by: Daniel Imms <2193314+Tyriar@users.noreply.github.com> --- .../contrib/terminal/browser/terminal.ts | 6 ++++++ .../contrib/terminal/browser/terminalActions.ts | 14 ++++++++++++++ .../contrib/terminal/browser/terminalInstance.ts | 15 +++++++++++++++ .../workbench/contrib/terminal/common/terminal.ts | 2 ++ 4 files changed, 37 insertions(+) diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index 3b0b1e1e250..8f2474b5dcd 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -678,6 +678,12 @@ export interface ITerminalInstance { */ copySelection(asHtml?: boolean, command?: ITerminalCommand): Promise; + + /** + * Copies the ouput of the last command + */ + copyLastCommandOutput(): Promise; + /** * Current selection in the terminal. */ diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index 0c70784c0e3..2f7da096e88 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -327,6 +327,20 @@ export function registerTerminalActions() { } } }); + registerAction2(class extends Action2 { + constructor() { + super({ + id: TerminalCommandId.CopyLastCommand, + title: { value: localize('workbench.action.terminal.copyLastCommand', 'Copy Last Command'), original: 'Copy Last Command' }, + f1: true, + category, + precondition: ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated) + }); + } + async run(accessor: ServicesAccessor): Promise { + await accessor.get(ITerminalService).activeInstance?.copyLastCommandOutput(); + } + }); registerAction2(class extends Action2 { constructor() { super({ diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 6c3e3c9f25c..995d7d64cd8 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -1239,6 +1239,21 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { } } + async copyLastCommandOutput(): Promise { + const commands = this.capabilities.get(TerminalCapability.CommandDetection)?.commands; + if (!commands || commands.length === 0) { + return; + } + const command = commands[commands.length - 1]; + if (!command?.hasOutput) { + return; + } + const output = command.getOutput(); + if (output) { + await this._clipboardService.writeText(output); + } + } + get selection(): string | undefined { return this.xterm && this.hasSelection() ? this.xterm.raw.getSelection() : undefined; } diff --git a/src/vs/workbench/contrib/terminal/common/terminal.ts b/src/vs/workbench/contrib/terminal/common/terminal.ts index 109988ca671..52e3969a13a 100644 --- a/src/vs/workbench/contrib/terminal/common/terminal.ts +++ b/src/vs/workbench/contrib/terminal/common/terminal.ts @@ -476,6 +476,7 @@ export const enum TerminalCommandId { OpenFileLink = 'workbench.action.terminal.openFileLink', OpenWebLink = 'workbench.action.terminal.openUrlLink', RunRecentCommand = 'workbench.action.terminal.runRecentCommand', + CopyLastCommand = 'workbench.action.terminal.copyLastCommand', GoToRecentDirectory = 'workbench.action.terminal.goToRecentDirectory', CopySelection = 'workbench.action.terminal.copySelection', CopySelectionAsHtml = 'workbench.action.terminal.copySelectionAsHtml', @@ -574,6 +575,7 @@ export const DEFAULT_COMMANDS_TO_SKIP_SHELL: string[] = [ TerminalCommandId.Clear, TerminalCommandId.CopySelection, TerminalCommandId.CopySelectionAsHtml, + TerminalCommandId.CopyLastCommand, TerminalCommandId.DeleteToLineStart, TerminalCommandId.DeleteWordLeft, TerminalCommandId.DeleteWordRight, From a20329d29143857188fcf81f44c903f495b9fa73 Mon Sep 17 00:00:00 2001 From: Logan Ramos Date: Wed, 6 Jul 2022 20:18:41 -0400 Subject: [PATCH 314/347] Switch extensions to 1DS (#154299) * Move extensions to 1DS * Switch extensions to 1DS --- extensions/git/package.json | 4 +- extensions/git/yarn.lock | 47 +++++++++++++++++-- extensions/github-authentication/package.json | 4 +- extensions/github-authentication/yarn.lock | 47 +++++++++++++++++-- .../html-language-features/package.json | 2 +- extensions/image-preview/package.json | 4 +- extensions/image-preview/yarn.lock | 47 +++++++++++++++++-- .../json-language-features/package.json | 4 +- extensions/json-language-features/yarn.lock | 47 +++++++++++++++++-- .../markdown-language-features/package.json | 4 +- .../markdown-language-features/yarn.lock | 47 +++++++++++++++++-- extensions/markdown-math/package.json | 2 +- extensions/merge-conflict/package.json | 2 +- .../microsoft-authentication/package.json | 4 +- extensions/microsoft-authentication/yarn.lock | 47 +++++++++++++++++-- extensions/simple-browser/package.json | 4 +- extensions/simple-browser/yarn.lock | 47 +++++++++++++++++-- .../typescript-language-features/package.json | 4 +- .../typescript-language-features/yarn.lock | 47 +++++++++++++++++-- 19 files changed, 363 insertions(+), 51 deletions(-) diff --git a/extensions/git/package.json b/extensions/git/package.json index acd208f3ac1..27811e8e93e 100644 --- a/extensions/git/package.json +++ b/extensions/git/package.json @@ -8,7 +8,7 @@ "engines": { "vscode": "^1.5.0" }, - "aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217", + "aiKey": "0c6ae279ed8443289764825290e4f9e2-1a736e7c-1324-4338-be46-fc2a58ae4d14-7255", "enabledApiProposals": [ "diffCommand", "contribMergeEditorToolbar", @@ -2712,7 +2712,7 @@ }, "dependencies": { "@joaomoreno/unique-names-generator": "5.0.0", - "@vscode/extension-telemetry": "0.6.1", + "@vscode/extension-telemetry": "0.6.2", "@vscode/iconv-lite-umd": "0.7.0", "byline": "^5.0.0", "file-type": "^7.2.0", diff --git a/extensions/git/yarn.lock b/extensions/git/yarn.lock index ef4044fdd1c..a5d6607b1d8 100644 --- a/extensions/git/yarn.lock +++ b/extensions/git/yarn.lock @@ -7,6 +7,42 @@ resolved "https://registry.yarnpkg.com/@joaomoreno/unique-names-generator/-/unique-names-generator-5.0.0.tgz#a67fe66e3d825c929fc97abfdf17fd80a72beab0" integrity sha512-3kP6z7aoGEoM3tvhTBZioYa1QFkovOU8uxAlVclnZlXivwF/WTE5EcOzvoDdM+jtjJyWvCMDR1Q4RBjDqupD3A== +"@microsoft/1ds-core-js@3.2.3", "@microsoft/1ds-core-js@^3.2.3": + version "3.2.3" + resolved "https://registry.yarnpkg.com/@microsoft/1ds-core-js/-/1ds-core-js-3.2.3.tgz#2217d92ec8b073caa4577a13f40ea3a5c4c4d4e7" + integrity sha512-796A8fd90oUKDRO7UXUT9BwZ3G+a9XzJj5v012FcCN/2qRhEsIV3x/0wkx2S08T4FiQEUPkB2uoYHpEjEneM7g== + dependencies: + "@microsoft/applicationinsights-core-js" "2.8.4" + "@microsoft/applicationinsights-shims" "^2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/1ds-post-js@^3.2.3": + version "3.2.3" + resolved "https://registry.yarnpkg.com/@microsoft/1ds-post-js/-/1ds-post-js-3.2.3.tgz#1fa7d51615a44f289632ae8c588007ba943db216" + integrity sha512-tcGJQXXr2LYoBbIXPoUVe1KCF3OtBsuKDFL7BXfmNtuSGtWF0yejm6H83DrR8/cUIGMRMUP9lqNlqFGwDYiwAQ== + dependencies: + "@microsoft/1ds-core-js" "3.2.3" + "@microsoft/applicationinsights-shims" "^2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/applicationinsights-core-js@2.8.4": + version "2.8.4" + resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-core-js/-/applicationinsights-core-js-2.8.4.tgz#607e531bb241a8920d43960f68a7c76a6f9af596" + integrity sha512-FoA0FNOsFbJnLyTyQlYs6+HR7HMEa6nAOE6WOm9WVejBHMHQ/Bdb+hfVFi6slxwCimr/ner90jchi4/sIYdnyQ== + dependencies: + "@microsoft/applicationinsights-shims" "2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/applicationinsights-shims@2.0.1", "@microsoft/applicationinsights-shims@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-shims/-/applicationinsights-shims-2.0.1.tgz#5d72fb7aaf4056c4fda54f9d7c93ccf8ca9bcbfd" + integrity sha512-G0MXf6R6HndRbDy9BbEj0zrLeuhwt2nsXk2zKtF0TnYo39KgYqhYC2ayIzKPTm2KAE+xzD7rgyLdZnrcRvt9WQ== + +"@microsoft/dynamicproto-js@^1.1.6": + version "1.1.6" + resolved "https://registry.yarnpkg.com/@microsoft/dynamicproto-js/-/dynamicproto-js-1.1.6.tgz#6fe03468862861f5f88ac4c3959a652b3797f1bc" + integrity sha512-D1Oivw1A4bIXhzBIy3/BBPn3p2On+kpO2NiYt9shICDK7L/w+cR6FFBUsBZ05l6iqzTeL+Jm8lAYn0g6G7DmDg== + "@types/byline@4.2.31": version "4.2.31" resolved "https://registry.yarnpkg.com/@types/byline/-/byline-4.2.31.tgz#0e61fcb9c03e047d21c4496554c7116297ab60cd" @@ -46,10 +82,13 @@ resolved "https://registry.yarnpkg.com/@types/which/-/which-1.0.28.tgz#016e387629b8817bed653fe32eab5d11279c8df6" integrity sha1-AW44dim4gXvtZT/jLqtdESecjfY= -"@vscode/extension-telemetry@0.6.1": - version "0.6.1" - resolved "https://registry.yarnpkg.com/@vscode/extension-telemetry/-/extension-telemetry-0.6.1.tgz#f8d1f7145baf932b75077c48107edff48501fc14" - integrity sha512-Y4Oc8yGURGVF4WhCZcu+EVy+MAIeQDLDVeDlLn59H0C1w+7xr8dL2ZtDBioy+Hog1Edrd6zOwr3Na7xe1iC/UA== +"@vscode/extension-telemetry@0.6.2": + version "0.6.2" + resolved "https://registry.yarnpkg.com/@vscode/extension-telemetry/-/extension-telemetry-0.6.2.tgz#b86814ee680615730da94220c2b03ea9c3c14a8e" + integrity sha512-yb/wxLuaaCRcBAZtDCjNYSisAXz3FWsSqAha5nhHcYxx2ZPdQdWuZqVXGKq0ZpHVndBWWtK6XqtpCN2/HB4S1w== + dependencies: + "@microsoft/1ds-core-js" "^3.2.3" + "@microsoft/1ds-post-js" "^3.2.3" "@vscode/iconv-lite-umd@0.7.0": version "0.7.0" diff --git a/extensions/github-authentication/package.json b/extensions/github-authentication/package.json index 78094e3c5f5..a130c199928 100644 --- a/extensions/github-authentication/package.json +++ b/extensions/github-authentication/package.json @@ -48,7 +48,7 @@ } } }, - "aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217", + "aiKey": "0c6ae279ed8443289764825290e4f9e2-1a736e7c-1324-4338-be46-fc2a58ae4d14-7255", "main": "./out/extension.js", "browser": "./dist/browser/extension.js", "scripts": { @@ -61,7 +61,7 @@ "dependencies": { "node-fetch": "2.6.7", "uuid": "8.1.0", - "@vscode/extension-telemetry": "0.6.1", + "@vscode/extension-telemetry": "0.6.2", "vscode-nls": "^5.0.0", "vscode-tas-client": "^0.1.47" }, diff --git a/extensions/github-authentication/yarn.lock b/extensions/github-authentication/yarn.lock index a390930318e..118ed320b0f 100644 --- a/extensions/github-authentication/yarn.lock +++ b/extensions/github-authentication/yarn.lock @@ -2,6 +2,42 @@ # yarn lockfile v1 +"@microsoft/1ds-core-js@3.2.3", "@microsoft/1ds-core-js@^3.2.3": + version "3.2.3" + resolved "https://registry.yarnpkg.com/@microsoft/1ds-core-js/-/1ds-core-js-3.2.3.tgz#2217d92ec8b073caa4577a13f40ea3a5c4c4d4e7" + integrity sha512-796A8fd90oUKDRO7UXUT9BwZ3G+a9XzJj5v012FcCN/2qRhEsIV3x/0wkx2S08T4FiQEUPkB2uoYHpEjEneM7g== + dependencies: + "@microsoft/applicationinsights-core-js" "2.8.4" + "@microsoft/applicationinsights-shims" "^2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/1ds-post-js@^3.2.3": + version "3.2.3" + resolved "https://registry.yarnpkg.com/@microsoft/1ds-post-js/-/1ds-post-js-3.2.3.tgz#1fa7d51615a44f289632ae8c588007ba943db216" + integrity sha512-tcGJQXXr2LYoBbIXPoUVe1KCF3OtBsuKDFL7BXfmNtuSGtWF0yejm6H83DrR8/cUIGMRMUP9lqNlqFGwDYiwAQ== + dependencies: + "@microsoft/1ds-core-js" "3.2.3" + "@microsoft/applicationinsights-shims" "^2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/applicationinsights-core-js@2.8.4": + version "2.8.4" + resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-core-js/-/applicationinsights-core-js-2.8.4.tgz#607e531bb241a8920d43960f68a7c76a6f9af596" + integrity sha512-FoA0FNOsFbJnLyTyQlYs6+HR7HMEa6nAOE6WOm9WVejBHMHQ/Bdb+hfVFi6slxwCimr/ner90jchi4/sIYdnyQ== + dependencies: + "@microsoft/applicationinsights-shims" "2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/applicationinsights-shims@2.0.1", "@microsoft/applicationinsights-shims@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-shims/-/applicationinsights-shims-2.0.1.tgz#5d72fb7aaf4056c4fda54f9d7c93ccf8ca9bcbfd" + integrity sha512-G0MXf6R6HndRbDy9BbEj0zrLeuhwt2nsXk2zKtF0TnYo39KgYqhYC2ayIzKPTm2KAE+xzD7rgyLdZnrcRvt9WQ== + +"@microsoft/dynamicproto-js@^1.1.6": + version "1.1.6" + resolved "https://registry.yarnpkg.com/@microsoft/dynamicproto-js/-/dynamicproto-js-1.1.6.tgz#6fe03468862861f5f88ac4c3959a652b3797f1bc" + integrity sha512-D1Oivw1A4bIXhzBIy3/BBPn3p2On+kpO2NiYt9shICDK7L/w+cR6FFBUsBZ05l6iqzTeL+Jm8lAYn0g6G7DmDg== + "@types/node-fetch@^2.5.7": version "2.5.7" resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.7.tgz#20a2afffa882ab04d44ca786449a276f9f6bbf3c" @@ -25,10 +61,13 @@ resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.0.0.tgz#165aae4819ad2174a17476dbe66feebd549556c0" integrity sha512-xSQfNcvOiE5f9dyd4Kzxbof1aTrLobL278pGLKOZI6esGfZ7ts9Ka16CzIN6Y8hFHE1C7jIBZokULhK1bOgjRw== -"@vscode/extension-telemetry@0.6.1": - version "0.6.1" - resolved "https://registry.yarnpkg.com/@vscode/extension-telemetry/-/extension-telemetry-0.6.1.tgz#f8d1f7145baf932b75077c48107edff48501fc14" - integrity sha512-Y4Oc8yGURGVF4WhCZcu+EVy+MAIeQDLDVeDlLn59H0C1w+7xr8dL2ZtDBioy+Hog1Edrd6zOwr3Na7xe1iC/UA== +"@vscode/extension-telemetry@0.6.2": + version "0.6.2" + resolved "https://registry.yarnpkg.com/@vscode/extension-telemetry/-/extension-telemetry-0.6.2.tgz#b86814ee680615730da94220c2b03ea9c3c14a8e" + integrity sha512-yb/wxLuaaCRcBAZtDCjNYSisAXz3FWsSqAha5nhHcYxx2ZPdQdWuZqVXGKq0ZpHVndBWWtK6XqtpCN2/HB4S1w== + dependencies: + "@microsoft/1ds-core-js" "^3.2.3" + "@microsoft/1ds-post-js" "^3.2.3" asynckit@^0.4.0: version "0.4.0" diff --git a/extensions/html-language-features/package.json b/extensions/html-language-features/package.json index 51d53e8984a..b3731cd0acd 100644 --- a/extensions/html-language-features/package.json +++ b/extensions/html-language-features/package.json @@ -5,7 +5,7 @@ "version": "1.0.0", "publisher": "vscode", "license": "MIT", - "aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217", + "aiKey": "0c6ae279ed8443289764825290e4f9e2-1a736e7c-1324-4338-be46-fc2a58ae4d14-7255", "engines": { "vscode": "0.10.x" }, diff --git a/extensions/image-preview/package.json b/extensions/image-preview/package.json index b6ff3579894..1ad296a9905 100644 --- a/extensions/image-preview/package.json +++ b/extensions/image-preview/package.json @@ -10,7 +10,7 @@ "publisher": "vscode", "icon": "icon.png", "license": "MIT", - "aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217", + "aiKey": "0c6ae279ed8443289764825290e4f9e2-1a736e7c-1324-4338-be46-fc2a58ae4d14-7255", "engines": { "vscode": "^1.39.0" }, @@ -79,7 +79,7 @@ "watch-web": "npx webpack-cli --config extension-browser.webpack.config --mode none --watch --info-verbosity verbose" }, "dependencies": { - "@vscode/extension-telemetry": "0.6.1", + "@vscode/extension-telemetry": "0.6.2", "vscode-nls": "^5.0.0" }, "repository": { diff --git a/extensions/image-preview/yarn.lock b/extensions/image-preview/yarn.lock index 65af1b8b351..da44f29eaa4 100644 --- a/extensions/image-preview/yarn.lock +++ b/extensions/image-preview/yarn.lock @@ -2,10 +2,49 @@ # yarn lockfile v1 -"@vscode/extension-telemetry@0.6.1": - version "0.6.1" - resolved "https://registry.yarnpkg.com/@vscode/extension-telemetry/-/extension-telemetry-0.6.1.tgz#f8d1f7145baf932b75077c48107edff48501fc14" - integrity sha512-Y4Oc8yGURGVF4WhCZcu+EVy+MAIeQDLDVeDlLn59H0C1w+7xr8dL2ZtDBioy+Hog1Edrd6zOwr3Na7xe1iC/UA== +"@microsoft/1ds-core-js@3.2.3", "@microsoft/1ds-core-js@^3.2.3": + version "3.2.3" + resolved "https://registry.yarnpkg.com/@microsoft/1ds-core-js/-/1ds-core-js-3.2.3.tgz#2217d92ec8b073caa4577a13f40ea3a5c4c4d4e7" + integrity sha512-796A8fd90oUKDRO7UXUT9BwZ3G+a9XzJj5v012FcCN/2qRhEsIV3x/0wkx2S08T4FiQEUPkB2uoYHpEjEneM7g== + dependencies: + "@microsoft/applicationinsights-core-js" "2.8.4" + "@microsoft/applicationinsights-shims" "^2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/1ds-post-js@^3.2.3": + version "3.2.3" + resolved "https://registry.yarnpkg.com/@microsoft/1ds-post-js/-/1ds-post-js-3.2.3.tgz#1fa7d51615a44f289632ae8c588007ba943db216" + integrity sha512-tcGJQXXr2LYoBbIXPoUVe1KCF3OtBsuKDFL7BXfmNtuSGtWF0yejm6H83DrR8/cUIGMRMUP9lqNlqFGwDYiwAQ== + dependencies: + "@microsoft/1ds-core-js" "3.2.3" + "@microsoft/applicationinsights-shims" "^2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/applicationinsights-core-js@2.8.4": + version "2.8.4" + resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-core-js/-/applicationinsights-core-js-2.8.4.tgz#607e531bb241a8920d43960f68a7c76a6f9af596" + integrity sha512-FoA0FNOsFbJnLyTyQlYs6+HR7HMEa6nAOE6WOm9WVejBHMHQ/Bdb+hfVFi6slxwCimr/ner90jchi4/sIYdnyQ== + dependencies: + "@microsoft/applicationinsights-shims" "2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/applicationinsights-shims@2.0.1", "@microsoft/applicationinsights-shims@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-shims/-/applicationinsights-shims-2.0.1.tgz#5d72fb7aaf4056c4fda54f9d7c93ccf8ca9bcbfd" + integrity sha512-G0MXf6R6HndRbDy9BbEj0zrLeuhwt2nsXk2zKtF0TnYo39KgYqhYC2ayIzKPTm2KAE+xzD7rgyLdZnrcRvt9WQ== + +"@microsoft/dynamicproto-js@^1.1.6": + version "1.1.6" + resolved "https://registry.yarnpkg.com/@microsoft/dynamicproto-js/-/dynamicproto-js-1.1.6.tgz#6fe03468862861f5f88ac4c3959a652b3797f1bc" + integrity sha512-D1Oivw1A4bIXhzBIy3/BBPn3p2On+kpO2NiYt9shICDK7L/w+cR6FFBUsBZ05l6iqzTeL+Jm8lAYn0g6G7DmDg== + +"@vscode/extension-telemetry@0.6.2": + version "0.6.2" + resolved "https://registry.yarnpkg.com/@vscode/extension-telemetry/-/extension-telemetry-0.6.2.tgz#b86814ee680615730da94220c2b03ea9c3c14a8e" + integrity sha512-yb/wxLuaaCRcBAZtDCjNYSisAXz3FWsSqAha5nhHcYxx2ZPdQdWuZqVXGKq0ZpHVndBWWtK6XqtpCN2/HB4S1w== + dependencies: + "@microsoft/1ds-core-js" "^3.2.3" + "@microsoft/1ds-post-js" "^3.2.3" vscode-nls@^5.0.0: version "5.0.0" diff --git a/extensions/json-language-features/package.json b/extensions/json-language-features/package.json index 60388c911af..b29d3137315 100644 --- a/extensions/json-language-features/package.json +++ b/extensions/json-language-features/package.json @@ -5,7 +5,7 @@ "version": "1.0.0", "publisher": "vscode", "license": "MIT", - "aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217", + "aiKey": "0c6ae279ed8443289764825290e4f9e2-1a736e7c-1324-4338-be46-fc2a58ae4d14-7255", "engines": { "vscode": "0.10.x" }, @@ -147,7 +147,7 @@ ] }, "dependencies": { - "@vscode/extension-telemetry": "0.6.1", + "@vscode/extension-telemetry": "0.6.2", "request-light": "^0.5.8", "vscode-languageclient": "^8.0.2-next.4", "vscode-nls": "^5.0.1" diff --git a/extensions/json-language-features/yarn.lock b/extensions/json-language-features/yarn.lock index 7cdc2d2ec2d..c7ee46da28d 100644 --- a/extensions/json-language-features/yarn.lock +++ b/extensions/json-language-features/yarn.lock @@ -2,15 +2,54 @@ # yarn lockfile v1 +"@microsoft/1ds-core-js@3.2.3", "@microsoft/1ds-core-js@^3.2.3": + version "3.2.3" + resolved "https://registry.yarnpkg.com/@microsoft/1ds-core-js/-/1ds-core-js-3.2.3.tgz#2217d92ec8b073caa4577a13f40ea3a5c4c4d4e7" + integrity sha512-796A8fd90oUKDRO7UXUT9BwZ3G+a9XzJj5v012FcCN/2qRhEsIV3x/0wkx2S08T4FiQEUPkB2uoYHpEjEneM7g== + dependencies: + "@microsoft/applicationinsights-core-js" "2.8.4" + "@microsoft/applicationinsights-shims" "^2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/1ds-post-js@^3.2.3": + version "3.2.3" + resolved "https://registry.yarnpkg.com/@microsoft/1ds-post-js/-/1ds-post-js-3.2.3.tgz#1fa7d51615a44f289632ae8c588007ba943db216" + integrity sha512-tcGJQXXr2LYoBbIXPoUVe1KCF3OtBsuKDFL7BXfmNtuSGtWF0yejm6H83DrR8/cUIGMRMUP9lqNlqFGwDYiwAQ== + dependencies: + "@microsoft/1ds-core-js" "3.2.3" + "@microsoft/applicationinsights-shims" "^2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/applicationinsights-core-js@2.8.4": + version "2.8.4" + resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-core-js/-/applicationinsights-core-js-2.8.4.tgz#607e531bb241a8920d43960f68a7c76a6f9af596" + integrity sha512-FoA0FNOsFbJnLyTyQlYs6+HR7HMEa6nAOE6WOm9WVejBHMHQ/Bdb+hfVFi6slxwCimr/ner90jchi4/sIYdnyQ== + dependencies: + "@microsoft/applicationinsights-shims" "2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/applicationinsights-shims@2.0.1", "@microsoft/applicationinsights-shims@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-shims/-/applicationinsights-shims-2.0.1.tgz#5d72fb7aaf4056c4fda54f9d7c93ccf8ca9bcbfd" + integrity sha512-G0MXf6R6HndRbDy9BbEj0zrLeuhwt2nsXk2zKtF0TnYo39KgYqhYC2ayIzKPTm2KAE+xzD7rgyLdZnrcRvt9WQ== + +"@microsoft/dynamicproto-js@^1.1.6": + version "1.1.6" + resolved "https://registry.yarnpkg.com/@microsoft/dynamicproto-js/-/dynamicproto-js-1.1.6.tgz#6fe03468862861f5f88ac4c3959a652b3797f1bc" + integrity sha512-D1Oivw1A4bIXhzBIy3/BBPn3p2On+kpO2NiYt9shICDK7L/w+cR6FFBUsBZ05l6iqzTeL+Jm8lAYn0g6G7DmDg== + "@types/node@16.x": version "16.11.6" resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.6.tgz#6bef7a2a0ad684cf6e90fcfe31cecabd9ce0a3ae" integrity sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w== -"@vscode/extension-telemetry@0.6.1": - version "0.6.1" - resolved "https://registry.yarnpkg.com/@vscode/extension-telemetry/-/extension-telemetry-0.6.1.tgz#f8d1f7145baf932b75077c48107edff48501fc14" - integrity sha512-Y4Oc8yGURGVF4WhCZcu+EVy+MAIeQDLDVeDlLn59H0C1w+7xr8dL2ZtDBioy+Hog1Edrd6zOwr3Na7xe1iC/UA== +"@vscode/extension-telemetry@0.6.2": + version "0.6.2" + resolved "https://registry.yarnpkg.com/@vscode/extension-telemetry/-/extension-telemetry-0.6.2.tgz#b86814ee680615730da94220c2b03ea9c3c14a8e" + integrity sha512-yb/wxLuaaCRcBAZtDCjNYSisAXz3FWsSqAha5nhHcYxx2ZPdQdWuZqVXGKq0ZpHVndBWWtK6XqtpCN2/HB4S1w== + dependencies: + "@microsoft/1ds-core-js" "^3.2.3" + "@microsoft/1ds-post-js" "^3.2.3" balanced-match@^1.0.0: version "1.0.0" diff --git a/extensions/markdown-language-features/package.json b/extensions/markdown-language-features/package.json index 13a77aa1f42..ec4b4d19e62 100644 --- a/extensions/markdown-language-features/package.json +++ b/extensions/markdown-language-features/package.json @@ -6,7 +6,7 @@ "icon": "icon.png", "publisher": "vscode", "license": "MIT", - "aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217", + "aiKey": "0c6ae279ed8443289764825290e4f9e2-1a736e7c-1324-4338-be46-fc2a58ae4d14-7255", "engines": { "vscode": "^1.20.0" }, @@ -544,7 +544,7 @@ "watch-web": "npx webpack-cli --config extension-browser.webpack.config --mode none --watch --info-verbosity verbose" }, "dependencies": { - "@vscode/extension-telemetry": "0.6.1", + "@vscode/extension-telemetry": "0.6.2", "dompurify": "^2.3.3", "highlight.js": "^11.4.0", "markdown-it": "^12.3.2", diff --git a/extensions/markdown-language-features/yarn.lock b/extensions/markdown-language-features/yarn.lock index b4ecb4b0303..13eeca2f9da 100644 --- a/extensions/markdown-language-features/yarn.lock +++ b/extensions/markdown-language-features/yarn.lock @@ -2,6 +2,42 @@ # yarn lockfile v1 +"@microsoft/1ds-core-js@3.2.3", "@microsoft/1ds-core-js@^3.2.3": + version "3.2.3" + resolved "https://registry.yarnpkg.com/@microsoft/1ds-core-js/-/1ds-core-js-3.2.3.tgz#2217d92ec8b073caa4577a13f40ea3a5c4c4d4e7" + integrity sha512-796A8fd90oUKDRO7UXUT9BwZ3G+a9XzJj5v012FcCN/2qRhEsIV3x/0wkx2S08T4FiQEUPkB2uoYHpEjEneM7g== + dependencies: + "@microsoft/applicationinsights-core-js" "2.8.4" + "@microsoft/applicationinsights-shims" "^2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/1ds-post-js@^3.2.3": + version "3.2.3" + resolved "https://registry.yarnpkg.com/@microsoft/1ds-post-js/-/1ds-post-js-3.2.3.tgz#1fa7d51615a44f289632ae8c588007ba943db216" + integrity sha512-tcGJQXXr2LYoBbIXPoUVe1KCF3OtBsuKDFL7BXfmNtuSGtWF0yejm6H83DrR8/cUIGMRMUP9lqNlqFGwDYiwAQ== + dependencies: + "@microsoft/1ds-core-js" "3.2.3" + "@microsoft/applicationinsights-shims" "^2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/applicationinsights-core-js@2.8.4": + version "2.8.4" + resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-core-js/-/applicationinsights-core-js-2.8.4.tgz#607e531bb241a8920d43960f68a7c76a6f9af596" + integrity sha512-FoA0FNOsFbJnLyTyQlYs6+HR7HMEa6nAOE6WOm9WVejBHMHQ/Bdb+hfVFi6slxwCimr/ner90jchi4/sIYdnyQ== + dependencies: + "@microsoft/applicationinsights-shims" "2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/applicationinsights-shims@2.0.1", "@microsoft/applicationinsights-shims@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-shims/-/applicationinsights-shims-2.0.1.tgz#5d72fb7aaf4056c4fda54f9d7c93ccf8ca9bcbfd" + integrity sha512-G0MXf6R6HndRbDy9BbEj0zrLeuhwt2nsXk2zKtF0TnYo39KgYqhYC2ayIzKPTm2KAE+xzD7rgyLdZnrcRvt9WQ== + +"@microsoft/dynamicproto-js@^1.1.6": + version "1.1.6" + resolved "https://registry.yarnpkg.com/@microsoft/dynamicproto-js/-/dynamicproto-js-1.1.6.tgz#6fe03468862861f5f88ac4c3959a652b3797f1bc" + integrity sha512-D1Oivw1A4bIXhzBIy3/BBPn3p2On+kpO2NiYt9shICDK7L/w+cR6FFBUsBZ05l6iqzTeL+Jm8lAYn0g6G7DmDg== + "@types/dompurify@^2.3.1": version "2.3.1" resolved "https://registry.yarnpkg.com/@types/dompurify/-/dompurify-2.3.1.tgz#2934adcd31c4e6b02676f9c22f9756e5091c04dd" @@ -59,10 +95,13 @@ resolved "https://registry.yarnpkg.com/@types/vscode-webview/-/vscode-webview-1.57.0.tgz#bad5194d45ae8d03afc1c0f67f71ff5e7a243bbf" integrity sha512-x3Cb/SMa1IwRHfSvKaZDZOTh4cNoG505c3NjTqGlMC082m++x/ETUmtYniDsw6SSmYzZXO8KBNhYxR0+VqymqA== -"@vscode/extension-telemetry@0.6.1": - version "0.6.1" - resolved "https://registry.yarnpkg.com/@vscode/extension-telemetry/-/extension-telemetry-0.6.1.tgz#f8d1f7145baf932b75077c48107edff48501fc14" - integrity sha512-Y4Oc8yGURGVF4WhCZcu+EVy+MAIeQDLDVeDlLn59H0C1w+7xr8dL2ZtDBioy+Hog1Edrd6zOwr3Na7xe1iC/UA== +"@vscode/extension-telemetry@0.6.2": + version "0.6.2" + resolved "https://registry.yarnpkg.com/@vscode/extension-telemetry/-/extension-telemetry-0.6.2.tgz#b86814ee680615730da94220c2b03ea9c3c14a8e" + integrity sha512-yb/wxLuaaCRcBAZtDCjNYSisAXz3FWsSqAha5nhHcYxx2ZPdQdWuZqVXGKq0ZpHVndBWWtK6XqtpCN2/HB4S1w== + dependencies: + "@microsoft/1ds-core-js" "^3.2.3" + "@microsoft/1ds-post-js" "^3.2.3" argparse@^2.0.1: version "2.0.1" diff --git a/extensions/markdown-math/package.json b/extensions/markdown-math/package.json index b8ed2d88a74..045da771eb9 100644 --- a/extensions/markdown-math/package.json +++ b/extensions/markdown-math/package.json @@ -6,7 +6,7 @@ "icon": "icon.png", "publisher": "vscode", "license": "MIT", - "aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217", + "aiKey": "0c6ae279ed8443289764825290e4f9e2-1a736e7c-1324-4338-be46-fc2a58ae4d14-7255", "engines": { "vscode": "^1.54.0" }, diff --git a/extensions/merge-conflict/package.json b/extensions/merge-conflict/package.json index 05603e468b2..efc984ed5b9 100644 --- a/extensions/merge-conflict/package.json +++ b/extensions/merge-conflict/package.json @@ -6,7 +6,7 @@ "icon": "media/icon.png", "version": "1.0.0", "license": "MIT", - "aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217", + "aiKey": "0c6ae279ed8443289764825290e4f9e2-1a736e7c-1324-4338-be46-fc2a58ae4d14-7255", "engines": { "vscode": "^1.5.0" }, diff --git a/extensions/microsoft-authentication/package.json b/extensions/microsoft-authentication/package.json index f206ce9e5a5..f8b8a6931d0 100644 --- a/extensions/microsoft-authentication/package.json +++ b/extensions/microsoft-authentication/package.json @@ -36,7 +36,7 @@ } ] }, - "aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217", + "aiKey": "0c6ae279ed8443289764825290e4f9e2-1a736e7c-1324-4338-be46-fc2a58ae4d14-7255", "main": "./out/extension.js", "browser": "./dist/browser/extension.js", "scripts": { @@ -60,7 +60,7 @@ "sha.js": "2.4.11", "stream": "0.0.2", "uuid": "^8.2.0", - "@vscode/extension-telemetry": "0.6.1", + "@vscode/extension-telemetry": "0.6.2", "vscode-nls": "^5.0.0" }, "repository": { diff --git a/extensions/microsoft-authentication/yarn.lock b/extensions/microsoft-authentication/yarn.lock index dea1d2e471a..9328b1d4b1a 100644 --- a/extensions/microsoft-authentication/yarn.lock +++ b/extensions/microsoft-authentication/yarn.lock @@ -2,6 +2,42 @@ # yarn lockfile v1 +"@microsoft/1ds-core-js@3.2.3", "@microsoft/1ds-core-js@^3.2.3": + version "3.2.3" + resolved "https://registry.yarnpkg.com/@microsoft/1ds-core-js/-/1ds-core-js-3.2.3.tgz#2217d92ec8b073caa4577a13f40ea3a5c4c4d4e7" + integrity sha512-796A8fd90oUKDRO7UXUT9BwZ3G+a9XzJj5v012FcCN/2qRhEsIV3x/0wkx2S08T4FiQEUPkB2uoYHpEjEneM7g== + dependencies: + "@microsoft/applicationinsights-core-js" "2.8.4" + "@microsoft/applicationinsights-shims" "^2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/1ds-post-js@^3.2.3": + version "3.2.3" + resolved "https://registry.yarnpkg.com/@microsoft/1ds-post-js/-/1ds-post-js-3.2.3.tgz#1fa7d51615a44f289632ae8c588007ba943db216" + integrity sha512-tcGJQXXr2LYoBbIXPoUVe1KCF3OtBsuKDFL7BXfmNtuSGtWF0yejm6H83DrR8/cUIGMRMUP9lqNlqFGwDYiwAQ== + dependencies: + "@microsoft/1ds-core-js" "3.2.3" + "@microsoft/applicationinsights-shims" "^2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/applicationinsights-core-js@2.8.4": + version "2.8.4" + resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-core-js/-/applicationinsights-core-js-2.8.4.tgz#607e531bb241a8920d43960f68a7c76a6f9af596" + integrity sha512-FoA0FNOsFbJnLyTyQlYs6+HR7HMEa6nAOE6WOm9WVejBHMHQ/Bdb+hfVFi6slxwCimr/ner90jchi4/sIYdnyQ== + dependencies: + "@microsoft/applicationinsights-shims" "2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/applicationinsights-shims@2.0.1", "@microsoft/applicationinsights-shims@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-shims/-/applicationinsights-shims-2.0.1.tgz#5d72fb7aaf4056c4fda54f9d7c93ccf8ca9bcbfd" + integrity sha512-G0MXf6R6HndRbDy9BbEj0zrLeuhwt2nsXk2zKtF0TnYo39KgYqhYC2ayIzKPTm2KAE+xzD7rgyLdZnrcRvt9WQ== + +"@microsoft/dynamicproto-js@^1.1.6": + version "1.1.6" + resolved "https://registry.yarnpkg.com/@microsoft/dynamicproto-js/-/dynamicproto-js-1.1.6.tgz#6fe03468862861f5f88ac4c3959a652b3797f1bc" + integrity sha512-D1Oivw1A4bIXhzBIy3/BBPn3p2On+kpO2NiYt9shICDK7L/w+cR6FFBUsBZ05l6iqzTeL+Jm8lAYn0g6G7DmDg== + "@types/node-fetch@^2.5.7": version "2.5.7" resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.7.tgz#20a2afffa882ab04d44ca786449a276f9f6bbf3c" @@ -39,10 +75,13 @@ resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.0.0.tgz#165aae4819ad2174a17476dbe66feebd549556c0" integrity sha512-xSQfNcvOiE5f9dyd4Kzxbof1aTrLobL278pGLKOZI6esGfZ7ts9Ka16CzIN6Y8hFHE1C7jIBZokULhK1bOgjRw== -"@vscode/extension-telemetry@0.6.1": - version "0.6.1" - resolved "https://registry.yarnpkg.com/@vscode/extension-telemetry/-/extension-telemetry-0.6.1.tgz#f8d1f7145baf932b75077c48107edff48501fc14" - integrity sha512-Y4Oc8yGURGVF4WhCZcu+EVy+MAIeQDLDVeDlLn59H0C1w+7xr8dL2ZtDBioy+Hog1Edrd6zOwr3Na7xe1iC/UA== +"@vscode/extension-telemetry@0.6.2": + version "0.6.2" + resolved "https://registry.yarnpkg.com/@vscode/extension-telemetry/-/extension-telemetry-0.6.2.tgz#b86814ee680615730da94220c2b03ea9c3c14a8e" + integrity sha512-yb/wxLuaaCRcBAZtDCjNYSisAXz3FWsSqAha5nhHcYxx2ZPdQdWuZqVXGKq0ZpHVndBWWtK6XqtpCN2/HB4S1w== + dependencies: + "@microsoft/1ds-core-js" "^3.2.3" + "@microsoft/1ds-post-js" "^3.2.3" asynckit@^0.4.0: version "0.4.0" diff --git a/extensions/simple-browser/package.json b/extensions/simple-browser/package.json index 7ba03888339..08344e234f1 100644 --- a/extensions/simple-browser/package.json +++ b/extensions/simple-browser/package.json @@ -9,7 +9,7 @@ "icon": "media/icon.png", "publisher": "vscode", "license": "MIT", - "aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217", + "aiKey": "0c6ae279ed8443289764825290e4f9e2-1a736e7c-1324-4338-be46-fc2a58ae4d14-7255", "engines": { "vscode": "^1.53.0" }, @@ -67,7 +67,7 @@ "watch-web": "npx webpack-cli --config extension-browser.webpack.config --mode none --watch --info-verbosity verbose" }, "dependencies": { - "@vscode/extension-telemetry": "0.6.1", + "@vscode/extension-telemetry": "0.6.2", "vscode-nls": "^5.0.0" }, "devDependencies": { diff --git a/extensions/simple-browser/yarn.lock b/extensions/simple-browser/yarn.lock index 0a897c7ddba..5faf627618c 100644 --- a/extensions/simple-browser/yarn.lock +++ b/extensions/simple-browser/yarn.lock @@ -2,15 +2,54 @@ # yarn lockfile v1 +"@microsoft/1ds-core-js@3.2.3", "@microsoft/1ds-core-js@^3.2.3": + version "3.2.3" + resolved "https://registry.yarnpkg.com/@microsoft/1ds-core-js/-/1ds-core-js-3.2.3.tgz#2217d92ec8b073caa4577a13f40ea3a5c4c4d4e7" + integrity sha512-796A8fd90oUKDRO7UXUT9BwZ3G+a9XzJj5v012FcCN/2qRhEsIV3x/0wkx2S08T4FiQEUPkB2uoYHpEjEneM7g== + dependencies: + "@microsoft/applicationinsights-core-js" "2.8.4" + "@microsoft/applicationinsights-shims" "^2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/1ds-post-js@^3.2.3": + version "3.2.3" + resolved "https://registry.yarnpkg.com/@microsoft/1ds-post-js/-/1ds-post-js-3.2.3.tgz#1fa7d51615a44f289632ae8c588007ba943db216" + integrity sha512-tcGJQXXr2LYoBbIXPoUVe1KCF3OtBsuKDFL7BXfmNtuSGtWF0yejm6H83DrR8/cUIGMRMUP9lqNlqFGwDYiwAQ== + dependencies: + "@microsoft/1ds-core-js" "3.2.3" + "@microsoft/applicationinsights-shims" "^2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/applicationinsights-core-js@2.8.4": + version "2.8.4" + resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-core-js/-/applicationinsights-core-js-2.8.4.tgz#607e531bb241a8920d43960f68a7c76a6f9af596" + integrity sha512-FoA0FNOsFbJnLyTyQlYs6+HR7HMEa6nAOE6WOm9WVejBHMHQ/Bdb+hfVFi6slxwCimr/ner90jchi4/sIYdnyQ== + dependencies: + "@microsoft/applicationinsights-shims" "2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/applicationinsights-shims@2.0.1", "@microsoft/applicationinsights-shims@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-shims/-/applicationinsights-shims-2.0.1.tgz#5d72fb7aaf4056c4fda54f9d7c93ccf8ca9bcbfd" + integrity sha512-G0MXf6R6HndRbDy9BbEj0zrLeuhwt2nsXk2zKtF0TnYo39KgYqhYC2ayIzKPTm2KAE+xzD7rgyLdZnrcRvt9WQ== + +"@microsoft/dynamicproto-js@^1.1.6": + version "1.1.6" + resolved "https://registry.yarnpkg.com/@microsoft/dynamicproto-js/-/dynamicproto-js-1.1.6.tgz#6fe03468862861f5f88ac4c3959a652b3797f1bc" + integrity sha512-D1Oivw1A4bIXhzBIy3/BBPn3p2On+kpO2NiYt9shICDK7L/w+cR6FFBUsBZ05l6iqzTeL+Jm8lAYn0g6G7DmDg== + "@types/vscode-webview@^1.57.0": version "1.57.0" resolved "https://registry.yarnpkg.com/@types/vscode-webview/-/vscode-webview-1.57.0.tgz#bad5194d45ae8d03afc1c0f67f71ff5e7a243bbf" integrity sha512-x3Cb/SMa1IwRHfSvKaZDZOTh4cNoG505c3NjTqGlMC082m++x/ETUmtYniDsw6SSmYzZXO8KBNhYxR0+VqymqA== -"@vscode/extension-telemetry@0.6.1": - version "0.6.1" - resolved "https://registry.yarnpkg.com/@vscode/extension-telemetry/-/extension-telemetry-0.6.1.tgz#f8d1f7145baf932b75077c48107edff48501fc14" - integrity sha512-Y4Oc8yGURGVF4WhCZcu+EVy+MAIeQDLDVeDlLn59H0C1w+7xr8dL2ZtDBioy+Hog1Edrd6zOwr3Na7xe1iC/UA== +"@vscode/extension-telemetry@0.6.2": + version "0.6.2" + resolved "https://registry.yarnpkg.com/@vscode/extension-telemetry/-/extension-telemetry-0.6.2.tgz#b86814ee680615730da94220c2b03ea9c3c14a8e" + integrity sha512-yb/wxLuaaCRcBAZtDCjNYSisAXz3FWsSqAha5nhHcYxx2ZPdQdWuZqVXGKq0ZpHVndBWWtK6XqtpCN2/HB4S1w== + dependencies: + "@microsoft/1ds-core-js" "^3.2.3" + "@microsoft/1ds-post-js" "^3.2.3" vscode-codicons@^0.0.14: version "0.0.14" diff --git a/extensions/typescript-language-features/package.json b/extensions/typescript-language-features/package.json index e3b7eadb0c4..be5a8bacb28 100644 --- a/extensions/typescript-language-features/package.json +++ b/extensions/typescript-language-features/package.json @@ -6,7 +6,7 @@ "author": "vscode", "publisher": "vscode", "license": "MIT", - "aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217", + "aiKey": "0c6ae279ed8443289764825290e4f9e2-1a736e7c-1324-4338-be46-fc2a58ae4d14-7255", "enabledApiProposals": [ "resolvers", "workspaceTrust" @@ -34,7 +34,7 @@ "Programming Languages" ], "dependencies": { - "@vscode/extension-telemetry": "0.6.1", + "@vscode/extension-telemetry": "0.6.2", "jsonc-parser": "^2.2.1", "semver": "5.5.1", "vscode-nls": "^5.0.0", diff --git a/extensions/typescript-language-features/yarn.lock b/extensions/typescript-language-features/yarn.lock index 9b17075c8c4..c400b672129 100644 --- a/extensions/typescript-language-features/yarn.lock +++ b/extensions/typescript-language-features/yarn.lock @@ -2,6 +2,42 @@ # yarn lockfile v1 +"@microsoft/1ds-core-js@3.2.3", "@microsoft/1ds-core-js@^3.2.3": + version "3.2.3" + resolved "https://registry.yarnpkg.com/@microsoft/1ds-core-js/-/1ds-core-js-3.2.3.tgz#2217d92ec8b073caa4577a13f40ea3a5c4c4d4e7" + integrity sha512-796A8fd90oUKDRO7UXUT9BwZ3G+a9XzJj5v012FcCN/2qRhEsIV3x/0wkx2S08T4FiQEUPkB2uoYHpEjEneM7g== + dependencies: + "@microsoft/applicationinsights-core-js" "2.8.4" + "@microsoft/applicationinsights-shims" "^2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/1ds-post-js@^3.2.3": + version "3.2.3" + resolved "https://registry.yarnpkg.com/@microsoft/1ds-post-js/-/1ds-post-js-3.2.3.tgz#1fa7d51615a44f289632ae8c588007ba943db216" + integrity sha512-tcGJQXXr2LYoBbIXPoUVe1KCF3OtBsuKDFL7BXfmNtuSGtWF0yejm6H83DrR8/cUIGMRMUP9lqNlqFGwDYiwAQ== + dependencies: + "@microsoft/1ds-core-js" "3.2.3" + "@microsoft/applicationinsights-shims" "^2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/applicationinsights-core-js@2.8.4": + version "2.8.4" + resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-core-js/-/applicationinsights-core-js-2.8.4.tgz#607e531bb241a8920d43960f68a7c76a6f9af596" + integrity sha512-FoA0FNOsFbJnLyTyQlYs6+HR7HMEa6nAOE6WOm9WVejBHMHQ/Bdb+hfVFi6slxwCimr/ner90jchi4/sIYdnyQ== + dependencies: + "@microsoft/applicationinsights-shims" "2.0.1" + "@microsoft/dynamicproto-js" "^1.1.6" + +"@microsoft/applicationinsights-shims@2.0.1", "@microsoft/applicationinsights-shims@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-shims/-/applicationinsights-shims-2.0.1.tgz#5d72fb7aaf4056c4fda54f9d7c93ccf8ca9bcbfd" + integrity sha512-G0MXf6R6HndRbDy9BbEj0zrLeuhwt2nsXk2zKtF0TnYo39KgYqhYC2ayIzKPTm2KAE+xzD7rgyLdZnrcRvt9WQ== + +"@microsoft/dynamicproto-js@^1.1.6": + version "1.1.6" + resolved "https://registry.yarnpkg.com/@microsoft/dynamicproto-js/-/dynamicproto-js-1.1.6.tgz#6fe03468862861f5f88ac4c3959a652b3797f1bc" + integrity sha512-D1Oivw1A4bIXhzBIy3/BBPn3p2On+kpO2NiYt9shICDK7L/w+cR6FFBUsBZ05l6iqzTeL+Jm8lAYn0g6G7DmDg== + "@types/node@16.x": version "16.11.6" resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.6.tgz#6bef7a2a0ad684cf6e90fcfe31cecabd9ce0a3ae" @@ -12,10 +48,13 @@ resolved "https://registry.yarnpkg.com/@types/semver/-/semver-5.5.0.tgz#146c2a29ee7d3bae4bf2fcb274636e264c813c45" integrity sha512-41qEJgBH/TWgo5NFSvBCJ1qkoi3Q6ONSF2avrHq1LVEZfYpdHmj0y9SuTK+u9ZhG1sYQKBL1AWXKyLWP4RaUoQ== -"@vscode/extension-telemetry@0.6.1": - version "0.6.1" - resolved "https://registry.yarnpkg.com/@vscode/extension-telemetry/-/extension-telemetry-0.6.1.tgz#f8d1f7145baf932b75077c48107edff48501fc14" - integrity sha512-Y4Oc8yGURGVF4WhCZcu+EVy+MAIeQDLDVeDlLn59H0C1w+7xr8dL2ZtDBioy+Hog1Edrd6zOwr3Na7xe1iC/UA== +"@vscode/extension-telemetry@0.6.2": + version "0.6.2" + resolved "https://registry.yarnpkg.com/@vscode/extension-telemetry/-/extension-telemetry-0.6.2.tgz#b86814ee680615730da94220c2b03ea9c3c14a8e" + integrity sha512-yb/wxLuaaCRcBAZtDCjNYSisAXz3FWsSqAha5nhHcYxx2ZPdQdWuZqVXGKq0ZpHVndBWWtK6XqtpCN2/HB4S1w== + dependencies: + "@microsoft/1ds-core-js" "^3.2.3" + "@microsoft/1ds-post-js" "^3.2.3" axios@^0.26.1: version "0.26.1" From a3153bb9dc4816c4f4034686997a6232b923769f Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Wed, 6 Jul 2022 20:25:03 -0400 Subject: [PATCH 315/347] Update src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts --- .../contrib/terminal/browser/terminalProfileResolverService.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts b/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts index 2abd550fedc..33e242184de 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts @@ -145,7 +145,6 @@ export abstract class BaseTerminalProfileResolverService implements ITerminalPro // Verify the icon is valid, and fallback correctly to the generic terminal id if there is // an issue - console.log('icon', this._configurationService.getValue(TerminalSettingId.TabsDefaultIcon)); shellLaunchConfig.icon = this._getCustomIcon(shellLaunchConfig.icon) || this._getCustomIcon(resolvedProfile.icon) || this.getDefaultIcon(); From d39ef2fc829dffe33ff7b9c341d787bb1198ef63 Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Wed, 6 Jul 2022 20:25:24 -0400 Subject: [PATCH 316/347] Update src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts --- .../contrib/terminal/browser/terminalProfileResolverService.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts b/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts index 33e242184de..f920f87442f 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts @@ -148,7 +148,6 @@ export abstract class BaseTerminalProfileResolverService implements ITerminalPro shellLaunchConfig.icon = this._getCustomIcon(shellLaunchConfig.icon) || this._getCustomIcon(resolvedProfile.icon) || this.getDefaultIcon(); - console.log('icon2', shellLaunchConfig.icon); // Override the name if specified if (resolvedProfile.overrideName) { From 2d9947ba4e53c0889c07e3a415572ec8bad1529e Mon Sep 17 00:00:00 2001 From: meganrogge Date: Wed, 6 Jul 2022 20:47:00 -0400 Subject: [PATCH 317/347] more specific setting names --- src/vs/platform/terminal/common/terminal.ts | 4 ++-- .../contrib/terminal/browser/terminalInstance.ts | 2 +- .../terminal/browser/terminalProfileResolverService.ts | 4 ++-- .../contrib/terminal/common/terminalConfiguration.ts | 8 ++++---- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/vs/platform/terminal/common/terminal.ts b/src/vs/platform/terminal/common/terminal.ts index 4ef5e51de3e..0619e9e87fa 100644 --- a/src/vs/platform/terminal/common/terminal.ts +++ b/src/vs/platform/terminal/common/terminal.ts @@ -40,8 +40,8 @@ export const enum TerminalSettingId { DefaultProfileMacOs = 'terminal.integrated.defaultProfile.osx', DefaultProfileWindows = 'terminal.integrated.defaultProfile.windows', UseWslProfiles = 'terminal.integrated.useWslProfiles', - TabsDefaultColor = 'terminal.integrated.tabs.defaultColor', - TabsDefaultIcon = 'terminal.integrated.tabs.defaultIcon', + TabsDefaultIconColor = 'terminal.integrated.tabs.defaultIconColor', + TabsDefaultIconId = 'terminal.integrated.tabs.defaultIconId', TabsEnabled = 'terminal.integrated.tabs.enabled', TabsEnableAnimation = 'terminal.integrated.tabs.enableAnimation', TabsHideCondition = 'terminal.integrated.tabs.hideCondition', diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index a02e18413dc..b392eb5bd70 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -550,7 +550,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { private _getIcon(): TerminalIcon | undefined { if (!this._icon) { this._icon = this._processManager.processState >= ProcessState.Launching - ? getIconRegistry().getIcon(this._configurationService.getValue(TerminalSettingId.TabsDefaultIcon)) + ? getIconRegistry().getIcon(this._configurationService.getValue(TerminalSettingId.TabsDefaultIconId)) : undefined; } return this._icon; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts b/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts index f920f87442f..b133c8e5d8d 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts @@ -117,7 +117,7 @@ export abstract class BaseTerminalProfileResolverService implements ITerminalPro } getDefaultIcon(): TerminalIcon & ThemeIcon { - return this._iconRegistry.getIcon(this._configurationService.getValue(TerminalSettingId.TabsDefaultIcon)) || Codicon.terminal; + return this._iconRegistry.getIcon(this._configurationService.getValue(TerminalSettingId.TabsDefaultIconId)) || Codicon.terminal; } async resolveShellLaunchConfig(shellLaunchConfig: IShellLaunchConfig, options: IShellLaunchConfigResolveOptions): Promise { @@ -157,7 +157,7 @@ export abstract class BaseTerminalProfileResolverService implements ITerminalPro // Apply the color shellLaunchConfig.color = shellLaunchConfig.color || resolvedProfile.color - || this._configurationService.getValue(TerminalSettingId.TabsDefaultColor); + || this._configurationService.getValue(TerminalSettingId.TabsDefaultIconColor); // Resolve useShellEnvironment based on the setting if it's not set if (shellLaunchConfig.useShellEnvironment === undefined) { diff --git a/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts b/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts index 5c982b8dc56..0458ff05172 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts @@ -40,12 +40,12 @@ const terminalConfiguration: IConfigurationNode = { type: 'boolean', default: false }, - [TerminalSettingId.TabsDefaultColor]: { - description: localize('terminal.integrated.tabs.defaultColor', "A theme color ID to associate with terminals by default."), + [TerminalSettingId.TabsDefaultIconColor]: { + description: localize('terminal.integrated.tabs.defaultIconColor', "A theme color ID to associate with terminals by default."), ...terminalColorSchema }, - [TerminalSettingId.TabsDefaultIcon]: { - description: localize('terminal.integrated.tabs.defaultIcon', "A codicon ID to associate with terminals by default."), + [TerminalSettingId.TabsDefaultIconId]: { + description: localize('terminal.integrated.tabs.defaultIconId', "A codicon ID to associate with terminals by default."), ...terminalIconSchema, default: Codicon.terminal.id, }, From 91b82c0f0b9d0c9a9135252663522a563be3f6eb Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Wed, 6 Jul 2022 21:59:27 -0400 Subject: [PATCH 318/347] increase barrier for available profiles to be ready (#154290) * fix #138999 Co-authored-by: Daniel Imms <2193314+Tyriar@users.noreply.github.com> --- .../contrib/terminal/browser/terminalProfileService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalProfileService.ts b/src/vs/workbench/contrib/terminal/browser/terminalProfileService.ts index 60c49b4b34b..7bdc8975d82 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalProfileService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalProfileService.ts @@ -67,7 +67,7 @@ export class TerminalProfileService implements ITerminalProfileService { // Wait up to 5 seconds for profiles to be ready so it's assured that we know the actual // default terminal before launching the first terminal. This isn't expected to ever take // this long. - this._profilesReadyBarrier = new AutoOpenBarrier(5000); + this._profilesReadyBarrier = new AutoOpenBarrier(20000); this.refreshAvailableProfiles(); this._setupConfigListener(); } From 374066b82984c3bf8afaa4828147ec29bd883bc8 Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Wed, 6 Jul 2022 19:06:36 -0700 Subject: [PATCH 319/347] re #153743. Move codicon out of translation string (#154323) --- .../browser/contrib/editorStatusBar/editorStatusBar.ts | 2 +- .../notebook/browser/controller/insertCellActions.ts | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/editorStatusBar/editorStatusBar.ts b/src/vs/workbench/contrib/notebook/browser/contrib/editorStatusBar/editorStatusBar.ts index 285dae8f94e..53ce0466795 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/editorStatusBar/editorStatusBar.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/editorStatusBar/editorStatusBar.ts @@ -243,7 +243,7 @@ registerAction2(class extends Action2 { quickPickItems.push({ id: 'installSuggested', description: suggestedExtension.displayName ?? suggestedExtension.extensionId, - label: nls.localize('installSuggestedKernel', '$({0}) Install suggested extensions', Codicon.lightbulb.id), + label: `$(${Codicon.lightbulb.id}) ` + nls.localize('installSuggestedKernel', 'Install suggested extensions'), }); } // there is no kernel, show the install from marketplace diff --git a/src/vs/workbench/contrib/notebook/browser/controller/insertCellActions.ts b/src/vs/workbench/contrib/notebook/browser/controller/insertCellActions.ts index 6a85c41a24a..454b565d71e 100644 --- a/src/vs/workbench/contrib/notebook/browser/controller/insertCellActions.ts +++ b/src/vs/workbench/contrib/notebook/browser/controller/insertCellActions.ts @@ -224,7 +224,7 @@ registerAction2(class InsertMarkdownCellAtTopAction extends NotebookAction { MenuRegistry.appendMenuItem(MenuId.NotebookCellBetween, { command: { id: INSERT_CODE_CELL_BELOW_COMMAND_ID, - title: localize('notebookActions.menu.insertCode', "$(add) Code"), + title: '$(add) ' + localize('notebookActions.menu.insertCode', "Code"), tooltip: localize('notebookActions.menu.insertCode.tooltip', "Add Code Cell") }, order: 0, @@ -269,7 +269,7 @@ MenuRegistry.appendMenuItem(MenuId.NotebookToolbar, { MenuRegistry.appendMenuItem(MenuId.NotebookCellListTop, { command: { id: INSERT_CODE_CELL_AT_TOP_COMMAND_ID, - title: localize('notebookActions.menu.insertCode', "$(add) Code"), + title: '$(add) ' + localize('notebookActions.menu.insertCode', "Code"), tooltip: localize('notebookActions.menu.insertCode.tooltip', "Add Code Cell") }, order: 0, @@ -299,7 +299,7 @@ MenuRegistry.appendMenuItem(MenuId.NotebookCellListTop, { MenuRegistry.appendMenuItem(MenuId.NotebookCellBetween, { command: { id: INSERT_MARKDOWN_CELL_BELOW_COMMAND_ID, - title: localize('notebookActions.menu.insertMarkdown', "$(add) Markdown"), + title: '$(add) ' + localize('notebookActions.menu.insertMarkdown', "Markdown"), tooltip: localize('notebookActions.menu.insertMarkdown.tooltip', "Add Markdown Cell") }, order: 1, @@ -331,7 +331,7 @@ MenuRegistry.appendMenuItem(MenuId.NotebookToolbar, { MenuRegistry.appendMenuItem(MenuId.NotebookCellListTop, { command: { id: INSERT_MARKDOWN_CELL_AT_TOP_COMMAND_ID, - title: localize('notebookActions.menu.insertMarkdown', "$(add) Markdown"), + title: '$(add) ' + localize('notebookActions.menu.insertMarkdown', "Markdown"), tooltip: localize('notebookActions.menu.insertMarkdown.tooltip', "Add Markdown Cell") }, order: 1, From ffdb7543feb9abccee23d2b3064bb5bd3d8593a7 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 6 Jul 2022 19:13:51 -0700 Subject: [PATCH 320/347] Correct conditional calling func instead of comparing Part of #152097 --- src/vs/workbench/contrib/terminal/browser/terminalInstance.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 995d7d64cd8..370ed54dd2d 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -1245,7 +1245,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { return; } const command = commands[commands.length - 1]; - if (!command?.hasOutput) { + if (!command?.hasOutput()) { return; } const output = command.getOutput(); From 93d1f7c88157cc4594ff7154b0f2ad6efc4db08c Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Wed, 6 Jul 2022 22:17:44 -0400 Subject: [PATCH 321/347] use user's `.zsh_history` (#154300) --- .../contrib/terminal/browser/media/shellIntegration-rc.zsh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-rc.zsh b/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-rc.zsh index a94e7c11c71..595c1261e18 100644 --- a/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-rc.zsh +++ b/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-rc.zsh @@ -21,6 +21,10 @@ if [[ "$VSCODE_INJECTION" == "1" ]]; then . $USER_ZDOTDIR/.zshrc ZDOTDIR=$VSCODE_ZDOTDIR fi + + if [[ -f $USER_ZDOTDIR/.zsh_history ]]; then + HISTFILE=$USER_ZDOTDIR/.zsh_history + fi fi # Shell integration was disabled by the shell, exit without warning assuming either the shell has From d6114a70bea1c9163c7c3538e31243affd3b9fd4 Mon Sep 17 00:00:00 2001 From: Logan Ramos Date: Wed, 6 Jul 2022 22:23:30 -0400 Subject: [PATCH 322/347] Remove app insights (#154296) * Remove app insights * Update product service to remove asimovKey --- .eslintrc.json | 4 +- build/package.json | 1 - build/yarn.lock | 73 +------- package.json | 3 - remote/package.json | 2 - remote/web/package.json | 1 - remote/web/yarn.lock | 63 ------- remote/yarn.lock | 144 ---------------- src/vs/base/common/product.ts | 2 - .../sharedProcess/sharedProcessMain.ts | 9 +- src/vs/code/node/cliProcessMain.ts | 10 +- .../telemetry/browser/appInsightsAppender.ts | 77 --------- .../platform/telemetry/common/1dsAppender.ts | 4 +- src/vs/platform/telemetry/node/1dsAppender.ts | 2 +- .../telemetry/node/appInsightsAppender.ts | 121 ------------- ...tsAppender.test.ts => 1dsAppender.test.ts} | 25 ++- src/vs/server/node/serverServices.ts | 14 +- .../contrib/debug/node/telemetryApp.ts | 4 +- .../telemetry/browser/telemetryService.ts | 13 +- yarn.lock | 161 +----------------- 20 files changed, 36 insertions(+), 697 deletions(-) delete mode 100644 src/vs/platform/telemetry/browser/appInsightsAppender.ts delete mode 100644 src/vs/platform/telemetry/node/appInsightsAppender.ts rename src/vs/platform/telemetry/test/electron-browser/{appInsightsAppender.test.ts => 1dsAppender.test.ts} (85%) diff --git a/.eslintrc.json b/.eslintrc.json index 7a53aeaad5a..af34ee181a9 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -210,8 +210,7 @@ // - electron-browser "when": "hasBrowser", "allow": [ - "vs/css!./**/*", - "@microsoft/applicationinsights-web" + "vs/css!./**/*" ] }, { @@ -226,7 +225,6 @@ "@vscode/vscode-languagedetection", "@vscode/ripgrep", "@vscode/iconv-lite-umd", - "applicationinsights", "assert", "child_process", "console", diff --git a/build/package.json b/build/package.json index b58f58be433..3b46323c250 100644 --- a/build/package.json +++ b/build/package.json @@ -43,7 +43,6 @@ "@typescript-eslint/experimental-utils": "^5.10.0", "@typescript-eslint/parser": "^5.10.0", "@vscode/iconv-lite-umd": "0.7.0", - "applicationinsights": "1.4.2", "byline": "^5.0.0", "colors": "^1.4.0", "commander": "^7.0.0", diff --git a/build/yarn.lock b/build/yarn.lock index bb6fcbcb482..4ea17c7f5d4 100644 --- a/build/yarn.lock +++ b/build/yarn.lock @@ -847,16 +847,6 @@ anymatch@^3.0.0, anymatch@^3.1.1, anymatch@~3.1.1: normalize-path "^3.0.0" picomatch "^2.0.4" -applicationinsights@1.4.2: - version "1.4.2" - resolved "https://registry.yarnpkg.com/applicationinsights/-/applicationinsights-1.4.2.tgz#2f25f7a3f3e5bf0ab4486b63e42a48a9ec321d52" - integrity sha512-1wE37G9zEMZTsPJVQ8BDrQtsGgG3DGMActLHwPAF8TYHAXkfqqpeZYCH0XV4lUZ7H4MffRMwN2Ln2nEtUmT8HQ== - dependencies: - cls-hooked "^4.2.2" - continuation-local-storage "^3.2.1" - diagnostic-channel "0.2.0" - diagnostic-channel-publishers "^0.3.3" - aproba@^1.0.3: version "1.2.0" resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" @@ -909,21 +899,6 @@ assign-symbols@^1.0.0: resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= -async-hook-jl@^1.7.6: - version "1.7.6" - resolved "https://registry.yarnpkg.com/async-hook-jl/-/async-hook-jl-1.7.6.tgz#4fd25c2f864dbaf279c610d73bf97b1b28595e68" - integrity sha512-gFaHkFfSxTjvoxDMYqDuGHlcRyUuamF8s+ZTtJdDzqjws4mCt7v0vuV79/E2Wr2/riMQgtG4/yUtXWs1gZ7JMg== - dependencies: - stack-chain "^1.3.7" - -async-listener@^0.6.0: - version "0.6.10" - resolved "https://registry.yarnpkg.com/async-listener/-/async-listener-0.6.10.tgz#a7c97abe570ba602d782273c0de60a51e3e17cbc" - integrity sha512-gpuo6xOyF4D5DE5WvyqZdPA3NGhiT6Qf07l7DCB0wwDEsLvDIbCr6j9S5aj5Ch96dLace5tXVzWBZkxU/c5ohw== - dependencies: - semver "^5.3.0" - shimmer "^1.1.0" - asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -1185,15 +1160,6 @@ cloneable-readable@^1.0.0: process-nextick-args "^2.0.0" readable-stream "^2.3.5" -cls-hooked@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/cls-hooked/-/cls-hooked-4.2.2.tgz#ad2e9a4092680cdaffeb2d3551da0e225eae1908" - integrity sha512-J4Xj5f5wq/4jAvcdgoGsL3G103BtWpZrMo8NEinRltN+xpTZdI+M38pyQqhuFU/P792xkMFvnKSf+Lm81U1bxw== - dependencies: - async-hook-jl "^1.7.6" - emitter-listener "^1.0.1" - semver "^5.4.1" - code-point-at@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" @@ -1290,14 +1256,6 @@ console-control-strings@^1.0.0, console-control-strings@~1.1.0: resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= -continuation-local-storage@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/continuation-local-storage/-/continuation-local-storage-3.2.1.tgz#11f613f74e914fe9b34c92ad2d28fe6ae1db7ffb" - integrity sha512-jx44cconVqkCEEyLSKWwkvUXwO561jXMa3LPjTPsm5QR22PA0/mhe33FT4Xb5y74JDvt/Cq+5lm8S8rskLv9ZA== - dependencies: - async-listener "^0.6.0" - emitter-listener "^1.1.1" - core-js@^3.6.5: version "3.15.2" resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.15.2.tgz#740660d2ff55ef34ce664d7e2455119c5bdd3d61" @@ -1427,18 +1385,6 @@ detect-node@^2.0.4: resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== -diagnostic-channel-publishers@^0.3.3: - version "0.3.5" - resolved "https://registry.yarnpkg.com/diagnostic-channel-publishers/-/diagnostic-channel-publishers-0.3.5.tgz#a84a05fd6cc1d7619fdd17791c17e540119a7536" - integrity sha512-AOIjw4T7Nxl0G2BoBPhkQ6i7T4bUd9+xvdYizwvG7vVAM1dvr+SDrcUudlmzwH0kbEwdR2V1EcnKT0wAeYLQNQ== - -diagnostic-channel@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/diagnostic-channel/-/diagnostic-channel-0.2.0.tgz#cc99af9612c23fb1fff13612c72f2cbfaa8d5a17" - integrity sha1-zJmvlhLCP7H/8TYSxy8sv6qNWhc= - dependencies: - semver "^5.3.0" - dir-compare@^2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/dir-compare/-/dir-compare-2.4.0.tgz#785c41dc5f645b34343a4eafc50b79bac7f11631" @@ -1510,13 +1456,6 @@ electron-osx-sign@^0.4.16: minimist "^1.2.0" plist "^3.0.1" -emitter-listener@^1.0.1, emitter-listener@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/emitter-listener/-/emitter-listener-1.1.2.tgz#56b140e8f6992375b3d7cb2cab1cc7432d9632e8" - integrity sha512-Bt1sBAGFHY9DKY+4/2cV6izcKJUf5T7/gkdmkxzX/qv9CcGH8xSwVRW5mtX03SWJtRTWSOpzCuWN9rBFYZepZQ== - dependencies: - shimmer "^1.2.0" - emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" @@ -3011,7 +2950,7 @@ semver-compare@^1.0.0: resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" integrity sha1-De4hahyUGrN+nvsXiPavxf9VN/w= -semver@^5.1.0, semver@^5.3.0: +semver@^5.1.0: version "5.6.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== @@ -3064,11 +3003,6 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -shimmer@^1.1.0, shimmer@^1.2.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/shimmer/-/shimmer-1.2.1.tgz#610859f7de327b587efebf501fb43117f9aff337" - integrity sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw== - side-channel@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" @@ -3122,11 +3056,6 @@ sprintf-js@~1.0.2: resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= -stack-chain@^1.3.7: - version "1.3.7" - resolved "https://registry.yarnpkg.com/stack-chain/-/stack-chain-1.3.7.tgz#d192c9ff4ea6a22c94c4dd459171e3f00cea1285" - integrity sha1-0ZLJ/06moiyUxN1FkXHj8AzqEoU= - stoppable@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/stoppable/-/stoppable-1.1.0.tgz#32da568e83ea488b08e4d7ea2c3bcc9d75015d5b" diff --git a/package.json b/package.json index 5dec1737bc8..a0ed5de58f5 100644 --- a/package.json +++ b/package.json @@ -61,14 +61,12 @@ "dependencies": { "@microsoft/1ds-core-js": "^3.2.2", "@microsoft/1ds-post-js": "^3.2.2", - "@microsoft/applicationinsights-web": "^2.8.4", "@parcel/watcher": "2.0.5", "@vscode/iconv-lite-umd": "0.7.0", "@vscode/ripgrep": "^1.14.2", "@vscode/sqlite3": "5.0.8", "@vscode/sudo-prompt": "9.3.1", "@vscode/vscode-languagedetection": "1.0.21", - "applicationinsights": "1.4.2", "graceful-fs": "4.2.8", "http-proxy-agent": "^2.1.0", "https-proxy-agent": "^2.2.3", @@ -99,7 +97,6 @@ "devDependencies": { "7zip": "0.0.6", "@playwright/test": "1.21.0", - "@types/applicationinsights": "0.20.0", "@types/cookie": "^0.3.3", "@types/copy-webpack-plugin": "^6.0.3", "@types/cssnano": "^4.0.0", diff --git a/remote/package.json b/remote/package.json index 6accf3d3154..8da57bba60b 100644 --- a/remote/package.json +++ b/remote/package.json @@ -5,12 +5,10 @@ "dependencies": { "@microsoft/1ds-core-js": "^3.2.2", "@microsoft/1ds-post-js": "^3.2.2", - "@microsoft/applicationinsights-web": "^2.8.4", "@parcel/watcher": "2.0.5", "@vscode/iconv-lite-umd": "0.7.0", "@vscode/ripgrep": "^1.14.2", "@vscode/vscode-languagedetection": "1.0.21", - "applicationinsights": "1.4.2", "cookie": "^0.4.0", "graceful-fs": "4.2.8", "http-proxy-agent": "^2.1.0", diff --git a/remote/web/package.json b/remote/web/package.json index 514de33e21c..c3a32f4d4ec 100644 --- a/remote/web/package.json +++ b/remote/web/package.json @@ -5,7 +5,6 @@ "dependencies": { "@microsoft/1ds-core-js": "^3.2.2", "@microsoft/1ds-post-js": "^3.2.2", - "@microsoft/applicationinsights-web": "^2.8.4", "@vscode/iconv-lite-umd": "0.7.0", "@vscode/vscode-languagedetection": "1.0.21", "jschardet": "3.0.0", diff --git a/remote/web/yarn.lock b/remote/web/yarn.lock index 275fa0853ef..75a41e50c82 100644 --- a/remote/web/yarn.lock +++ b/remote/web/yarn.lock @@ -20,35 +20,6 @@ "@microsoft/applicationinsights-shims" "^2.0.1" "@microsoft/dynamicproto-js" "^1.1.6" -"@microsoft/applicationinsights-analytics-js@2.8.4": - version "2.8.4" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-analytics-js/-/applicationinsights-analytics-js-2.8.4.tgz#3b32d8a2122be5d5993c74ef3217ebbf4876ea69" - integrity sha512-n/FPs8SS6rB8h+u157fiRh0TwUWKctxGNvr4M+LKeSdgDvf9c759gUeMR7r8xF6kBBfgkbmyaVORjsA1WJsU4g== - dependencies: - "@microsoft/applicationinsights-common" "2.8.4" - "@microsoft/applicationinsights-core-js" "2.8.4" - "@microsoft/applicationinsights-shims" "2.0.1" - "@microsoft/dynamicproto-js" "^1.1.6" - -"@microsoft/applicationinsights-channel-js@2.8.4": - version "2.8.4" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-channel-js/-/applicationinsights-channel-js-2.8.4.tgz#6de7210d87e61c72d3a9a06cbaeae14e1b543484" - integrity sha512-aml49Jya8LxX4tvyBbIvcxSo7UGI0k3HeiJQRFLeO+QlA+Ocsl10PqphU/OYJ4hh/P5/2QhEAq5bBM/b9/PNrg== - dependencies: - "@microsoft/applicationinsights-common" "2.8.4" - "@microsoft/applicationinsights-core-js" "2.8.4" - "@microsoft/applicationinsights-shims" "2.0.1" - "@microsoft/dynamicproto-js" "^1.1.6" - -"@microsoft/applicationinsights-common@2.8.4": - version "2.8.4" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-common/-/applicationinsights-common-2.8.4.tgz#45b422cf1804df06d5abb2ceda5ed65268a92135" - integrity sha512-uDvd4zxNGNYFE0TF4h7tAg+eMIPatyd1QdkP8fA4UYwshF4/+UwS1wegjXLEWQRRH87+UAyvx4IKQjobzzEX0A== - dependencies: - "@microsoft/applicationinsights-core-js" "2.8.4" - "@microsoft/applicationinsights-shims" "2.0.1" - "@microsoft/dynamicproto-js" "^1.1.6" - "@microsoft/applicationinsights-core-js@2.8.4": version "2.8.4" resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-core-js/-/applicationinsights-core-js-2.8.4.tgz#607e531bb241a8920d43960f68a7c76a6f9af596" @@ -57,45 +28,11 @@ "@microsoft/applicationinsights-shims" "2.0.1" "@microsoft/dynamicproto-js" "^1.1.6" -"@microsoft/applicationinsights-dependencies-js@2.8.4": - version "2.8.4" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-dependencies-js/-/applicationinsights-dependencies-js-2.8.4.tgz#b9afbb81fb44aeb3033ecff1d2e4d33d71c1d41c" - integrity sha512-dr11EBFBR+vmtTipubZv9KSWRXLk6XdutkEgilgzXdSFun0dqR+ZSHEmMWyqE8ZsJtW+1HzdKuGtODSQY6uHyw== - dependencies: - "@microsoft/applicationinsights-common" "2.8.4" - "@microsoft/applicationinsights-core-js" "2.8.4" - "@microsoft/applicationinsights-shims" "2.0.1" - "@microsoft/dynamicproto-js" "^1.1.6" - -"@microsoft/applicationinsights-properties-js@2.8.4": - version "2.8.4" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-properties-js/-/applicationinsights-properties-js-2.8.4.tgz#c52a6ce03b8f99b2110a097b4ef30686dfb433f8" - integrity sha512-UI0afK5e8yUJ1qIdy+7FA/G9TB+st0++trx4bUMa+Hb6gJggdQPq94lBFJL0yzo4QsgQwozVwkInXy4534tTYQ== - dependencies: - "@microsoft/applicationinsights-common" "2.8.4" - "@microsoft/applicationinsights-core-js" "2.8.4" - "@microsoft/applicationinsights-shims" "2.0.1" - "@microsoft/dynamicproto-js" "^1.1.6" - "@microsoft/applicationinsights-shims@2.0.1", "@microsoft/applicationinsights-shims@^2.0.1": version "2.0.1" resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-shims/-/applicationinsights-shims-2.0.1.tgz#5d72fb7aaf4056c4fda54f9d7c93ccf8ca9bcbfd" integrity sha512-G0MXf6R6HndRbDy9BbEj0zrLeuhwt2nsXk2zKtF0TnYo39KgYqhYC2ayIzKPTm2KAE+xzD7rgyLdZnrcRvt9WQ== -"@microsoft/applicationinsights-web@^2.8.4": - version "2.8.4" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-web/-/applicationinsights-web-2.8.4.tgz#6b385d385790b9574dad0754b860e656cde470b7" - integrity sha512-3CtZiM6e5Q0AA+1NE4k8A0+Y0FE1jsK4u0sb4AkvV7b4cwb86I9l7F7fQPU+V/ltkni0g2WtDrMNU93RuxSmNw== - dependencies: - "@microsoft/applicationinsights-analytics-js" "2.8.4" - "@microsoft/applicationinsights-channel-js" "2.8.4" - "@microsoft/applicationinsights-common" "2.8.4" - "@microsoft/applicationinsights-core-js" "2.8.4" - "@microsoft/applicationinsights-dependencies-js" "2.8.4" - "@microsoft/applicationinsights-properties-js" "2.8.4" - "@microsoft/applicationinsights-shims" "2.0.1" - "@microsoft/dynamicproto-js" "^1.1.6" - "@microsoft/dynamicproto-js@^1.1.6": version "1.1.6" resolved "https://registry.yarnpkg.com/@microsoft/dynamicproto-js/-/dynamicproto-js-1.1.6.tgz#6fe03468862861f5f88ac4c3959a652b3797f1bc" diff --git a/remote/yarn.lock b/remote/yarn.lock index 3d2078713be..bc084bb74dc 100644 --- a/remote/yarn.lock +++ b/remote/yarn.lock @@ -20,35 +20,6 @@ "@microsoft/applicationinsights-shims" "^2.0.1" "@microsoft/dynamicproto-js" "^1.1.6" -"@microsoft/applicationinsights-analytics-js@2.8.4": - version "2.8.4" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-analytics-js/-/applicationinsights-analytics-js-2.8.4.tgz#3b32d8a2122be5d5993c74ef3217ebbf4876ea69" - integrity sha512-n/FPs8SS6rB8h+u157fiRh0TwUWKctxGNvr4M+LKeSdgDvf9c759gUeMR7r8xF6kBBfgkbmyaVORjsA1WJsU4g== - dependencies: - "@microsoft/applicationinsights-common" "2.8.4" - "@microsoft/applicationinsights-core-js" "2.8.4" - "@microsoft/applicationinsights-shims" "2.0.1" - "@microsoft/dynamicproto-js" "^1.1.6" - -"@microsoft/applicationinsights-channel-js@2.8.4": - version "2.8.4" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-channel-js/-/applicationinsights-channel-js-2.8.4.tgz#6de7210d87e61c72d3a9a06cbaeae14e1b543484" - integrity sha512-aml49Jya8LxX4tvyBbIvcxSo7UGI0k3HeiJQRFLeO+QlA+Ocsl10PqphU/OYJ4hh/P5/2QhEAq5bBM/b9/PNrg== - dependencies: - "@microsoft/applicationinsights-common" "2.8.4" - "@microsoft/applicationinsights-core-js" "2.8.4" - "@microsoft/applicationinsights-shims" "2.0.1" - "@microsoft/dynamicproto-js" "^1.1.6" - -"@microsoft/applicationinsights-common@2.8.4": - version "2.8.4" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-common/-/applicationinsights-common-2.8.4.tgz#45b422cf1804df06d5abb2ceda5ed65268a92135" - integrity sha512-uDvd4zxNGNYFE0TF4h7tAg+eMIPatyd1QdkP8fA4UYwshF4/+UwS1wegjXLEWQRRH87+UAyvx4IKQjobzzEX0A== - dependencies: - "@microsoft/applicationinsights-core-js" "2.8.4" - "@microsoft/applicationinsights-shims" "2.0.1" - "@microsoft/dynamicproto-js" "^1.1.6" - "@microsoft/applicationinsights-core-js@2.8.4": version "2.8.4" resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-core-js/-/applicationinsights-core-js-2.8.4.tgz#607e531bb241a8920d43960f68a7c76a6f9af596" @@ -57,45 +28,11 @@ "@microsoft/applicationinsights-shims" "2.0.1" "@microsoft/dynamicproto-js" "^1.1.6" -"@microsoft/applicationinsights-dependencies-js@2.8.4": - version "2.8.4" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-dependencies-js/-/applicationinsights-dependencies-js-2.8.4.tgz#b9afbb81fb44aeb3033ecff1d2e4d33d71c1d41c" - integrity sha512-dr11EBFBR+vmtTipubZv9KSWRXLk6XdutkEgilgzXdSFun0dqR+ZSHEmMWyqE8ZsJtW+1HzdKuGtODSQY6uHyw== - dependencies: - "@microsoft/applicationinsights-common" "2.8.4" - "@microsoft/applicationinsights-core-js" "2.8.4" - "@microsoft/applicationinsights-shims" "2.0.1" - "@microsoft/dynamicproto-js" "^1.1.6" - -"@microsoft/applicationinsights-properties-js@2.8.4": - version "2.8.4" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-properties-js/-/applicationinsights-properties-js-2.8.4.tgz#c52a6ce03b8f99b2110a097b4ef30686dfb433f8" - integrity sha512-UI0afK5e8yUJ1qIdy+7FA/G9TB+st0++trx4bUMa+Hb6gJggdQPq94lBFJL0yzo4QsgQwozVwkInXy4534tTYQ== - dependencies: - "@microsoft/applicationinsights-common" "2.8.4" - "@microsoft/applicationinsights-core-js" "2.8.4" - "@microsoft/applicationinsights-shims" "2.0.1" - "@microsoft/dynamicproto-js" "^1.1.6" - "@microsoft/applicationinsights-shims@2.0.1", "@microsoft/applicationinsights-shims@^2.0.1": version "2.0.1" resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-shims/-/applicationinsights-shims-2.0.1.tgz#5d72fb7aaf4056c4fda54f9d7c93ccf8ca9bcbfd" integrity sha512-G0MXf6R6HndRbDy9BbEj0zrLeuhwt2nsXk2zKtF0TnYo39KgYqhYC2ayIzKPTm2KAE+xzD7rgyLdZnrcRvt9WQ== -"@microsoft/applicationinsights-web@^2.8.4": - version "2.8.4" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-web/-/applicationinsights-web-2.8.4.tgz#6b385d385790b9574dad0754b860e656cde470b7" - integrity sha512-3CtZiM6e5Q0AA+1NE4k8A0+Y0FE1jsK4u0sb4AkvV7b4cwb86I9l7F7fQPU+V/ltkni0g2WtDrMNU93RuxSmNw== - dependencies: - "@microsoft/applicationinsights-analytics-js" "2.8.4" - "@microsoft/applicationinsights-channel-js" "2.8.4" - "@microsoft/applicationinsights-common" "2.8.4" - "@microsoft/applicationinsights-core-js" "2.8.4" - "@microsoft/applicationinsights-dependencies-js" "2.8.4" - "@microsoft/applicationinsights-properties-js" "2.8.4" - "@microsoft/applicationinsights-shims" "2.0.1" - "@microsoft/dynamicproto-js" "^1.1.6" - "@microsoft/dynamicproto-js@^1.1.6": version "1.1.6" resolved "https://registry.yarnpkg.com/@microsoft/dynamicproto-js/-/dynamicproto-js-1.1.6.tgz#6fe03468862861f5f88ac4c3959a652b3797f1bc" @@ -168,16 +105,6 @@ ansi-regex@^5.0.1: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== -applicationinsights@1.4.2: - version "1.4.2" - resolved "https://registry.yarnpkg.com/applicationinsights/-/applicationinsights-1.4.2.tgz#2f25f7a3f3e5bf0ab4486b63e42a48a9ec321d52" - integrity sha512-1wE37G9zEMZTsPJVQ8BDrQtsGgG3DGMActLHwPAF8TYHAXkfqqpeZYCH0XV4lUZ7H4MffRMwN2Ln2nEtUmT8HQ== - dependencies: - cls-hooked "^4.2.2" - continuation-local-storage "^3.2.1" - diagnostic-channel "0.2.0" - diagnostic-channel-publishers "^0.3.3" - aproba@^1.0.3: version "1.2.0" resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" @@ -191,21 +118,6 @@ are-we-there-yet@~1.1.2: delegates "^1.0.0" readable-stream "^2.0.6" -async-hook-jl@^1.7.6: - version "1.7.6" - resolved "https://registry.yarnpkg.com/async-hook-jl/-/async-hook-jl-1.7.6.tgz#4fd25c2f864dbaf279c610d73bf97b1b28595e68" - integrity sha512-gFaHkFfSxTjvoxDMYqDuGHlcRyUuamF8s+ZTtJdDzqjws4mCt7v0vuV79/E2Wr2/riMQgtG4/yUtXWs1gZ7JMg== - dependencies: - stack-chain "^1.3.7" - -async-listener@^0.6.0: - version "0.6.10" - resolved "https://registry.yarnpkg.com/async-listener/-/async-listener-0.6.10.tgz#a7c97abe570ba602d782273c0de60a51e3e17cbc" - integrity sha512-gpuo6xOyF4D5DE5WvyqZdPA3NGhiT6Qf07l7DCB0wwDEsLvDIbCr6j9S5aj5Ch96dLace5tXVzWBZkxU/c5ohw== - dependencies: - semver "^5.3.0" - shimmer "^1.1.0" - base64-js@^1.3.1: version "1.5.1" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" @@ -245,15 +157,6 @@ chownr@^1.1.1: resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== -cls-hooked@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/cls-hooked/-/cls-hooked-4.2.2.tgz#ad2e9a4092680cdaffeb2d3551da0e225eae1908" - integrity sha512-J4Xj5f5wq/4jAvcdgoGsL3G103BtWpZrMo8NEinRltN+xpTZdI+M38pyQqhuFU/P792xkMFvnKSf+Lm81U1bxw== - dependencies: - async-hook-jl "^1.7.6" - emitter-listener "^1.0.1" - semver "^5.4.1" - code-point-at@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" @@ -264,14 +167,6 @@ console-control-strings@^1.0.0, console-control-strings@~1.1.0: resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= -continuation-local-storage@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/continuation-local-storage/-/continuation-local-storage-3.2.1.tgz#11f613f74e914fe9b34c92ad2d28fe6ae1db7ffb" - integrity sha512-jx44cconVqkCEEyLSKWwkvUXwO561jXMa3LPjTPsm5QR22PA0/mhe33FT4Xb5y74JDvt/Cq+5lm8S8rskLv9ZA== - dependencies: - async-listener "^0.6.0" - emitter-listener "^1.1.1" - cookie@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" @@ -325,25 +220,6 @@ detect-libc@^2.0.0: resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.1.tgz#e1897aa88fa6ad197862937fbc0441ef352ee0cd" integrity sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w== -diagnostic-channel-publishers@^0.3.3: - version "0.3.5" - resolved "https://registry.yarnpkg.com/diagnostic-channel-publishers/-/diagnostic-channel-publishers-0.3.5.tgz#a84a05fd6cc1d7619fdd17791c17e540119a7536" - integrity sha512-AOIjw4T7Nxl0G2BoBPhkQ6i7T4bUd9+xvdYizwvG7vVAM1dvr+SDrcUudlmzwH0kbEwdR2V1EcnKT0wAeYLQNQ== - -diagnostic-channel@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/diagnostic-channel/-/diagnostic-channel-0.2.0.tgz#cc99af9612c23fb1fff13612c72f2cbfaa8d5a17" - integrity sha512-awkcaaNNi0RfUGJf7r2+K4oJs1OyiIG2m/Jwvyi0OeQxdw+UU/iwbiejTPa3tUeyXtBcp2fef0JOJNdD62r/zg== - dependencies: - semver "^5.3.0" - -emitter-listener@^1.0.1, emitter-listener@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/emitter-listener/-/emitter-listener-1.1.2.tgz#56b140e8f6992375b3d7cb2cab1cc7432d9632e8" - integrity sha512-Bt1sBAGFHY9DKY+4/2cV6izcKJUf5T7/gkdmkxzX/qv9CcGH8xSwVRW5mtX03SWJtRTWSOpzCuWN9rBFYZepZQ== - dependencies: - shimmer "^1.2.0" - emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" @@ -706,16 +582,6 @@ safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -semver@^5.3.0: - version "5.6.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" - integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== - -semver@^5.4.1: - version "5.7.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== - semver@^7.3.5: version "7.3.5" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" @@ -728,11 +594,6 @@ set-blocking@~2.0.0: resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= -shimmer@^1.1.0, shimmer@^1.2.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/shimmer/-/shimmer-1.2.1.tgz#610859f7de327b587efebf501fb43117f9aff337" - integrity sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw== - signal-exit@^3.0.0: version "3.0.6" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.6.tgz#24e630c4b0f03fea446a2bd299e62b4a6ca8d0af" @@ -783,11 +644,6 @@ spdlog@^0.13.0: mkdirp "^0.5.5" nan "^2.14.0" -stack-chain@^1.3.7: - version "1.3.7" - resolved "https://registry.yarnpkg.com/stack-chain/-/stack-chain-1.3.7.tgz#d192c9ff4ea6a22c94c4dd459171e3f00cea1285" - integrity sha1-0ZLJ/06moiyUxN1FkXHj8AzqEoU= - string-width@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" diff --git a/src/vs/base/common/product.ts b/src/vs/base/common/product.ts index 0e9dcdcba96..1ae8079810e 100644 --- a/src/vs/base/common/product.ts +++ b/src/vs/base/common/product.ts @@ -99,9 +99,7 @@ export interface IProductConfiguration { readonly enableTelemetry?: boolean; readonly openToWelcomeMainPage?: boolean; readonly aiConfig?: { - readonly asimovKey: string; readonly ariaKey: string; - readonly preferAria: boolean; }; readonly sendASmile?: { diff --git a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts index f166be81aeb..9cf505e2470 100644 --- a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts +++ b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts @@ -64,7 +64,6 @@ import { TelemetryAppenderChannel } from 'vs/platform/telemetry/common/telemetry import { TelemetryLogAppender } from 'vs/platform/telemetry/common/telemetryLogAppender'; import { TelemetryService } from 'vs/platform/telemetry/common/telemetryService'; import { supportsTelemetry, ITelemetryAppender, NullAppender, NullTelemetryService, getPiiPathsFromEnvironment } from 'vs/platform/telemetry/common/telemetryUtils'; -import { AppInsightsAppender } from 'vs/platform/telemetry/node/appInsightsAppender'; import { CustomEndpointTelemetryService } from 'vs/platform/telemetry/node/customEndpointTelemetryService'; import { LocalReconnectConstants, TerminalIpcChannels, TerminalSettingId } from 'vs/platform/terminal/common/terminal'; import { ILocalPtyService } from 'vs/platform/terminal/electron-sandbox/terminal'; @@ -282,16 +281,10 @@ class SharedProcessMain extends Disposable { const logAppender = new TelemetryLogAppender(loggerService, environmentService); appenders.push(logAppender); const { installSourcePath } = environmentService; - const internalTesting = configurationService.getValue('telemetry.internalTesting'); - if (internalTesting && productService.aiConfig?.ariaKey) { + if (productService.aiConfig?.ariaKey) { const collectorAppender = new OneDataSystemWebAppender(configurationService, 'monacoworkbench', null, productService.aiConfig.ariaKey); this._register(toDisposable(() => collectorAppender.flush())); // Ensure the 1DS appender is disposed so that it flushes remaining data appenders.push(collectorAppender); - } else if (productService.aiConfig && productService.aiConfig.asimovKey) { - // Application Insights - const appInsightsAppender = new AppInsightsAppender('monacoworkbench', null, productService.aiConfig.asimovKey); - this._register(toDisposable(() => appInsightsAppender.flush())); // Ensure the AI appender is disposed so that it flushes remaining data - appenders.push(appInsightsAppender); } telemetryService = new TelemetryService({ diff --git a/src/vs/code/node/cliProcessMain.ts b/src/vs/code/node/cliProcessMain.ts index bc4ca25f492..79c5b02e686 100644 --- a/src/vs/code/node/cliProcessMain.ts +++ b/src/vs/code/node/cliProcessMain.ts @@ -53,7 +53,7 @@ import { resolveCommonProperties } from 'vs/platform/telemetry/common/commonProp import { ITelemetryService, machineIdKey } from 'vs/platform/telemetry/common/telemetry'; import { ITelemetryServiceConfig, TelemetryService } from 'vs/platform/telemetry/common/telemetryService'; import { supportsTelemetry, NullTelemetryService, getPiiPathsFromEnvironment } from 'vs/platform/telemetry/common/telemetryUtils'; -import { AppInsightsAppender } from 'vs/platform/telemetry/node/appInsightsAppender'; +import { OneDataSystemAppender } from 'vs/platform/telemetry/node/1dsAppender'; import { buildTelemetryMessage } from 'vs/platform/telemetry/node/telemetry'; import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'; import { UriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentityService'; @@ -104,7 +104,7 @@ class CliMain extends Disposable { }); } - private async initServices(): Promise<[IInstantiationService, AppInsightsAppender[]]> { + private async initServices(): Promise<[IInstantiationService, OneDataSystemAppender[]]> { const services = new ServiceCollection(); // Product @@ -186,10 +186,10 @@ class CliMain extends Disposable { services.set(ILanguagePackService, new SyncDescriptor(NativeLanguagePackService)); // Telemetry - const appenders: AppInsightsAppender[] = []; + const appenders: OneDataSystemAppender[] = []; if (supportsTelemetry(productService, environmentService)) { - if (productService.aiConfig && productService.aiConfig.asimovKey) { - appenders.push(new AppInsightsAppender('monacoworkbench', null, productService.aiConfig.asimovKey)); + if (productService.aiConfig && productService.aiConfig.ariaKey) { + appenders.push(new OneDataSystemAppender(configurationService, 'monacoworkbench', null, productService.aiConfig.ariaKey)); } const { installSourcePath } = environmentService; diff --git a/src/vs/platform/telemetry/browser/appInsightsAppender.ts b/src/vs/platform/telemetry/browser/appInsightsAppender.ts deleted file mode 100644 index cd4b32c13af..00000000000 --- a/src/vs/platform/telemetry/browser/appInsightsAppender.ts +++ /dev/null @@ -1,77 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import type { ApplicationInsights } from '@microsoft/applicationinsights-web'; -import { ITelemetryAppender, validateTelemetryData } from 'vs/platform/telemetry/common/telemetryUtils'; - -export class WebAppInsightsAppender implements ITelemetryAppender { - private _aiClient: ApplicationInsights | undefined; - private _aiClientLoaded = false; - private _telemetryCache: { eventName: string; data: any }[] = []; - - constructor(private _eventPrefix: string, aiKey: string) { - const endpointUrl = 'https://vscode.vortex.data.microsoft.com/collect/v1'; - import('@microsoft/applicationinsights-web').then(aiLibrary => { - this._aiClient = new aiLibrary.ApplicationInsights({ - config: { - instrumentationKey: aiKey, - endpointUrl, - disableAjaxTracking: true, - disableExceptionTracking: true, - disableFetchTracking: true, - disableCorrelationHeaders: true, - disableCookiesUsage: true, - autoTrackPageVisitTime: false, - emitLineDelimitedJson: true, - }, - }); - this._aiClient.loadAppInsights(); - // Client is loaded we can now flush the cached events - this._aiClientLoaded = true; - this._telemetryCache.forEach(cacheEntry => this.log(cacheEntry.eventName, cacheEntry.data)); - this._telemetryCache = []; - - // If we cannot access the endpoint this most likely means it's being blocked - // and we should not attempt to send any telemetry. - fetch(endpointUrl, { method: 'POST' }).catch(() => (this._aiClient = undefined)); - }).catch(err => { - console.error(err); - }); - } - - /** - * Logs a telemetry event with eventName and data - * @param eventName The event name - * @param data The data associated with the events - */ - public log(eventName: string, data: any): void { - if (!this._aiClient && this._aiClientLoaded) { - return; - } else if (!this._aiClient && !this._aiClientLoaded) { - this._telemetryCache.push({ eventName, data }); - return; - } - - data = validateTelemetryData(data); - - // Web does not expect properties and measurements so we must - // spread them out. This is different from desktop which expects them - data = { ...data.properties, ...data.measurements }; - - // undefined assertion is ok since above two if statements cover both cases - this._aiClient!.trackEvent({ name: this._eventPrefix + '/' + eventName }, data); - } - - /** - * Flushes all the telemetry data still in the buffer - */ - public flush(): Promise { - if (this._aiClient) { - this._aiClient.flush(); - this._aiClient = undefined; - } - return Promise.resolve(undefined); - } -} diff --git a/src/vs/platform/telemetry/common/1dsAppender.ts b/src/vs/platform/telemetry/common/1dsAppender.ts index 8023931f50f..ba7cac9d693 100644 --- a/src/vs/platform/telemetry/common/1dsAppender.ts +++ b/src/vs/platform/telemetry/common/1dsAppender.ts @@ -63,7 +63,7 @@ export abstract class AbstractOneDataSystemAppender implements ITelemetryAppende protected readonly endPointUrl = endpointUrl; constructor( - private readonly _configurationService: IConfigurationService, + private readonly _configurationService: IConfigurationService | undefined, private _eventPrefix: string, private _defaultData: { [key: string]: any } | null, iKeyOrClientFactory: string | (() => AppInsightsCore), // allow factory function for testing @@ -92,7 +92,7 @@ export abstract class AbstractOneDataSystemAppender implements ITelemetryAppende } if (!this._asyncAiCore) { - const isInternal = this._configurationService.getValue('telemetry.internalTesting'); + const isInternal = this._configurationService?.getValue('telemetry.internalTesting'); this._asyncAiCore = getClient(this._aiCoreOrKey, isInternal, this._xhrOverride); } diff --git a/src/vs/platform/telemetry/node/1dsAppender.ts b/src/vs/platform/telemetry/node/1dsAppender.ts index 2e7b1b6f491..c7b6442cf7a 100644 --- a/src/vs/platform/telemetry/node/1dsAppender.ts +++ b/src/vs/platform/telemetry/node/1dsAppender.ts @@ -13,7 +13,7 @@ import { AbstractOneDataSystemAppender } from 'vs/platform/telemetry/common/1dsA export class OneDataSystemAppender extends AbstractOneDataSystemAppender { constructor( - configurationService: IConfigurationService, + configurationService: IConfigurationService | undefined, eventPrefix: string, defaultData: { [key: string]: any } | null, iKeyOrClientFactory: string | (() => AppInsightsCore), // allow factory function for testing diff --git a/src/vs/platform/telemetry/node/appInsightsAppender.ts b/src/vs/platform/telemetry/node/appInsightsAppender.ts deleted file mode 100644 index d5fc5987438..00000000000 --- a/src/vs/platform/telemetry/node/appInsightsAppender.ts +++ /dev/null @@ -1,121 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import type { TelemetryClient } from 'applicationinsights'; -import { onUnexpectedError } from 'vs/base/common/errors'; -import { mixin } from 'vs/base/common/objects'; -import { ITelemetryAppender, validateTelemetryData } from 'vs/platform/telemetry/common/telemetryUtils'; - -async function getClient(aiKey: string): Promise { - const appInsights = await import('applicationinsights'); - let client: TelemetryClient; - if (appInsights.defaultClient) { - client = new appInsights.TelemetryClient(aiKey); - client.channel.setUseDiskRetryCaching(true); - } else { - appInsights.setup(aiKey) - .setAutoCollectRequests(false) - .setAutoCollectPerformance(false) - .setAutoCollectExceptions(false) - .setAutoCollectDependencies(false) - .setAutoDependencyCorrelation(false) - .setAutoCollectConsole(false) - .setInternalLogging(false, false) - .setUseDiskRetryCaching(true) - .start(); - client = appInsights.defaultClient; - } - - if (aiKey.indexOf('AIF-') === 0) { - client.config.endpointUrl = 'https://mobile.events.data.microsoft.com/collect/v1'; - } - return client; -} - - -export class AppInsightsAppender implements ITelemetryAppender { - - private _aiClient: string | TelemetryClient | undefined; - private _asyncAIClient: Promise | null; - - constructor( - private _eventPrefix: string, - private _defaultData: { [key: string]: any } | null, - aiKeyOrClientFactory: string | (() => TelemetryClient), // allow factory function for testing - ) { - if (!this._defaultData) { - this._defaultData = Object.create(null); - } - - if (typeof aiKeyOrClientFactory === 'function') { - this._aiClient = aiKeyOrClientFactory(); - } else { - this._aiClient = aiKeyOrClientFactory; - } - this._asyncAIClient = null; - } - - private _withAIClient(callback: (aiClient: TelemetryClient) => void): void { - if (!this._aiClient) { - return; - } - - if (typeof this._aiClient !== 'string') { - callback(this._aiClient); - return; - } - - if (!this._asyncAIClient) { - this._asyncAIClient = getClient(this._aiClient); - } - - this._asyncAIClient.then( - (aiClient) => { - callback(aiClient); - }, - (err) => { - onUnexpectedError(err); - console.error(err); - } - ); - } - - log(eventName: string, data?: any): void { - if (!this._aiClient) { - return; - } - data = mixin(data, this._defaultData); - data = validateTelemetryData(data); - - // Attemps to suppress https://github.com/microsoft/vscode/issues/140624 - try { - this._withAIClient((aiClient) => aiClient.trackEvent({ - name: this._eventPrefix + '/' + eventName, - properties: data.properties, - measurements: data.measurements - })); - } catch { } - } - - flush(): Promise { - if (this._aiClient) { - return new Promise(resolve => { - this._withAIClient((aiClient) => { - // Attempts to suppress https://github.com/microsoft/vscode/issues/140624 - try { - aiClient.flush({ - callback: () => { - // all data flushed - this._aiClient = undefined; - resolve(undefined); - } - }); - } catch { } - }); - }); - } - return Promise.resolve(undefined); - } -} diff --git a/src/vs/platform/telemetry/test/electron-browser/appInsightsAppender.test.ts b/src/vs/platform/telemetry/test/electron-browser/1dsAppender.test.ts similarity index 85% rename from src/vs/platform/telemetry/test/electron-browser/appInsightsAppender.test.ts rename to src/vs/platform/telemetry/test/electron-browser/1dsAppender.test.ts index 09f1f611da9..3b734414796 100644 --- a/src/vs/platform/telemetry/test/electron-browser/appInsightsAppender.test.ts +++ b/src/vs/platform/telemetry/test/electron-browser/1dsAppender.test.ts @@ -2,23 +2,22 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Contracts, TelemetryClient } from 'applicationinsights'; +import { AppInsightsCore } from '@microsoft/1ds-core-js'; import * as assert from 'assert'; -import { AppInsightsAppender } from 'vs/platform/telemetry/node/appInsightsAppender'; +import { OneDataSystemAppender } from 'vs/platform/telemetry/node/1dsAppender'; -class AppInsightsMock extends TelemetryClient { +class AppInsightsCoreMock extends AppInsightsCore { public override config: any; - public override channel: any; - public events: Contracts.EventTelemetry[] = []; + public events: any[] = []; public IsTrackingPageView: boolean = false; public exceptions: any[] = []; constructor() { - super('testKey'); + super(); } - public override trackEvent(event: any) { - this.events.push(event); + public override track(event: any) { + this.events.push(event.baseData); } public override flush(options: any): void { @@ -27,14 +26,14 @@ class AppInsightsMock extends TelemetryClient { } suite('AIAdapter', () => { - let appInsightsMock: AppInsightsMock; - let adapter: AppInsightsAppender; + let appInsightsMock: AppInsightsCoreMock; + let adapter: OneDataSystemAppender; const prefix = 'prefix'; setup(() => { - appInsightsMock = new AppInsightsMock(); - adapter = new AppInsightsAppender(prefix, undefined!, () => appInsightsMock); + appInsightsMock = new AppInsightsCoreMock(); + adapter = new OneDataSystemAppender(undefined, prefix, undefined!, () => appInsightsMock); }); teardown(() => { @@ -49,7 +48,7 @@ suite('AIAdapter', () => { }); test('addional data', () => { - adapter = new AppInsightsAppender(prefix, { first: '1st', second: 2, third: true }, () => appInsightsMock); + adapter = new OneDataSystemAppender(undefined, prefix, { first: '1st', second: 2, third: true }, () => appInsightsMock); adapter.log('testEvent'); assert.strictEqual(appInsightsMock.events.length, 1); diff --git a/src/vs/server/node/serverServices.ts b/src/vs/server/node/serverServices.ts index 797f29fd9e5..c20bd776c55 100644 --- a/src/vs/server/node/serverServices.ts +++ b/src/vs/server/node/serverServices.ts @@ -50,7 +50,6 @@ import { resolveCommonProperties } from 'vs/platform/telemetry/common/commonProp import { ITelemetryService, TelemetryLevel } from 'vs/platform/telemetry/common/telemetry'; import { ITelemetryServiceConfig } from 'vs/platform/telemetry/common/telemetryService'; import { getPiiPathsFromEnvironment, ITelemetryAppender, NullAppender, supportsTelemetry } from 'vs/platform/telemetry/common/telemetryUtils'; -import { AppInsightsAppender } from 'vs/platform/telemetry/node/appInsightsAppender'; import ErrorTelemetry from 'vs/platform/telemetry/node/errorTelemetry'; import { IPtyService, TerminalSettingId } from 'vs/platform/terminal/common/terminal'; import { PtyHostService } from 'vs/platform/terminal/node/ptyHostService'; @@ -73,6 +72,7 @@ import { ExtensionsScannerService } from 'vs/server/node/extensionsScannerServic import { ExtensionsProfileScannerService, IExtensionsProfileScannerService } from 'vs/platform/extensionManagement/common/extensionsProfileScannerService'; import { IUserDataProfilesService, UserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile'; import { NullPolicyService } from 'vs/platform/policy/common/policy'; +import { OneDataSystemAppender } from 'vs/platform/telemetry/node/1dsAppender'; const eventPrefix = 'monacoworkbench'; @@ -128,16 +128,16 @@ export async function setupServerServices(connectionToken: ServerConnectionToken // Request services.set(IRequestService, new SyncDescriptor(RequestService)); - let appInsightsAppender: ITelemetryAppender = NullAppender; + let oneDsAppender: ITelemetryAppender = NullAppender; const machineId = await getMachineId(); if (supportsTelemetry(productService, environmentService)) { - if (productService.aiConfig && productService.aiConfig.asimovKey) { - appInsightsAppender = new AppInsightsAppender(eventPrefix, null, productService.aiConfig.asimovKey); - disposables.add(toDisposable(() => appInsightsAppender!.flush())); // Ensure the AI appender is disposed so that it flushes remaining data + if (productService.aiConfig && productService.aiConfig.ariaKey) { + oneDsAppender = new OneDataSystemAppender(configurationService, eventPrefix, null, productService.aiConfig.ariaKey); + disposables.add(toDisposable(() => oneDsAppender?.flush())); // Ensure the AI appender is disposed so that it flushes remaining data } const config: ITelemetryServiceConfig = { - appenders: [appInsightsAppender], + appenders: [oneDsAppender], commonProperties: resolveCommonProperties(fileService, release(), hostname(), process.arch, productService.commit, productService.version + '-remote', machineId, productService.msftInternalDomains, environmentService.installSourcePath, 'remoteAgent'), piiPaths: getPiiPathsFromEnvironment(environmentService) }; @@ -193,7 +193,7 @@ export async function setupServerServices(connectionToken: ServerConnectionToken const remoteExtensionEnvironmentChannel = new RemoteAgentEnvironmentChannel(connectionToken, environmentService, userDataProfilesService, extensionManagementCLIService, logService, extensionHostStatusService, extensionsScannerService); socketServer.registerChannel('remoteextensionsenvironment', remoteExtensionEnvironmentChannel); - const telemetryChannel = new ServerTelemetryChannel(accessor.get(IServerTelemetryService), appInsightsAppender); + const telemetryChannel = new ServerTelemetryChannel(accessor.get(IServerTelemetryService), oneDsAppender); socketServer.registerChannel('telemetry', telemetryChannel); socketServer.registerChannel(REMOTE_TERMINAL_CHANNEL_NAME, new RemoteTerminalChannel(environmentService, logService, ptyService, productService, extensionManagementService)); diff --git a/src/vs/workbench/contrib/debug/node/telemetryApp.ts b/src/vs/workbench/contrib/debug/node/telemetryApp.ts index ab6d37993ca..601ff4f9b1e 100644 --- a/src/vs/workbench/contrib/debug/node/telemetryApp.ts +++ b/src/vs/workbench/contrib/debug/node/telemetryApp.ts @@ -4,10 +4,10 @@ *--------------------------------------------------------------------------------------------*/ import { Server } from 'vs/base/parts/ipc/node/ipc.cp'; -import { AppInsightsAppender } from 'vs/platform/telemetry/node/appInsightsAppender'; import { TelemetryAppenderChannel } from 'vs/platform/telemetry/common/telemetryIpc'; +import { OneDataSystemAppender } from 'vs/platform/telemetry/node/1dsAppender'; -const appender = new AppInsightsAppender(process.argv[2], JSON.parse(process.argv[3]), process.argv[4]); +const appender = new OneDataSystemAppender(undefined, process.argv[2], JSON.parse(process.argv[3]), process.argv[4]); process.once('exit', () => appender.flush()); const channel = new TelemetryAppenderChannel([appender]); diff --git a/src/vs/workbench/services/telemetry/browser/telemetryService.ts b/src/vs/workbench/services/telemetry/browser/telemetryService.ts index 75701e1a088..3ad179570b6 100644 --- a/src/vs/workbench/services/telemetry/browser/telemetryService.ts +++ b/src/vs/workbench/services/telemetry/browser/telemetryService.ts @@ -11,7 +11,6 @@ import { ILoggerService } from 'vs/platform/log/common/log'; import { IProductService } from 'vs/platform/product/common/productService'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { OneDataSystemWebAppender } from 'vs/platform/telemetry/browser/1dsAppender'; -import { WebAppInsightsAppender } from 'vs/platform/telemetry/browser/appInsightsAppender'; import { ClassifiedEvent, GDPRClassification, StrictPropertyCheck } from 'vs/platform/telemetry/common/gdprTypings'; import { ITelemetryData, ITelemetryInfo, ITelemetryService, TelemetryLevel } from 'vs/platform/telemetry/common/telemetry'; import { TelemetryLogAppender } from 'vs/platform/telemetry/common/telemetryLogAppender'; @@ -38,17 +37,11 @@ export class TelemetryService extends Disposable implements ITelemetryService { ) { super(); - if (supportsTelemetry(productService, environmentService) && productService.aiConfig?.asimovKey && productService.aiConfig?.ariaKey) { + if (supportsTelemetry(productService, environmentService) && productService.aiConfig?.ariaKey) { // If remote server is present send telemetry through that, else use the client side appender - const internalTesting = configurationService.getValue('telemetry.internalTesting'); const appenders = []; - if (internalTesting || productService.aiConfig?.preferAria) { - const telemetryProvider: ITelemetryAppender = remoteAgentService.getConnection() !== null ? { log: remoteAgentService.logTelemetry.bind(remoteAgentService), flush: remoteAgentService.flushTelemetry.bind(remoteAgentService) } : new OneDataSystemWebAppender(configurationService, 'monacoworkbench', null, productService.aiConfig?.ariaKey); - appenders.push(telemetryProvider); - } else { - const telemetryProvider: ITelemetryAppender = remoteAgentService.getConnection() !== null ? { log: remoteAgentService.logTelemetry.bind(remoteAgentService), flush: remoteAgentService.flushTelemetry.bind(remoteAgentService) } : new WebAppInsightsAppender('monacoworkbench', productService.aiConfig?.asimovKey); - appenders.push(telemetryProvider); - } + const telemetryProvider: ITelemetryAppender = remoteAgentService.getConnection() !== null ? { log: remoteAgentService.logTelemetry.bind(remoteAgentService), flush: remoteAgentService.flushTelemetry.bind(remoteAgentService) } : new OneDataSystemWebAppender(configurationService, 'monacoworkbench', null, productService.aiConfig?.ariaKey); + appenders.push(telemetryProvider); appenders.push(new TelemetryLogAppender(loggerService, environmentService)); const config: ITelemetryServiceConfig = { appenders, diff --git a/yarn.lock b/yarn.lock index 4189162c56a..9c823e24f88 100644 --- a/yarn.lock +++ b/yarn.lock @@ -850,35 +850,6 @@ "@microsoft/applicationinsights-shims" "^2.0.1" "@microsoft/dynamicproto-js" "^1.1.6" -"@microsoft/applicationinsights-analytics-js@2.8.4": - version "2.8.4" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-analytics-js/-/applicationinsights-analytics-js-2.8.4.tgz#3b32d8a2122be5d5993c74ef3217ebbf4876ea69" - integrity sha512-n/FPs8SS6rB8h+u157fiRh0TwUWKctxGNvr4M+LKeSdgDvf9c759gUeMR7r8xF6kBBfgkbmyaVORjsA1WJsU4g== - dependencies: - "@microsoft/applicationinsights-common" "2.8.4" - "@microsoft/applicationinsights-core-js" "2.8.4" - "@microsoft/applicationinsights-shims" "2.0.1" - "@microsoft/dynamicproto-js" "^1.1.6" - -"@microsoft/applicationinsights-channel-js@2.8.4": - version "2.8.4" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-channel-js/-/applicationinsights-channel-js-2.8.4.tgz#6de7210d87e61c72d3a9a06cbaeae14e1b543484" - integrity sha512-aml49Jya8LxX4tvyBbIvcxSo7UGI0k3HeiJQRFLeO+QlA+Ocsl10PqphU/OYJ4hh/P5/2QhEAq5bBM/b9/PNrg== - dependencies: - "@microsoft/applicationinsights-common" "2.8.4" - "@microsoft/applicationinsights-core-js" "2.8.4" - "@microsoft/applicationinsights-shims" "2.0.1" - "@microsoft/dynamicproto-js" "^1.1.6" - -"@microsoft/applicationinsights-common@2.8.4": - version "2.8.4" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-common/-/applicationinsights-common-2.8.4.tgz#45b422cf1804df06d5abb2ceda5ed65268a92135" - integrity sha512-uDvd4zxNGNYFE0TF4h7tAg+eMIPatyd1QdkP8fA4UYwshF4/+UwS1wegjXLEWQRRH87+UAyvx4IKQjobzzEX0A== - dependencies: - "@microsoft/applicationinsights-core-js" "2.8.4" - "@microsoft/applicationinsights-shims" "2.0.1" - "@microsoft/dynamicproto-js" "^1.1.6" - "@microsoft/applicationinsights-core-js@2.8.3": version "2.8.3" resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-core-js/-/applicationinsights-core-js-2.8.3.tgz#d07abd6e8bfec7d101518494ad4bd62516df5c51" @@ -887,53 +858,11 @@ "@microsoft/applicationinsights-shims" "2.0.1" "@microsoft/dynamicproto-js" "^1.1.6" -"@microsoft/applicationinsights-core-js@2.8.4": - version "2.8.4" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-core-js/-/applicationinsights-core-js-2.8.4.tgz#607e531bb241a8920d43960f68a7c76a6f9af596" - integrity sha512-FoA0FNOsFbJnLyTyQlYs6+HR7HMEa6nAOE6WOm9WVejBHMHQ/Bdb+hfVFi6slxwCimr/ner90jchi4/sIYdnyQ== - dependencies: - "@microsoft/applicationinsights-shims" "2.0.1" - "@microsoft/dynamicproto-js" "^1.1.6" - -"@microsoft/applicationinsights-dependencies-js@2.8.4": - version "2.8.4" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-dependencies-js/-/applicationinsights-dependencies-js-2.8.4.tgz#b9afbb81fb44aeb3033ecff1d2e4d33d71c1d41c" - integrity sha512-dr11EBFBR+vmtTipubZv9KSWRXLk6XdutkEgilgzXdSFun0dqR+ZSHEmMWyqE8ZsJtW+1HzdKuGtODSQY6uHyw== - dependencies: - "@microsoft/applicationinsights-common" "2.8.4" - "@microsoft/applicationinsights-core-js" "2.8.4" - "@microsoft/applicationinsights-shims" "2.0.1" - "@microsoft/dynamicproto-js" "^1.1.6" - -"@microsoft/applicationinsights-properties-js@2.8.4": - version "2.8.4" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-properties-js/-/applicationinsights-properties-js-2.8.4.tgz#c52a6ce03b8f99b2110a097b4ef30686dfb433f8" - integrity sha512-UI0afK5e8yUJ1qIdy+7FA/G9TB+st0++trx4bUMa+Hb6gJggdQPq94lBFJL0yzo4QsgQwozVwkInXy4534tTYQ== - dependencies: - "@microsoft/applicationinsights-common" "2.8.4" - "@microsoft/applicationinsights-core-js" "2.8.4" - "@microsoft/applicationinsights-shims" "2.0.1" - "@microsoft/dynamicproto-js" "^1.1.6" - "@microsoft/applicationinsights-shims@2.0.1", "@microsoft/applicationinsights-shims@^2.0.1": version "2.0.1" resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-shims/-/applicationinsights-shims-2.0.1.tgz#5d72fb7aaf4056c4fda54f9d7c93ccf8ca9bcbfd" integrity sha512-G0MXf6R6HndRbDy9BbEj0zrLeuhwt2nsXk2zKtF0TnYo39KgYqhYC2ayIzKPTm2KAE+xzD7rgyLdZnrcRvt9WQ== -"@microsoft/applicationinsights-web@^2.8.4": - version "2.8.4" - resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-web/-/applicationinsights-web-2.8.4.tgz#6b385d385790b9574dad0754b860e656cde470b7" - integrity sha512-3CtZiM6e5Q0AA+1NE4k8A0+Y0FE1jsK4u0sb4AkvV7b4cwb86I9l7F7fQPU+V/ltkni0g2WtDrMNU93RuxSmNw== - dependencies: - "@microsoft/applicationinsights-analytics-js" "2.8.4" - "@microsoft/applicationinsights-channel-js" "2.8.4" - "@microsoft/applicationinsights-common" "2.8.4" - "@microsoft/applicationinsights-core-js" "2.8.4" - "@microsoft/applicationinsights-dependencies-js" "2.8.4" - "@microsoft/applicationinsights-properties-js" "2.8.4" - "@microsoft/applicationinsights-shims" "2.0.1" - "@microsoft/dynamicproto-js" "^1.1.6" - "@microsoft/dynamicproto-js@^1.1.6": version "1.1.6" resolved "https://registry.yarnpkg.com/@microsoft/dynamicproto-js/-/dynamicproto-js-1.1.6.tgz#6fe03468862861f5f88ac4c3959a652b3797f1bc" @@ -1191,13 +1120,6 @@ resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a" integrity sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA== -"@types/applicationinsights@0.20.0": - version "0.20.0" - resolved "https://registry.yarnpkg.com/@types/applicationinsights/-/applicationinsights-0.20.0.tgz#fa7b36dc954f635fa9037cad27c378446b1048fb" - integrity sha512-dQ3Hb58ERe5YNKFVyvU9BrEvpgKeb6Ht9HkCyBvsOZxhx6yKSwF3e+xml3PJQ3JiVOvf6gM/PmE3MdWDl1L6aA== - dependencies: - applicationinsights "*" - "@types/color-name@^1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" @@ -2217,26 +2139,6 @@ append-buffer@^1.0.2: dependencies: buffer-equal "^1.0.0" -applicationinsights@*: - version "1.5.0" - resolved "https://registry.yarnpkg.com/applicationinsights/-/applicationinsights-1.5.0.tgz#074df9e525dcfd592822e7b80723b9284d2716fd" - integrity sha512-D+JyPrDx9RWVNIwukoe03ANKNdyVe/ejExbR7xMvZTm09553TzXenW2oPZmfN9jeguKSDugzIWdbILMPNSRRlg== - dependencies: - cls-hooked "^4.2.2" - continuation-local-storage "^3.2.1" - diagnostic-channel "0.2.0" - diagnostic-channel-publishers "^0.3.3" - -applicationinsights@1.4.2: - version "1.4.2" - resolved "https://registry.yarnpkg.com/applicationinsights/-/applicationinsights-1.4.2.tgz#2f25f7a3f3e5bf0ab4486b63e42a48a9ec321d52" - integrity sha512-1wE37G9zEMZTsPJVQ8BDrQtsGgG3DGMActLHwPAF8TYHAXkfqqpeZYCH0XV4lUZ7H4MffRMwN2Ln2nEtUmT8HQ== - dependencies: - cls-hooked "^4.2.2" - continuation-local-storage "^3.2.1" - diagnostic-channel "0.2.0" - diagnostic-channel-publishers "^0.3.3" - aproba@^1.0.3, aproba@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" @@ -2452,21 +2354,6 @@ async-each@^1.0.1: resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== -async-hook-jl@^1.7.6: - version "1.7.6" - resolved "https://registry.yarnpkg.com/async-hook-jl/-/async-hook-jl-1.7.6.tgz#4fd25c2f864dbaf279c610d73bf97b1b28595e68" - integrity sha512-gFaHkFfSxTjvoxDMYqDuGHlcRyUuamF8s+ZTtJdDzqjws4mCt7v0vuV79/E2Wr2/riMQgtG4/yUtXWs1gZ7JMg== - dependencies: - stack-chain "^1.3.7" - -async-listener@^0.6.0: - version "0.6.10" - resolved "https://registry.yarnpkg.com/async-listener/-/async-listener-0.6.10.tgz#a7c97abe570ba602d782273c0de60a51e3e17cbc" - integrity sha512-gpuo6xOyF4D5DE5WvyqZdPA3NGhiT6Qf07l7DCB0wwDEsLvDIbCr6j9S5aj5Ch96dLace5tXVzWBZkxU/c5ohw== - dependencies: - semver "^5.3.0" - shimmer "^1.1.0" - async-settle@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/async-settle/-/async-settle-1.0.0.tgz#1d0a914bb02575bec8a8f3a74e5080f72b2c0c6b" @@ -3236,15 +3123,6 @@ cloneable-readable@^1.0.0: process-nextick-args "^2.0.0" readable-stream "^2.3.5" -cls-hooked@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/cls-hooked/-/cls-hooked-4.2.2.tgz#ad2e9a4092680cdaffeb2d3551da0e225eae1908" - integrity sha512-J4Xj5f5wq/4jAvcdgoGsL3G103BtWpZrMo8NEinRltN+xpTZdI+M38pyQqhuFU/P792xkMFvnKSf+Lm81U1bxw== - dependencies: - async-hook-jl "^1.7.6" - emitter-listener "^1.0.1" - semver "^5.4.1" - co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" @@ -3477,14 +3355,6 @@ content-type@^1.0.4: resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== -continuation-local-storage@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/continuation-local-storage/-/continuation-local-storage-3.2.1.tgz#11f613f74e914fe9b34c92ad2d28fe6ae1db7ffb" - integrity sha512-jx44cconVqkCEEyLSKWwkvUXwO561jXMa3LPjTPsm5QR22PA0/mhe33FT4Xb5y74JDvt/Cq+5lm8S8rskLv9ZA== - dependencies: - async-listener "^0.6.0" - emitter-listener "^1.1.1" - convert-source-map@^1.0.0, convert-source-map@^1.5.0, convert-source-map@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" @@ -4147,18 +4017,6 @@ detect-node@^2.0.4: resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c" integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw== -diagnostic-channel-publishers@^0.3.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/diagnostic-channel-publishers/-/diagnostic-channel-publishers-0.3.3.tgz#376b7798f4fa90f37eb4f94d2caca611b0e9c330" - integrity sha512-qIocRYU5TrGUkBlDDxaziAK1+squ8Yf2Ls4HldL3xxb/jzmWO2Enux7CvevNKYmF2kDXZ9HiRqwjPsjk8L+i2Q== - -diagnostic-channel@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/diagnostic-channel/-/diagnostic-channel-0.2.0.tgz#cc99af9612c23fb1fff13612c72f2cbfaa8d5a17" - integrity sha1-zJmvlhLCP7H/8TYSxy8sv6qNWhc= - dependencies: - semver "^5.3.0" - diff-sequences@^27.4.0: version "27.4.0" resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.4.0.tgz#d783920ad8d06ec718a060d00196dfef25b132a5" @@ -4357,13 +4215,6 @@ elliptic@^6.5.3: minimalistic-assert "^1.0.1" minimalistic-crypto-utils "^1.0.1" -emitter-listener@^1.0.1, emitter-listener@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/emitter-listener/-/emitter-listener-1.1.2.tgz#56b140e8f6992375b3d7cb2cab1cc7432d9632e8" - integrity sha512-Bt1sBAGFHY9DKY+4/2cV6izcKJUf5T7/gkdmkxzX/qv9CcGH8xSwVRW5mtX03SWJtRTWSOpzCuWN9rBFYZepZQ== - dependencies: - shimmer "^1.2.0" - emoji-regex@^7.0.1: version "7.0.3" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" @@ -10155,7 +10006,7 @@ semver-greatest-satisfied-range@^1.1.0: dependencies: sver-compat "^1.5.0" -"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0: +"semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== @@ -10296,11 +10147,6 @@ shell-quote@^1.6.1: resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.3.tgz#aa40edac170445b9a431e17bb62c0b881b9c4123" integrity sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw== -shimmer@^1.1.0, shimmer@^1.2.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/shimmer/-/shimmer-1.2.1.tgz#610859f7de327b587efebf501fb43117f9aff337" - integrity sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw== - sigmund@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" @@ -10610,11 +10456,6 @@ stable@^0.1.8: resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== -stack-chain@^1.3.7: - version "1.3.7" - resolved "https://registry.yarnpkg.com/stack-chain/-/stack-chain-1.3.7.tgz#d192c9ff4ea6a22c94c4dd459171e3f00cea1285" - integrity sha1-0ZLJ/06moiyUxN1FkXHj8AzqEoU= - stack-trace@0.0.10: version "0.0.10" resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" From e337c0289b320ad9e2e6d5b9b63958f75fdaaa7d Mon Sep 17 00:00:00 2001 From: Robert Jin <20613660+jzyrobert@users.noreply.github.com> Date: Thu, 7 Jul 2022 07:55:48 +0100 Subject: [PATCH 323/347] Edit showFoldingControls to have a never setting (#153764) --- src/vs/editor/common/config/editorOptions.ts | 10 ++++++---- src/vs/editor/contrib/folding/browser/folding.ts | 4 ++-- .../contrib/folding/browser/foldingDecorations.ts | 6 +++--- src/vs/monaco.d.ts | 4 ++-- .../comments/browser/commentsEditorContribution.ts | 2 +- .../contrib/notebook/browser/notebook.contribution.ts | 3 ++- .../contrib/notebook/common/notebookOptions.ts | 4 ++-- 7 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/vs/editor/common/config/editorOptions.ts b/src/vs/editor/common/config/editorOptions.ts index bafc557e3e4..2158431d8b1 100644 --- a/src/vs/editor/common/config/editorOptions.ts +++ b/src/vs/editor/common/config/editorOptions.ts @@ -563,7 +563,7 @@ export interface IEditorOptions { * Controls whether the fold actions in the gutter stay always visible or hide unless the mouse is over the gutter. * Defaults to 'mouseover'. */ - showFoldingControls?: 'always' | 'mouseover'; + showFoldingControls?: 'always' | 'never' | 'mouseover'; /** * Controls whether clicking on the empty content after a folded line will unfold the line. * Defaults to false. @@ -2331,6 +2331,7 @@ export class EditorLayoutInfoComputer extends ComputedEditorOption; selectionHighlight: IEditorOption; selectOnLineNumbers: IEditorOption; - showFoldingControls: IEditorOption; + showFoldingControls: IEditorOption; showUnused: IEditorOption; showDeprecated: IEditorOption; inlayHints: IEditorOption>>; diff --git a/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts b/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts index a0e155d0bdd..335976fbac8 100644 --- a/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts +++ b/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts @@ -859,7 +859,7 @@ export class CommentController implements IEditorContribution { } const options = this.editor.getOptions(); - if (options.get(EditorOption.folding)) { + if (options.get(EditorOption.folding) && options.get(EditorOption.showFoldingControls) !== 'never') { lineDecorationsWidth -= 16; } lineDecorationsWidth += 9; diff --git a/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts b/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts index 466fd1bf565..6111d9f1caa 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts @@ -846,9 +846,10 @@ configurationRegistry.registerConfiguration({ [NotebookSetting.showFoldingControls]: { description: nls.localize('notebook.showFoldingControls.description', "Controls when the Markdown header folding arrow is shown."), type: 'string', - enum: ['always', 'mouseover'], + enum: ['always', 'never', 'mouseover'], enumDescriptions: [ nls.localize('showFoldingControls.always', "The folding controls are always visible."), + nls.localize('showFoldingControls.never', "Never show the folding controls and reduce the gutter size."), nls.localize('showFoldingControls.mouseover', "The folding controls are visible only on mouseover."), ], default: 'mouseover', diff --git a/src/vs/workbench/contrib/notebook/common/notebookOptions.ts b/src/vs/workbench/contrib/notebook/common/notebookOptions.ts index 426871f84fa..2aa4ca14cf8 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookOptions.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookOptions.ts @@ -59,7 +59,7 @@ export interface NotebookLayoutConfiguration { globalToolbar: boolean; consolidatedOutputButton: boolean; consolidatedRunButton: boolean; - showFoldingControls: 'always' | 'mouseover'; + showFoldingControls: 'always' | 'never' | 'mouseover'; dragAndDropEnabled: boolean; fontSize: number; outputFontSize: number; @@ -385,7 +385,7 @@ export class NotebookOptions extends Disposable { } private _computeShowFoldingControlsOption() { - return this.configurationService.getValue<'always' | 'mouseover'>(NotebookSetting.showFoldingControls) ?? 'mouseover'; + return this.configurationService.getValue<'always' | 'never' | 'mouseover'>(NotebookSetting.showFoldingControls) ?? 'mouseover'; } private _computeFocusIndicatorOption() { From b4525a77fbb5009a94413750e69e4c537fe4c517 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Thu, 7 Jul 2022 09:26:12 +0200 Subject: [PATCH 324/347] update yarn.lock (#154336) --- extensions/markdown-language-features/server/yarn.lock | 5 ----- 1 file changed, 5 deletions(-) diff --git a/extensions/markdown-language-features/server/yarn.lock b/extensions/markdown-language-features/server/yarn.lock index 32cc01c3263..8eb67340365 100644 --- a/extensions/markdown-language-features/server/yarn.lock +++ b/extensions/markdown-language-features/server/yarn.lock @@ -2,11 +2,6 @@ # yarn lockfile v1 -"@types/mocha@^9.1.1": - version "9.1.1" - resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-9.1.1.tgz#e7c4f1001eefa4b8afbd1eee27a237fee3bf29c4" - integrity sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw== - "@types/node@16.x": version "16.11.43" resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.43.tgz#555e5a743f76b6b897d47f945305b618525ddbe6" From 7efebe8df8edfd69fc7da5a8315be6703b9cf647 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 7 Jul 2022 10:42:21 +0200 Subject: [PATCH 325/347] focus last (not first) symbol enclosing position, refines https://github.com/microsoft/vscode/issues/154246 (#154340) --- .../contrib/quickAccess/browser/gotoSymbolQuickAccess.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/quickAccess/browser/gotoSymbolQuickAccess.ts b/src/vs/editor/contrib/quickAccess/browser/gotoSymbolQuickAccess.ts index b1ba09a6133..0702c58a85c 100644 --- a/src/vs/editor/contrib/quickAccess/browser/gotoSymbolQuickAccess.ts +++ b/src/vs/editor/contrib/quickAccess/browser/gotoSymbolQuickAccess.ts @@ -20,6 +20,7 @@ import { localize } from 'vs/nls'; import { IQuickPick, IQuickPickItem, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput'; import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures'; import { Position } from 'vs/editor/common/core/position'; +import { findLast } from 'vs/base/common/arrays'; export interface IGotoSymbolQuickPickItem extends IQuickPickItem { kind: SymbolKind; @@ -177,7 +178,7 @@ export abstract class AbstractGotoSymbolQuickAccessProvider extends AbstractEdit if (items.length > 0) { picker.items = items; if (positionToEnclose && query.original.length === 0) { - const candidate = items.find(item => item.type !== 'separator' && item.range && Range.containsPosition(item.range.decoration, positionToEnclose)); + const candidate = findLast(items, item => Boolean(item.type !== 'separator' && item.range && Range.containsPosition(item.range.decoration, positionToEnclose))); if (candidate) { picker.activeItems = [candidate]; } From ce8b7a9c132b49a74d9ab7f4373ae57b3402755d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Thu, 7 Jul 2022 11:18:31 +0200 Subject: [PATCH 326/347] bump distro (#154344) --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index a0ed5de58f5..1cdc1dc30d1 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.69.0", - "distro": "ed09627fa6e06b81792498a4e72e20becb6164f8", + "distro": "87b1d47dad0ad97ea5867ccfca4e43dd64a1bad2", "author": { "name": "Microsoft Corporation" }, @@ -229,4 +229,4 @@ "elliptic": "^6.5.3", "nwmatcher": "^1.4.4" } -} +} \ No newline at end of file From a5ed786a96d431daa9d85fb832f6ac1b799938da Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 7 Jul 2022 05:15:51 -0700 Subject: [PATCH 327/347] Revert "more specific setting names" This reverts commit 2d9947ba4e53c0889c07e3a415572ec8bad1529e. --- src/vs/platform/terminal/common/terminal.ts | 4 ++-- .../contrib/terminal/browser/terminalInstance.ts | 2 +- .../terminal/browser/terminalProfileResolverService.ts | 4 ++-- .../contrib/terminal/common/terminalConfiguration.ts | 8 ++++---- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/vs/platform/terminal/common/terminal.ts b/src/vs/platform/terminal/common/terminal.ts index 0619e9e87fa..4ef5e51de3e 100644 --- a/src/vs/platform/terminal/common/terminal.ts +++ b/src/vs/platform/terminal/common/terminal.ts @@ -40,8 +40,8 @@ export const enum TerminalSettingId { DefaultProfileMacOs = 'terminal.integrated.defaultProfile.osx', DefaultProfileWindows = 'terminal.integrated.defaultProfile.windows', UseWslProfiles = 'terminal.integrated.useWslProfiles', - TabsDefaultIconColor = 'terminal.integrated.tabs.defaultIconColor', - TabsDefaultIconId = 'terminal.integrated.tabs.defaultIconId', + TabsDefaultColor = 'terminal.integrated.tabs.defaultColor', + TabsDefaultIcon = 'terminal.integrated.tabs.defaultIcon', TabsEnabled = 'terminal.integrated.tabs.enabled', TabsEnableAnimation = 'terminal.integrated.tabs.enableAnimation', TabsHideCondition = 'terminal.integrated.tabs.hideCondition', diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index dbba638fbd9..527493739e4 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -550,7 +550,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { private _getIcon(): TerminalIcon | undefined { if (!this._icon) { this._icon = this._processManager.processState >= ProcessState.Launching - ? getIconRegistry().getIcon(this._configurationService.getValue(TerminalSettingId.TabsDefaultIconId)) + ? getIconRegistry().getIcon(this._configurationService.getValue(TerminalSettingId.TabsDefaultIcon)) : undefined; } return this._icon; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts b/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts index b133c8e5d8d..f920f87442f 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalProfileResolverService.ts @@ -117,7 +117,7 @@ export abstract class BaseTerminalProfileResolverService implements ITerminalPro } getDefaultIcon(): TerminalIcon & ThemeIcon { - return this._iconRegistry.getIcon(this._configurationService.getValue(TerminalSettingId.TabsDefaultIconId)) || Codicon.terminal; + return this._iconRegistry.getIcon(this._configurationService.getValue(TerminalSettingId.TabsDefaultIcon)) || Codicon.terminal; } async resolveShellLaunchConfig(shellLaunchConfig: IShellLaunchConfig, options: IShellLaunchConfigResolveOptions): Promise { @@ -157,7 +157,7 @@ export abstract class BaseTerminalProfileResolverService implements ITerminalPro // Apply the color shellLaunchConfig.color = shellLaunchConfig.color || resolvedProfile.color - || this._configurationService.getValue(TerminalSettingId.TabsDefaultIconColor); + || this._configurationService.getValue(TerminalSettingId.TabsDefaultColor); // Resolve useShellEnvironment based on the setting if it's not set if (shellLaunchConfig.useShellEnvironment === undefined) { diff --git a/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts b/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts index 2675a545b60..9a63b3777a8 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts @@ -40,12 +40,12 @@ const terminalConfiguration: IConfigurationNode = { type: 'boolean', default: false }, - [TerminalSettingId.TabsDefaultIconColor]: { - description: localize('terminal.integrated.tabs.defaultIconColor', "A theme color ID to associate with terminals by default."), + [TerminalSettingId.TabsDefaultColor]: { + description: localize('terminal.integrated.tabs.defaultColor', "A theme color ID to associate with terminals by default."), ...terminalColorSchema }, - [TerminalSettingId.TabsDefaultIconId]: { - description: localize('terminal.integrated.tabs.defaultIconId', "A codicon ID to associate with terminals by default."), + [TerminalSettingId.TabsDefaultIcon]: { + description: localize('terminal.integrated.tabs.defaultIcon', "A codicon ID to associate with terminals by default."), ...terminalIconSchema, default: Codicon.terminal.id, }, From f7f3f48049934cf5d3a060aa911dafed5046500c Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 7 Jul 2022 05:17:24 -0700 Subject: [PATCH 328/347] Mention icon in terminal icon/color settings Fixes #154354 --- .../platform/terminal/common/terminalPlatformConfiguration.ts | 4 ++-- .../contrib/terminal/common/terminalConfiguration.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vs/platform/terminal/common/terminalPlatformConfiguration.ts b/src/vs/platform/terminal/common/terminalPlatformConfiguration.ts index 79db8443a33..45bad3159a1 100644 --- a/src/vs/platform/terminal/common/terminalPlatformConfiguration.ts +++ b/src/vs/platform/terminal/common/terminalPlatformConfiguration.ts @@ -46,11 +46,11 @@ const terminalProfileBaseProperties: IJSONSchemaMap = { type: 'boolean' }, icon: { - description: localize('terminalProfile.icon', 'A codicon ID to associate with this terminal.'), + description: localize('terminalProfile.icon', 'A codicon ID to associate with the terminal icon.'), ...terminalIconSchema }, color: { - description: localize('terminalProfile.color', 'A theme color ID to associate with this terminal.'), + description: localize('terminalProfile.color', 'A theme color ID to associate with the terminal icon.'), ...terminalColorSchema }, env: { diff --git a/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts b/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts index 9a63b3777a8..3c5513e7c90 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts @@ -41,11 +41,11 @@ const terminalConfiguration: IConfigurationNode = { default: false }, [TerminalSettingId.TabsDefaultColor]: { - description: localize('terminal.integrated.tabs.defaultColor', "A theme color ID to associate with terminals by default."), + description: localize('terminal.integrated.tabs.defaultColor', "A theme color ID to associate with terminal icons by default."), ...terminalColorSchema }, [TerminalSettingId.TabsDefaultIcon]: { - description: localize('terminal.integrated.tabs.defaultIcon', "A codicon ID to associate with terminals by default."), + description: localize('terminal.integrated.tabs.defaultIcon', "A codicon ID to associate with terminal icons by default."), ...terminalIconSchema, default: Codicon.terminal.id, }, From d68ae55c9a9135461e948382900c88ef38e442b6 Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Thu, 7 Jul 2022 08:38:13 -0400 Subject: [PATCH 329/347] show fit to content width in command palette (#154325) * fix #152748 * better solution Co-authored-by: Daniel Imms <2193314+Tyriar@users.noreply.github.com> * Update src/vs/workbench/contrib/terminal/browser/terminalActions.ts * add comma Co-authored-by: Daniel Imms <2193314+Tyriar@users.noreply.github.com> --- .../workbench/contrib/terminal/browser/terminalActions.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index ee79622f1c2..c46f4d33c30 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -2127,10 +2127,11 @@ export function registerTerminalActions() { title: { value: localize('workbench.action.terminal.sizeToContentWidth', "Toggle Size to Content Width"), original: 'Toggle Size to Content Width' }, f1: true, category, - precondition: ContextKeyExpr.and(ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated), TerminalContextKeys.isOpen, TerminalContextKeys.focus), + precondition: ContextKeyExpr.and(ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated), TerminalContextKeys.isOpen), keybinding: { primary: KeyMod.Alt | KeyCode.KeyZ, - weight: KeybindingWeight.WorkbenchContrib + weight: KeybindingWeight.WorkbenchContrib, + when: TerminalContextKeys.focus } }); } @@ -2138,12 +2139,13 @@ export function registerTerminalActions() { await accessor.get(ITerminalService).doWithActiveInstance(t => t.toggleSizeToContentWidth()); } }); + registerAction2(class extends Action2 { constructor() { super({ id: TerminalCommandId.SizeToContentWidthInstance, title: terminalStrings.toggleSizeToContentWidth, - f1: true, + f1: false, category, precondition: ContextKeyExpr.and(ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated), TerminalContextKeys.focus) }); From 6cf558d7a0bf13ef6726bb5fe91219633a042094 Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Thu, 7 Jul 2022 08:38:30 -0400 Subject: [PATCH 330/347] make task setting keys into an enum (#154322) --- .../tasks/browser/abstractTaskService.ts | 28 ++++++++++--------- .../tasks/browser/task.contribution.ts | 20 ++++++------- .../tasks/browser/terminalTaskSystem.ts | 6 ++-- .../workbench/contrib/tasks/common/tasks.ts | 23 +++++++++++++++ .../test/browser/configurationService.test.ts | 11 ++++---- 5 files changed, 57 insertions(+), 31 deletions(-) diff --git a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts index da7e0dccf58..644103faf6a 100644 --- a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts +++ b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts @@ -53,7 +53,9 @@ import { ITaskSet, TaskGroup, ExecutionEngine, JsonSchemaVersion, TaskSourceKind, TaskSorter, ITaskIdentifier, TASK_RUNNING_STATE, TaskRunSource, KeyedTaskIdentifier as KeyedTaskIdentifier, TaskDefinition, RuntimeType, - USER_TASKS_GROUP_KEY + USER_TASKS_GROUP_KEY, + TaskSettingId, + TasksSchemaProperties } from 'vs/workbench/contrib/tasks/common/tasks'; import { ITaskService, ITaskProvider, IProblemMatcherRunOptions, ICustomizationProperties, ITaskFilter, IWorkspaceFolderTaskResult, CustomExecutionSupportedContext, ShellExecutionSupportedContext, ProcessExecutionSupportedContext } from 'vs/workbench/contrib/tasks/common/taskService'; import { getTemplates as getTaskTemplates } from 'vs/workbench/contrib/tasks/common/taskTemplates'; @@ -1093,7 +1095,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } private _isProvideTasksEnabled(): boolean { - const settingValue = this._configurationService.getValue('task.autoDetect'); + const settingValue = this._configurationService.getValue(TaskSettingId.AutoDetect); return settingValue === 'on'; } @@ -1688,7 +1690,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer Prompt = 'prompt' } - const saveBeforeRunTaskConfig: SaveBeforeRunConfigOptions = this._configurationService.getValue('task.saveBeforeRun'); + const saveBeforeRunTaskConfig: SaveBeforeRunConfigOptions = this._configurationService.getValue(TaskSettingId.SaveBeforeRun); if (saveBeforeRunTaskConfig === SaveBeforeRunConfigOptions.Never) { return false; @@ -3523,11 +3525,11 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } const configTasks: (TaskConfig.ICustomTask | TaskConfig.IConfiguringTask)[] = []; - const suppressTaskName = !!this._configurationService.getValue('tasks.suppressTaskName', { resource: folder.uri }); + const suppressTaskName = !!this._configurationService.getValue(TasksSchemaProperties.SuppressTaskName, { resource: folder.uri }); const globalConfig = { - windows: this._configurationService.getValue('tasks.windows', { resource: folder.uri }), - osx: this._configurationService.getValue('tasks.osx', { resource: folder.uri }), - linux: this._configurationService.getValue('tasks.linux', { resource: folder.uri }) + windows: this._configurationService.getValue(TasksSchemaProperties.Windows, { resource: folder.uri }), + osx: this._configurationService.getValue(TasksSchemaProperties.Osx, { resource: folder.uri }), + linux: this._configurationService.getValue(TasksSchemaProperties.Linux, { resource: folder.uri }) }; tasks.get(folder).forEach(task => { const configTask = this._upgradeTask(task, suppressTaskName, globalConfig); @@ -3539,14 +3541,14 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer this._workspaceTasksPromise = undefined; await this._writeConfiguration(folder, 'tasks.tasks', configTasks); await this._writeConfiguration(folder, 'tasks.version', '2.0.0'); - if (this._configurationService.getValue('tasks.showOutput', { resource: folder.uri })) { - await this._configurationService.updateValue('tasks.showOutput', undefined, { resource: folder.uri }); + if (this._configurationService.getValue(TasksSchemaProperties.ShowOutput, { resource: folder.uri })) { + await this._configurationService.updateValue(TasksSchemaProperties.ShowOutput, undefined, { resource: folder.uri }); } - if (this._configurationService.getValue('tasks.isShellCommand', { resource: folder.uri })) { - await this._configurationService.updateValue('tasks.isShellCommand', undefined, { resource: folder.uri }); + if (this._configurationService.getValue(TasksSchemaProperties.IsShellCommand, { resource: folder.uri })) { + await this._configurationService.updateValue(TasksSchemaProperties.IsShellCommand, undefined, { resource: folder.uri }); } - if (this._configurationService.getValue('tasks.suppressTaskName', { resource: folder.uri })) { - await this._configurationService.updateValue('tasks.suppressTaskName', undefined, { resource: folder.uri }); + if (this._configurationService.getValue(TasksSchemaProperties.SuppressTaskName, { resource: folder.uri })) { + await this._configurationService.updateValue(TasksSchemaProperties.SuppressTaskName, undefined, { resource: folder.uri }); } } this._updateSetup(); diff --git a/src/vs/workbench/contrib/tasks/browser/task.contribution.ts b/src/vs/workbench/contrib/tasks/browser/task.contribution.ts index eff66ddba5f..911ee6ec393 100644 --- a/src/vs/workbench/contrib/tasks/browser/task.contribution.ts +++ b/src/vs/workbench/contrib/tasks/browser/task.contribution.ts @@ -20,7 +20,7 @@ import { StatusbarAlignment, IStatusbarService, IStatusbarEntryAccessor, IStatus import { IOutputChannelRegistry, Extensions as OutputExt } from 'vs/workbench/services/output/common/output'; -import { ITaskEvent, TaskEventKind, TaskGroup, TASKS_CATEGORY, TASK_RUNNING_STATE } from 'vs/workbench/contrib/tasks/common/tasks'; +import { ITaskEvent, TaskEventKind, TaskGroup, TaskSettingId, TASKS_CATEGORY, TASK_RUNNING_STATE } from 'vs/workbench/contrib/tasks/common/tasks'; import { ITaskService, ProcessExecutionSupportedContext, ShellExecutionSupportedContext } from 'vs/workbench/contrib/tasks/common/taskService'; import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry, IWorkbenchContribution } from 'vs/workbench/common/contributions'; @@ -431,7 +431,7 @@ configurationRegistry.registerConfiguration({ title: nls.localize('tasksConfigurationTitle', "Tasks"), type: 'object', properties: { - 'task.problemMatchers.neverPrompt': { + [TaskSettingId.ProblemMatchersNeverPrompt]: { markdownDescription: nls.localize('task.problemMatchers.neverPrompt', "Configures whether to show the problem matcher prompt when running a task. Set to `true` to never prompt, or use a dictionary of task types to turn off prompting only for specific task types."), 'oneOf': [ { @@ -453,13 +453,13 @@ configurationRegistry.registerConfiguration({ ], default: false }, - 'task.autoDetect': { + [TaskSettingId.AutoDetect]: { markdownDescription: nls.localize('task.autoDetect', "Controls enablement of `provideTasks` for all task provider extension. If the Tasks: Run Task command is slow, disabling auto detect for task providers may help. Individual extensions may also provide settings that disable auto detection."), type: 'string', enum: ['on', 'off'], default: 'on' }, - 'task.slowProviderWarning': { + [TaskSettingId.SlowProviderWarning]: { markdownDescription: nls.localize('task.slowProviderWarning', "Configures whether a warning is shown when a provider is slow"), 'oneOf': [ { @@ -476,32 +476,32 @@ configurationRegistry.registerConfiguration({ ], default: true }, - 'task.quickOpen.history': { + [TaskSettingId.QuickOpenHistory]: { markdownDescription: nls.localize('task.quickOpen.history', "Controls the number of recent items tracked in task quick open dialog."), type: 'number', default: 30, minimum: 0, maximum: 30 }, - 'task.quickOpen.detail': { + [TaskSettingId.QuickOpenDetail]: { markdownDescription: nls.localize('task.quickOpen.detail', "Controls whether to show the task detail for tasks that have a detail in task quick picks, such as Run Task."), type: 'boolean', default: true }, - 'task.quickOpen.skip': { + [TaskSettingId.QuickOpenSkip]: { type: 'boolean', description: nls.localize('task.quickOpen.skip', "Controls whether the task quick pick is skipped when there is only one task to pick from."), default: false }, - 'task.quickOpen.showAll': { + [TaskSettingId.QuickOpenShowAll]: { type: 'boolean', description: nls.localize('task.quickOpen.showAll', "Causes the Tasks: Run Task command to use the slower \"show all\" behavior instead of the faster two level picker where tasks are grouped by provider."), default: false }, - 'task.showDecorations': { + [TaskSettingId.ShowDecorations]: { type: 'boolean', description: nls.localize('task.showDecorations', "Shows decorations at points of interest in the terminal buffer such as the first problem found via a watch task. Note that this will only take effect for future tasks."), default: true }, - 'task.saveBeforeRun': { + [TaskSettingId.SaveBeforeRun]: { markdownDescription: nls.localize( 'task.saveBeforeRun', 'Save all dirty editors before running a task.' diff --git a/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts b/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts index 0beaded25b4..754a84163c1 100644 --- a/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts +++ b/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts @@ -31,7 +31,7 @@ import { IOutputService } from 'vs/workbench/services/output/common/output'; import { StartStopProblemCollector, WatchingProblemCollector, ProblemCollectorEventKind, ProblemHandlingStrategy } from 'vs/workbench/contrib/tasks/common/problemCollectors'; import { Task, CustomTask, ContributedTask, RevealKind, CommandOptions, IShellConfiguration, RuntimeType, PanelKind, - TaskEvent, TaskEventKind, IShellQuotingOptions, ShellQuoting, CommandString, ICommandConfiguration, IExtensionTaskSource, TaskScope, RevealProblemKind, DependsOrder, TaskSourceKind, InMemoryTask, ITaskEvent + TaskEvent, TaskEventKind, IShellQuotingOptions, ShellQuoting, CommandString, ICommandConfiguration, IExtensionTaskSource, TaskScope, RevealProblemKind, DependsOrder, TaskSourceKind, InMemoryTask, ITaskEvent, TaskSettingId } from 'vs/workbench/contrib/tasks/common/tasks'; import { ITaskSystem, ITaskSummary, ITaskExecuteResult, TaskExecuteKind, TaskError, TaskErrors, ITaskResolver, @@ -209,10 +209,10 @@ export class TerminalTaskSystem extends Disposable implements ITaskSystem { private readonly _onDidStateChange: Emitter; get taskShellIntegrationStartSequence(): string { - return this._configurationService.getValue('task.showDecorations') ? VSCodeSequence(VSCodeOscPt.PromptStart) + VSCodeSequence(VSCodeOscPt.Property, `${VSCodeOscProperty.Task}=True`) + VSCodeSequence(VSCodeOscPt.CommandStart) : ''; + return this._configurationService.getValue(TaskSettingId.ShowDecorations) ? VSCodeSequence(VSCodeOscPt.PromptStart) + VSCodeSequence(VSCodeOscPt.Property, `${VSCodeOscProperty.Task}=True`) + VSCodeSequence(VSCodeOscPt.CommandStart) : ''; } get taskShellIntegrationOutputSequence(): string { - return this._configurationService.getValue('task.showDecorations') ? VSCodeSequence(VSCodeOscPt.CommandExecuted) : ''; + return this._configurationService.getValue(TaskSettingId.ShowDecorations) ? VSCodeSequence(VSCodeOscPt.CommandExecuted) : ''; } constructor( diff --git a/src/vs/workbench/contrib/tasks/common/tasks.ts b/src/vs/workbench/contrib/tasks/common/tasks.ts index f4956cc9aef..2300c659cb0 100644 --- a/src/vs/workbench/contrib/tasks/common/tasks.ts +++ b/src/vs/workbench/contrib/tasks/common/tasks.ts @@ -1190,6 +1190,29 @@ export namespace KeyedTaskIdentifier { } } +export const enum TaskSettingId { + AutoDetect = 'task.autoDetect', + SaveBeforeRun = 'task.saveBeforeRun', + ShowDecorations = 'task.showDecorations', + ProblemMatchersNeverPrompt = 'task.problemMatchers.neverPrompt', + SlowProviderWarning = 'task.slowProviderWarning', + QuickOpenHistory = 'task.quickOpen.history', + QuickOpenDetail = 'task.quickOpen.detail', + QuickOpenSkip = 'task.quickOpen.skip', + QuickOpenShowAll = 'task.quickOpen.showAll' +} + +export const enum TasksSchemaProperties { + Tasks = 'tasks', + SuppressTaskName = 'tasks.suppressTaskName', + Windows = 'tasks.windows', + Osx = 'tasks.osx', + Linux = 'tasks.linux', + ShowOutput = 'tasks.showOutput', + IsShellCommand = 'tasks.isShellCommand', + ServiceTestSetting = 'tasks.service.testSetting', +} + export namespace TaskDefinition { export function createTaskIdentifier(external: ITaskIdentifier, reporter: { error(message: string): void }): KeyedTaskIdentifier | undefined { const definition = TaskDefinitionRegistry.get(external.type); diff --git a/src/vs/workbench/services/configuration/test/browser/configurationService.test.ts b/src/vs/workbench/services/configuration/test/browser/configurationService.test.ts index 1254e1a9b0b..41573109ed5 100644 --- a/src/vs/workbench/services/configuration/test/browser/configurationService.test.ts +++ b/src/vs/workbench/services/configuration/test/browser/configurationService.test.ts @@ -50,6 +50,7 @@ import { FilePolicyService } from 'vs/platform/policy/common/filePolicyService'; import { runWithFakedTimers } from 'vs/base/test/common/timeTravelScheduler'; import { UserDataProfileService } from 'vs/workbench/services/userDataProfile/common/userDataProfileService'; import { IUserDataProfileService } from 'vs/workbench/services/userDataProfile/common/userDataProfile'; +import { TasksSchemaProperties } from 'vs/workbench/contrib/tasks/common/tasks'; function convertToWorkspacePayload(folder: URI): ISingleFolderWorkspaceIdentifier { return { @@ -1096,7 +1097,7 @@ suite('WorkspaceConfigurationService - Folder', () => { test('update workspace configuration', () => { return testObject.updateValue('tasks.service.testSetting', 'value', ConfigurationTarget.WORKSPACE) - .then(() => assert.strictEqual(testObject.getValue('tasks.service.testSetting'), 'value')); + .then(() => assert.strictEqual(testObject.getValue(TasksSchemaProperties.ServiceTestSetting), 'value')); }); test('update resource configuration', () => { @@ -1150,7 +1151,7 @@ suite('WorkspaceConfigurationService - Folder', () => { test('update tasks configuration', () => { return testObject.updateValue('tasks', { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask' }] }, ConfigurationTarget.WORKSPACE) - .then(() => assert.deepStrictEqual(testObject.getValue('tasks'), { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask' }] })); + .then(() => assert.deepStrictEqual(testObject.getValue(TasksSchemaProperties.Tasks), { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask' }] })); }); test('update user configuration should trigger change event before promise is resolve', () => { @@ -1994,7 +1995,7 @@ suite('WorkspaceConfigurationService-Multiroot', () => { }; await jsonEditingServce.write((workspaceContextService.getWorkspace().configuration!), [{ path: ['tasks'], value: expectedTasksConfiguration }], true); await testObject.reloadConfiguration(); - const actual = testObject.getValue('tasks'); + const actual = testObject.getValue(TasksSchemaProperties.Tasks); assert.deepStrictEqual(actual, expectedTasksConfiguration); }); @@ -2119,7 +2120,7 @@ suite('WorkspaceConfigurationService-Multiroot', () => { test('update tasks configuration in a folder', async () => { const workspace = workspaceContextService.getWorkspace(); await testObject.updateValue('tasks', { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask' }] }, { resource: workspace.folders[0].uri }, ConfigurationTarget.WORKSPACE_FOLDER); - assert.deepStrictEqual(testObject.getValue('tasks', { resource: workspace.folders[0].uri }), { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask' }] }); + assert.deepStrictEqual(testObject.getValue(TasksSchemaProperties.Tasks, { resource: workspace.folders[0].uri }), { 'version': '1.0.0', tasks: [{ 'taskName': 'myTask' }] }); }); test('update launch configuration in a workspace', async () => { @@ -2132,7 +2133,7 @@ suite('WorkspaceConfigurationService-Multiroot', () => { const workspace = workspaceContextService.getWorkspace(); const tasks = { 'version': '2.0.0', tasks: [{ 'label': 'myTask' }] }; await testObject.updateValue('tasks', tasks, { resource: workspace.folders[0].uri }, ConfigurationTarget.WORKSPACE, true); - assert.deepStrictEqual(testObject.getValue('tasks'), tasks); + assert.deepStrictEqual(testObject.getValue(TasksSchemaProperties.Tasks), tasks); }); test('configuration of newly added folder is available on configuration change event', async () => { From e5f5a16b745e27bd87ffc774c26e502e8b1a2d61 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 7 Jul 2022 14:55:51 +0200 Subject: [PATCH 331/347] joh/issue145374 (#154360) * enroll more places into `snippetWorkspaceEdit` proposal, https://github.com/microsoft/vscode/issues/145374 * tweak API proposal for snippet edits, make this `WorkspaceEdit` only, remove old proposal bit https://github.com/microsoft/vscode/issues/145374 --- .../src/singlefolder-tests/workspace.test.ts | 5 +--- .../common/extHostFileSystemEventService.ts | 11 +++++---- .../api/common/extHostLanguageFeatures.ts | 8 +++---- .../api/common/extHostTypeConverters.ts | 23 ++++++++++++++----- src/vs/workbench/api/common/extHostTypes.ts | 20 ++++++++++++---- .../vscode.proposed.snippetWorkspaceEdit.d.ts | 7 +++--- 6 files changed, 47 insertions(+), 27 deletions(-) diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts index 9ea22bb3d19..d09fe8fe5c5 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts @@ -1157,10 +1157,8 @@ suite('vscode API - workspace', () => { assert.ok(edt === vscode.window.activeTextEditor); const we = new vscode.WorkspaceEdit(); - we.set(document.uri, [{ range: new vscode.Range(0, 0, 0, 0), newText: '', newText2: new vscode.SnippetString('${1:foo}${2:bar}') }]); + we.replace(document.uri, new vscode.Range(0, 0, 0, 0), new vscode.SnippetString('${1:foo}${2:bar}')); const success = await vscode.workspace.applyEdit(we); - - if (edt !== vscode.window.activeTextEditor) { return this.skip(); } @@ -1168,6 +1166,5 @@ suite('vscode API - workspace', () => { assert.ok(success); assert.strictEqual(document.getText(), 'foobarhello\nworld'); assert.deepStrictEqual(edt.selections, [new vscode.Selection(0, 0, 0, 3)]); - }); }); diff --git a/src/vs/workbench/api/common/extHostFileSystemEventService.ts b/src/vs/workbench/api/common/extHostFileSystemEventService.ts index d4f86a58255..79aa5cd22f4 100644 --- a/src/vs/workbench/api/common/extHostFileSystemEventService.ts +++ b/src/vs/workbench/api/common/extHostFileSystemEventService.ts @@ -16,6 +16,7 @@ import { FileOperation } from 'vs/platform/files/common/files'; import { CancellationToken } from 'vs/base/common/cancellation'; import { ILogService } from 'vs/platform/log/common/log'; import { IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace'; +import { isProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions'; class FileSystemWatcher implements vscode.FileSystemWatcher { @@ -223,14 +224,14 @@ export class ExtHostFileSystemEventService implements ExtHostFileSystemEventServ private async _fireWillEvent(emitter: AsyncEmitter, data: IWaitUntilData, timeout: number, token: CancellationToken): Promise { const extensionNames = new Set(); - const edits: WorkspaceEdit[] = []; + const edits: [IExtensionDescription, WorkspaceEdit][] = []; - await emitter.fireAsync(data, token, async (thenable, listener) => { + await emitter.fireAsync(data, token, async (thenable: Promise, listener) => { // ignore all results except for WorkspaceEdits. Those are stored in an array. const now = Date.now(); const result = await Promise.resolve(thenable); if (result instanceof WorkspaceEdit) { - edits.push(result); + edits.push([(>listener).extension, result]); extensionNames.add((>listener).extension.displayName ?? (>listener).extension.identifier.value); } @@ -249,11 +250,11 @@ export class ExtHostFileSystemEventService implements ExtHostFileSystemEventServ // concat all WorkspaceEdits collected via waitUntil-call and send them over to the renderer const dto: IWorkspaceEditDto = { edits: [] }; - for (const edit of edits) { + for (const [extension, edit] of edits) { const { edits } = typeConverter.WorkspaceEdit.from(edit, { getTextDocumentVersion: uri => this._extHostDocumentsAndEditors.getDocument(uri)?.version, getNotebookDocumentVersion: () => undefined, - }); + }, isProposedApiEnabled(extension, 'snippetWorkspaceEdit')); dto.edits = dto.edits.concat(edits); } return { edit: dto, extensionNames: Array.from(extensionNames) }; diff --git a/src/vs/workbench/api/common/extHostLanguageFeatures.ts b/src/vs/workbench/api/common/extHostLanguageFeatures.ts index afdb6fbb015..4c70e92c5e6 100644 --- a/src/vs/workbench/api/common/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/common/extHostLanguageFeatures.ts @@ -446,7 +446,7 @@ class CodeActionAdapter { title: candidate.title, command: candidate.command && this._commands.toInternal(candidate.command, disposables), diagnostics: candidate.diagnostics && candidate.diagnostics.map(typeConvert.Diagnostic.from), - edit: candidate.edit && typeConvert.WorkspaceEdit.from(candidate.edit), + edit: candidate.edit && typeConvert.WorkspaceEdit.from(candidate.edit, undefined, isProposedApiEnabled(this._extension, 'snippetWorkspaceEdit')), kind: candidate.kind && candidate.kind.value, isPreferred: candidate.isPreferred, disabled: candidate.disabled?.reason @@ -467,7 +467,7 @@ class CodeActionAdapter { } const resolvedItem = (await this._provider.resolveCodeAction(item, token)) ?? item; return resolvedItem?.edit - ? typeConvert.WorkspaceEdit.from(resolvedItem.edit) + ? typeConvert.WorkspaceEdit.from(resolvedItem.edit, undefined, isProposedApiEnabled(this._extension, 'snippetWorkspaceEdit')) : undefined; } @@ -522,7 +522,7 @@ class DocumentPasteEditProvider { return { insertText: typeof edit.insertText === 'string' ? edit.insertText : { snippet: edit.insertText.value }, - additionalEdit: edit.additionalEdit ? typeConvert.WorkspaceEdit.from(edit.additionalEdit) : undefined, + additionalEdit: edit.additionalEdit ? typeConvert.WorkspaceEdit.from(edit.additionalEdit, undefined, true) : undefined, }; } } @@ -1808,7 +1808,7 @@ class DocumentOnDropEditAdapter { } return { insertText: typeof edit.insertText === 'string' ? edit.insertText : { snippet: edit.insertText.value }, - additionalEdit: edit.additionalEdit ? typeConvert.WorkspaceEdit.from(edit.additionalEdit) : undefined, + additionalEdit: edit.additionalEdit ? typeConvert.WorkspaceEdit.from(edit.additionalEdit, undefined, true) : undefined, }; } } diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index f7917e317d2..52b5d2c712e 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -598,17 +598,28 @@ export namespace WorkspaceEdit { } else if (entry._type === types.FileEditType.Text) { // text edits - const edit = { + result.edits.push({ resource: entry.uri, textEdit: TextEdit.from(entry.edit), versionId: !toCreate.has(entry.uri) ? versionInfo?.getTextDocumentVersion(entry.uri) : undefined, metadata: entry.metadata - }; - if (allowSnippetTextEdit && entry.edit.newText2 instanceof types.SnippetString) { - edit.textEdit.insertAsSnippet = true; - edit.textEdit.text = entry.edit.newText2.value; + }); + } else if (entry._type === types.FileEditType.Snippet) { + // snippet text edits + if (!allowSnippetTextEdit) { + console.warn(`DROPPING snippet text edit because proposal IS NOT ENABLED`, entry); + continue; } - result.edits.push(edit); + result.edits.push({ + resource: entry.uri, + textEdit: { + range: Range.from(entry.range), + text: entry.edit.value, + insertAsSnippet: true + }, + versionId: !toCreate.has(entry.uri) ? versionInfo?.getTextDocumentVersion(entry.uri) : undefined, + metadata: entry.metadata + }); } else if (entry._type === types.FileEditType.Cell) { // cell edit diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index ce30f68d26e..4eac2a31120 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -549,7 +549,6 @@ export class TextEdit { protected _range: Range; protected _newText: string | null; - newText2?: string | SnippetString; protected _newEol?: EndOfLine; get range(): Range { @@ -660,6 +659,7 @@ export const enum FileEditType { Text = 2, Cell = 3, CellReplace = 5, + Snippet = 6, } export interface IFileOperation { @@ -677,6 +677,14 @@ export interface IFileTextEdit { metadata?: vscode.WorkspaceEditEntryMetadata; } +export interface IFileSnippetTextEdit { + _type: FileEditType.Snippet; + uri: URI; + range: vscode.Range; + edit: vscode.SnippetString; + metadata?: vscode.WorkspaceEditEntryMetadata; +} + export interface IFileCellEdit { _type: FileEditType.Cell; uri: URI; @@ -695,7 +703,7 @@ export interface ICellEdit { } -type WorkspaceEditEntry = IFileOperation | IFileTextEdit | IFileCellEdit | ICellEdit; +type WorkspaceEditEntry = IFileOperation | IFileTextEdit | IFileSnippetTextEdit | IFileCellEdit | ICellEdit; @es5ClassCompat export class WorkspaceEdit implements vscode.WorkspaceEdit { @@ -762,8 +770,12 @@ export class WorkspaceEdit implements vscode.WorkspaceEdit { // --- text - replace(uri: URI, range: Range, newText: string, metadata?: vscode.WorkspaceEditEntryMetadata): void { - this._edits.push({ _type: FileEditType.Text, uri, edit: new TextEdit(range, newText), metadata }); + replace(uri: URI, range: Range, newText: string | vscode.SnippetString, metadata?: vscode.WorkspaceEditEntryMetadata): void { + if (typeof newText === 'string') { + this._edits.push({ _type: FileEditType.Text, uri, edit: new TextEdit(range, newText), metadata }); + } else { + this._edits.push({ _type: FileEditType.Snippet, uri, range, edit: newText, metadata }); + } } insert(resource: URI, position: Position, newText: string, metadata?: vscode.WorkspaceEditEntryMetadata): void { diff --git a/src/vscode-dts/vscode.proposed.snippetWorkspaceEdit.d.ts b/src/vscode-dts/vscode.proposed.snippetWorkspaceEdit.d.ts index 43305c7b56e..46c485216c2 100644 --- a/src/vscode-dts/vscode.proposed.snippetWorkspaceEdit.d.ts +++ b/src/vscode-dts/vscode.proposed.snippetWorkspaceEdit.d.ts @@ -7,10 +7,9 @@ declare module 'vscode' { // https://github.com/microsoft/vscode/issues/145374 - export interface TextEdit { + interface WorkspaceEdit { - // will be merged with newText - // will NOT be supported everywhere, only: `workspace.applyEdit` - newText2?: string | SnippetString; + // todo@API have a SnippetTextEdit and allow to set that? + replace(uri: Uri, range: Range, newText: string | SnippetString, metadata?: WorkspaceEditEntryMetadata): void; } } From dd17e8276e1628c5c12b69754c56ff536ac7e580 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Thu, 7 Jul 2022 15:20:33 +0200 Subject: [PATCH 332/347] standalone theme service: improve detection, toggle (#154357) * standalone theme service: clean up os theme detection * toggle to matching high contrast --- .../browser/standaloneThemeService.ts | 70 ++++++++++--------- .../toggleHighContrast/toggleHighContrast.ts | 12 ++-- 2 files changed, 43 insertions(+), 39 deletions(-) diff --git a/src/vs/editor/standalone/browser/standaloneThemeService.ts b/src/vs/editor/standalone/browser/standaloneThemeService.ts index 4690b299892..1366682b48f 100644 --- a/src/vs/editor/standalone/browser/standaloneThemeService.ts +++ b/src/vs/editor/standalone/browser/standaloneThemeService.ts @@ -17,13 +17,13 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { asCssVariableName, ColorIdentifier, Extensions, IColorRegistry } from 'vs/platform/theme/common/colorRegistry'; import { Extensions as ThemingExtensions, ICssStyleCollector, IFileIconTheme, IProductIconTheme, IThemingRegistry, ITokenStyle } from 'vs/platform/theme/common/themeService'; import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; -import { ColorScheme, isDark } from 'vs/platform/theme/common/theme'; +import { ColorScheme, isDark, isHighContrast } from 'vs/platform/theme/common/theme'; import { getIconsStyleSheet, UnthemedProductIconTheme } from 'vs/platform/theme/browser/iconsStyleSheet'; -const VS_THEME_NAME = 'vs'; -const VS_DARK_THEME_NAME = 'vs-dark'; -const HC_BLACK_THEME_NAME = 'hc-black'; -const HC_LIGHT_THEME_NAME = 'hc-light'; +export const VS_LIGHT_THEME_NAME = 'vs'; +export const VS_DARK_THEME_NAME = 'vs-dark'; +export const HC_BLACK_THEME_NAME = 'hc-black'; +export const HC_LIGHT_THEME_NAME = 'hc-light'; const colorRegistry = Registry.as(Extensions.ColorContribution); const themingRegistry = Registry.as(ThemingExtensions.ThemingContribution); @@ -118,7 +118,7 @@ class StandaloneTheme implements IStandaloneTheme { public get type(): ColorScheme { switch (this.base) { - case VS_THEME_NAME: return ColorScheme.LIGHT; + case VS_LIGHT_THEME_NAME: return ColorScheme.LIGHT; case HC_BLACK_THEME_NAME: return ColorScheme.HIGH_CONTRAST_DARK; case HC_LIGHT_THEME_NAME: return ColorScheme.HIGH_CONTRAST_LIGHT; default: return ColorScheme.DARK; @@ -182,7 +182,7 @@ class StandaloneTheme implements IStandaloneTheme { function isBuiltinTheme(themeName: string): themeName is BuiltinTheme { return ( - themeName === VS_THEME_NAME + themeName === VS_LIGHT_THEME_NAME || themeName === VS_DARK_THEME_NAME || themeName === HC_BLACK_THEME_NAME || themeName === HC_LIGHT_THEME_NAME @@ -191,7 +191,7 @@ function isBuiltinTheme(themeName: string): themeName is BuiltinTheme { function getBuiltinRules(builtinTheme: BuiltinTheme): IStandaloneThemeData { switch (builtinTheme) { - case VS_THEME_NAME: + case VS_LIGHT_THEME_NAME: return vs; case VS_DARK_THEME_NAME: return vs_dark; @@ -229,7 +229,6 @@ export class StandaloneThemeService extends Disposable implements IStandaloneThe private _globalStyleElement: HTMLStyleElement | null; private _styleElements: HTMLStyleElement[]; private _colorMapOverride: Color[] | null; - private _desiredTheme!: IStandaloneTheme; private _theme!: IStandaloneTheme; private _builtInProductIconTheme = new UnthemedProductIconTheme(); @@ -240,7 +239,7 @@ export class StandaloneThemeService extends Disposable implements IStandaloneThe this._autoDetectHighContrast = true; this._knownThemes = new Map(); - this._knownThemes.set(VS_THEME_NAME, newBuiltInTheme(VS_THEME_NAME)); + this._knownThemes.set(VS_LIGHT_THEME_NAME, newBuiltInTheme(VS_LIGHT_THEME_NAME)); this._knownThemes.set(VS_DARK_THEME_NAME, newBuiltInTheme(VS_DARK_THEME_NAME)); this._knownThemes.set(HC_BLACK_THEME_NAME, newBuiltInTheme(HC_BLACK_THEME_NAME)); this._knownThemes.set(HC_LIGHT_THEME_NAME, newBuiltInTheme(HC_LIGHT_THEME_NAME)); @@ -253,7 +252,8 @@ export class StandaloneThemeService extends Disposable implements IStandaloneThe this._globalStyleElement = null; this._styleElements = []; this._colorMapOverride = null; - this.setTheme(VS_THEME_NAME); + this.setTheme(VS_LIGHT_THEME_NAME); + this._onOSSchemeChanged(); iconsStyleSheet.onDidChange(() => { this._codiconCSS = iconsStyleSheet.getCSS(); @@ -261,7 +261,7 @@ export class StandaloneThemeService extends Disposable implements IStandaloneThe }); addMatchMediaChangeListener('(forced-colors: active)', () => { - this._updateActualTheme(); + this._onOSSchemeChanged(); }); } @@ -331,41 +331,43 @@ export class StandaloneThemeService extends Disposable implements IStandaloneThe } public setTheme(themeName: string): void { - let theme: StandaloneTheme; + let theme: StandaloneTheme | undefined; if (this._knownThemes.has(themeName)) { - theme = this._knownThemes.get(themeName)!; + theme = this._knownThemes.get(themeName); } else { - theme = this._knownThemes.get(VS_THEME_NAME)!; + theme = this._knownThemes.get(VS_LIGHT_THEME_NAME); } - this._desiredTheme = theme; - this._updateActualTheme(); + this._updateActualTheme(theme); } - private getHighContrastTheme() { - if (isDark(this._desiredTheme.type)) { - return HC_BLACK_THEME_NAME; - } else { - return HC_LIGHT_THEME_NAME; - } - } - - private _updateActualTheme(): void { - const theme = ( - this._autoDetectHighContrast && window.matchMedia(`(forced-colors: active)`).matches - ? this._knownThemes.get(this.getHighContrastTheme())! - : this._desiredTheme - ); - if (this._theme === theme) { + private _updateActualTheme(desiredTheme: IStandaloneTheme | undefined): void { + if (!desiredTheme || this._theme === desiredTheme) { // Nothing to do return; } - this._theme = theme; + this._theme = desiredTheme; this._updateThemeOrColorMap(); } + private _onOSSchemeChanged() { + if (this._autoDetectHighContrast) { + const wantsHighContrast = window.matchMedia(`(forced-colors: active)`).matches; + if (wantsHighContrast !== isHighContrast(this._theme.type)) { + // switch to high contrast or non-high contrast but stick to dark or light + let newThemeName; + if (isDark(this._theme.type)) { + newThemeName = wantsHighContrast ? HC_BLACK_THEME_NAME : VS_DARK_THEME_NAME; + } else { + newThemeName = wantsHighContrast ? HC_LIGHT_THEME_NAME : VS_LIGHT_THEME_NAME; + } + this._updateActualTheme(this._knownThemes.get(newThemeName)); + } + } + } + public setAutoDetectHighContrast(autoDetectHighContrast: boolean): void { this._autoDetectHighContrast = autoDetectHighContrast; - this._updateActualTheme(); + this._onOSSchemeChanged(); } private _updateThemeOrColorMap(): void { diff --git a/src/vs/editor/standalone/browser/toggleHighContrast/toggleHighContrast.ts b/src/vs/editor/standalone/browser/toggleHighContrast/toggleHighContrast.ts index d10e1ccafb9..4fe1552ebd5 100644 --- a/src/vs/editor/standalone/browser/toggleHighContrast/toggleHighContrast.ts +++ b/src/vs/editor/standalone/browser/toggleHighContrast/toggleHighContrast.ts @@ -7,7 +7,8 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { EditorAction, ServicesAccessor, registerEditorAction } from 'vs/editor/browser/editorExtensions'; import { IStandaloneThemeService } from 'vs/editor/standalone/common/standaloneTheme'; import { ToggleHighContrastNLS } from 'vs/editor/common/standaloneStrings'; -import { isHighContrast } from 'vs/platform/theme/common/theme'; +import { isDark, isHighContrast } from 'vs/platform/theme/common/theme'; +import { HC_BLACK_THEME_NAME, HC_LIGHT_THEME_NAME, VS_DARK_THEME_NAME, VS_LIGHT_THEME_NAME } from 'vs/editor/standalone/browser/standaloneThemeService'; class ToggleHighContrast extends EditorAction { @@ -25,13 +26,14 @@ class ToggleHighContrast extends EditorAction { public run(accessor: ServicesAccessor, editor: ICodeEditor): void { const standaloneThemeService = accessor.get(IStandaloneThemeService); - if (isHighContrast(standaloneThemeService.getColorTheme().type)) { + const currentTheme = standaloneThemeService.getColorTheme(); + if (isHighContrast(currentTheme.type)) { // We must toggle back to the integrator's theme - standaloneThemeService.setTheme(this._originalThemeName || 'vs'); + standaloneThemeService.setTheme(this._originalThemeName || (isDark(currentTheme.type) ? VS_DARK_THEME_NAME : VS_LIGHT_THEME_NAME)); this._originalThemeName = null; } else { - this._originalThemeName = standaloneThemeService.getColorTheme().themeName; - standaloneThemeService.setTheme('hc-black'); + standaloneThemeService.setTheme(isDark(currentTheme.type) ? HC_BLACK_THEME_NAME : HC_LIGHT_THEME_NAME); + this._originalThemeName = currentTheme.themeName; } } } From 30c88106734239138e6b875552ce4a90fef79386 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 7 Jul 2022 06:32:54 -0700 Subject: [PATCH 333/347] Use BASH_COMMAND instead of history for empty command detection Part of #143766 --- .../browser/media/shellIntegration-bash.sh | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh b/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh index b0c525a298d..c57e7eb13db 100755 --- a/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh +++ b/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh @@ -39,13 +39,6 @@ if [[ "$PROMPT_COMMAND" =~ .*(' '.*\;)|(\;.*' ').* ]]; then builtin return fi -# Disable shell integration if HISTCONTROL is set to erase duplicate entries as the exit code -# reporting relies on the duplicates existing -if [[ "$HISTCONTROL" =~ .*erasedups.* ]]; then - builtin unset VSCODE_SHELL_INTEGRATION - builtin return -fi - if [ -z "$VSCODE_SHELL_INTEGRATION" ]; then builtin return fi @@ -56,7 +49,7 @@ __vsc_original_PS2="$PS2" __vsc_custom_PS1="" __vsc_custom_PS2="" __vsc_in_command_execution="1" -__vsc_last_history_id=$(history 1 | awk '{print $1;}') +__vsc_current_command="" __vsc_prompt_start() { builtin printf "\033]633;A\007" @@ -72,6 +65,13 @@ __vsc_update_cwd() { __vsc_command_output_start() { builtin printf "\033]633;C\007" + if [[ ! "$BASH_COMMAND" =~ ^__vsc_prompt* ]]; then + __vsc_current_command=$BASH_COMMAND + builtin printf "\033]633;E;$BASH_COMMAND\007" + else + __vsc_current_command="" + builtin printf "\033]633;E\007" + fi } __vsc_continuation_start() { @@ -83,12 +83,10 @@ __vsc_continuation_end() { } __vsc_command_complete() { - local __vsc_history_id=$(builtin history 1 | awk '{print $1;}') - if [[ "$__vsc_history_id" == "$__vsc_last_history_id" ]]; then + if [ "$__vsc_current_command" = "" ]; then builtin printf "\033]633;D\007" else builtin printf "\033]633;D;%s\007" "$__vsc_status" - __vsc_last_history_id=$__vsc_history_id fi __vsc_update_cwd } From d8dabf05a79990ee3f714c3dcae662e59419a442 Mon Sep 17 00:00:00 2001 From: deepak1556 Date: Thu, 7 Jul 2022 21:24:21 +0900 Subject: [PATCH 334/347] chore: update distro --- build/.cachesalt | 2 +- package.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build/.cachesalt b/build/.cachesalt index 11b63081f5a..f69e77227c0 100644 --- a/build/.cachesalt +++ b/build/.cachesalt @@ -1 +1 @@ -2022-06-10T10:20:54.664Z +2022-07-07T13:42:16.836Z diff --git a/package.json b/package.json index 1cdc1dc30d1..0ed87dce91d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.69.0", - "distro": "87b1d47dad0ad97ea5867ccfca4e43dd64a1bad2", + "distro": "954078b4ad7e8d2b00615cfda5d89e5de196f696", "author": { "name": "Microsoft Corporation" }, @@ -229,4 +229,4 @@ "elliptic": "^6.5.3", "nwmatcher": "^1.4.4" } -} \ No newline at end of file +} From f52f2ed7b5f50dac9aa71e899d12078c31020ca0 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 7 Jul 2022 06:55:01 -0700 Subject: [PATCH 335/347] Use preexec $1 not history and send command Fixes #143766 --- .../browser/media/shellIntegration-bash.sh | 14 ++++++------- .../browser/media/shellIntegration-rc.zsh | 20 +++++++------------ 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh b/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh index c57e7eb13db..88498fbfb9a 100755 --- a/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh +++ b/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh @@ -65,13 +65,7 @@ __vsc_update_cwd() { __vsc_command_output_start() { builtin printf "\033]633;C\007" - if [[ ! "$BASH_COMMAND" =~ ^__vsc_prompt* ]]; then - __vsc_current_command=$BASH_COMMAND - builtin printf "\033]633;E;$BASH_COMMAND\007" - else - __vsc_current_command="" - builtin printf "\033]633;E\007" - fi + builtin printf "\033]633;E;$__vsc_current_command\007" } __vsc_continuation_start() { @@ -111,6 +105,7 @@ __vsc_update_prompt() { __vsc_precmd() { __vsc_command_complete "$__vsc_status" + __vsc_current_command="" __vsc_update_prompt } @@ -118,6 +113,11 @@ __vsc_preexec() { if [ "$__vsc_in_command_execution" = "0" ]; then __vsc_initialized=1 __vsc_in_command_execution="1" + if [[ ! "$BASH_COMMAND" =~ ^__vsc_prompt* ]]; then + __vsc_current_command=$BASH_COMMAND + else + __vsc_current_command="" + fi __vsc_command_output_start fi } diff --git a/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-rc.zsh b/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-rc.zsh index 595c1261e18..7db2583a817 100644 --- a/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-rc.zsh +++ b/src/vs/workbench/contrib/terminal/browser/media/shellIntegration-rc.zsh @@ -33,9 +33,8 @@ if [ -z "$VSCODE_SHELL_INTEGRATION" ]; then builtin return fi -__vsc_initialized="0" __vsc_in_command_execution="1" -__vsc_last_history_id=0 +__vsc_current_command="" __vsc_prompt_start() { builtin printf "\033]633;A\007" @@ -51,6 +50,7 @@ __vsc_update_cwd() { __vsc_command_output_start() { builtin printf "\033]633;C\007" + builtin printf "\033]633;E;$__vsc_current_command\007" } __vsc_continuation_start() { @@ -70,17 +70,10 @@ __vsc_right_prompt_end() { } __vsc_command_complete() { - builtin local __vsc_history_id=$(builtin history | tail -n1 | awk '{print $1;}') - # Don't write the command complete sequence for the first prompt without an associated command - if [[ "$__vsc_initialized" == "1" ]]; then - if [[ "$__vsc_history_id" == "$__vsc_last_history_id" ]]; then - builtin printf "\033]633;D\007" - else - builtin printf "\033]633;D;%s\007" "$__vsc_status" - __vsc_last_history_id=$__vsc_history_id - fi - else + if [[ "$__vsc_current_command" == "" ]]; then builtin printf "\033]633;D\007" + else + builtin printf "\033]633;D;%s\007" "$__vsc_status" fi __vsc_update_cwd } @@ -112,6 +105,7 @@ __vsc_precmd() { fi __vsc_command_complete "$__vsc_status" + __vsc_current_command="" # in command execution if [ -n "$__vsc_in_command_execution" ]; then @@ -125,8 +119,8 @@ __vsc_preexec() { if [ -n "$RPROMPT" ]; then RPROMPT="$__vsc_prior_rprompt" fi - __vsc_initialized="1" __vsc_in_command_execution="1" + __vsc_current_command=$1 __vsc_command_output_start } add-zsh-hook precmd __vsc_precmd From 2fb56e9d62a9835379c114a7bd2c1bf09f03ca89 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 7 Jul 2022 07:30:03 -0700 Subject: [PATCH 336/347] Move smart select and folding to md language server (#154334) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Move smart select and folding to md language server Also fixes a few minor issues: - Don't log to web console - Remove convert code since it is no longer needed - Use correct extension id * bump cache * Bump package version Co-authored-by: João Moreno --- build/.cachesalt | 2 +- .../server/src/logging.ts | 30 +- .../server/src/server.ts | 71 +- .../server/yarn.lock | 4 +- .../src/extension.node.ts | 2 +- .../src/extension.shared.ts | 4 - .../src/languageFeatures/folding.ts | 123 --- .../src/languageFeatures/smartSelect.ts | 259 ------- .../src/test/foldingProvider.test.ts | 230 ------ .../src/test/smartSelect.test.ts | 731 ------------------ 10 files changed, 55 insertions(+), 1401 deletions(-) delete mode 100644 extensions/markdown-language-features/src/languageFeatures/folding.ts delete mode 100644 extensions/markdown-language-features/src/languageFeatures/smartSelect.ts delete mode 100644 extensions/markdown-language-features/src/test/foldingProvider.test.ts delete mode 100644 extensions/markdown-language-features/src/test/smartSelect.test.ts diff --git a/build/.cachesalt b/build/.cachesalt index 11b63081f5a..0e813896e58 100644 --- a/build/.cachesalt +++ b/build/.cachesalt @@ -1 +1 @@ -2022-06-10T10:20:54.664Z +2022-07-07T05:37:58.279Z \ No newline at end of file diff --git a/extensions/markdown-language-features/server/src/logging.ts b/extensions/markdown-language-features/server/src/logging.ts index 2172ef8d1d6..2a026caf580 100644 --- a/extensions/markdown-language-features/server/src/logging.ts +++ b/extensions/markdown-language-features/server/src/logging.ts @@ -5,14 +5,7 @@ import { ILogger } from 'vscode-markdown-languageservice'; -class ConsoleLogger implements ILogger { - - public verbose(title: string, message: string, data?: any): void { - this.appendLine(`[Verbose ${ConsoleLogger.now()}] ${title}: ${message}`); - if (data) { - this.appendLine(ConsoleLogger.data2String(data)); - } - } +export class LogFunctionLogger implements ILogger { private static now(): string { const now = new Date(); @@ -21,10 +14,6 @@ class ConsoleLogger implements ILogger { + ':' + String(now.getUTCSeconds()).padStart(2, '0') + '.' + String(now.getMilliseconds()).padStart(3, '0'); } - private appendLine(value: string): void { - console.log(value); - } - private static data2String(data: any): string { if (data instanceof Error) { if (typeof data.stack === 'string') { @@ -37,6 +26,21 @@ class ConsoleLogger implements ILogger { } return JSON.stringify(data, undefined, 2); } + + constructor( + private readonly _logFn: typeof console.log + ) { } + + public verbose(title: string, message: string, data?: any): void { + this.appendLine(`[Verbose ${LogFunctionLogger.now()}] ${title}: ${message}`); + if (data) { + this.appendLine(LogFunctionLogger.data2String(data)); + } + } + + private appendLine(value: string): void { + this._logFn(value); + } } -export const consoleLogger = new ConsoleLogger(); +export const consoleLogger = new LogFunctionLogger(console.log); diff --git a/extensions/markdown-language-features/server/src/server.ts b/extensions/markdown-language-features/server/src/server.ts index 8a2ec6dbba8..8bc1d4b9271 100644 --- a/extensions/markdown-language-features/server/src/server.ts +++ b/extensions/markdown-language-features/server/src/server.ts @@ -5,10 +5,10 @@ import { Connection, Emitter, Event, InitializeParams, InitializeResult, RequestType, TextDocuments } from 'vscode-languageserver'; import { TextDocument } from 'vscode-languageserver-textdocument'; -import { DocumentSymbol, Position, Range } from 'vscode-languageserver-types'; +import * as lsp from 'vscode-languageserver-types'; import * as md from 'vscode-markdown-languageservice'; import { URI } from 'vscode-uri'; -import { consoleLogger } from './logging'; +import { LogFunctionLogger } from './logging'; const parseRequestType: RequestType<{ uri: string }, md.Token[], any> = new RequestType('markdown/parse'); @@ -31,8 +31,7 @@ class TextDocumentToITextDocumentAdapter implements md.ITextDocument { } positionAt(offset: number): md.IPosition { - const pos = this._doc.positionAt(offset); - return md.makePosition(pos.line, pos.character); + return this._doc.positionAt(offset); } } @@ -44,6 +43,8 @@ export function startServer(connection: Connection) { return { capabilities: { documentSymbolProvider: true, + foldingRangeProvider: true, + selectionRangeProvider: true, } }; }); @@ -85,15 +86,38 @@ export function startServer(connection: Connection) { } }; - const provider = md.createLanguageService(workspace, parser, consoleLogger); + const logger = new LogFunctionLogger(connection.console.log.bind(connection.console)); + const provider = md.createLanguageService(workspace, parser, logger); - connection.onDocumentSymbol(async (documentSymbolParams, _token): Promise => { + connection.onDocumentSymbol(async (params, token): Promise => { try { - const document = documents.get(documentSymbolParams.textDocument.uri) as TextDocument | undefined; + const document = documents.get(params.textDocument.uri); if (document) { - const response = await provider.provideDocumentSymbols(new TextDocumentToITextDocumentAdapter(document)); - // TODO: only required because extra methods returned on positions/ranges - return response.map(symbol => convertDocumentSymbol(symbol)); + return await provider.provideDocumentSymbols(new TextDocumentToITextDocumentAdapter(document), token); + } + } catch (e) { + console.error(e.stack); + } + return []; + }); + + connection.onFoldingRanges(async (params, token): Promise => { + try { + const document = documents.get(params.textDocument.uri); + if (document) { + return await provider.provideFoldingRanges(new TextDocumentToITextDocumentAdapter(document), token); + } + } catch (e) { + console.error(e.stack); + } + return []; + }); + + connection.onSelectionRanges(async (params, token): Promise => { + try { + const document = documents.get(params.textDocument.uri); + if (document) { + return await provider.provideSelectionRanges(new TextDocumentToITextDocumentAdapter(document), params.positions, token); } } catch (e) { console.error(e.stack); @@ -103,30 +127,3 @@ export function startServer(connection: Connection) { connection.listen(); } - - -function convertDocumentSymbol(sym: DocumentSymbol): DocumentSymbol { - return { - kind: sym.kind, - name: sym.name, - range: convertRange(sym.range), - selectionRange: convertRange(sym.selectionRange), - children: sym.children?.map(convertDocumentSymbol), - detail: sym.detail, - tags: sym.tags, - }; -} - -function convertRange(range: Range): Range { - return { - start: convertPosition(range.start), - end: convertPosition(range.end), - }; -} - -function convertPosition(start: Position): Position { - return { - character: start.character, - line: start.line, - }; -} diff --git a/extensions/markdown-language-features/server/yarn.lock b/extensions/markdown-language-features/server/yarn.lock index 8eb67340365..d0bce38f189 100644 --- a/extensions/markdown-language-features/server/yarn.lock +++ b/extensions/markdown-language-features/server/yarn.lock @@ -43,8 +43,8 @@ vscode-languageserver@^8.0.2-next.4: vscode-languageserver-protocol "3.17.2-next.6" vscode-markdown-languageservice@mjbvz/vscode-markdown-languageservice: - version "1.0.0" - resolved "https://codeload.github.com/mjbvz/vscode-markdown-languageservice/tar.gz/e410b5df64659fbc186cf0a7a7c882c451e07b8b" + version "0.0.0-alpha.1" + resolved "https://codeload.github.com/mjbvz/vscode-markdown-languageservice/tar.gz/e1a0e00bf6a99cc543da64964cc0995537647d15" dependencies: vscode-languageserver-types "^3.17.1" vscode-uri "^3.0.3" diff --git a/extensions/markdown-language-features/src/extension.node.ts b/extensions/markdown-language-features/src/extension.node.ts index ffa76f3fde3..45dba90d3ca 100644 --- a/extensions/markdown-language-features/src/extension.node.ts +++ b/extensions/markdown-language-features/src/extension.node.ts @@ -30,7 +30,7 @@ export function activate(context: vscode.ExtensionContext) { } async function startServer(context: vscode.ExtensionContext, workspace: IMdWorkspace, parser: IMdParser): Promise { - const clientMain = vscode.extensions.getExtension('vscode.css-language-features')?.packageJSON?.main || ''; + const clientMain = vscode.extensions.getExtension('vscode.markdown-language-features')?.packageJSON?.main || ''; const serverMain = `./server/${clientMain.indexOf('/dist/') !== -1 ? 'dist' : 'out'}/node/main`; const serverModule = context.asAbsolutePath(serverMain); diff --git a/extensions/markdown-language-features/src/extension.shared.ts b/extensions/markdown-language-features/src/extension.shared.ts index 57f9f9d99d7..2a850191004 100644 --- a/extensions/markdown-language-features/src/extension.shared.ts +++ b/extensions/markdown-language-features/src/extension.shared.ts @@ -13,11 +13,9 @@ import { MdLinkProvider, registerDocumentLinkSupport } from './languageFeatures/ import { MdDocumentSymbolProvider } from './languageFeatures/documentSymbols'; import { registerDropIntoEditorSupport } from './languageFeatures/dropIntoEditor'; import { registerFindFileReferenceSupport } from './languageFeatures/fileReferences'; -import { registerFoldingSupport } from './languageFeatures/folding'; import { registerPathCompletionSupport } from './languageFeatures/pathCompletions'; import { MdReferencesProvider, registerReferencesSupport } from './languageFeatures/references'; import { registerRenameSupport } from './languageFeatures/rename'; -import { registerSmartSelectSupport } from './languageFeatures/smartSelect'; import { registerWorkspaceSymbolSupport } from './languageFeatures/workspaceSymbols'; import { ILogger } from './logging'; import { IMdParser, MarkdownItEngine, MdParsingProvider } from './markdownEngine'; @@ -81,12 +79,10 @@ function registerMarkdownLanguageFeatures( registerDocumentLinkSupport(selector, linkProvider), registerDropIntoEditorSupport(selector), registerFindFileReferenceSupport(commandManager, referencesProvider), - registerFoldingSupport(selector, parser, tocProvider), registerPasteSupport(selector), registerPathCompletionSupport(selector, workspace, parser, linkProvider), registerReferencesSupport(selector, referencesProvider), registerRenameSupport(selector, workspace, referencesProvider, parser.slugifier), - registerSmartSelectSupport(selector, parser, tocProvider), registerWorkspaceSymbolSupport(workspace, symbolProvider), ); } diff --git a/extensions/markdown-language-features/src/languageFeatures/folding.ts b/extensions/markdown-language-features/src/languageFeatures/folding.ts deleted file mode 100644 index 2fef6f67958..00000000000 --- a/extensions/markdown-language-features/src/languageFeatures/folding.ts +++ /dev/null @@ -1,123 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import type Token = require('markdown-it/lib/token'); -import * as vscode from 'vscode'; -import { IMdParser } from '../markdownEngine'; -import { MdTableOfContentsProvider } from '../tableOfContents'; -import { getLine, ITextDocument } from '../types/textDocument'; -import { isEmptyOrWhitespace } from '../util/string'; - -const rangeLimit = 5000; - -interface MarkdownItTokenWithMap extends Token { - map: [number, number]; -} - -export class MdFoldingProvider implements vscode.FoldingRangeProvider { - - constructor( - private readonly parser: IMdParser, - private readonly tocProvide: MdTableOfContentsProvider, - ) { } - - public async provideFoldingRanges( - document: ITextDocument, - _: vscode.FoldingContext, - _token: vscode.CancellationToken - ): Promise { - const foldables = await Promise.all([ - this.getRegions(document), - this.getHeaderFoldingRanges(document), - this.getBlockFoldingRanges(document) - ]); - return foldables.flat().slice(0, rangeLimit); - } - - private async getRegions(document: ITextDocument): Promise { - const tokens = await this.parser.tokenize(document); - const regionMarkers = tokens.filter(isRegionMarker) - .map(token => ({ line: token.map[0], isStart: isStartRegion(token.content) })); - - const nestingStack: { line: number; isStart: boolean }[] = []; - return regionMarkers - .map(marker => { - if (marker.isStart) { - nestingStack.push(marker); - } else if (nestingStack.length && nestingStack[nestingStack.length - 1].isStart) { - return new vscode.FoldingRange(nestingStack.pop()!.line, marker.line, vscode.FoldingRangeKind.Region); - } else { - // noop: invalid nesting (i.e. [end, start] or [start, end, end]) - } - return null; - }) - .filter((region: vscode.FoldingRange | null): region is vscode.FoldingRange => !!region); - } - - private async getHeaderFoldingRanges(document: ITextDocument): Promise { - const toc = await this.tocProvide.getForDocument(document); - return toc.entries.map(entry => { - let endLine = entry.sectionLocation.range.end.line; - if (isEmptyOrWhitespace(getLine(document, endLine)) && endLine >= entry.line + 1) { - endLine = endLine - 1; - } - return new vscode.FoldingRange(entry.line, endLine); - }); - } - - private async getBlockFoldingRanges(document: ITextDocument): Promise { - const tokens = await this.parser.tokenize(document); - const multiLineListItems = tokens.filter(isFoldableToken); - return multiLineListItems.map(listItem => { - const start = listItem.map[0]; - let end = listItem.map[1] - 1; - if (isEmptyOrWhitespace(getLine(document, end)) && end >= start + 1) { - end = end - 1; - } - return new vscode.FoldingRange(start, end, this.getFoldingRangeKind(listItem)); - }); - } - - private getFoldingRangeKind(listItem: Token): vscode.FoldingRangeKind | undefined { - return listItem.type === 'html_block' && listItem.content.startsWith('/.test(t); -const isEndRegion = (t: string) => /^\s*/.test(t); - -const isRegionMarker = (token: Token): token is MarkdownItTokenWithMap => - !!token.map && token.type === 'html_block' && (isStartRegion(token.content) || isEndRegion(token.content)); - -const isFoldableToken = (token: Token): token is MarkdownItTokenWithMap => { - if (!token.map) { - return false; - } - - switch (token.type) { - case 'fence': - case 'list_item_open': - return token.map[1] > token.map[0]; - - case 'html_block': - if (isRegionMarker(token)) { - return false; - } - return token.map[1] > token.map[0] + 1; - - default: - return false; - } -}; - -export function registerFoldingSupport( - selector: vscode.DocumentSelector, - parser: IMdParser, - tocProvider: MdTableOfContentsProvider, -): vscode.Disposable { - return vscode.languages.registerFoldingRangeProvider(selector, new MdFoldingProvider(parser, tocProvider)); -} diff --git a/extensions/markdown-language-features/src/languageFeatures/smartSelect.ts b/extensions/markdown-language-features/src/languageFeatures/smartSelect.ts deleted file mode 100644 index 61fa887073f..00000000000 --- a/extensions/markdown-language-features/src/languageFeatures/smartSelect.ts +++ /dev/null @@ -1,259 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -import Token = require('markdown-it/lib/token'); -import * as vscode from 'vscode'; -import { IMdParser } from '../markdownEngine'; -import { MdTableOfContentsProvider, TocEntry } from '../tableOfContents'; -import { getLine, ITextDocument } from '../types/textDocument'; -import { isEmptyOrWhitespace } from '../util/string'; - -interface MarkdownItTokenWithMap extends Token { - map: [number, number]; -} - -export class MdSmartSelect implements vscode.SelectionRangeProvider { - - constructor( - private readonly parser: IMdParser, - private readonly tocProvider: MdTableOfContentsProvider, - ) { } - - public async provideSelectionRanges(document: ITextDocument, positions: vscode.Position[], _token: vscode.CancellationToken): Promise { - const promises = await Promise.all(positions.map((position) => { - return this.provideSelectionRange(document, position, _token); - })); - return promises.filter(item => item !== undefined) as vscode.SelectionRange[]; - } - - private async provideSelectionRange(document: ITextDocument, position: vscode.Position, _token: vscode.CancellationToken): Promise { - const headerRange = await this.getHeaderSelectionRange(document, position); - const blockRange = await this.getBlockSelectionRange(document, position, headerRange); - const inlineRange = await this.getInlineSelectionRange(document, position, blockRange); - return inlineRange || blockRange || headerRange; - } - private async getInlineSelectionRange(document: ITextDocument, position: vscode.Position, blockRange?: vscode.SelectionRange): Promise { - return createInlineRange(document, position, blockRange); - } - - private async getBlockSelectionRange(document: ITextDocument, position: vscode.Position, headerRange?: vscode.SelectionRange): Promise { - const tokens = await this.parser.tokenize(document); - const blockTokens = getBlockTokensForPosition(tokens, position, headerRange); - - if (blockTokens.length === 0) { - return undefined; - } - - let currentRange: vscode.SelectionRange | undefined = headerRange ? headerRange : createBlockRange(blockTokens.shift()!, document, position.line); - - for (let i = 0; i < blockTokens.length; i++) { - currentRange = createBlockRange(blockTokens[i], document, position.line, currentRange); - } - return currentRange; - } - - private async getHeaderSelectionRange(document: ITextDocument, position: vscode.Position): Promise { - const toc = await this.tocProvider.getForDocument(document); - - const headerInfo = getHeadersForPosition(toc.entries, position); - - const headers = headerInfo.headers; - - let currentRange: vscode.SelectionRange | undefined; - - for (let i = 0; i < headers.length; i++) { - currentRange = createHeaderRange(headers[i], i === headers.length - 1, headerInfo.headerOnThisLine, currentRange, getFirstChildHeader(document, headers[i], toc.entries)); - } - return currentRange; - } -} - -function getHeadersForPosition(toc: readonly TocEntry[], position: vscode.Position): { headers: TocEntry[]; headerOnThisLine: boolean } { - const enclosingHeaders = toc.filter(header => header.sectionLocation.range.start.line <= position.line && header.sectionLocation.range.end.line >= position.line); - const sortedHeaders = enclosingHeaders.sort((header1, header2) => (header1.line - position.line) - (header2.line - position.line)); - const onThisLine = toc.find(header => header.line === position.line) !== undefined; - return { - headers: sortedHeaders, - headerOnThisLine: onThisLine - }; -} - -function createHeaderRange(header: TocEntry, isClosestHeaderToPosition: boolean, onHeaderLine: boolean, parent?: vscode.SelectionRange, startOfChildRange?: vscode.Position): vscode.SelectionRange | undefined { - const range = header.sectionLocation.range; - const contentRange = new vscode.Range(range.start.translate(1), range.end); - if (onHeaderLine && isClosestHeaderToPosition && startOfChildRange) { - // selection was made on this header line, so select header and its content until the start of its first child - // then all of its content - return new vscode.SelectionRange(range.with(undefined, startOfChildRange), new vscode.SelectionRange(range, parent)); - } else if (onHeaderLine && isClosestHeaderToPosition) { - // selection was made on this header line and no children so expand to all of its content - return new vscode.SelectionRange(range, parent); - } else if (isClosestHeaderToPosition && startOfChildRange) { - // selection was made within content and has child so select content - // of this header then all content then header - return new vscode.SelectionRange(contentRange.with(undefined, startOfChildRange), new vscode.SelectionRange(contentRange, (new vscode.SelectionRange(range, parent)))); - } else { - // not on this header line so select content then header - return new vscode.SelectionRange(contentRange, new vscode.SelectionRange(range, parent)); - } -} - -function getBlockTokensForPosition(tokens: Token[], position: vscode.Position, parent?: vscode.SelectionRange): MarkdownItTokenWithMap[] { - const enclosingTokens = tokens.filter((token): token is MarkdownItTokenWithMap => !!token.map && (token.map[0] <= position.line && token.map[1] > position.line) && (!parent || (token.map[0] >= parent.range.start.line && token.map[1] <= parent.range.end.line + 1)) && isBlockElement(token)); - if (enclosingTokens.length === 0) { - return []; - } - const sortedTokens = enclosingTokens.sort((token1, token2) => (token2.map[1] - token2.map[0]) - (token1.map[1] - token1.map[0])); - return sortedTokens; -} - -function createBlockRange(block: MarkdownItTokenWithMap, document: ITextDocument, cursorLine: number, parent?: vscode.SelectionRange): vscode.SelectionRange | undefined { - if (block.type === 'fence') { - return createFencedRange(block, cursorLine, document, parent); - } else { - let startLine = isEmptyOrWhitespace(getLine(document, block.map[0])) ? block.map[0] + 1 : block.map[0]; - let endLine = startLine === block.map[1] ? block.map[1] : block.map[1] - 1; - if (block.type === 'paragraph_open' && block.map[1] - block.map[0] === 2) { - startLine = endLine = cursorLine; - } else if (isList(block) && isEmptyOrWhitespace(getLine(document, endLine))) { - endLine = endLine - 1; - } - const range = new vscode.Range(startLine, 0, endLine, getLine(document, endLine).length); - if (parent?.range.contains(range) && !parent.range.isEqual(range)) { - return new vscode.SelectionRange(range, parent); - } else if (parent?.range.isEqual(range)) { - return parent; - } else { - return new vscode.SelectionRange(range); - } - } -} - -function createInlineRange(document: ITextDocument, cursorPosition: vscode.Position, parent?: vscode.SelectionRange): vscode.SelectionRange | undefined { - const lineText = getLine(document, cursorPosition.line); - const boldSelection = createBoldRange(lineText, cursorPosition.character, cursorPosition.line, parent); - const italicSelection = createOtherInlineRange(lineText, cursorPosition.character, cursorPosition.line, true, parent); - let comboSelection: vscode.SelectionRange | undefined; - if (boldSelection && italicSelection && !boldSelection.range.isEqual(italicSelection.range)) { - if (boldSelection.range.contains(italicSelection.range)) { - comboSelection = createOtherInlineRange(lineText, cursorPosition.character, cursorPosition.line, true, boldSelection); - } else if (italicSelection.range.contains(boldSelection.range)) { - comboSelection = createBoldRange(lineText, cursorPosition.character, cursorPosition.line, italicSelection); - } - } - const linkSelection = createLinkRange(lineText, cursorPosition.character, cursorPosition.line, comboSelection || boldSelection || italicSelection || parent); - const inlineCodeBlockSelection = createOtherInlineRange(lineText, cursorPosition.character, cursorPosition.line, false, linkSelection || parent); - return inlineCodeBlockSelection || linkSelection || comboSelection || boldSelection || italicSelection; -} - -function createFencedRange(token: MarkdownItTokenWithMap, cursorLine: number, document: ITextDocument, parent?: vscode.SelectionRange): vscode.SelectionRange { - const startLine = token.map[0]; - const endLine = token.map[1] - 1; - const onFenceLine = cursorLine === startLine || cursorLine === endLine; - const fenceRange = new vscode.Range(startLine, 0, endLine, getLine(document, endLine).length); - const contentRange = endLine - startLine > 2 && !onFenceLine ? new vscode.Range(startLine + 1, 0, endLine - 1, getLine(document, endLine - 1).length) : undefined; - if (contentRange) { - return new vscode.SelectionRange(contentRange, new vscode.SelectionRange(fenceRange, parent)); - } else { - if (parent?.range.isEqual(fenceRange)) { - return parent; - } else { - return new vscode.SelectionRange(fenceRange, parent); - } - } -} - -function createBoldRange(lineText: string, cursorChar: number, cursorLine: number, parent?: vscode.SelectionRange): vscode.SelectionRange | undefined { - const regex = /\*\*([^*]+\*?[^*]+\*?[^*]+)\*\*/gim; - const matches = [...lineText.matchAll(regex)].filter(match => lineText.indexOf(match[0]) <= cursorChar && lineText.indexOf(match[0]) + match[0].length >= cursorChar); - if (matches.length) { - // should only be one match, so select first and index 0 contains the entire match - const bold = matches[0][0]; - const startIndex = lineText.indexOf(bold); - const cursorOnStars = cursorChar === startIndex || cursorChar === startIndex + 1 || cursorChar === startIndex + bold.length || cursorChar === startIndex + bold.length - 1; - const contentAndStars = new vscode.SelectionRange(new vscode.Range(cursorLine, startIndex, cursorLine, startIndex + bold.length), parent); - const content = new vscode.SelectionRange(new vscode.Range(cursorLine, startIndex + 2, cursorLine, startIndex + bold.length - 2), contentAndStars); - return cursorOnStars ? contentAndStars : content; - } - return undefined; -} - -function createOtherInlineRange(lineText: string, cursorChar: number, cursorLine: number, isItalic: boolean, parent?: vscode.SelectionRange): vscode.SelectionRange | undefined { - const italicRegexes = [/(?:[^*]+)(\*([^*]+)(?:\*\*[^*]*\*\*)*([^*]+)\*)(?:[^*]+)/g, /^(?:[^*]*)(\*([^*]+)(?:\*\*[^*]*\*\*)*([^*]+)\*)(?:[^*]*)$/g]; - let matches = []; - if (isItalic) { - matches = [...lineText.matchAll(italicRegexes[0])].filter(match => lineText.indexOf(match[0]) <= cursorChar && lineText.indexOf(match[0]) + match[0].length >= cursorChar); - if (!matches.length) { - matches = [...lineText.matchAll(italicRegexes[1])].filter(match => lineText.indexOf(match[0]) <= cursorChar && lineText.indexOf(match[0]) + match[0].length >= cursorChar); - } - } else { - matches = [...lineText.matchAll(/\`[^\`]*\`/g)].filter(match => lineText.indexOf(match[0]) <= cursorChar && lineText.indexOf(match[0]) + match[0].length >= cursorChar); - } - if (matches.length) { - // should only be one match, so select first and select group 1 for italics because that contains just the italic section - // doesn't include the leading and trailing characters which are guaranteed to not be * so as not to be confused with bold - const match = isItalic ? matches[0][1] : matches[0][0]; - const startIndex = lineText.indexOf(match); - const cursorOnType = cursorChar === startIndex || cursorChar === startIndex + match.length; - const contentAndType = new vscode.SelectionRange(new vscode.Range(cursorLine, startIndex, cursorLine, startIndex + match.length), parent); - const content = new vscode.SelectionRange(new vscode.Range(cursorLine, startIndex + 1, cursorLine, startIndex + match.length - 1), contentAndType); - return cursorOnType ? contentAndType : content; - } - return undefined; -} - -function createLinkRange(lineText: string, cursorChar: number, cursorLine: number, parent?: vscode.SelectionRange): vscode.SelectionRange | undefined { - const regex = /(\[[^\(\)]*\])(\([^\[\]]*\))/g; - const matches = [...lineText.matchAll(regex)].filter(match => lineText.indexOf(match[0]) <= cursorChar && lineText.indexOf(match[0]) + match[0].length > cursorChar); - - if (matches.length) { - // should only be one match, so select first and index 0 contains the entire match, so match = [text](url) - const link = matches[0][0]; - const linkRange = new vscode.SelectionRange(new vscode.Range(cursorLine, lineText.indexOf(link), cursorLine, lineText.indexOf(link) + link.length), parent); - - const linkText = matches[0][1]; - const url = matches[0][2]; - - // determine if cursor is within [text] or (url) in order to know which should be selected - const nearestType = cursorChar >= lineText.indexOf(linkText) && cursorChar < lineText.indexOf(linkText) + linkText.length ? linkText : url; - - const indexOfType = lineText.indexOf(nearestType); - // determine if cursor is on a bracket or paren and if so, return the [content] or (content), skipping over the content range - const cursorOnType = cursorChar === indexOfType || cursorChar === indexOfType + nearestType.length; - - const contentAndNearestType = new vscode.SelectionRange(new vscode.Range(cursorLine, indexOfType, cursorLine, indexOfType + nearestType.length), linkRange); - const content = new vscode.SelectionRange(new vscode.Range(cursorLine, indexOfType + 1, cursorLine, indexOfType + nearestType.length - 1), contentAndNearestType); - return cursorOnType ? contentAndNearestType : content; - } - return undefined; -} - -function isList(token: Token): boolean { - return token.type ? ['ordered_list_open', 'list_item_open', 'bullet_list_open'].includes(token.type) : false; -} - -function isBlockElement(token: Token): boolean { - return !['list_item_close', 'paragraph_close', 'bullet_list_close', 'inline', 'heading_close', 'heading_open'].includes(token.type); -} - -function getFirstChildHeader(document: ITextDocument, header?: TocEntry, toc?: readonly TocEntry[]): vscode.Position | undefined { - let childRange: vscode.Position | undefined; - if (header && toc) { - const children = toc.filter(t => header.sectionLocation.range.contains(t.sectionLocation.range) && t.sectionLocation.range.start.line > header.sectionLocation.range.start.line).sort((t1, t2) => t1.line - t2.line); - if (children.length > 0) { - childRange = children[0].sectionLocation.range.start; - const lineText = getLine(document, childRange.line - 1); - return childRange ? childRange.translate(-1, lineText.length) : undefined; - } - } - return undefined; -} - -export function registerSmartSelectSupport( - selector: vscode.DocumentSelector, - parser: IMdParser, - tocProvider: MdTableOfContentsProvider, -): vscode.Disposable { - return vscode.languages.registerSelectionRangeProvider(selector, new MdSmartSelect(parser, tocProvider)); -} diff --git a/extensions/markdown-language-features/src/test/foldingProvider.test.ts b/extensions/markdown-language-features/src/test/foldingProvider.test.ts deleted file mode 100644 index 85cbd84c581..00000000000 --- a/extensions/markdown-language-features/src/test/foldingProvider.test.ts +++ /dev/null @@ -1,230 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as assert from 'assert'; -import 'mocha'; -import * as vscode from 'vscode'; -import { MdFoldingProvider } from '../languageFeatures/folding'; -import { MdTableOfContentsProvider } from '../tableOfContents'; -import { noopToken } from '../util/cancellation'; -import { DisposableStore } from '../util/dispose'; -import { InMemoryDocument } from '../util/inMemoryDocument'; -import { createNewMarkdownEngine } from './engine'; -import { InMemoryMdWorkspace } from './inMemoryWorkspace'; -import { nulLogger } from './nulLogging'; -import { joinLines, withStore } from './util'; - -const testFileName = vscode.Uri.file('test.md'); - -async function getFoldsForDocument(store: DisposableStore, contents: string) { - const doc = new InMemoryDocument(testFileName, contents); - const workspace = store.add(new InMemoryMdWorkspace([doc])); - const engine = createNewMarkdownEngine(); - const tocProvider = store.add(new MdTableOfContentsProvider(engine, workspace, nulLogger)); - const provider = new MdFoldingProvider(engine, tocProvider); - return provider.provideFoldingRanges(doc, {}, noopToken); -} - -suite('markdown.FoldingProvider', () => { - test('Should not return anything for empty document', withStore(async (store) => { - const folds = await getFoldsForDocument(store, ``); - assert.strictEqual(folds.length, 0); - })); - - test('Should not return anything for document without headers', withStore(async (store) => { - const folds = await getFoldsForDocument(store, joinLines( - `a`, - `**b** afas`, - `a#b`, - `a`, - )); - assert.strictEqual(folds.length, 0); - })); - - test('Should fold from header to end of document', withStore(async (store) => { - const folds = await getFoldsForDocument(store, joinLines( - `a`, - `# b`, - `c`, - `d`, - )); - assert.strictEqual(folds.length, 1); - const firstFold = folds[0]; - assert.strictEqual(firstFold.start, 1); - assert.strictEqual(firstFold.end, 3); - })); - - test('Should leave single newline before next header', withStore(async (store) => { - const folds = await getFoldsForDocument(store, joinLines( - ``, - `# a`, - `x`, - ``, - `# b`, - `y`, - )); - assert.strictEqual(folds.length, 2); - const firstFold = folds[0]; - assert.strictEqual(firstFold.start, 1); - assert.strictEqual(firstFold.end, 2); - })); - - test('Should collapse multiple newlines to single newline before next header', withStore(async (store) => { - const folds = await getFoldsForDocument(store, joinLines( - ``, - `# a`, - `x`, - ``, - ``, - ``, - `# b`, - `y` - )); - assert.strictEqual(folds.length, 2); - const firstFold = folds[0]; - assert.strictEqual(firstFold.start, 1); - assert.strictEqual(firstFold.end, 4); - })); - - test('Should not collapse if there is no newline before next header', withStore(async (store) => { - const folds = await getFoldsForDocument(store, joinLines( - ``, - `# a`, - `x`, - `# b`, - `y`, - )); - assert.strictEqual(folds.length, 2); - const firstFold = folds[0]; - assert.strictEqual(firstFold.start, 1); - assert.strictEqual(firstFold.end, 2); - })); - - test('Should fold nested markers', withStore(async (store) => { - const folds = await getFoldsForDocument(store, joinLines( - `a`, - ``, - `b`, - ``, - `b.a`, - ``, - `b`, - ``, - `b.b`, - ``, - `b`, - ``, - `a`, - )); - assert.strictEqual(folds.length, 3); - const [outer, first, second] = folds.sort((a, b) => a.start - b.start); - - assert.strictEqual(outer.start, 1); - assert.strictEqual(outer.end, 11); - assert.strictEqual(first.start, 3); - assert.strictEqual(first.end, 5); - assert.strictEqual(second.start, 7); - assert.strictEqual(second.end, 9); - })); - - test('Should fold from list to end of document', withStore(async (store) => { - const folds = await getFoldsForDocument(store, joinLines( - `a`, - `- b`, - `c`, - `d`, - )); - assert.strictEqual(folds.length, 1); - const firstFold = folds[0]; - assert.strictEqual(firstFold.start, 1); - assert.strictEqual(firstFold.end, 3); - })); - - test('lists folds should span multiple lines of content', withStore(async (store) => { - const folds = await getFoldsForDocument(store, joinLines( - `a`, - `- This list item\n spans multiple\n lines.`, - )); - assert.strictEqual(folds.length, 1); - const firstFold = folds[0]; - assert.strictEqual(firstFold.start, 1); - assert.strictEqual(firstFold.end, 3); - })); - - test('List should leave single blankline before new element', withStore(async (store) => { - const folds = await getFoldsForDocument(store, joinLines( - `- a`, - `a`, - ``, - ``, - `b` - )); - assert.strictEqual(folds.length, 1); - const firstFold = folds[0]; - assert.strictEqual(firstFold.start, 0); - assert.strictEqual(firstFold.end, 2); - })); - - test('Should fold fenced code blocks', withStore(async (store) => { - const folds = await getFoldsForDocument(store, joinLines( - `~~~ts`, - `a`, - `~~~`, - `b`, - )); - assert.strictEqual(folds.length, 1); - const firstFold = folds[0]; - assert.strictEqual(firstFold.start, 0); - assert.strictEqual(firstFold.end, 2); - })); - - test('Should fold fenced code blocks with yaml front matter', withStore(async (store) => { - const folds = await getFoldsForDocument(store, joinLines( - `---`, - `title: bla`, - `---`, - ``, - `~~~ts`, - `a`, - `~~~`, - ``, - `a`, - `a`, - `b`, - `a`, - )); - assert.strictEqual(folds.length, 1); - const firstFold = folds[0]; - assert.strictEqual(firstFold.start, 4); - assert.strictEqual(firstFold.end, 6); - })); - - test('Should fold html blocks', withStore(async (store) => { - const folds = await getFoldsForDocument(store, joinLines( - `x`, - `
`, - ` fa`, - `
`, - )); - assert.strictEqual(folds.length, 1); - const firstFold = folds[0]; - assert.strictEqual(firstFold.start, 1); - assert.strictEqual(firstFold.end, 3); - })); - - test('Should fold html block comments', withStore(async (store) => { - const folds = await getFoldsForDocument(store, joinLines( - `x`, - `` - )); - assert.strictEqual(folds.length, 1); - const firstFold = folds[0]; - assert.strictEqual(firstFold.start, 1); - assert.strictEqual(firstFold.end, 3); - assert.strictEqual(firstFold.kind, vscode.FoldingRangeKind.Comment); - })); -}); diff --git a/extensions/markdown-language-features/src/test/smartSelect.test.ts b/extensions/markdown-language-features/src/test/smartSelect.test.ts deleted file mode 100644 index eb0be03af34..00000000000 --- a/extensions/markdown-language-features/src/test/smartSelect.test.ts +++ /dev/null @@ -1,731 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as assert from 'assert'; -import * as vscode from 'vscode'; -import { MdSmartSelect } from '../languageFeatures/smartSelect'; -import { MdTableOfContentsProvider } from '../tableOfContents'; -import { InMemoryDocument } from '../util/inMemoryDocument'; -import { createNewMarkdownEngine } from './engine'; -import { InMemoryMdWorkspace } from './inMemoryWorkspace'; -import { nulLogger } from './nulLogging'; -import { CURSOR, getCursorPositions, joinLines } from './util'; - -const testFileName = vscode.Uri.file('test.md'); - -suite('markdown.SmartSelect', () => { - test('Smart select single word', async () => { - const ranges = await getSelectionRangesForDocument(`Hel${CURSOR}lo`); - assertNestedLineNumbersEqual(ranges![0], [0, 0]); - }); - - test('Smart select multi-line paragraph', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `Many of the core components and extensions to ${CURSOR}VS Code live in their own repositories on GitHub. `, - `For example, the[node debug adapter](https://github.com/microsoft/vscode-node-debug) and the [mono debug adapter]`, - `(https://github.com/microsoft/vscode-mono-debug) have their own repositories. For a complete list, please visit the [Related Projects](https://github.com/microsoft/vscode/wiki/Related-Projects) page on our [wiki](https://github.com/microsoft/vscode/wiki).` - )); - assertNestedLineNumbersEqual(ranges![0], [0, 2]); - }); - - test('Smart select paragraph', async () => { - const ranges = await getSelectionRangesForDocument(`Many of the core components and extensions to ${CURSOR}VS Code live in their own repositories on GitHub. For example, the [node debug adapter](https://github.com/microsoft/vscode-node-debug) and the [mono debug adapter](https://github.com/microsoft/vscode-mono-debug) have their own repositories. For a complete list, please visit the [Related Projects](https://github.com/microsoft/vscode/wiki/Related-Projects) page on our [wiki](https://github.com/microsoft/vscode/wiki).`); - - assertNestedLineNumbersEqual(ranges![0], [0, 0]); - }); - - test('Smart select html block', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `

`, - `${CURSOR}VS Code in action`, - `

`)); - - assertNestedLineNumbersEqual(ranges![0], [0, 2]); - }); - - test('Smart select header on header line', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `# Header${CURSOR}`, - `Hello`)); - - assertNestedLineNumbersEqual(ranges![0], [0, 1]); - - }); - - test('Smart select single word w grandparent header on text line', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `## ParentHeader`, - `# Header`, - `${CURSOR}Hello` - )); - - assertNestedLineNumbersEqual(ranges![0], [2, 2], [1, 2]); - }); - - test('Smart select html block w parent header', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `# Header`, - `${CURSOR}

`, - `VS Code in action`, - `

`)); - - assertNestedLineNumbersEqual(ranges![0], [1, 1], [1, 3], [0, 3]); - }); - - test('Smart select fenced code block', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `~~~`, - `a${CURSOR}`, - `~~~`)); - - assertNestedLineNumbersEqual(ranges![0], [0, 2]); - }); - - test('Smart select list', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `- item 1`, - `- ${CURSOR}item 2`, - `- item 3`, - `- item 4`)); - assertNestedLineNumbersEqual(ranges![0], [1, 1], [0, 3]); - }); - - test('Smart select list with fenced code block', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `- item 1`, - `- ~~~`, - ` ${CURSOR}a`, - ` ~~~`, - `- item 3`, - `- item 4`)); - - assertNestedLineNumbersEqual(ranges![0], [1, 3], [0, 5]); - }); - - test('Smart select multi cursor', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `- ${CURSOR}item 1`, - `- ~~~`, - ` a`, - ` ~~~`, - `- ${CURSOR}item 3`, - `- item 4`)); - - assertNestedLineNumbersEqual(ranges![0], [0, 0], [0, 5]); - assertNestedLineNumbersEqual(ranges![1], [4, 4], [0, 5]); - }); - - test('Smart select nested block quotes', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `> item 1`, - `> item 2`, - `>> ${CURSOR}item 3`, - `>> item 4`)); - assertNestedLineNumbersEqual(ranges![0], [2, 2], [2, 3], [0, 3]); - }); - - test('Smart select multi nested block quotes', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `> item 1`, - `>> item 2`, - `>>> ${CURSOR}item 3`, - `>>>> item 4`)); - assertNestedLineNumbersEqual(ranges![0], [2, 2], [2, 3], [1, 3], [0, 3]); - }); - - test('Smart select subheader content', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `# main header 1`, - `content 1`, - `## sub header 1`, - `${CURSOR}content 2`, - `# main header 2`)); - - assertNestedLineNumbersEqual(ranges![0], [3, 3], [2, 3], [1, 3], [0, 3]); - }); - - test('Smart select subheader line', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `# main header 1`, - `content 1`, - `## sub header 1${CURSOR}`, - `content 2`, - `# main header 2`)); - - assertNestedLineNumbersEqual(ranges![0], [2, 3], [1, 3], [0, 3]); - }); - - test('Smart select blank line', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `# main header 1`, - `content 1`, - `${CURSOR} `, - `content 2`, - `# main header 2`)); - - assertNestedLineNumbersEqual(ranges![0], [1, 3], [0, 3]); - }); - - test('Smart select line between paragraphs', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `paragraph 1`, - `${CURSOR}`, - `paragraph 2`)); - - assertNestedLineNumbersEqual(ranges![0], [0, 2]); - }); - - test('Smart select empty document', async () => { - const ranges = await getSelectionRangesForDocument(``, [new vscode.Position(0, 0)]); - assert.strictEqual(ranges!.length, 0); - }); - - test('Smart select fenced code block then list then subheader content then subheader then header content then header', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - /* 00 */ `# main header 1`, - /* 01 */ `content 1`, - /* 02 */ `## sub header 1`, - /* 03 */ `- item 1`, - /* 04 */ `- ~~~`, - /* 05 */ ` ${CURSOR}a`, - /* 06 */ ` ~~~`, - /* 07 */ `- item 3`, - /* 08 */ `- item 4`, - /* 09 */ ``, - /* 10 */ `more content`, - /* 11 */ `# main header 2`)); - - assertNestedLineNumbersEqual(ranges![0], [4, 6], [3, 8], [3, 10], [2, 10], [1, 10], [0, 10]); - }); - - test('Smart select list with one element without selecting child subheader', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - /* 00 */ `# main header 1`, - /* 01 */ ``, - /* 02 */ `- list ${CURSOR}`, - /* 03 */ ``, - /* 04 */ `## sub header`, - /* 05 */ ``, - /* 06 */ `content 2`, - /* 07 */ `# main header 2`)); - - assertNestedLineNumbersEqual(ranges![0], [2, 2], [1, 3], [1, 6], [0, 6]); - }); - - test('Smart select content under header then subheaders and their content', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `# main ${CURSOR}header 1`, - ``, - `- list`, - `paragraph`, - `## sub header`, - ``, - `content 2`, - `# main header 2`)); - - assertNestedLineNumbersEqual(ranges![0], [0, 3], [0, 6]); - }); - - test('Smart select last blockquote element under header then subheaders and their content', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `# main header 1`, - ``, - `> block`, - `> block`, - `>> block`, - `>> ${CURSOR}block`, - ``, - `paragraph`, - `## sub header`, - ``, - `content 2`, - `# main header 2`)); - - assertNestedLineNumbersEqual(ranges![0], [5, 5], [4, 5], [2, 5], [1, 7], [1, 10], [0, 10]); - }); - - test('Smart select content of subheader then subheader then content of main header then main header', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `# main header 1`, - ``, - `> block`, - `> block`, - `>> block`, - `>> block`, - ``, - `paragraph`, - `## sub header`, - ``, - ``, - `${CURSOR}`, - ``, - `### main header 2`, - `- content 2`, - `- content 2`, - `- content 2`, - `content 2`)); - - assertNestedLineNumbersEqual(ranges![0], [11, 11], [9, 12], [9, 17], [8, 17], [1, 17], [0, 17]); - }); - - test('Smart select last line content of subheader then subheader then content of main header then main header', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `# main header 1`, - ``, - `> block`, - `> block`, - `>> block`, - `>> block`, - ``, - `paragraph`, - `## sub header`, - ``, - ``, - ``, - ``, - `### main header 2`, - `- content 2`, - `- content 2`, - `- content 2`, - `- ${CURSOR}content 2`)); - - assertNestedLineNumbersEqual(ranges![0], [17, 17], [14, 17], [13, 17], [9, 17], [8, 17], [1, 17], [0, 17]); - }); - - test('Smart select last line content after content of subheader then subheader then content of main header then main header', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `# main header 1`, - ``, - `> block`, - `> block`, - `>> block`, - `>> block`, - ``, - `paragraph`, - `## sub header`, - ``, - ``, - ``, - ``, - `### main header 2`, - `- content 2`, - `- content 2`, - `- content 2`, - `- content 2${CURSOR}`)); - - assertNestedLineNumbersEqual(ranges![0], [17, 17], [14, 17], [13, 17], [9, 17], [8, 17], [1, 17], [0, 17]); - }); - - test('Smart select fenced code block then list then rest of content', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `# main header 1`, - ``, - `> block`, - `> block`, - `>> block`, - `>> block`, - ``, - `- paragraph`, - `- ~~~`, - ` my`, - ` ${CURSOR}code`, - ` goes here`, - ` ~~~`, - `- content`, - `- content 2`, - `- content 2`, - `- content 2`, - `- content 2`)); - - assertNestedLineNumbersEqual(ranges![0], [9, 11], [8, 12], [8, 12], [7, 17], [1, 17], [0, 17]); - }); - - test('Smart select fenced code block then list then rest of content on fenced line', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `# main header 1`, - ``, - `> block`, - `> block`, - `>> block`, - `>> block`, - ``, - `- paragraph`, - `- ~~~${CURSOR}`, - ` my`, - ` code`, - ` goes here`, - ` ~~~`, - `- content`, - `- content 2`, - `- content 2`, - `- content 2`, - `- content 2`)); - - assertNestedLineNumbersEqual(ranges![0], [8, 12], [7, 17], [1, 17], [0, 17]); - }); - - test('Smart select without multiple ranges', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `# main header 1`, - ``, - ``, - `- ${CURSOR}paragraph`, - `- content`)); - - assertNestedLineNumbersEqual(ranges![0], [3, 3], [3, 4], [1, 4], [0, 4]); - }); - - test('Smart select on second level of a list', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `* level 0`, - ` * level 1`, - ` * level 1`, - ` * level 2`, - ` * level 1`, - ` * level ${CURSOR}1`, - `* level 0`)); - - assertNestedLineNumbersEqual(ranges![0], [5, 5], [1, 5], [0, 5], [0, 6]); - }); - - test('Smart select on third level of a list', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `* level 0`, - ` * level 1`, - ` * level 1`, - ` * level ${CURSOR}2`, - ` * level 2`, - ` * level 1`, - ` * level 1`, - `* level 0`)); - assertNestedLineNumbersEqual(ranges![0], [3, 3], [3, 4], [2, 4], [1, 6], [0, 6], [0, 7]); - }); - - test('Smart select level 2 then level 1', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `* level 1`, - ` * level ${CURSOR}2`, - ` * level 2`, - `* level 1`)); - assertNestedLineNumbersEqual(ranges![0], [1, 1], [1, 2], [0, 2], [0, 3]); - }); - - test('Smart select last list item', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `- level 1`, - `- level 2`, - `- level 2`, - `- level ${CURSOR}1`)); - assertNestedLineNumbersEqual(ranges![0], [3, 3], [0, 3]); - }); - - test('Smart select without multiple ranges', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `# main header 1`, - ``, - ``, - `- ${CURSOR}paragraph`, - `- content`)); - - assertNestedLineNumbersEqual(ranges![0], [3, 3], [3, 4], [1, 4], [0, 4]); - }); - - test('Smart select on second level of a list', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `* level 0`, - ` * level 1`, - ` * level 1`, - ` * level 2`, - ` * level 1`, - ` * level ${CURSOR}1`, - `* level 0`)); - - assertNestedLineNumbersEqual(ranges![0], [5, 5], [1, 5], [0, 5], [0, 6]); - }); - - test('Smart select on third level of a list', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `* level 0`, - ` * level 1`, - ` * level 1`, - ` * level ${CURSOR}2`, - ` * level 2`, - ` * level 1`, - ` * level 1`, - `* level 0`)); - assertNestedLineNumbersEqual(ranges![0], [3, 3], [3, 4], [2, 4], [1, 6], [0, 6], [0, 7]); - }); - - test('Smart select level 2 then level 1', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `* level 1`, - ` * level ${CURSOR}2`, - ` * level 2`, - `* level 1`)); - assertNestedLineNumbersEqual(ranges![0], [1, 1], [1, 2], [0, 2], [0, 3]); - }); - - test('Smart select bold', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `stuff here **new${CURSOR}item** and here` - )); - assertNestedRangesEqual(ranges![0], [0, 13, 0, 30], [0, 11, 0, 32], [0, 0, 0, 41]); - }); - - test('Smart select link', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `stuff here [text](https${CURSOR}://google.com) and here` - )); - assertNestedRangesEqual(ranges![0], [0, 18, 0, 46], [0, 17, 0, 47], [0, 11, 0, 47], [0, 0, 0, 56]); - }); - - test('Smart select brackets', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `stuff here [te${CURSOR}xt](https://google.com) and here` - )); - assertNestedRangesEqual(ranges![0], [0, 12, 0, 26], [0, 11, 0, 27], [0, 11, 0, 47], [0, 0, 0, 56]); - }); - - test('Smart select brackets under header in list', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `# main header 1`, - ``, - `- list`, - `paragraph`, - `## sub header`, - `- list`, - `- stuff here [te${CURSOR}xt](https://google.com) and here`, - `- list` - )); - assertNestedRangesEqual(ranges![0], [6, 14, 6, 28], [6, 13, 6, 29], [6, 13, 6, 49], [6, 0, 6, 58], [5, 0, 7, 6], [4, 0, 7, 6], [1, 0, 7, 6], [0, 0, 7, 6]); - }); - - test('Smart select link under header in list', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `# main header 1`, - ``, - `- list`, - `paragraph`, - `## sub header`, - `- list`, - `- stuff here [text](${CURSOR}https://google.com) and here`, - `- list` - )); - assertNestedRangesEqual(ranges![0], [6, 20, 6, 48], [6, 19, 6, 49], [6, 13, 6, 49], [6, 0, 6, 58], [5, 0, 7, 6], [4, 0, 7, 6], [1, 0, 7, 6], [0, 0, 7, 6]); - }); - - test('Smart select bold within list where multiple bold elements exists', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `# main header 1`, - ``, - `- list`, - `paragraph`, - `## sub header`, - `- list`, - `- stuff here [text] **${CURSOR}items in here** and **here**`, - `- list` - )); - assertNestedRangesEqual(ranges![0], [6, 22, 6, 45], [6, 20, 6, 47], [6, 0, 6, 60], [5, 0, 7, 6], [4, 0, 7, 6], [1, 0, 7, 6], [0, 0, 7, 6]); - }); - - test('Smart select link in paragraph with multiple links', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `This[extension](https://marketplace.visualstudio.com/items?itemName=meganrogge.template-string-converter) addresses this [requ${CURSOR}est](https://github.com/microsoft/vscode/issues/56704) to convert Javascript/Typescript quotes to backticks when has been entered within a string.` - )); - assertNestedRangesEqual(ranges![0], [0, 123, 0, 140], [0, 122, 0, 141], [0, 122, 0, 191], [0, 0, 0, 283]); - }); - - test('Smart select bold link', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `**[extens${CURSOR}ion](https://google.com)**` - )); - assertNestedRangesEqual(ranges![0], [0, 3, 0, 22], [0, 2, 0, 23], [0, 2, 0, 43], [0, 2, 0, 43], [0, 0, 0, 45], [0, 0, 0, 45]); - }); - - test('Smart select inline code block', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `[\`code ${CURSOR} link\`]` - )); - assertNestedRangesEqual(ranges![0], [0, 2, 0, 22], [0, 1, 0, 23], [0, 0, 0, 24]); - }); - - test('Smart select link with inline code block text', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `[\`code ${CURSOR} link\`](http://example.com)` - )); - assertNestedRangesEqual(ranges![0], [0, 2, 0, 22], [0, 1, 0, 23], [0, 1, 0, 23], [0, 0, 0, 24], [0, 0, 0, 44], [0, 0, 0, 44]); - }); - - test('Smart select italic', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `*some nice ${CURSOR}text*` - )); - assertNestedRangesEqual(ranges![0], [0, 1, 0, 25], [0, 0, 0, 26], [0, 0, 0, 26]); - }); - - test('Smart select italic link', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `*[extens${CURSOR}ion](https://google.com)*` - )); - assertNestedRangesEqual(ranges![0], [0, 2, 0, 21], [0, 1, 0, 22], [0, 1, 0, 42], [0, 1, 0, 42], [0, 0, 0, 43], [0, 0, 0, 43]); - }); - - test('Smart select italic on end', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `*word1 word2 word3${CURSOR}*` - )); - assertNestedRangesEqual(ranges![0], [0, 1, 0, 28], [0, 0, 0, 29], [0, 0, 0, 29]); - }); - - test('Smart select italic then bold', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `outer text **bold words *italic ${CURSOR} words* bold words** outer text` - )); - assertNestedRangesEqual(ranges![0], [0, 25, 0, 48], [0, 24, 0, 49], [0, 13, 0, 60], [0, 11, 0, 62], [0, 0, 0, 73]); - }); - - test('Smart select bold then italic', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `outer text *italic words **bold ${CURSOR} words** italic words* outer text` - )); - assertNestedRangesEqual(ranges![0], [0, 27, 0, 48], [0, 25, 0, 50], [0, 12, 0, 63], [0, 11, 0, 64], [0, 0, 0, 75]); - }); - - test('Third level header from release notes', async () => { - const ranges = await getSelectionRangesForDocument( - joinLines( - `---`, - `Order: 60`, - `TOCTitle: October 2020`, - `PageTitle: Visual Studio Code October 2020`, - `MetaDescription: Learn what is new in the Visual Studio Code October 2020 Release (1.51)`, - `MetaSocialImage: 1_51/release-highlights.png`, - `Date: 2020-11-6`, - `DownloadVersion: 1.51.1`, - `---`, - `# October 2020 (version 1.51)`, - ``, - `**Update 1.51.1**: The update addresses these [issues](https://github.com/microsoft/vscode/issues?q=is%3Aissue+milestone%3A%22October+2020+Recovery%22+is%3Aclosed+).`, - ``, - ``, - ``, - `---`, - ``, - `Welcome to the October 2020 release of Visual Studio Code. As announced in the [October iteration plan](https://github.com/microsoft/vscode/issues/108473), we focused on housekeeping GitHub issues and pull requests as documented in our issue grooming guide.`, - ``, - `We also worked with our partners at GitHub on GitHub Codespaces, which ended up being more involved than originally anticipated. To that end, we'll continue working on housekeeping for part of the November iteration.`, - ``, - `During this housekeeping milestone, we also addressed several feature requests and community [pull requests](#thank-you). Read on to learn about new features and settings.`, - ``, - `## Workbench`, - ``, - `### More prominent pinned tabs`, - ``, - `${CURSOR}Pinned tabs will now always show their pin icon, even while inactive, to make them easier to identify. If an editor is both pinned and contains unsaved changes, the icon reflects both states.`, - ``, - `![Inactive pinned tabs showing pin icons](images/1_51/pinned-tabs.png)` - ) - ); - assertNestedRangesEqual(ranges![0], [27, 0, 27, 201], [26, 0, 29, 70], [25, 0, 29, 70], [24, 0, 29, 70], [23, 0, 29, 70], [10, 0, 29, 70], [9, 0, 29, 70]); - }); - -}); - - -function assertNestedLineNumbersEqual(range: vscode.SelectionRange, ...expectedRanges: [number, number][]) { - const lineage = getLineage(range); - assert.strictEqual(lineage.length, expectedRanges.length, `expected depth: ${expectedRanges.length}, but was ${lineage.length} ${getValues(lineage)}`); - for (let i = 0; i < lineage.length; i++) { - assertLineNumbersEqual(lineage[i], expectedRanges[i][0], expectedRanges[i][1], `parent at a depth of ${i}`); - } -} - -function assertNestedRangesEqual(range: vscode.SelectionRange, ...expectedRanges: [number, number, number, number][]) { - const lineage = getLineage(range); - assert.strictEqual(lineage.length, expectedRanges.length, `expected depth: ${expectedRanges.length}, but was ${lineage.length} ${getValues(lineage)}`); - for (let i = 0; i < lineage.length; i++) { - assertLineNumbersEqual(lineage[i], expectedRanges[i][0], expectedRanges[i][2], `parent at a depth of ${i}`); - assert(lineage[i].range.start.character === expectedRanges[i][1], `parent at a depth of ${i} on start char`); - assert(lineage[i].range.end.character === expectedRanges[i][3], `parent at a depth of ${i} on end char`); - } -} - -function getLineage(range: vscode.SelectionRange): vscode.SelectionRange[] { - const result: vscode.SelectionRange[] = []; - let currentRange: vscode.SelectionRange | undefined = range; - while (currentRange) { - result.push(currentRange); - currentRange = currentRange.parent; - } - return result; -} - -function getValues(ranges: vscode.SelectionRange[]): string[] { - return ranges.map(range => { - return range.range.start.line + ' ' + range.range.start.character + ' ' + range.range.end.line + ' ' + range.range.end.character; - }); -} - -function assertLineNumbersEqual(selectionRange: vscode.SelectionRange, startLine: number, endLine: number, message: string) { - assert.strictEqual(selectionRange.range.start.line, startLine, `failed on start line ${message}`); - assert.strictEqual(selectionRange.range.end.line, endLine, `failed on end line ${message}`); -} - -function getSelectionRangesForDocument(contents: string, pos?: vscode.Position[]): Promise { - const doc = new InMemoryDocument(testFileName, contents); - const workspace = new InMemoryMdWorkspace([doc]); - const engine = createNewMarkdownEngine(); - const provider = new MdSmartSelect(engine, new MdTableOfContentsProvider(engine, workspace, nulLogger)); - const positions = pos ? pos : getCursorPositions(contents, doc); - return provider.provideSelectionRanges(doc, positions, new vscode.CancellationTokenSource().token); -} From 4dc272701b0a6e5cf59cfc38d1e08f8862604b05 Mon Sep 17 00:00:00 2001 From: Jean Pierre Date: Thu, 7 Jul 2022 10:15:07 -0500 Subject: [PATCH 337/347] Only update storage `IS_NEW_KEY` once (#154313) * Fixes #153913 * spelling error Co-authored-by: Benjamin Pasero --- .../storage/browser/storageService.ts | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/vs/workbench/services/storage/browser/storageService.ts b/src/vs/workbench/services/storage/browser/storageService.ts index a939ea7e567..e267855723c 100644 --- a/src/vs/workbench/services/storage/browser/storageService.ts +++ b/src/vs/workbench/services/storage/browser/storageService.ts @@ -23,7 +23,7 @@ export class BrowserStorageService extends AbstractStorageService { private applicationStorage: IStorage | undefined; private applicationStorageDatabase: IIndexedDBStorageDatabase | undefined; - private readonly applicationStoragePromise = new DeferredPromise<{ indededDb: IIndexedDBStorageDatabase; storage: IStorage }>(); + private readonly applicationStoragePromise = new DeferredPromise<{ indexedDb: IIndexedDBStorageDatabase; storage: IStorage }>(); private profileStorage: IStorage | undefined; private profileStorageDatabase: IIndexedDBStorageDatabase | undefined; @@ -92,7 +92,7 @@ export class BrowserStorageService extends AbstractStorageService { this.updateIsNew(this.applicationStorage); - this.applicationStoragePromise.complete({ indededDb: applicationStorageIndexedDB, storage: this.applicationStorage }); + this.applicationStoragePromise.complete({ indexedDb: applicationStorageIndexedDB, storage: this.applicationStorage }); } private async createProfileStorage(profile: IUserDataProfile): Promise { @@ -110,22 +110,24 @@ export class BrowserStorageService extends AbstractStorageService { // avoid creating the storage library a second time on // the same DB. - const { indededDb: applicationStorageIndexedDB, storage: applicationStorage } = await this.applicationStoragePromise.p; + const { indexedDb: applicationStorageIndexedDB, storage: applicationStorage } = await this.applicationStoragePromise.p; this.profileStorageDatabase = applicationStorageIndexedDB; this.profileStorage = applicationStorage; + + this.profileStorageDisposables.add(this.profileStorage.onDidChangeStorage(key => this.emitDidChangeValue(StorageScope.PROFILE, key))); } else { const profileStorageIndexedDB = await IndexedDBStorageDatabase.create({ id: this.getId(StorageScope.PROFILE), broadcastChanges: true }, this.logService); this.profileStorageDatabase = this.profileStorageDisposables.add(profileStorageIndexedDB); this.profileStorage = this.profileStorageDisposables.add(new Storage(this.profileStorageDatabase)); + + this.profileStorageDisposables.add(this.profileStorage.onDidChangeStorage(key => this.emitDidChangeValue(StorageScope.PROFILE, key))); + + await this.profileStorage.init(); + + this.updateIsNew(this.profileStorage); } - - this.profileStorageDisposables.add(this.profileStorage.onDidChangeStorage(key => this.emitDidChangeValue(StorageScope.PROFILE, key))); - - await this.profileStorage.init(); - - this.updateIsNew(this.profileStorage); } private async createWorkspaceStorage(): Promise { From 1b8ac1d09d6eea72e9305ba977d6449106251349 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Thu, 7 Jul 2022 17:40:22 +0200 Subject: [PATCH 338/347] Fix 2 clicks to show collapsed comments (#154365) Fixes #153924 --- .../contrib/comments/browser/commentsEditorContribution.ts | 1 + src/vs/workbench/contrib/comments/browser/commentsView.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts b/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts index 335976fbac8..41ed64d6d55 100644 --- a/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts +++ b/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts @@ -382,6 +382,7 @@ export class CommentController implements IEditorContribution { this._commentingRangeDecorator.update(this.editor, []); this._commentThreadRangeDecorator.update(this.editor, []); dispose(this._commentWidgets); + this._commentWidgets = []; } })); diff --git a/src/vs/workbench/contrib/comments/browser/commentsView.ts b/src/vs/workbench/contrib/comments/browser/commentsView.ts index d6883919fa6..4c38db0a895 100644 --- a/src/vs/workbench/contrib/comments/browser/commentsView.ts +++ b/src/vs/workbench/contrib/comments/browser/commentsView.ts @@ -234,7 +234,7 @@ export class CommentsPanel extends ViewPane { const commentToReveal = element instanceof ResourceWithCommentThreads ? element.commentThreads[0].comment.uniqueIdInThread : element.comment.uniqueIdInThread; if (threadToReveal && isCodeEditor(editor)) { const controller = CommentController.get(editor); - controller?.revealCommentThread(threadToReveal, commentToReveal, false); + controller?.revealCommentThread(threadToReveal, commentToReveal, true); } return true; From cdb606fc061c2536111dded4403a72b333321fcd Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 7 Jul 2022 08:46:18 -0700 Subject: [PATCH 339/347] Bump api notebook milestone (#154369) --- .vscode/notebooks/api.github-issues | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode/notebooks/api.github-issues b/.vscode/notebooks/api.github-issues index 3120d4ad8fc..6ba33aa8ae8 100644 --- a/.vscode/notebooks/api.github-issues +++ b/.vscode/notebooks/api.github-issues @@ -7,7 +7,7 @@ { "kind": 2, "language": "github-issues", - "value": "$repo=repo:microsoft/vscode\n$milestone=milestone:\"June 2022\"" + "value": "$repo=repo:microsoft/vscode\n$milestone=milestone:\"July 2022\"" }, { "kind": 1, From db734e88c12b9f078b79d33abffc25b0fed1a408 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Thu, 7 Jul 2022 09:03:07 -0700 Subject: [PATCH 340/347] Bump version to 1.70 (#154371) Bump version 1.70 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0ed87dce91d..592494a447a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "code-oss-dev", - "version": "1.69.0", + "version": "1.70.0", "distro": "954078b4ad7e8d2b00615cfda5d89e5de196f696", "author": { "name": "Microsoft Corporation" From 755d39f1e079d103fc7f6dce43e9bc00071f24fe Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Thu, 7 Jul 2022 13:58:38 -0400 Subject: [PATCH 341/347] add allow automatic tasks setting (#154171) --- .../tasks/browser/abstractTaskService.ts | 2 +- .../tasks/browser/runAutomaticTasks.ts | 48 ++++++++++--------- .../tasks/browser/task.contribution.ts | 12 +++++ .../workbench/contrib/tasks/common/tasks.ts | 3 +- 4 files changed, 41 insertions(+), 24 deletions(-) diff --git a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts index 644103faf6a..1a3261a3335 100644 --- a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts +++ b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts @@ -1084,7 +1084,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer }).then((value) => { if (runSource === TaskRunSource.User) { this.getWorkspaceTasks().then(workspaceTasks => { - RunAutomaticTasks.promptForPermission(this, this._storageService, this._notificationService, this._workspaceTrustManagementService, this._openerService, workspaceTasks); + RunAutomaticTasks.promptForPermission(this, this._storageService, this._notificationService, this._workspaceTrustManagementService, this._openerService, this._configurationService, workspaceTasks); }); } return value; diff --git a/src/vs/workbench/contrib/tasks/browser/runAutomaticTasks.ts b/src/vs/workbench/contrib/tasks/browser/runAutomaticTasks.ts index 55d63c00125..aa0d0441b79 100644 --- a/src/vs/workbench/contrib/tasks/browser/runAutomaticTasks.ts +++ b/src/vs/workbench/contrib/tasks/browser/runAutomaticTasks.ts @@ -15,18 +15,19 @@ import { IQuickPickItem, IQuickInputService } from 'vs/platform/quickinput/commo import { Action2 } from 'vs/platform/actions/common/actions'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IWorkspaceTrustManagementService } from 'vs/platform/workspace/common/workspaceTrust'; -import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; +import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { URI } from 'vs/base/common/uri'; import { Event } from 'vs/base/common/event'; import { ILogService } from 'vs/platform/log/common/log'; -const ARE_AUTOMATIC_TASKS_ALLOWED_IN_WORKSPACE = 'tasks.run.allowAutomatic'; +const HAS_PROMPTED_FOR_AUTOMATIC_TASKS = 'task.hasPromptedForAutomaticTasks'; +const ALLOW_AUTOMATIC_TASKS = 'task.allowAutomaticTasks'; export class RunAutomaticTasks extends Disposable implements IWorkbenchContribution { constructor( @ITaskService private readonly _taskService: ITaskService, - @IStorageService private readonly _storageService: IStorageService, + @IConfigurationService private readonly _configurationService: IConfigurationService, @IWorkspaceTrustManagementService private readonly _workspaceTrustManagementService: IWorkspaceTrustManagementService, @ILogService private readonly _logService: ILogService) { super(); @@ -42,7 +43,7 @@ export class RunAutomaticTasks extends Disposable implements IWorkbenchContribut } this._logService.trace('RunAutomaticTasks: Checking if automatic tasks should run.'); - const isFolderAutomaticAllowed = this._storageService.getBoolean(ARE_AUTOMATIC_TASKS_ALLOWED_IN_WORKSPACE, StorageScope.WORKSPACE, undefined); + const isFolderAutomaticAllowed = this._configurationService.getValue(ALLOW_AUTOMATIC_TASKS) !== 'off'; await this._workspaceTrustManagementService.workspaceTrustInitialized; const isWorkspaceTrusted = this._workspaceTrustManagementService.isWorkspaceTrusted(); // Only run if allowed. Prompting for permission occurs when a user first tries to run a task. @@ -128,30 +129,33 @@ export class RunAutomaticTasks extends Disposable implements IWorkbenchContribut } public static async promptForPermission(taskService: ITaskService, storageService: IStorageService, notificationService: INotificationService, workspaceTrustManagementService: IWorkspaceTrustManagementService, - openerService: IOpenerService, workspaceTaskResult: Map) { + openerService: IOpenerService, configurationService: IConfigurationService, workspaceTaskResult: Map) { const isWorkspaceTrusted = workspaceTrustManagementService.isWorkspaceTrusted; if (!isWorkspaceTrusted) { return; } - - const isFolderAutomaticAllowed = storageService.getBoolean(ARE_AUTOMATIC_TASKS_ALLOWED_IN_WORKSPACE, StorageScope.WORKSPACE, undefined); - if (isFolderAutomaticAllowed !== undefined) { + if (configurationService.getValue(ALLOW_AUTOMATIC_TASKS) === 'off') { return; } + const hasShownPromptForAutomaticTasks = storageService.getBoolean(HAS_PROMPTED_FOR_AUTOMATIC_TASKS, StorageScope.WORKSPACE, undefined); const { tasks, taskNames, locations } = RunAutomaticTasks._findAutoTasks(taskService, workspaceTaskResult); if (taskNames.length > 0) { - // We have automatic tasks, prompt to allow. - this._showPrompt(notificationService, storageService, taskService, openerService, taskNames, locations).then(allow => { - if (allow) { - RunAutomaticTasks._runTasks(taskService, tasks); - } - }); + if (configurationService.getValue(ALLOW_AUTOMATIC_TASKS) === 'on') { + RunAutomaticTasks._runTasks(taskService, tasks); + } else if (!hasShownPromptForAutomaticTasks) { + // We have automatic tasks, prompt to allow. + this._showPrompt(notificationService, storageService, openerService, configurationService, taskNames, locations).then(allow => { + if (allow) { + RunAutomaticTasks._runTasks(taskService, tasks); + } + }); + } } } - private static _showPrompt(notificationService: INotificationService, storageService: IStorageService, taskService: ITaskService, - openerService: IOpenerService, taskNames: Array, locations: Map): Promise { + private static _showPrompt(notificationService: INotificationService, storageService: IStorageService, + openerService: IOpenerService, configurationService: IConfigurationService, taskNames: Array, locations: Map): Promise { return new Promise(resolve => { notificationService.prompt(Severity.Info, nls.localize('tasks.run.allowAutomatic', "This workspace has tasks ({0}) defined ({1}) that run automatically when you open this workspace. Do you allow automatic tasks to run when you open this workspace?", @@ -162,14 +166,15 @@ export class RunAutomaticTasks extends Disposable implements IWorkbenchContribut label: nls.localize('allow', "Allow and run"), run: () => { resolve(true); - storageService.store(ARE_AUTOMATIC_TASKS_ALLOWED_IN_WORKSPACE, true, StorageScope.WORKSPACE, StorageTarget.MACHINE); + configurationService.updateValue(ALLOW_AUTOMATIC_TASKS, true, ConfigurationTarget.WORKSPACE); } }, { label: nls.localize('disallow', "Disallow"), run: () => { resolve(false); - storageService.store(ARE_AUTOMATIC_TASKS_ALLOWED_IN_WORKSPACE, false, StorageScope.WORKSPACE, StorageTarget.MACHINE); + configurationService.updateValue(ALLOW_AUTOMATIC_TASKS, false, ConfigurationTarget.WORKSPACE); + } }, { @@ -182,9 +187,9 @@ export class RunAutomaticTasks extends Disposable implements IWorkbenchContribut } }] ); + storageService.store(HAS_PROMPTED_FOR_AUTOMATIC_TASKS, true, StorageScope.WORKSPACE, StorageTarget.MACHINE); }); } - } export class ManageAutomaticTaskRunning extends Action2 { @@ -202,14 +207,13 @@ export class ManageAutomaticTaskRunning extends Action2 { public async run(accessor: ServicesAccessor): Promise { const quickInputService = accessor.get(IQuickInputService); - const storageService = accessor.get(IStorageService); + const configurationService = accessor.get(IConfigurationService); const allowItem: IQuickPickItem = { label: nls.localize('workbench.action.tasks.allowAutomaticTasks', "Allow Automatic Tasks in Folder") }; const disallowItem: IQuickPickItem = { label: nls.localize('workbench.action.tasks.disallowAutomaticTasks', "Disallow Automatic Tasks in Folder") }; const value = await quickInputService.pick([allowItem, disallowItem], { canPickMany: false }); if (!value) { return; } - - storageService.store(ARE_AUTOMATIC_TASKS_ALLOWED_IN_WORKSPACE, value === allowItem, StorageScope.WORKSPACE, StorageTarget.MACHINE); + configurationService.updateValue(ALLOW_AUTOMATIC_TASKS, value === allowItem, ConfigurationTarget.WORKSPACE); } } diff --git a/src/vs/workbench/contrib/tasks/browser/task.contribution.ts b/src/vs/workbench/contrib/tasks/browser/task.contribution.ts index 911ee6ec393..00c85294b7b 100644 --- a/src/vs/workbench/contrib/tasks/browser/task.contribution.ts +++ b/src/vs/workbench/contrib/tasks/browser/task.contribution.ts @@ -496,6 +496,18 @@ configurationRegistry.registerConfiguration({ description: nls.localize('task.quickOpen.showAll', "Causes the Tasks: Run Task command to use the slower \"show all\" behavior instead of the faster two level picker where tasks are grouped by provider."), default: false }, + [TaskSettingId.AllowAutomaticTasks]: { + type: 'string', + enum: ['on', 'auto', 'off'], + enumDescriptions: [ + nls.localize('ttask.allowAutomaticTasks.on', "Always"), + nls.localize('task.allowAutomaticTasks.auto', "Prompt for permission for each folder"), + nls.localize('task.allowAutomaticTasks.off', "Never"), + ], + description: nls.localize('task.allowAutomaticTasks', "Enable automatic tasks in the folder."), + default: 'auto', + restricted: true + }, [TaskSettingId.ShowDecorations]: { type: 'boolean', description: nls.localize('task.showDecorations', "Shows decorations at points of interest in the terminal buffer such as the first problem found via a watch task. Note that this will only take effect for future tasks."), diff --git a/src/vs/workbench/contrib/tasks/common/tasks.ts b/src/vs/workbench/contrib/tasks/common/tasks.ts index 2300c659cb0..5877beb6437 100644 --- a/src/vs/workbench/contrib/tasks/common/tasks.ts +++ b/src/vs/workbench/contrib/tasks/common/tasks.ts @@ -1199,7 +1199,8 @@ export const enum TaskSettingId { QuickOpenHistory = 'task.quickOpen.history', QuickOpenDetail = 'task.quickOpen.detail', QuickOpenSkip = 'task.quickOpen.skip', - QuickOpenShowAll = 'task.quickOpen.showAll' + QuickOpenShowAll = 'task.quickOpen.showAll', + AllowAutomaticTasks = 'task.allowAutomaticTasks' } export const enum TasksSchemaProperties { From 1cc52ae41064ad363a214e7e0c67921b64e9c8df Mon Sep 17 00:00:00 2001 From: Raymond Zhao <7199958+rzhao271@users.noreply.github.com> Date: Thu, 7 Jul 2022 11:01:16 -0700 Subject: [PATCH 342/347] Fix broken Not Synced indicator (#154381) Fixes #154379 --- .../browser/settingsEditorSettingIndicators.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/contrib/preferences/browser/settingsEditorSettingIndicators.ts b/src/vs/workbench/contrib/preferences/browser/settingsEditorSettingIndicators.ts index a10179c4ac7..bbb035a2c99 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsEditorSettingIndicators.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsEditorSettingIndicators.ts @@ -51,12 +51,6 @@ export class SettingsTreeIndicatorsLabel implements IDisposable { this.indicatorsContainerElement = DOM.append(container, $('.misc-label')); this.indicatorsContainerElement.style.display = 'inline'; - const scopeOverridesIndicator = this.createScopeOverridesIndicator(); - this.scopeOverridesElement = scopeOverridesIndicator.element; - this.scopeOverridesLabel = scopeOverridesIndicator.label; - this.syncIgnoredElement = this.createSyncIgnoredElement(); - this.defaultOverrideIndicatorElement = this.createDefaultOverrideIndicator(); - this.hoverDelegate = { showHover: (options: IHoverDelegateOptions, focus?: boolean) => { return hoverService.showHover(options, focus); @@ -65,6 +59,12 @@ export class SettingsTreeIndicatorsLabel implements IDisposable { delay: configurationService.getValue('workbench.hover.delay'), placement: 'element' }; + + const scopeOverridesIndicator = this.createScopeOverridesIndicator(); + this.scopeOverridesElement = scopeOverridesIndicator.element; + this.scopeOverridesLabel = scopeOverridesIndicator.label; + this.syncIgnoredElement = this.createSyncIgnoredElement(); + this.defaultOverrideIndicatorElement = this.createDefaultOverrideIndicator(); } private createScopeOverridesIndicator(): { element: HTMLElement; label: SimpleIconLabel } { From 368400c1907a62a920b7a94ee10ff74a083f34c5 Mon Sep 17 00:00:00 2001 From: Andrea Mah <31675041+andreamah@users.noreply.github.com> Date: Thu, 7 Jul 2022 11:01:33 -0700 Subject: [PATCH 343/347] Check save settings before debug restart (#154206) * Fix bug: Files automatically saved when restarting debugger, even though it is set not to Fixes #149885 --- src/vs/workbench/api/browser/mainThreadDebugService.ts | 7 ++++--- .../workbench/contrib/debug/browser/debugCommands.ts | 2 +- src/vs/workbench/contrib/debug/browser/debugService.ts | 10 ++++++++-- src/vs/workbench/contrib/debug/browser/debugSession.ts | 4 ++++ src/vs/workbench/contrib/debug/common/debug.ts | 4 +++- .../workbench/contrib/debug/test/browser/mockDebug.ts | 4 ++++ 6 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadDebugService.ts b/src/vs/workbench/api/browser/mainThreadDebugService.ts index c0ec9d1b550..1b0e0389246 100644 --- a/src/vs/workbench/api/browser/mainThreadDebugService.ts +++ b/src/vs/workbench/api/browser/mainThreadDebugService.ts @@ -223,6 +223,7 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb const folderUri = folder ? uri.revive(folder) : undefined; const launch = this.debugService.getConfigurationManager().getLaunch(folderUri); const parentSession = this.getSession(options.parentSessionID); + const saveBeforeStart = typeof options.suppressSaveBeforeStart === 'boolean' ? !options.suppressSaveBeforeStart : undefined; const debugOptions: IDebugSessionOptions = { noDebug: options.noDebug, parentSession, @@ -230,11 +231,11 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb repl: options.repl, compact: options.compact, debugUI: options.debugUI, - compoundRoot: parentSession?.compoundRoot + compoundRoot: parentSession?.compoundRoot, + saveBeforeStart: saveBeforeStart }; try { - const saveBeforeStart = typeof options.suppressSaveBeforeStart === 'boolean' ? !options.suppressSaveBeforeStart : undefined; - return this.debugService.startDebugging(launch, nameOrConfig, debugOptions, saveBeforeStart); + return this.debugService.startDebugging(launch, nameOrConfig, debugOptions); } catch (err) { throw new ErrorNoTelemetry(err && err.message ? err.message : 'cannot start debugging'); } diff --git a/src/vs/workbench/contrib/debug/browser/debugCommands.ts b/src/vs/workbench/contrib/debug/browser/debugCommands.ts index 25da3464ac6..596bbd9c32d 100644 --- a/src/vs/workbench/contrib/debug/browser/debugCommands.ts +++ b/src/vs/workbench/contrib/debug/browser/debugCommands.ts @@ -723,7 +723,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ const { launch, name, getConfig } = debugService.getConfigurationManager().selectedConfiguration; const config = await getConfig(); const configOrName = config ? Object.assign(deepClone(config), debugStartOptions?.config) : name; - await debugService.startDebugging(launch, configOrName, { noDebug: debugStartOptions?.noDebug, startedByUser: true }, false); + await debugService.startDebugging(launch, configOrName, { noDebug: debugStartOptions?.noDebug, startedByUser: true, saveBeforeStart: false }); } }); diff --git a/src/vs/workbench/contrib/debug/browser/debugService.ts b/src/vs/workbench/contrib/debug/browser/debugService.ts index b308716a8bb..2474922a5ad 100644 --- a/src/vs/workbench/contrib/debug/browser/debugService.ts +++ b/src/vs/workbench/contrib/debug/browser/debugService.ts @@ -312,7 +312,10 @@ export class DebugService implements IDebugService { * main entry point * properly manages compounds, checks for errors and handles the initializing state. */ - async startDebugging(launch: ILaunch | undefined, configOrName?: IConfig | string, options?: IDebugSessionOptions, saveBeforeStart = !options?.parentSession): Promise { + async startDebugging(launch: ILaunch | undefined, configOrName?: IConfig | string, options?: IDebugSessionOptions): Promise { + + const saveBeforeStart = options?.saveBeforeStart ?? !options?.parentSession; + const message = options && options.noDebug ? nls.localize('runTrust', "Running executes build tasks and program code from your workspace.") : nls.localize('debugTrust', "Debugging executes build tasks and program code from your workspace."); const trust = await this.workspaceTrustRequestService.requestWorkspaceTrust({ message }); if (!trust) { @@ -701,7 +704,10 @@ export class DebugService implements IDebugService { } async restartSession(session: IDebugSession, restartData?: any): Promise { - await this.editorService.saveAll(); + if (session.saveBeforeStart) { + await saveAllBeforeDebugStart(this.configurationService, this.editorService); + } + const isAutoRestart = !!restartData; const runTasks: () => Promise = async () => { diff --git a/src/vs/workbench/contrib/debug/browser/debugSession.ts b/src/vs/workbench/contrib/debug/browser/debugSession.ts index de26f713ef0..29a568d478b 100644 --- a/src/vs/workbench/contrib/debug/browser/debugSession.ts +++ b/src/vs/workbench/contrib/debug/browser/debugSession.ts @@ -164,6 +164,10 @@ export class DebugSession implements IDebugSession { return !!this._options.compact; } + get saveBeforeStart(): boolean { + return this._options.saveBeforeStart ?? !this._options?.parentSession; + } + get compoundRoot(): DebugCompoundRoot | undefined { return this._options.compoundRoot; } diff --git a/src/vs/workbench/contrib/debug/common/debug.ts b/src/vs/workbench/contrib/debug/common/debug.ts index a8397f69aef..21dc92d475c 100644 --- a/src/vs/workbench/contrib/debug/common/debug.ts +++ b/src/vs/workbench/contrib/debug/common/debug.ts @@ -206,6 +206,7 @@ export interface IDebugSessionOptions { simple?: boolean; }; startedByUser?: boolean; + saveBeforeStart?: boolean; } export interface IDataBreakpointInfoResponse { @@ -296,6 +297,7 @@ export interface IDebugSession extends ITreeElement { readonly subId: string | undefined; readonly compact: boolean; readonly compoundRoot: DebugCompoundRoot | undefined; + readonly saveBeforeStart: boolean; readonly name: string; readonly isSimpleUI: boolean; readonly autoExpandLazyVariables: boolean; @@ -1088,7 +1090,7 @@ export interface IDebugService { * Returns true if the start debugging was successful. For compound launches, all configurations have to start successfully for it to return success. * On errors the startDebugging will throw an error, however some error and cancelations are handled and in that case will simply return false. */ - startDebugging(launch: ILaunch | undefined, configOrName?: IConfig | string, options?: IDebugSessionOptions, saveBeforeStart?: boolean): Promise; + startDebugging(launch: ILaunch | undefined, configOrName?: IConfig | string, options?: IDebugSessionOptions): Promise; /** * Restarts a session or creates a new one if there is no active session. diff --git a/src/vs/workbench/contrib/debug/test/browser/mockDebug.ts b/src/vs/workbench/contrib/debug/test/browser/mockDebug.ts index 1bebaa31adb..1596e346e31 100644 --- a/src/vs/workbench/contrib/debug/test/browser/mockDebug.ts +++ b/src/vs/workbench/contrib/debug/test/browser/mockDebug.ts @@ -190,6 +190,10 @@ export class MockSession implements IDebugSession { return undefined; } + get saveBeforeStart(): boolean { + return true; + } + get isSimpleUI(): boolean { return false; } From d5379b5e34e4bb0f5ddb33688da91f787ebc159f Mon Sep 17 00:00:00 2001 From: Raymond Zhao <7199958+rzhao271@users.noreply.github.com> Date: Thu, 7 Jul 2022 11:14:03 -0700 Subject: [PATCH 344/347] Fix more settings description setting links (#154383) Ref #154317 --- src/vs/editor/common/config/editorOptions.ts | 12 ++++++------ src/vs/workbench/browser/workbench.contribution.ts | 10 +++++----- .../contrib/files/browser/files.contribution.ts | 6 +++--- .../notebook/browser/notebook.contribution.ts | 6 +++--- .../contrib/remote/common/remote.contribution.ts | 4 ++-- .../contrib/search/browser/search.contribution.ts | 2 +- 6 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/vs/editor/common/config/editorOptions.ts b/src/vs/editor/common/config/editorOptions.ts index 2158431d8b1..7292a7e132b 100644 --- a/src/vs/editor/common/config/editorOptions.ts +++ b/src/vs/editor/common/config/editorOptions.ts @@ -2562,12 +2562,12 @@ class EditorInlayHints extends BaseEditorOption(ConfigurationExtensions.Con }, 'workbench.editor.restoreViewState': { 'type': 'boolean', - 'markdownDescription': localize('restoreViewState', "Restores the last editor view state (e.g. scroll position) when re-opening editors after they have been closed. Editor view state is stored per editor group and discarded when a group closes. Use the `#workbench.editor.sharedViewState#` setting to use the last known view state across all editor groups in case no previous view state was found for a editor group."), + 'markdownDescription': localize('restoreViewState', "Restores the last editor view state (e.g. scroll position) when re-opening editors after they have been closed. Editor view state is stored per editor group and discarded when a group closes. Use the {0} setting to use the last known view state across all editor groups in case no previous view state was found for a editor group.", '`#workbench.editor.sharedViewState#`'), 'default': true, 'scope': ConfigurationScope.LANGUAGE_OVERRIDABLE }, @@ -278,7 +278,7 @@ const registry = Registry.as(ConfigurationExtensions.Con 'type': 'number', 'default': 10, 'exclusiveMinimum': 0, - 'markdownDescription': localize('limitEditorsMaximum', "Controls the maximum number of opened editors. Use the `#workbench.editor.limit.perEditorGroup#` setting to control this limit per editor group or across all groups.") + 'markdownDescription': localize('limitEditorsMaximum', "Controls the maximum number of opened editors. Use the {0} setting to control this limit per editor group or across all groups.", '`#workbench.editor.limit.perEditorGroup#`') }, 'workbench.editor.limit.excludeDirty': { 'type': 'boolean', @@ -540,12 +540,12 @@ const registry = Registry.as(ConfigurationExtensions.Con 'window.titleSeparator': { 'type': 'string', 'default': isMacintosh ? ' \u2014 ' : ' - ', - 'markdownDescription': localize("window.titleSeparator", "Separator used by `window.title`.") + 'markdownDescription': localize("window.titleSeparator", "Separator used by {0}.", '`#window.title#`') }, 'window.commandCenter': { type: 'boolean', default: false, - markdownDescription: localize('window.commandCenter', "Show command launcher together with the window title. This setting only has an effect when `#window.titleBarStyle#` is set to `custom`.") + markdownDescription: localize('window.commandCenter', "Show command launcher together with the window title. This setting only has an effect when {0} is set to {1}.", '`#window.titleBarStyle#`', '`custom`') }, 'window.menuBarVisibility': { 'type': 'string', @@ -557,7 +557,7 @@ const registry = Registry.as(ConfigurationExtensions.Con localize('window.menuBarVisibility.toggle.mac', "Menu is hidden but can be displayed at the top of the window by executing the `Focus Application Menu` command.") : localize('window.menuBarVisibility.toggle', "Menu is hidden but can be displayed at the top of the window via the Alt key."), localize('window.menuBarVisibility.hidden', "Menu is always hidden."), - localize('window.menuBarVisibility.compact', "Menu is displayed as a compact button in the side bar. This value is ignored when `#window.titleBarStyle#` is `native`.") + localize('window.menuBarVisibility.compact', "Menu is displayed as a compact button in the side bar. This value is ignored when {0} is {1}.", '`#window.titleBarStyle#`', '`native`') ], 'default': isWeb ? 'compact' : 'classic', 'scope': ConfigurationScope.APPLICATION, diff --git a/src/vs/workbench/contrib/files/browser/files.contribution.ts b/src/vs/workbench/contrib/files/browser/files.contribution.ts index 592d559451a..0db2db173e1 100644 --- a/src/vs/workbench/contrib/files/browser/files.contribution.ts +++ b/src/vs/workbench/contrib/files/browser/files.contribution.ts @@ -185,7 +185,7 @@ configurationRegistry.registerConfiguration({ 'files.autoGuessEncoding': { 'type': 'boolean', 'default': false, - 'markdownDescription': nls.localize('autoGuessEncoding', "When enabled, the editor will attempt to guess the character set encoding when opening files. This setting can also be configured per language. Note, this setting is not respected by text search. Only `#files.encoding#` is respected."), + 'markdownDescription': nls.localize('autoGuessEncoding', "When enabled, the editor will attempt to guess the character set encoding when opening files. This setting can also be configured per language. Note, this setting is not respected by text search. Only {0} is respected.", '`#files.encoding#`'), 'scope': ConfigurationScope.LANGUAGE_OVERRIDABLE }, 'files.eol': { @@ -475,7 +475,7 @@ configurationRegistry.registerConfiguration({ }, 'explorer.excludeGitIgnore': { type: 'boolean', - markdownDescription: nls.localize('excludeGitignore', "Controls whether entries in .gitignore should be parsed and excluded from the explorer. Similar to `#files.exclude#`."), + markdownDescription: nls.localize('excludeGitignore', "Controls whether entries in .gitignore should be parsed and excluded from the explorer. Similar to {0}.", '`#files.exclude#`'), default: false, scope: ConfigurationScope.RESOURCE }, @@ -487,7 +487,7 @@ configurationRegistry.registerConfiguration({ }, 'explorer.fileNesting.expand': { 'type': 'boolean', - 'markdownDescription': nls.localize('fileNestingExpand', "Controls whether file nests are automatically expanded. `#explorer.fileNesting.enabled#` must be set for this to take effect."), + 'markdownDescription': nls.localize('fileNestingExpand', "Controls whether file nests are automatically expanded. {0} must be set for this to take effect.", '`#explorer.fileNesting.enabled#`'), 'default': true, }, 'explorer.fileNesting.patterns': { diff --git a/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts b/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts index 6111d9f1caa..33bf079467f 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts @@ -881,7 +881,7 @@ configurationRegistry.registerConfiguration({ tags: ['notebookLayout'] }, [NotebookSetting.markupFontSize]: { - markdownDescription: nls.localize('notebook.markup.fontSize', "Controls the font size in pixels of rendered markup in notebooks. When set to `0`, 120% of `#editor.fontSize#` is used."), + markdownDescription: nls.localize('notebook.markup.fontSize', "Controls the font size in pixels of rendered markup in notebooks. When set to {0}, 120% of {1} is used.", '`0`', '`#editor.fontSize#`'), type: 'number', default: 0, tags: ['notebookLayout'] @@ -900,13 +900,13 @@ configurationRegistry.registerConfiguration({ tags: ['notebookLayout'] }, [NotebookSetting.outputFontSize]: { - markdownDescription: nls.localize('notebook.outputFontSize', "Font size for the output text for notebook cells. When set to 0 `#editor.fontSize#` is used."), + markdownDescription: nls.localize('notebook.outputFontSize', "Font size for the output text for notebook cells. When set to {0}, {1} is used.", '`0`', '`#editor.fontSize#`'), type: 'number', default: 0, tags: ['notebookLayout'] }, [NotebookSetting.outputFontFamily]: { - markdownDescription: nls.localize('notebook.outputFontFamily', "The font family for the output text for notebook cells. When set to empty, the `#editor.fontFamily#` is used."), + markdownDescription: nls.localize('notebook.outputFontFamily', "The font family for the output text for notebook cells. When set to empty, the {0} is used.", '`#editor.fontFamily#`'), type: 'string', tags: ['notebookLayout'] }, diff --git a/src/vs/workbench/contrib/remote/common/remote.contribution.ts b/src/vs/workbench/contrib/remote/common/remote.contribution.ts index b6488780711..0b2e94b01bc 100644 --- a/src/vs/workbench/contrib/remote/common/remote.contribution.ts +++ b/src/vs/workbench/contrib/remote/common/remote.contribution.ts @@ -353,7 +353,7 @@ Registry.as(ConfigurationExtensions.Configuration) }, 'remote.autoForwardPortsSource': { type: 'string', - markdownDescription: localize('remote.autoForwardPortsSource', "Sets the source from which ports are automatically forwarded when `remote.autoForwardPorts` is true. On Windows and Mac remotes, the `process` option has no effect and `output` will be used. Requires a reload to take effect."), + markdownDescription: localize('remote.autoForwardPortsSource', "Sets the source from which ports are automatically forwarded when {0} is true. On Windows and Mac remotes, the `process` option has no effect and `output` will be used. Requires a reload to take effect.", '`#remote.autoForwardPorts#`'), enum: ['process', 'output'], enumDescriptions: [ localize('remote.autoForwardPortsSource.process', "Ports will be automatically forwarded when discovered by watching for processes that are started and include a port."), @@ -463,7 +463,7 @@ Registry.as(ConfigurationExtensions.Configuration) } }, defaultSnippets: [{ body: { onAutoForward: 'ignore' } }], - markdownDescription: localize('remote.portsAttributes.defaults', "Set default properties that are applied to all ports that don't get properties from the setting `remote.portsAttributes`. For example:\n\n```\n{\n \"onAutoForward\": \"ignore\"\n}\n```"), + markdownDescription: localize('remote.portsAttributes.defaults', "Set default properties that are applied to all ports that don't get properties from the setting {0}. For example:\n\n```\n{\n \"onAutoForward\": \"ignore\"\n}\n```", '`#remote.portsAttributes#`'), additionalProperties: false }, 'remote.localPortHost': { diff --git a/src/vs/workbench/contrib/search/browser/search.contribution.ts b/src/vs/workbench/contrib/search/browser/search.contribution.ts index 08f7dc2cf25..54450eb71c4 100644 --- a/src/vs/workbench/contrib/search/browser/search.contribution.ts +++ b/src/vs/workbench/contrib/search/browser/search.contribution.ts @@ -996,7 +996,7 @@ configurationRegistry.registerConfiguration({ 'search.searchOnTypeDebouncePeriod': { type: 'number', default: 300, - markdownDescription: nls.localize('search.searchOnTypeDebouncePeriod', "When `#search.searchOnType#` is enabled, controls the timeout in milliseconds between a character being typed and the search starting. Has no effect when `search.searchOnType` is disabled.") + markdownDescription: nls.localize('search.searchOnTypeDebouncePeriod', "When {0} is enabled, controls the timeout in milliseconds between a character being typed and the search starting. Has no effect when {0} is disabled.", '`#search.searchOnType#`') }, 'search.searchEditor.doubleClickBehaviour': { type: 'string', From bc0bdc5d0969030f114d5931b18e134059da00c1 Mon Sep 17 00:00:00 2001 From: Raymond Zhao <7199958+rzhao271@users.noreply.github.com> Date: Thu, 7 Jul 2022 11:55:35 -0700 Subject: [PATCH 345/347] Fix hover underline issue on "Modified in" label (#154386) Fixes #154385 --- .../contrib/preferences/browser/media/settingsEditor2.css | 2 +- .../preferences/browser/settingsEditorSettingIndicators.ts | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css b/src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css index d44eec7e5d5..11f242b2646 100644 --- a/src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css +++ b/src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css @@ -351,7 +351,7 @@ font-style: italic; } -.settings-editor > .settings-body .settings-tree-container .setting-item-contents .setting-item-title > .misc-label .setting-item-overrides:hover, +.settings-editor > .settings-body .settings-tree-container .setting-item-contents .setting-item-title > .misc-label .setting-item-overrides.with-custom-hover:hover, .settings-editor > .settings-body .settings-tree-container .setting-item-contents .setting-item-title > .misc-label .setting-item-ignored:hover, .settings-editor > .settings-body .settings-tree-container .setting-item-contents .setting-item-title > .misc-label .setting-item-default-overridden:hover { text-decoration: underline; diff --git a/src/vs/workbench/contrib/preferences/browser/settingsEditorSettingIndicators.ts b/src/vs/workbench/contrib/preferences/browser/settingsEditorSettingIndicators.ts index bbb035a2c99..ae71ad571f6 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsEditorSettingIndicators.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsEditorSettingIndicators.ts @@ -139,6 +139,7 @@ export class SettingsTreeIndicatorsLabel implements IDisposable { // Render inline if we have the flag and there are scope overrides to render, // or if there is only one scope override to render and no language overrides. this.scopeOverridesElement.style.display = 'inline'; + this.scopeOverridesElement.classList.remove('with-custom-hover'); this.hover?.dispose(); // Just show all the text in the label. @@ -170,6 +171,7 @@ export class SettingsTreeIndicatorsLabel implements IDisposable { // show the text in a custom hover only if // the feature flag isn't on. this.scopeOverridesElement.style.display = 'inline'; + this.scopeOverridesElement.classList.add('with-custom-hover'); const scopeOverridesLabelText = element.isConfigured ? localize('alsoConfiguredElsewhere', "Also modified elsewhere") : localize('configuredElsewhere', "Modified elsewhere"); From eb2e5d855895b9cfdd6e3b81177897046281f882 Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com> Date: Thu, 7 Jul 2022 21:31:10 +0200 Subject: [PATCH 346/347] Git - Commit action button should use smart commit settings (#154169) Consider smart commit settings when rendering the commit action button --- extensions/git/src/actionButton.ts | 61 +++++++++++++++++++++++------- 1 file changed, 47 insertions(+), 14 deletions(-) diff --git a/extensions/git/src/actionButton.ts b/extensions/git/src/actionButton.ts index eaa93ccbe8c..856280b414a 100644 --- a/extensions/git/src/actionButton.ts +++ b/extensions/git/src/actionButton.ts @@ -3,11 +3,11 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Disposable, Event, EventEmitter, SourceControlActionButton, Uri, workspace } from 'vscode'; import * as nls from 'vscode-nls'; +import { Disposable, Event, EventEmitter, SourceControlActionButton, Uri, workspace } from 'vscode'; +import { Branch, Status } from './api/git'; import { Repository, Operation } from './repository'; import { dispose } from './util'; -import { Branch } from './api/git'; const localize = nls.loadMessageBundle(); @@ -16,7 +16,7 @@ interface ActionButtonState { readonly isCommitInProgress: boolean; readonly isMergeInProgress: boolean; readonly isSyncInProgress: boolean; - readonly repositoryHasChanges: boolean; + readonly repositoryHasChangesToCommit: boolean; } export class ActionButtonCommand { @@ -40,7 +40,7 @@ export class ActionButtonCommand { isCommitInProgress: false, isMergeInProgress: false, isSyncInProgress: false, - repositoryHasChanges: false + repositoryHasChangesToCommit: false }; repository.onDidRunGitStatus(this.onDidRunGitStatus, this, this.disposables); @@ -48,11 +48,16 @@ export class ActionButtonCommand { const root = Uri.file(repository.root); this.disposables.push(workspace.onDidChangeConfiguration(e => { + if (e.affectsConfiguration('git.enableSmartCommit', root) || + e.affectsConfiguration('git.smartCommitChanges', root) || + e.affectsConfiguration('git.suggestSmartCommit', root)) { + this.onDidChangeSmartCommitSettings(); + } + if (e.affectsConfiguration('git.branchProtection', root) || e.affectsConfiguration('git.branchProtectionPrompt', root) || e.affectsConfiguration('git.postCommitCommand', root) || - e.affectsConfiguration('git.showActionButton', root) - ) { + e.affectsConfiguration('git.showActionButton', root)) { this._onDidChange.fire(); } })); @@ -63,7 +68,7 @@ export class ActionButtonCommand { let actionButton: SourceControlActionButton | undefined; - if (this.state.repositoryHasChanges) { + if (this.state.repositoryHasChangesToCommit) { // Commit Changes (enabled) actionButton = this.getCommitActionButton(); } @@ -160,7 +165,7 @@ export class ActionButtonCommand { }, ] ], - enabled: this.state.repositoryHasChanges && !this.state.isCommitInProgress && !this.state.isMergeInProgress + enabled: this.state.repositoryHasChangesToCommit && !this.state.isCommitInProgress && !this.state.isMergeInProgress }; } @@ -223,19 +228,47 @@ export class ActionButtonCommand { this.state = { ...this.state, isCommitInProgress, isSyncInProgress }; } + private onDidChangeSmartCommitSettings(): void { + this.state = { + ...this.state, + repositoryHasChangesToCommit: this.repositoryHasChangesToCommit() + }; + } + private onDidRunGitStatus(): void { this.state = { ...this.state, HEAD: this.repository.HEAD, - isMergeInProgress: - this.repository.mergeGroup.resourceStates.length !== 0, - repositoryHasChanges: - this.repository.indexGroup.resourceStates.length !== 0 || - this.repository.untrackedGroup.resourceStates.length !== 0 || - this.repository.workingTreeGroup.resourceStates.length !== 0 + isMergeInProgress: this.repository.mergeGroup.resourceStates.length !== 0, + repositoryHasChangesToCommit: this.repositoryHasChangesToCommit() }; } + private repositoryHasChangesToCommit(): boolean { + const config = workspace.getConfiguration('git', Uri.file(this.repository.root)); + const enableSmartCommit = config.get('enableSmartCommit') === true; + const suggestSmartCommit = config.get('suggestSmartCommit') === true; + const smartCommitChanges = config.get<'all' | 'tracked'>('smartCommitChanges', 'all'); + + const resources = [...this.repository.indexGroup.resourceStates]; + + if ( + // Smart commit enabled (all) + (enableSmartCommit && smartCommitChanges === 'all') || + // Smart commit disabled, smart suggestion enabled + (!enableSmartCommit && suggestSmartCommit) + ) { + resources.push(...this.repository.workingTreeGroup.resourceStates); + } + + // Smart commit enabled (tracked only) + if (enableSmartCommit && smartCommitChanges === 'tracked') { + resources.push(...this.repository.workingTreeGroup.resourceStates.filter(r => r.type !== Status.UNTRACKED)); + } + + return resources.length !== 0; + } + dispose(): void { this.disposables = dispose(this.disposables); } From 00eb9c4356c520299e7e2c95eb2089698b30b7fd Mon Sep 17 00:00:00 2001 From: Tyler James Leonhardt Date: Thu, 7 Jul 2022 13:38:32 -0700 Subject: [PATCH 347/347] Polish up restart dialogs and switch to using Language instead of language (#154382) --- .../localization/browser/localeService.ts | 51 ++++++++++++++---- .../browser/localizationsActions.ts | 39 +------------- .../contrib/localization/common/locale.ts | 4 +- .../electron-sandbox/localeService.ts | 52 ++++++++++++++----- 4 files changed, 83 insertions(+), 63 deletions(-) diff --git a/src/vs/workbench/contrib/localization/browser/localeService.ts b/src/vs/workbench/contrib/localization/browser/localeService.ts index c59d84821b2..4768a1752b4 100644 --- a/src/vs/workbench/contrib/localization/browser/localeService.ts +++ b/src/vs/workbench/contrib/localization/browser/localeService.ts @@ -3,31 +3,62 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { language } from 'vs/base/common/platform'; +import { localize } from 'vs/nls'; +import { Language } from 'vs/base/common/platform'; +import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { ILanguagePackItem } from 'vs/platform/languagePacks/common/languagePacks'; import { ILocaleService } from 'vs/workbench/contrib/localization/common/locale'; +import { IHostService } from 'vs/workbench/services/host/browser/host'; +import { IProductService } from 'vs/platform/product/common/productService'; export class WebLocaleService implements ILocaleService { declare readonly _serviceBrand: undefined; - async setLocale(languagePackItem: ILanguagePackItem): Promise { + constructor( + @IDialogService private readonly dialogService: IDialogService, + @IHostService private readonly hostService: IHostService, + @IProductService private readonly productService: IProductService + ) { } + + async setLocale(languagePackItem: ILanguagePackItem): Promise { const locale = languagePackItem.id; - if (locale === language || (!locale && language === navigator.language)) { - return false; + if (locale === Language.value() || (!locale && Language.value() === navigator.language)) { + return; } if (locale) { window.localStorage.setItem('vscode.nls.locale', locale); } else { window.localStorage.removeItem('vscode.nls.locale'); } - return true; + + const restartDialog = await this.dialogService.confirm({ + type: 'info', + message: localize('relaunchDisplayLanguageMessage', "{0} needs to reload to change the display language", this.productService.nameLong), + detail: localize('relaunchDisplayLanguageDetail', "Press the reload button to refresh the page and set the display language to {0}.", languagePackItem.label), + primaryButton: localize({ key: 'reload', comment: ['&& denotes a mnemonic character'] }, "&&Reload"), + }); + + if (restartDialog.confirmed) { + this.hostService.restart(); + } } - async clearLocalePreference(): Promise { - if (language === navigator.language) { - return false; - } + async clearLocalePreference(): Promise { window.localStorage.removeItem('vscode.nls.locale'); - return true; + + if (Language.value() === navigator.language) { + return; + } + + const restartDialog = await this.dialogService.confirm({ + type: 'info', + message: localize('clearDisplayLanguageMessage', "{0} needs to reload to change the display language", this.productService.nameLong), + detail: localize('clearDisplayLanguageDetail', "Press the reload button to refresh the page and use your browser's language."), + primaryButton: localize({ key: 'reload', comment: ['&& denotes a mnemonic character'] }, "&&Reload"), + }); + + if (restartDialog.confirmed) { + this.hostService.restart(); + } } } diff --git a/src/vs/workbench/contrib/localization/browser/localizationsActions.ts b/src/vs/workbench/contrib/localization/browser/localizationsActions.ts index 5bdb7500724..2be6435942d 100644 --- a/src/vs/workbench/contrib/localization/browser/localizationsActions.ts +++ b/src/vs/workbench/contrib/localization/browser/localizationsActions.ts @@ -5,9 +5,6 @@ import { localize } from 'vs/nls'; import { IQuickInputService, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput'; -import { IHostService } from 'vs/workbench/services/host/browser/host'; -import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; -import { IProductService } from 'vs/platform/product/common/productService'; import { CancellationTokenSource } from 'vs/base/common/cancellation'; import { DisposableStore } from 'vs/base/common/lifecycle'; import { Action2, MenuId } from 'vs/platform/actions/common/actions'; @@ -15,8 +12,6 @@ import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation import { ILanguagePackItem, ILanguagePackService } from 'vs/platform/languagePacks/common/languagePacks'; import { ILocaleService } from 'vs/workbench/contrib/localization/common/locale'; -const restart = localize('restart', "&&Restart"); - export class ConfigureDisplayLanguageAction extends Action2 { public static readonly ID = 'workbench.action.configureLocale'; public static readonly LABEL = localize('configureLocale', "Configure Display Language"); @@ -34,9 +29,6 @@ export class ConfigureDisplayLanguageAction extends Action2 { public async run(accessor: ServicesAccessor): Promise { const languagePackService: ILanguagePackService = accessor.get(ILanguagePackService); const quickInputService: IQuickInputService = accessor.get(IQuickInputService); - const hostService: IHostService = accessor.get(IHostService); - const dialogService: IDialogService = accessor.get(IDialogService); - const productService: IProductService = accessor.get(IProductService); const localeService: ILocaleService = accessor.get(ILocaleService); const installedLanguages = await languagePackService.getInstalledLanguages(); @@ -72,19 +64,7 @@ export class ConfigureDisplayLanguageAction extends Action2 { disposables.add(qp.onDidAccept(async () => { const selectedLanguage = qp.activeItems[0]; qp.hide(); - - if (await localeService.setLocale(selectedLanguage)) { - const restartDialog = await dialogService.confirm({ - type: 'info', - message: localize('relaunchDisplayLanguageMessage', "A restart is required for the change in display language to take effect."), - detail: localize('relaunchDisplayLanguageDetail', "Press the restart button to restart {0} and change the display language.", productService.nameLong), - primaryButton: restart - }); - - if (restartDialog.confirmed) { - hostService.restart(); - } - } + await localeService.setLocale(selectedLanguage); })); qp.show(); @@ -108,21 +88,6 @@ export class ClearDisplayLanguageAction extends Action2 { public async run(accessor: ServicesAccessor): Promise { const localeService: ILocaleService = accessor.get(ILocaleService); - const dialogService: IDialogService = accessor.get(IDialogService); - const productService: IProductService = accessor.get(IProductService); - const hostService: IHostService = accessor.get(IHostService); - - if (await localeService.clearLocalePreference()) { - const restartDialog = await dialogService.confirm({ - type: 'info', - message: localize('relaunchAfterClearDisplayLanguageMessage', "A restart is required for the change in display language to take effect."), - detail: localize('relaunchAfterClearDisplayLanguageDetail', "Press the restart button to restart {0} and change the display language.", productService.nameLong), - primaryButton: restart - }); - - if (restartDialog.confirmed) { - hostService.restart(); - } - } + await localeService.clearLocalePreference(); } } diff --git a/src/vs/workbench/contrib/localization/common/locale.ts b/src/vs/workbench/contrib/localization/common/locale.ts index f447d40bc41..f2e8417c443 100644 --- a/src/vs/workbench/contrib/localization/common/locale.ts +++ b/src/vs/workbench/contrib/localization/common/locale.ts @@ -10,6 +10,6 @@ export const ILocaleService = createDecorator('localizationServi export interface ILocaleService { readonly _serviceBrand: undefined; - setLocale(languagePackItem: ILanguagePackItem): Promise; - clearLocalePreference(): Promise; + setLocale(languagePackItem: ILanguagePackItem): Promise; + clearLocalePreference(): Promise; } diff --git a/src/vs/workbench/contrib/localization/electron-sandbox/localeService.ts b/src/vs/workbench/contrib/localization/electron-sandbox/localeService.ts index 00a6ec7036f..59b10dc5fcf 100644 --- a/src/vs/workbench/contrib/localization/electron-sandbox/localeService.ts +++ b/src/vs/workbench/contrib/localization/electron-sandbox/localeService.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { language } from 'vs/base/common/platform'; +import { Language } from 'vs/base/common/platform'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; import { IJSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditing'; @@ -19,6 +19,9 @@ import { toAction } from 'vs/base/common/actions'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { stripComments } from 'vs/base/common/stripComments'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { IHostService } from 'vs/workbench/services/host/browser/host'; +import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; +import { IProductService } from 'vs/platform/product/common/productService'; export class NativeLocaleService implements ILocaleService { _serviceBrand: undefined; @@ -32,7 +35,10 @@ export class NativeLocaleService implements ILocaleService { @IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService, @IProgressService private readonly progressService: IProgressService, @ITextFileService private readonly textFileService: ITextFileService, - @IEditorService private readonly editorService: IEditorService + @IEditorService private readonly editorService: IEditorService, + @IDialogService private readonly dialogService: IDialogService, + @IHostService private readonly hostService: IHostService, + @IProductService private readonly productService: IProductService ) { } private async validateLocaleFile(): Promise { @@ -69,10 +75,10 @@ export class NativeLocaleService implements ILocaleService { return true; } - async setLocale(languagePackItem: ILanguagePackItem): Promise { + async setLocale(languagePackItem: ILanguagePackItem): Promise { const locale = languagePackItem.id; - if (locale === language || (!locale && language === 'en')) { - return false; + if (locale === Language.value() || (!locale && Language.isDefaultVariant())) { + return; } const installedLanguages = await this.languagePackService.getInstalledLanguages(); try { @@ -87,7 +93,7 @@ export class NativeLocaleService implements ILocaleService { // as of now, there are no 3rd party language packs available on the Marketplace. const viewlet = await this.paneCompositePartService.openPaneComposite(EXTENSIONS_VIEWLET_ID, ViewContainerLocation.Sidebar); (viewlet?.getViewPaneContainer() as IExtensionsViewPaneContainer).search(`@id:${languagePackItem.extensionId}`); - return false; + return; } await this.progressService.withProgress( @@ -102,22 +108,40 @@ export class NativeLocaleService implements ILocaleService { ); } - return await this.writeLocaleValue(locale); + if (await this.writeLocaleValue(locale)) { + await this.showRestartDialog(languagePackItem.label); + } } catch (err) { this.notificationService.error(err); - return false; } } - async clearLocalePreference(): Promise { - if (language === 'en') { - return false; - } + async clearLocalePreference(): Promise { try { - return await this.writeLocaleValue(undefined); + await this.writeLocaleValue(undefined); + if (!Language.isDefaultVariant()) { + await this.showRestartDialog('English'); + } } catch (err) { this.notificationService.error(err); - return false; + } + } + + private async showRestartDialog(languageName: string) { + const restartDialog = await this.dialogService.confirm({ + type: 'info', + message: localize('restartDisplayLanguageMessage', "{0} needs to restart to change the display language", this.productService.nameLong), + detail: localize( + 'restartDisplayLanguageDetail', + "Press the restart button to restart {0} and set the display language to {1}.", + this.productService.nameLong, + languageName + ), + primaryButton: localize({ key: 'restart', comment: ['&& denotes a mnemonic character'] }, "&&Restart"), + }); + + if (restartDialog.confirmed) { + this.hostService.restart(); } } }