From 31a11d3b786d32e212d1088771ccad51183a12cc Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Fri, 4 Jun 2021 12:15:40 -0700 Subject: [PATCH 01/40] Disable consolidated run button by default. Fix #125544 --- .../workbench/contrib/notebook/browser/notebook.contribution.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts b/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts index 5c000e4c0800a..4bacef840b79a 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts @@ -698,7 +698,7 @@ configurationRegistry.registerConfiguration({ [ConsolidatedRunButton]: { description: nls.localize('notebook.consolidatedRunButton.description', "Control whether extra actions are shown in a dropdown next to the run button."), type: 'boolean', - default: true, + default: false, tags: ['notebookLayout'] }, [NotebookCellEditorOptionsCustomizations]: editorOptionsCustomizationSchema From de98ebbc81e013c50867d4ab06bca85dca42dceb Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Fri, 4 Jun 2021 15:30:46 -0500 Subject: [PATCH 02/40] only show notification once per window reload (#125548) --- .../contrib/terminal/browser/terminalInstance.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 2377fc9bbd048..33ea45275c1b2 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -68,6 +68,8 @@ const NUMBER_OF_FRAMES_TO_MEASURE = 20; const SHOULD_PROMPT_FOR_PROFILE_MIGRATION_KEY = 'terminals.integrated.profile-migration'; +let migrationMessageShown = false; + const enum Constants { /** * The maximum amount of milliseconds to wait for a container before starting to create the @@ -143,8 +145,6 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { private _hasHadInput: boolean; - messageShown: boolean = false; - readonly statusList: ITerminalStatusList = new TerminalStatusList(); disableLayout: boolean = false; get instanceId(): number { return this._instanceId; } @@ -362,7 +362,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { const shouldMigrateToProfile = (!!this._configurationService.getValue(TerminalSettingPrefix.Shell + platform) || !!this._configurationService.inspect(TerminalSettingPrefix.ShellArgs + platform).userValue) && !!this._configurationService.getValue(TerminalSettingPrefix.DefaultProfile + platform); - if (shouldMigrateToProfile && this._storageService.getBoolean(SHOULD_PROMPT_FOR_PROFILE_MIGRATION_KEY, StorageScope.WORKSPACE, true) && !this.messageShown) { + if (shouldMigrateToProfile && this._storageService.getBoolean(SHOULD_PROMPT_FOR_PROFILE_MIGRATION_KEY, StorageScope.WORKSPACE, true) && !migrationMessageShown) { this._notificationService.prompt( Severity.Info, nls.localize('terminalProfileMigration', "The terminal is using deprecated shell/shellArgs settings, do you want to migrate it to a profile?"), @@ -396,7 +396,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { neverShowAgain: { id: SHOULD_PROMPT_FOR_PROFILE_MIGRATION_KEY, scope: NeverShowAgainScope.WORKSPACE } } ); - this.messageShown = true; + migrationMessageShown = true; } } From ce8505d55808bddc83ecabf8d000ce1aefd5be35 Mon Sep 17 00:00:00 2001 From: Christof Marti Date: Fri, 4 Jun 2021 22:06:15 +0200 Subject: [PATCH 03/40] Add "hostRequirements" to schema (microsoft/vscode-remote-release#5144) --- .../devContainer.schema.generated.json | 110 ++++++++++++++++++ .../schemas/devContainer.schema.src.json | 26 +++++ 2 files changed, 136 insertions(+) diff --git a/extensions/configuration-editing/schemas/devContainer.schema.generated.json b/extensions/configuration-editing/schemas/devContainer.schema.generated.json index 095a0e355f133..112b4e4827953 100644 --- a/extensions/configuration-editing/schemas/devContainer.schema.generated.json +++ b/extensions/configuration-editing/schemas/devContainer.schema.generated.json @@ -357,6 +357,28 @@ "type": "object", "additionalProperties": true, "description": "Codespaces-specific configuration." + }, + "hostRequirements": { + "type": "object", + "description": "Host hardware requirements.", + "properties": { + "cpus": { + "type": "integer", + "minimum": 1, + "description": "Number of required CPUs." + }, + "memory": { + "type": "string", + "pattern": "^\\d+([tgmk]b)?$", + "description": "Amount of required RAM in bytes. Supports units tb, gb, mb and kb." + }, + "storage": { + "type": "string", + "pattern": "^\\d+([tgmk]b)?$", + "description": "Amount of required disk space in bytes. Supports units tb, gb, mb and kb." + } + }, + "additionalProperties": false } }, "required": [ @@ -714,6 +736,28 @@ "type": "object", "additionalProperties": true, "description": "Codespaces-specific configuration." + }, + "hostRequirements": { + "type": "object", + "description": "Host hardware requirements.", + "properties": { + "cpus": { + "type": "integer", + "minimum": 1, + "description": "Number of required CPUs." + }, + "memory": { + "type": "string", + "pattern": "^\\d+([tgmk]b)?$", + "description": "Amount of required RAM in bytes. Supports units tb, gb, mb and kb." + }, + "storage": { + "type": "string", + "pattern": "^\\d+([tgmk]b)?$", + "description": "Amount of required disk space in bytes. Supports units tb, gb, mb and kb." + } + }, + "additionalProperties": false } }, "required": [ @@ -1047,6 +1091,28 @@ "type": "object", "additionalProperties": true, "description": "Codespaces-specific configuration." + }, + "hostRequirements": { + "type": "object", + "description": "Host hardware requirements.", + "properties": { + "cpus": { + "type": "integer", + "minimum": 1, + "description": "Number of required CPUs." + }, + "memory": { + "type": "string", + "pattern": "^\\d+([tgmk]b)?$", + "description": "Amount of required RAM in bytes. Supports units tb, gb, mb and kb." + }, + "storage": { + "type": "string", + "pattern": "^\\d+([tgmk]b)?$", + "description": "Amount of required disk space in bytes. Supports units tb, gb, mb and kb." + } + }, + "additionalProperties": false } }, "required": [ @@ -1346,6 +1412,28 @@ "type": "object", "additionalProperties": true, "description": "Codespaces-specific configuration." + }, + "hostRequirements": { + "type": "object", + "description": "Host hardware requirements.", + "properties": { + "cpus": { + "type": "integer", + "minimum": 1, + "description": "Number of required CPUs." + }, + "memory": { + "type": "string", + "pattern": "^\\d+([tgmk]b)?$", + "description": "Amount of required RAM in bytes. Supports units tb, gb, mb and kb." + }, + "storage": { + "type": "string", + "pattern": "^\\d+([tgmk]b)?$", + "description": "Amount of required disk space in bytes. Supports units tb, gb, mb and kb." + } + }, + "additionalProperties": false } }, "required": [ @@ -1614,6 +1702,28 @@ "type": "object", "additionalProperties": true, "description": "Codespaces-specific configuration." + }, + "hostRequirements": { + "type": "object", + "description": "Host hardware requirements.", + "properties": { + "cpus": { + "type": "integer", + "minimum": 1, + "description": "Number of required CPUs." + }, + "memory": { + "type": "string", + "pattern": "^\\d+([tgmk]b)?$", + "description": "Amount of required RAM in bytes. Supports units tb, gb, mb and kb." + }, + "storage": { + "type": "string", + "pattern": "^\\d+([tgmk]b)?$", + "description": "Amount of required disk space in bytes. Supports units tb, gb, mb and kb." + } + }, + "additionalProperties": false } }, "additionalProperties": false diff --git a/extensions/configuration-editing/schemas/devContainer.schema.src.json b/extensions/configuration-editing/schemas/devContainer.schema.src.json index 3d1536fa7437b..14c13a958b3b2 100644 --- a/extensions/configuration-editing/schemas/devContainer.schema.src.json +++ b/extensions/configuration-editing/schemas/devContainer.schema.src.json @@ -256,6 +256,32 @@ "type": "object", "additionalProperties": true, "description": "Codespaces-specific configuration." + }, + "hostRequirements": { + "type": "object", + "description": "Host hardware requirements.", + "allOf": [ + { + "type": "object", + "properties": { + "cpus": { + "type": "integer", + "minimum": 1, + "description": "Number of required CPUs." + }, + "memory": { + "type": "string", + "pattern": "^\\d+([tgmk]b)?$", + "description": "Amount of required RAM in bytes. Supports units tb, gb, mb and kb." + }, + "storage": { + "type": "string", + "pattern": "^\\d+([tgmk]b)?$", + "description": "Amount of required disk space in bytes. Supports units tb, gb, mb and kb." + } + } + } + ] } } }, From dcc182fe3d219b3c650db7d264c22bcb0b72e0db Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 7 Jun 2021 03:37:00 +0200 Subject: [PATCH 04/40] Revert ESBuild updates and fix #125518 (#125574) * avoid strictNull bypass (fix #125518) * Revert "Update lock file" This reverts commit f843c51bca8e05ee8d026fb81bb5b34825bab941. * Revert "Bump es build" This reverts commit 8d87a664274d23477388e750d40d4ab942c83751. --- build/package.json | 2 +- build/yarn.lock | 8 ++-- .../editor/browser/editorOverrideService.ts | 40 ++++++++----------- 3 files changed, 22 insertions(+), 28 deletions(-) diff --git a/build/package.json b/build/package.json index f683c3241dc13..6e12a9c4abc8e 100644 --- a/build/package.json +++ b/build/package.json @@ -42,7 +42,7 @@ "colors": "^1.4.0", "commander": "^7.0.0", "electron-osx-sign": "^0.4.16", - "esbuild": "^0.12.6", + "esbuild": "^0.12.1", "fs-extra": "^9.1.0", "got": "11.8.1", "iconv-lite-umd": "0.6.8", diff --git a/build/yarn.lock b/build/yarn.lock index b0449db06eebd..07536a575ace9 100644 --- a/build/yarn.lock +++ b/build/yarn.lock @@ -992,10 +992,10 @@ entities@^1.1.1, entities@~1.1.1: resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w== -esbuild@^0.12.6: - version "0.12.6" - resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.12.6.tgz#85bc755c7cf3005d4f34b4f10f98049ce0ee67ce" - integrity sha512-RDvVLvAjsq/kIZJoneMiUOH7EE7t2QaW7T3Q7EdQij14+bZbDq5sndb0tTanmHIFSqZVMBMMyqzVHkS3dJobeA== +esbuild@^0.12.1: + version "0.12.1" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.12.1.tgz#f652d5b3b9432dbb42fc2c034ddd62360296e03d" + integrity sha512-WfQ00MKm/Y4ysz1u9PCUAsV66k5lbrcEvS6aG9jhBIavpB94FBdaWeBkaZXxCZB4w+oqh+j4ozJFWnnFprOXbg== eslint-scope@^5.0.0: version "5.0.0" diff --git a/src/vs/workbench/services/editor/browser/editorOverrideService.ts b/src/vs/workbench/services/editor/browser/editorOverrideService.ts index bd54a0ec39d35..d0eec2dba448b 100644 --- a/src/vs/workbench/services/editor/browser/editorOverrideService.ts +++ b/src/vs/workbench/services/editor/browser/editorOverrideService.ts @@ -10,7 +10,7 @@ import { basename, extname, isEqual } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { EditorActivation, EditorOverride, IEditorOptions } from 'vs/platform/editor/common/editor'; -import { EditorResourceAccessor, IEditorInput, IEditorInputWithOptions, IEditorInputWithOptionsAndGroup } from 'vs/workbench/common/editor'; +import { EditorResourceAccessor, IEditorInput, IEditorInputWithOptions, IEditorInputWithOptionsAndGroup, SideBySideEditor } from 'vs/workbench/common/editor'; import { IEditorGroup, IEditorGroupsService, preferredSideBySideGroupDirection } from 'vs/workbench/services/editor/common/editorGroupsService'; import { Schemas } from 'vs/base/common/network'; import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; @@ -91,11 +91,8 @@ export class EditorOverrideService extends Disposable implements IEditorOverride } // Always ensure inputs have populated resource fields - if (editor instanceof DiffEditorInput) { - if ((!editor.modifiedInput.resource || !editor.originalInput.resource)) { - return { editor, options, group }; - } - } else if (!editor.resource) { + const resource = EditorResourceAccessor.getCanonicalUri(editor, { supportSideBySide: SideBySideEditor.PRIMARY }); + if (!resource) { return { editor, options, group }; } @@ -116,7 +113,7 @@ export class EditorOverrideService extends Disposable implements IEditorOverride } // Resolved the override as much as possible, now find a given contribution - const { contributionPoint, conflictingDefault } = this.getContributionPoint(editor instanceof DiffEditorInput ? editor.modifiedInput.resource! : editor.resource!, override); + const { contributionPoint, conflictingDefault } = this.getContributionPoint(resource, override); const selectedContribution = contributionPoint; if (!selectedContribution) { return { editor, options, group }; @@ -131,10 +128,10 @@ export class EditorOverrideService extends Disposable implements IEditorOverride if (selectedContribution.editorInfo.describes(editor)) { return; } - const input = await this.doOverrideEditorInput(editor, options, group, selectedContribution); + const input = await this.doOverrideEditorInput(resource, editor, options, group, selectedContribution); if (conflictingDefault && input) { // Show the conflicting default dialog - await this.doHandleConflictingDefaults(selectedContribution.editorInfo.label, input.editor, input.options ?? options, group); + await this.doHandleConflictingDefaults(resource, selectedContribution.editorInfo.label, input.editor, input.options ?? options, group); } // Add the group as we might've changed it with the quickpick @@ -152,10 +149,12 @@ export class EditorOverrideService extends Disposable implements IEditorOverride createEditorInput: EditorInputFactoryFunction, createDiffEditorInput?: DiffEditorInputFactoryFunction ): IDisposable { - if (this._contributionPoints.get(globPattern) === undefined) { - this._contributionPoints.set(globPattern, []); + let contributionPoint = this._contributionPoints.get(globPattern); + if (contributionPoint === undefined) { + contributionPoint = []; + this._contributionPoints.set(globPattern, contributionPoint); } - const remove = insert(this._contributionPoints.get(globPattern)!, { + const remove = insert(contributionPoint, { globPattern, editorInfo, options, @@ -231,8 +230,7 @@ export class EditorOverrideService extends Disposable implements IEditorOverride const userSettings = this.getAssociationsForResource(resource); let contributions: ContributionPoint[] = []; // Then all glob patterns - for (const key of this._contributionPoints.keys()) { - const contributionPoints = this._contributionPoints.get(key)!; + for (const [key, contributionPoints] of this._contributionPoints) { for (const contributionPoint of contributionPoints) { const foundInSettings = userSettings.find(setting => setting.viewType === contributionPoint.editorInfo.id); if (foundInSettings || globMatchesResource(key, resource)) { @@ -292,7 +290,7 @@ export class EditorOverrideService extends Disposable implements IEditorOverride }; } - private async doOverrideEditorInput(editor: IEditorInput, options: IEditorOptions | undefined, group: IEditorGroup, selectedContribution: ContributionPoint): Promise { + private async doOverrideEditorInput(resource: URI, editor: IEditorInput, options: IEditorOptions | undefined, group: IEditorGroup, selectedContribution: ContributionPoint): Promise { // If no activation option is provided, populate it. if (options && typeof options.activation === 'undefined') { @@ -308,9 +306,6 @@ export class EditorOverrideService extends Disposable implements IEditorOverride return inputWithOptions; } - // We only call this function from one place and there we do the check to ensure editor.resource is not undefined - const resource = editor.resource!; - // Respect options passed back const inputWithOptions = selectedContribution.createEditorInput(resource, options, group); options = inputWithOptions.options ?? options; @@ -375,13 +370,13 @@ export class EditorOverrideService extends Disposable implements IEditorOverride return out; } - private async doHandleConflictingDefaults(editorName: string, currentEditor: IContributedEditorInput, options: IEditorOptions | undefined, group: IEditorGroup) { + private async doHandleConflictingDefaults(resource: URI, editorName: string, currentEditor: IContributedEditorInput, options: IEditorOptions | undefined, group: IEditorGroup) { type StoredChoice = { [key: string]: string[]; }; - const contributionPoints = this.findMatchingContributions(currentEditor.resource!); + const contributionPoints = this.findMatchingContributions(resource); const storedChoices: StoredChoice = JSON.parse(this.storageService.get(EditorOverrideService.conflictingDefaultsStorageID, StorageScope.GLOBAL, '{}')); - const globForResource = `*${extname(currentEditor.resource!)}`; + const globForResource = `*${extname(resource)}`; // Writes to the storage service that a choice has been made for the currently installed editors const writeCurrentEditorsToStorage = () => { storedChoices[globForResource] = []; @@ -599,8 +594,7 @@ export class EditorOverrideService extends Disposable implements IEditorOverride const cacheStorage: Set = new Set(); // Store just the relative pattern pieces without any path info - for (const globPattern of this._contributionPoints.keys()) { - const contribPoint = this._contributionPoints.get(globPattern)!; + for (const [globPattern, contribPoint] of this._contributionPoints) { const nonOptional = !!contribPoint.find(c => c.editorInfo.priority !== ContributedEditorPriority.option && c.editorInfo.id !== DEFAULT_EDITOR_ASSOCIATION.id); // Don't keep a cache of the optional ones as those wouldn't be opened on start anyways if (!nonOptional) { From b3d2cd902b7eaf93c7b9bf0d654d03b644186601 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 7 Jun 2021 11:00:55 +0200 Subject: [PATCH 05/40] re-throw and dispose reference when resolving failed --- .../notebookEditorModelResolverServiceImpl.ts | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/common/notebookEditorModelResolverServiceImpl.ts b/src/vs/workbench/contrib/notebook/common/notebookEditorModelResolverServiceImpl.ts index 17babc5a8f15e..0b5f0490b45a5 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookEditorModelResolverServiceImpl.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookEditorModelResolverServiceImpl.ts @@ -181,12 +181,15 @@ export class NotebookModelResolverServiceImpl implements INotebookEditorModelRes } const reference = this._data.acquire(resource.toString(), viewType); - const model = await reference.object; - return { - object: model, - dispose() { - reference.dispose(); - } - }; + try { + const model = await reference.object; + return { + object: model, + dispose() { reference.dispose(); } + }; + } catch (err) { + reference.dispose(); + throw err; + } } } From 5ba2e425f31a0730f255a0e5080f098244880a26 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Mon, 7 Jun 2021 12:14:07 +0200 Subject: [PATCH 06/40] Fixes #125524 by focusing editor after commit. --- src/vs/editor/contrib/inlineCompletions/ghostTextController.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/inlineCompletions/ghostTextController.ts b/src/vs/editor/contrib/inlineCompletions/ghostTextController.ts index f7de4aa6484ae..fb442b4c0592f 100644 --- a/src/vs/editor/contrib/inlineCompletions/ghostTextController.ts +++ b/src/vs/editor/contrib/inlineCompletions/ghostTextController.ts @@ -34,7 +34,7 @@ export class GhostTextController extends Disposable { private triggeredExplicitly = false; constructor( - private readonly editor: ICodeEditor, + public readonly editor: ICodeEditor, @IInstantiationService private readonly instantiationService: IInstantiationService, @IContextKeyService contextKeyService: IContextKeyService, ) { @@ -251,6 +251,7 @@ export const commitInlineSuggestionAction = new GhostTextCommand({ }, handler(x) { x.commit(); + x.editor.focus(); } }); registerEditorCommand(commitInlineSuggestionAction); From 7b724945310a2a8f1ef7bd4a5539d089422042ad Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Mon, 7 Jun 2021 12:27:37 +0200 Subject: [PATCH 07/40] Reduces flickering of inline completions & fixes context key. * Pending update operations are cleared immediately (and not debounced). * Context Key is updated when suggest widget becomes inactive. * Suggest Widget only becomes inactive after an 100ms timeout. * Leading whitespace is only ignored when the inline completion is about indentation. --- .../inlineCompletions/ghostTextController.ts | 3 +++ .../inlineCompletions/inlineCompletionsModel.ts | 13 ++++++++++++- .../suggestWidgetAdapterModel.ts | 17 ++++++++++++++++- 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/vs/editor/contrib/inlineCompletions/ghostTextController.ts b/src/vs/editor/contrib/inlineCompletions/ghostTextController.ts index f7de4aa6484ae..81a8da0ef031e 100644 --- a/src/vs/editor/contrib/inlineCompletions/ghostTextController.ts +++ b/src/vs/editor/contrib/inlineCompletions/ghostTextController.ts @@ -159,6 +159,9 @@ export class ActiveGhostTextController extends Disposable { this._register(this.suggestWidgetAdapterModel.onDidChange(() => { this.updateModel(); + // When the suggest widget becomes inactive and an inline completion + // becomes visible, we need to update the context keys. + this.updateContextKeys(); })); this.updateModel(); diff --git a/src/vs/editor/contrib/inlineCompletions/inlineCompletionsModel.ts b/src/vs/editor/contrib/inlineCompletions/inlineCompletionsModel.ts index 026b39f07c42c..612991e5b9398 100644 --- a/src/vs/editor/contrib/inlineCompletions/inlineCompletionsModel.ts +++ b/src/vs/editor/contrib/inlineCompletions/inlineCompletionsModel.ts @@ -294,6 +294,9 @@ class InlineCompletionsSession extends BaseGhostTextWidgetModel { } public scheduleAutomaticUpdate(): void { + // Since updateSoon debounces, starvation can happen. + // To prevent stale cache, we clear the current update operation. + this.updateOperation.clear(); this.updateSoon.schedule(); } @@ -366,6 +369,8 @@ class InlineCompletionsSession extends BaseGhostTextWidgetModel { cache?.dispose(); }) .then(undefined, onUnexpectedExternalError); + } else { + cache?.dispose(); } this.onDidChangeEmitter.fire(); @@ -475,15 +480,21 @@ export function inlineCompletionToGhostText(inlineCompletion: NormalizedInlineCo // "\t\tfoo" -> "\t\t\tfoobar" (+"\t", +"bar") // "\t\tfoo" -> "\tfoobar" (-"\t", +"\bar") + const firstNonWsCol = textModel.getLineFirstNonWhitespaceColumn(inlineCompletion.range.startLineNumber); + if (inlineCompletion.text.startsWith(valueToBeReplaced)) { remainingInsertText = inlineCompletion.text.substr(valueToBeReplaced.length); - } else { + } else if (firstNonWsCol === 0 || inlineCompletion.range.startColumn < firstNonWsCol) { + // Only allow ignoring leading whitespace in indentation. + // This prevents flickering when the user types whitespace that extends an empty range. const valueToBeReplacedTrimmed = leftTrim(valueToBeReplaced); const insertTextTrimmed = leftTrim(inlineCompletion.text); if (!insertTextTrimmed.startsWith(valueToBeReplacedTrimmed)) { return undefined; } remainingInsertText = insertTextTrimmed.substr(valueToBeReplacedTrimmed.length); + } else { + return undefined; } const position = inlineCompletion.range.getEndPosition(); diff --git a/src/vs/editor/contrib/inlineCompletions/suggestWidgetAdapterModel.ts b/src/vs/editor/contrib/inlineCompletions/suggestWidgetAdapterModel.ts index 765d200b5dab3..eac1ad30f5382 100644 --- a/src/vs/editor/contrib/inlineCompletions/suggestWidgetAdapterModel.ts +++ b/src/vs/editor/contrib/inlineCompletions/suggestWidgetAdapterModel.ts @@ -3,6 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { RunOnceScheduler } from 'vs/base/common/async'; import { Event } from 'vs/base/common/event'; import { toDisposable } from 'vs/base/common/lifecycle'; import { IActiveCodeEditor } from 'vs/editor/browser/editorBrowser'; @@ -20,10 +21,21 @@ import { ISelectedSuggestion } from 'vs/editor/contrib/suggest/suggestWidget'; export class SuggestWidgetAdapterModel extends BaseGhostTextWidgetModel { private isSuggestWidgetVisible: boolean = false; private currentGhostText: GhostText | undefined = undefined; + private _isActive: boolean = false; public override minReservedLineCount: number = 0; - public get isActive() { return this.isSuggestWidgetVisible; } + public get isActive() { return this._isActive; } + + // This delay fixes an suggest widget issue when typing "." immediately restarts the suggestion session. + private setInactiveDelayed = this._register(new RunOnceScheduler(() => { + if (!this.isSuggestWidgetVisible) { + if (this.isActive) { + this._isActive = false; + this.onDidChangeEmitter.fire(); + } + } + }, 100)); constructor( editor: IActiveCodeEditor @@ -41,15 +53,18 @@ export class SuggestWidgetAdapterModel extends BaseGhostTextWidgetModel { this._register(suggestController.widget.value.onDidShow(() => { this.isSuggestWidgetVisible = true; + this._isActive = true; this.updateFromSuggestion(); })); this._register(suggestController.widget.value.onDidHide(() => { this.isSuggestWidgetVisible = false; + this.setInactiveDelayed.schedule(); this.minReservedLineCount = 0; this.updateFromSuggestion(); })); this._register(suggestController.widget.value.onDidFocus(() => { this.isSuggestWidgetVisible = true; + this._isActive = true; this.updateFromSuggestion(); })); }; From 9bde552381404aa8e723508441493f1f1c4b40ce Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Mon, 7 Jun 2021 13:16:28 +0200 Subject: [PATCH 08/40] Adjusts inline completions color. Fixes #125646. --- src/vs/editor/common/view/editorColorRegistry.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/editor/common/view/editorColorRegistry.ts b/src/vs/editor/common/view/editorColorRegistry.ts index b5acf0adac584..df5cdcf3e1f4e 100644 --- a/src/vs/editor/common/view/editorColorRegistry.ts +++ b/src/vs/editor/common/view/editorColorRegistry.ts @@ -44,7 +44,7 @@ export const editorUnnecessaryCodeBorder = registerColor('editorUnnecessaryCode. export const editorUnnecessaryCodeOpacity = registerColor('editorUnnecessaryCode.opacity', { dark: Color.fromHex('#000a'), light: Color.fromHex('#0007'), hc: null }, nls.localize('unnecessaryCodeOpacity', 'Opacity of unnecessary (unused) source code in the editor. For example, "#000000c0" will render the code with 75% opacity. For high contrast themes, use the \'editorUnnecessaryCode.border\' theme color to underline unnecessary code instead of fading it out.')); export const ghostTextBorder = registerColor('editorGhostText.border', { dark: null, light: null, hc: Color.fromHex('#fff').transparent(0.8) }, nls.localize('editorGhostTextBorder', 'Border color of ghost text in the editor.')); -export const ghostTextForeground = registerColor('editorGhostText.foreground', { dark: Color.fromHex('#FFFa'), light: Color.fromHex('#0007'), hc: null }, nls.localize('editorGhostTextForeground', 'Foreground color of the ghost text in the editor.')); +export const ghostTextForeground = registerColor('editorGhostText.foreground', { dark: Color.fromHex('#ffffff56'), light: Color.fromHex('#0007'), hc: null }, nls.localize('editorGhostTextForeground', 'Foreground color of the ghost text in the editor.')); const rulerRangeDefault = new Color(new RGBA(0, 122, 204, 0.6)); export const overviewRulerRangeHighlight = registerColor('editorOverviewRuler.rangeHighlightForeground', { dark: rulerRangeDefault, light: rulerRangeDefault, hc: rulerRangeDefault }, nls.localize('overviewRulerRangeHighlight', 'Overview ruler marker color for range highlights. The color must not be opaque so as not to hide underlying decorations.'), true); From b915673f7b2de2d8859617937fef341a7e3e727c Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com> Date: Mon, 7 Jun 2021 14:10:11 +0200 Subject: [PATCH 09/40] Fix #125569 (#125650) --- .../contrib/workspace/browser/workspace.contribution.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts b/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts index acc89ff6576c8..89ee35a2fe081 100644 --- a/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts +++ b/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts @@ -442,7 +442,9 @@ export class WorkspaceTrustUXHandler extends Disposable implements IWorkbenchCon })); // TODO: Consider moving the check into setWorkspaceTrust() if (this.workspaceTrustManagementService.canSetWorkspaceTrust()) { - this.workspaceTrustManagementService.setWorkspaceTrust(this.configurationService.getValue(WORKSPACE_TRUST_EMPTY_WINDOW) ?? false); + if (this.configurationService.getValue(WORKSPACE_TRUST_EMPTY_WINDOW)) { + this.workspaceTrustManagementService.setWorkspaceTrust(true); + } } } } From bf84ee619e0b67443d0307c04348fa575bc3c363 Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com> Date: Mon, 7 Jun 2021 14:19:44 +0200 Subject: [PATCH 10/40] #125527 (#125651) --- .../services/workspaces/common/workspaceTrust.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/services/workspaces/common/workspaceTrust.ts b/src/vs/workbench/services/workspaces/common/workspaceTrust.ts index 802aeff50fd50..360edf0f75f4b 100644 --- a/src/vs/workbench/services/workspaces/common/workspaceTrust.ts +++ b/src/vs/workbench/services/workspaces/common/workspaceTrust.ts @@ -272,6 +272,11 @@ export class WorkspaceTrustManagementService extends Disposable implements IWork // Update workspace trust this._trustState.isTrusted = trusted; + // Reset acceptsOutOfWorkspaceFiles + if (!trusted) { + this._trustState.acceptsOutOfWorkspaceFiles = false; + } + // Run workspace trust transition participants await this._trustTransitionManager.participate(trusted); @@ -742,10 +747,6 @@ class WorkspaceTrustState { set isTrusted(value: boolean | undefined) { this._mementoObject[this._isTrustedKey] = value; - if (!value) { - this._mementoObject[this._acceptsOutOfWorkspaceFilesKey] = value; - } - this._memento.saveMemento(); } } From 2c9833b549de2d9d2a8f26af0cce1f9c2e7c5937 Mon Sep 17 00:00:00 2001 From: isidor Date: Mon, 7 Jun 2021 19:01:21 +0200 Subject: [PATCH 11/40] better context key for run menu --- .../contrib/debug/browser/debug.contribution.ts | 3 +-- .../contrib/debug/browser/debugAdapterManager.ts | 9 ++++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts index b5a853fa432c8..b8ac11b437924 100644 --- a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts +++ b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts @@ -50,7 +50,6 @@ import { registerColors } from 'vs/workbench/contrib/debug/browser/debugColors'; import { DebugEditorContribution } from 'vs/workbench/contrib/debug/browser/debugEditorContribution'; import { FileAccess } from 'vs/base/common/network'; import * as icons from 'vs/workbench/contrib/debug/browser/debugIcons'; -import { IsWebContext } from 'vs/platform/contextkey/common/contextkeys'; const debugCategory = nls.localize('debugCategory', "Debug"); registerColors(); @@ -186,7 +185,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarMainMenu, { original: 'Run', mnemonicTitle: nls.localize({ key: 'mRun', comment: ['&& denotes a mnemonic'] }, "&&Run") }, - when: ContextKeyExpr.or(CONTEXT_DEBUGGERS_AVAILABLE, IsWebContext.toNegated()), + when: ContextKeyExpr.or(CONTEXT_DEBUGGERS_AVAILABLE), order: 6 }); diff --git a/src/vs/workbench/contrib/debug/browser/debugAdapterManager.ts b/src/vs/workbench/contrib/debug/browser/debugAdapterManager.ts index 46760eab9bd5b..f3e32f051f075 100644 --- a/src/vs/workbench/contrib/debug/browser/debugAdapterManager.ts +++ b/src/vs/workbench/contrib/debug/browser/debugAdapterManager.ts @@ -28,8 +28,11 @@ import { IModeService } from 'vs/editor/common/services/modeService'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import Severity from 'vs/base/common/severity'; import { TaskDefinitionRegistry } from 'vs/workbench/contrib/tasks/common/taskDefinitionRegistry'; +import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; const jsonRegistry = Registry.as(JSONExtensions.JSONContribution); +const DEBUGGERS_AVAILABLE_KEY = 'debug.debuggersavailable'; + export class AdapterManager implements IAdapterManager { private debuggers: Debugger[]; @@ -49,12 +52,15 @@ export class AdapterManager implements IAdapterManager { @IExtensionService private readonly extensionService: IExtensionService, @IContextKeyService contextKeyService: IContextKeyService, @IModeService private readonly modeService: IModeService, - @IDialogService private readonly dialogService: IDialogService + @IDialogService private readonly dialogService: IDialogService, + @IStorageService private readonly storageService: IStorageService ) { this.adapterDescriptorFactories = []; this.debuggers = []; this.registerListeners(); + const debuggersAvailable = this.storageService.getBoolean(DEBUGGERS_AVAILABLE_KEY, StorageScope.WORKSPACE, false); this.debuggersAvailable = CONTEXT_DEBUGGERS_AVAILABLE.bindTo(contextKeyService); + this.debuggersAvailable.set(debuggersAvailable); } private registerListeners(): void { @@ -158,6 +164,7 @@ export class AdapterManager implements IAdapterManager { registerDebugAdapterFactory(debugTypes: string[], debugAdapterLauncher: IDebugAdapterFactory): IDisposable { debugTypes.forEach(debugType => this.debugAdapterFactories.set(debugType, debugAdapterLauncher)); this.debuggersAvailable.set(this.debugAdapterFactories.size > 0); + this.storageService.store(DEBUGGERS_AVAILABLE_KEY, this.debugAdapterFactories.size > 0, StorageScope.WORKSPACE, StorageTarget.MACHINE); this._onDidRegisterDebugger.fire(); return { From 6d4a8af5cfc237c0463bb7fca66acb37f23f5c24 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 4 Jun 2021 04:39:31 -0700 Subject: [PATCH 12/40] Hide terminal menu if no process support is registered --- src/vs/workbench/browser/parts/titlebar/menubarControl.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/browser/parts/titlebar/menubarControl.ts b/src/vs/workbench/browser/parts/titlebar/menubarControl.ts index 144ec97e83099..87dbc5d320483 100644 --- a/src/vs/workbench/browser/parts/titlebar/menubarControl.ts +++ b/src/vs/workbench/browser/parts/titlebar/menubarControl.ts @@ -7,7 +7,7 @@ import { localize } from 'vs/nls'; import { IMenuService, MenuId, IMenu, SubmenuItemAction, registerAction2, Action2, MenuItemAction, MenuRegistry } from 'vs/platform/actions/common/actions'; import { registerThemingParticipant, IThemeService } from 'vs/platform/theme/common/themeService'; import { MenuBarVisibility, getTitleBarStyle, IWindowOpenable, getMenuBarVisibility } from 'vs/platform/windows/common/windows'; -import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IAction, Action, SubmenuAction, Separator } from 'vs/base/common/actions'; import { addDisposableListener, Dimension, EventType } from 'vs/base/browser/dom'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; @@ -98,7 +98,8 @@ MenuRegistry.appendMenuItem(MenuId.MenubarMainMenu, { original: 'Terminal', mnemonicTitle: localize({ key: 'mTerminal', comment: ['&& denotes a mnemonic'] }, "&&Terminal") }, - order: 7 + order: 7, + when: ContextKeyExpr.has('terminalProcessSupported') }); MenuRegistry.appendMenuItem(MenuId.MenubarMainMenu, { From c926ecf021ab972f2c239ed94b3836c2231571f4 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Mon, 7 Jun 2021 12:55:46 -0700 Subject: [PATCH 13/40] Clone object before applying migrated setting (#125696) Fixes #125177 --- 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 33ea45275c1b2..4bcb9ca5da80e 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -377,7 +377,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { await this._configurationService.updateValue(TerminalSettingPrefix.DefaultProfile + platform, profile); this._logService.trace(`migrated from shell/shellArgs, using existing profile ${profile}`); } else { - const profiles = this._configurationService.inspect<{ [key: string]: ITerminalProfileObject }>(TerminalSettingPrefix.Profiles + platform).userValue || {}; + const profiles = { ...this._configurationService.inspect>(TerminalSettingPrefix.Profiles + platform).userValue } || {}; const profileConfig: ITerminalProfileObject = { path: profile.path }; if (profile.args) { profileConfig.args = profile.args; From 008c3ecf4cde9987fde6373286b638a55f9c3aee Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Mon, 7 Jun 2021 15:48:39 -0700 Subject: [PATCH 14/40] Port fix for git diff paths in webviews to 1.57 (#125704) Fixes #125602 --- src/vs/workbench/contrib/webview/browser/baseWebviewElement.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/webview/browser/baseWebviewElement.ts b/src/vs/workbench/contrib/webview/browser/baseWebviewElement.ts index f1b6fb31cc1f6..05c9310208f71 100644 --- a/src/vs/workbench/contrib/webview/browser/baseWebviewElement.ts +++ b/src/vs/workbench/contrib/webview/browser/baseWebviewElement.ts @@ -247,7 +247,7 @@ export abstract class BaseWebview extends Disposable { scheme: entry.scheme, authority: entry.authority, path: decodeURIComponent(entry.path), // This gets re-encoded - query: entry.query, + query: entry.query ? decodeURIComponent(entry.query) : entry.query, }); this.loadResource(entry.id, uri, entry.ifNoneMatch); } catch (e) { From e27b85b995847e9c5801c287522320971ccfbd5d Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Mon, 7 Jun 2021 15:49:51 -0700 Subject: [PATCH 15/40] fix #125702 (#125703) --- .../contrib/notebook/browser/contrib/coreActions.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts b/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts index df23ae81bf6b4..dfb33a2cc08e5 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts @@ -1874,14 +1874,18 @@ registerAction2(class NotebookConfigureLayoutAction extends Action2 { group: 'notebookLayout', when: ContextKeyExpr.and( NOTEBOOK_IS_ACTIVE_EDITOR, - ContextKeyExpr.notEquals('config.notebook.globalToolbar', true) + ContextKeyExpr.notEquals('config.notebook.globalToolbar', true), + ContextKeyExpr.equals('config.notebook.experimental.openGettingStarted', true) ), order: 0 }, { id: MenuId.NotebookToolbar, group: 'notebookLayout', - when: ContextKeyExpr.equals('config.notebook.globalToolbar', true), + when: ContextKeyExpr.and( + ContextKeyExpr.equals('config.notebook.globalToolbar', true), + ContextKeyExpr.equals('config.notebook.experimental.openGettingStarted', true) + ), order: 0 } ] From c188ea91a6471850a2a114e6f985a913c7d76c04 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 8 Jun 2021 09:53:23 +0200 Subject: [PATCH 16/40] make sure to transform notebook data metadata --- .../api/common/extHostTypeConverters.ts | 2 +- .../browser/api/extHostTypeConverter.test.ts | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index 9dc02f2235abc..c5b64e74910aa 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -1460,7 +1460,7 @@ export namespace NotebookData { export function from(data: vscode.NotebookData): notebooks.NotebookDataDto { const res: notebooks.NotebookDataDto = { - metadata: Object.create(null), + metadata: data.metadata ?? Object.create(null), cells: [], }; for (let cell of data.cells) { diff --git a/src/vs/workbench/test/browser/api/extHostTypeConverter.test.ts b/src/vs/workbench/test/browser/api/extHostTypeConverter.test.ts index 48cdcba4d1385..a635a390c670f 100644 --- a/src/vs/workbench/test/browser/api/extHostTypeConverter.test.ts +++ b/src/vs/workbench/test/browser/api/extHostTypeConverter.test.ts @@ -6,7 +6,7 @@ import * as assert from 'assert'; import * as extHostTypes from 'vs/workbench/api/common/extHostTypes'; -import { MarkdownString, NotebookCellOutputItem } from 'vs/workbench/api/common/extHostTypeConverters'; +import { MarkdownString, NotebookCellOutputItem, NotebookData } 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'; @@ -83,6 +83,20 @@ suite('ExtHostTypeConverter', function () { }); }); + test('Notebook metadata is ignored when using Notebook Serializer #125716', function () { + + const d = new extHostTypes.NotebookData([]); + d.cells.push(new extHostTypes.NotebookCellData(extHostTypes.NotebookCellKind.Code, 'hello', 'fooLang')); + d.metadata = { custom: { foo: 'bar', bar: 123 } }; + + const dto = NotebookData.from(d); + + assert.strictEqual(dto.cells.length, 1); + assert.strictEqual(dto.cells[0].language, 'fooLang'); + assert.strictEqual(dto.cells[0].source, 'hello'); + assert.deepStrictEqual(dto.metadata, d.metadata); + }); + test('NotebookCellOutputItem', function () { const item = extHostTypes.NotebookCellOutputItem.text('Hello', 'foo/bar'); From 098c99e22372589b52a2d9dad76c70fbb5ac2c75 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Tue, 8 Jun 2021 05:21:52 -0700 Subject: [PATCH 17/40] Set terminal title in ctor for custom pty terminals Fixes #125729 --- .../workbench/contrib/terminal/browser/terminalInstance.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 4bcb9ca5da80e..611101f004621 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -281,6 +281,12 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this._terminalProfileResolverService.resolveIcon(this._shellLaunchConfig, OS); } + // When a custom pty is used set the name immediately so it gets passed over to the exthost + // and is available when Pseudoterminal.open fires. + if (this.shellLaunchConfig.customPtyImplementation) { + this.setTitle(this._shellLaunchConfig.name, TitleEventSource.Api); + } + this._initDimensions(); this._createProcessManager(); From 629091038fc958d28d3a6e443052c80701e057bf Mon Sep 17 00:00:00 2001 From: Tyler James Leonhardt Date: Tue, 8 Jun 2021 09:52:37 -0700 Subject: [PATCH 18/40] allow a 3rd character for first part of language id (#125761) --- build/npm/update-localization-extension.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/npm/update-localization-extension.js b/build/npm/update-localization-extension.js index 43bc792d9f849..7c6a73aa9d848 100644 --- a/build/npm/update-localization-extension.js +++ b/build/npm/update-localization-extension.js @@ -25,7 +25,7 @@ function update(options) { throw new Error(`${location} doesn't exist.`); } let locExtFolder = idOrPath; - if (/^\w{2}(-\w+)?$/.test(idOrPath)) { + if (/^\w{2,3}(-\w+)?$/.test(idOrPath)) { locExtFolder = path.join('..', 'vscode-loc', 'i18n', `vscode-language-pack-${idOrPath}`); } let locExtStat = fs.statSync(locExtFolder); From 26317e8dccdfbab49935e5e59f27a9171bbd1981 Mon Sep 17 00:00:00 2001 From: SteVen Batten <6561887+sbatten@users.noreply.github.com> Date: Tue, 8 Jun 2021 10:52:30 -0700 Subject: [PATCH 19/40] fixes #125722 (#125768) --- .../contrib/workspace/browser/workspaceTrustEditor.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.ts b/src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.ts index 230f468978cd9..4f95167c1f1ca 100644 --- a/src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.ts +++ b/src/vs/workbench/contrib/workspace/browser/workspaceTrustEditor.ts @@ -823,13 +823,13 @@ export class WorkspaceTrustEditor extends EditorPane { [ localize('untrustedTasks', "Tasks are disabled"), localize('untrustedDebugging', "Debugging is disabled"), - localize('untrustedExtensions', "[{0} extensions](command:{1}) are disabled or have limited functionality", numExtensions, LIST_WORKSPACE_UNSUPPORTED_EXTENSIONS_COMMAND_ID) + localize('untrustedExtensions', "[{0} extensions]({1}) are disabled or have limited functionality", numExtensions, `command:${LIST_WORKSPACE_UNSUPPORTED_EXTENSIONS_COMMAND_ID}`) ] : [ localize('untrustedTasks', "Tasks are disabled"), localize('untrustedDebugging', "Debugging is disabled"), - numSettings ? localize('untrustedSettings', "[{0} workspace settings](command:{1}) are not applied", numSettings, 'settings.filterUntrusted') : localize('no untrustedSettings', "Workspace settings requiring trust are not applied"), - localize('untrustedExtensions', "[{0} extensions](command:{1}) are disabled or have limited functionality", numExtensions, LIST_WORKSPACE_UNSUPPORTED_EXTENSIONS_COMMAND_ID) + numSettings ? localize('untrustedSettings', "[{0} workspace settings]({1}) are not applied", numSettings, 'command:settings.filterUntrusted') : localize('no untrustedSettings', "Workspace settings requiring trust are not applied"), + localize('untrustedExtensions', "[{0} extensions]({1}) are disabled or have limited functionality", numExtensions, `command:${LIST_WORKSPACE_UNSUPPORTED_EXTENSIONS_COMMAND_ID}`) ]; this.renderLimitationsListElement(untrustedContainer, untrustedContainerItems, xListIcon.classNamesArray); From 134cc8b7711ecd399f61e7cda9688989a65c83ce Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Tue, 8 Jun 2021 11:48:45 -0700 Subject: [PATCH 20/40] Update values for keybinding query context to match real keybindings. Fix #122768 --- .../executionStatusBarItemController.ts | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/statusBar/executionStatusBarItemController.ts b/src/vs/workbench/contrib/notebook/browser/contrib/statusBar/executionStatusBarItemController.ts index e32ba0518d534..5b5a85e9e03b0 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/statusBar/executionStatusBarItemController.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/statusBar/executionStatusBarItemController.ts @@ -13,7 +13,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { themeColorFromId } from 'vs/platform/theme/common/themeService'; import { ICellVisibilityChangeEvent, NotebookVisibleCellObserver } from 'vs/workbench/contrib/notebook/browser/contrib/statusBar/notebookVisibleCellObserver'; -import { EXECUTE_CELL_COMMAND_ID, ICellViewModel, INotebookEditor, INotebookEditorContribution, NOTEBOOK_CELL_EXECUTION_STATE, QUIT_EDIT_CELL_COMMAND_ID } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { EXECUTE_CELL_COMMAND_ID, ICellViewModel, INotebookEditor, INotebookEditorContribution, NOTEBOOK_CELL_EXECUTION_STATE, NOTEBOOK_CELL_LIST_FOCUSED, NOTEBOOK_CELL_TYPE, NOTEBOOK_EDITOR_FOCUSED, QUIT_EDIT_CELL_COMMAND_ID } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { registerNotebookContribution } from 'vs/workbench/contrib/notebook/browser/notebookEditorExtensions'; import { cellStatusIconError, cellStatusIconSuccess } from 'vs/workbench/contrib/notebook/browser/notebookEditorWidget'; import { NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel'; @@ -232,7 +232,8 @@ class TimerCellStatusBarHelper extends Disposable { */ class KeybindingPlaceholderStatusBarHelper extends Disposable { private _currentItemIds: string[] = []; - private readonly _contextKeyService: IContextKeyService; + private readonly _codeContextKeyService: IContextKeyService; + private readonly _markupContextKeyService: IContextKeyService; constructor( private readonly _notebookViewModel: NotebookViewModel, @@ -243,12 +244,20 @@ class KeybindingPlaceholderStatusBarHelper extends Disposable { super(); // Create a fake ContextKeyService, and look up the keybindings within this context. - this._contextKeyService = this._register(_contextKeyService.createScoped(document.createElement('div'))); - InputFocusedContext.bindTo(this._contextKeyService).set(true); - EditorContextKeys.editorTextFocus.bindTo(this._contextKeyService).set(true); - EditorContextKeys.focus.bindTo(this._contextKeyService).set(true); - EditorContextKeys.textInputFocus.bindTo(this._contextKeyService).set(true); - NOTEBOOK_CELL_EXECUTION_STATE.bindTo(this._contextKeyService).set('idle'); + const commonContextKeyService = this._register(_contextKeyService.createScoped(document.createElement('div'))); + InputFocusedContext.bindTo(commonContextKeyService).set(true); + EditorContextKeys.editorTextFocus.bindTo(commonContextKeyService).set(true); + EditorContextKeys.focus.bindTo(commonContextKeyService).set(true); + EditorContextKeys.textInputFocus.bindTo(commonContextKeyService).set(true); + NOTEBOOK_CELL_EXECUTION_STATE.bindTo(commonContextKeyService).set('idle'); + NOTEBOOK_CELL_LIST_FOCUSED.bindTo(commonContextKeyService).set(true); + NOTEBOOK_EDITOR_FOCUSED.bindTo(commonContextKeyService).set(true); + + this._codeContextKeyService = this._register(commonContextKeyService.createScoped(document.createElement('div'))); + NOTEBOOK_CELL_TYPE.bindTo(this._codeContextKeyService).set('code'); + + this._markupContextKeyService = this._register(commonContextKeyService.createScoped(document.createElement('div'))); + NOTEBOOK_CELL_TYPE.bindTo(this._markupContextKeyService).set('markup'); this._update(); this._register(this._cell.model.onDidChangeInternalMetadata(() => this._update())); @@ -268,14 +277,14 @@ class KeybindingPlaceholderStatusBarHelper extends Disposable { let text: string; if (cell.cellKind === CellKind.Code) { - const keybinding = this._keybindingService.lookupKeybinding(EXECUTE_CELL_COMMAND_ID, this._contextKeyService)?.getLabel(); + const keybinding = this._keybindingService.lookupKeybinding(EXECUTE_CELL_COMMAND_ID, this._codeContextKeyService)?.getLabel(); if (!keybinding) { return []; } text = localize('notebook.cell.status.codeExecuteTip', "Press {0} to execute cell", keybinding); } else { - const keybinding = this._keybindingService.lookupKeybinding(QUIT_EDIT_CELL_COMMAND_ID, this._contextKeyService)?.getLabel(); + const keybinding = this._keybindingService.lookupKeybinding(QUIT_EDIT_CELL_COMMAND_ID, this._markupContextKeyService)?.getLabel(); if (!keybinding) { return []; } From 47c2272a70d4bcdbe5eb43e459c22ab60aea2b45 Mon Sep 17 00:00:00 2001 From: SteVen Batten <6561887+sbatten@users.noreply.github.com> Date: Tue, 8 Jun 2021 15:02:46 -0700 Subject: [PATCH 21/40] candy/125576 (#125787) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * #125576 * 💄 remove debug message Co-authored-by: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com> --- .../services/workspaces/common/workspaceTrust.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/services/workspaces/common/workspaceTrust.ts b/src/vs/workbench/services/workspaces/common/workspaceTrust.ts index 360edf0f75f4b..97a83689a8596 100644 --- a/src/vs/workbench/services/workspaces/common/workspaceTrust.ts +++ b/src/vs/workbench/services/workspaces/common/workspaceTrust.ts @@ -235,8 +235,8 @@ export class WorkspaceTrustManagementService extends Disposable implements IWork return true; } - if (!this._initialized) { - return false; + if (this.environmentService.extensionTestsLocationURI) { + return true; // trust running tests with vscode-test } // Remote - remote authority explicitly sets workspace trust @@ -244,16 +244,16 @@ export class WorkspaceTrustManagementService extends Disposable implements IWork return this._remoteAuthority.options.isTrusted; } - if (this.environmentService.extensionTestsLocationURI) { - return true; // trust running tests with vscode-test - } - if (this.workspaceService.getWorkbenchState() === WorkbenchState.EMPTY) { // Use memento if present, otherwise default to restricted mode // Workspace may transition to trusted based on the opened editors return this._trustState.isTrusted ?? false; } + if (!this._initialized) { + return false; + } + return this.getUrisTrust(this.getWorkspaceUris()); } From 78429fb87366710e4b0a3743892f1a64a0dc1557 Mon Sep 17 00:00:00 2001 From: Jackson Kearl Date: Tue, 8 Jun 2021 16:19:20 -0700 Subject: [PATCH 22/40] Use interpolation to keep special syntax out of strings to be translated (#125790) Ref #125786 --- .../browser/gettingStartedExtensionPoint.ts | 6 ++- .../common/gettingStartedContent.ts | 42 ++++++++++--------- 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedExtensionPoint.ts b/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedExtensionPoint.ts index d3cc402e9055a..c02fe90975990 100644 --- a/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedExtensionPoint.ts +++ b/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedExtensionPoint.ts @@ -7,6 +7,8 @@ import { localize } from 'vs/nls'; import { IStartEntry, IWalkthrough } from 'vs/platform/extensions/common/extensions'; import { ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry'; +const titleTranslated = localize('title', "Title"); + export const walkthroughsExtensionPoint = ExtensionsRegistry.registerExtensionPoint({ extensionPoint: 'walkthroughs', jsonSchema: { @@ -64,10 +66,10 @@ export const walkthroughsExtensionPoint = ExtensionsRegistry.registerExtensionPo }, description: { type: 'string', - description: localize('walkthroughs.steps.description', "Description of step. Supports ``preformatted``, __italic__, and **bold** text. Use markdown-style links for commands or external links: [Title](command:myext.command), [Title](command:toSide:myext.command), or [Title](https://aka.ms). Links on their own line will be rendered as buttons.") + description: localize('walkthroughs.steps.description.interpolated', "Description of step. Supports ``preformatted``, __italic__, and **bold** text. Use markdown-style links for commands or external links: {0}, {1}, or {2}. Links on their own line will be rendered as buttons.", `[${titleTranslated}](command:myext.command)`, `[${titleTranslated}](command:toSide:myext.command)`, `[${titleTranslated}](https://aka.ms)`) }, button: { - deprecationMessage: localize('walkthroughs.steps.button.deprecated', "Deprecated. Use markdown links in the description instead, i.e. [Title](command:myext.command), [Title](command:toSide:myext.command), or [Title](https://aka.ms), "), + deprecationMessage: localize('walkthroughs.steps.button.deprecated.interpolated', "Deprecated. Use markdown links in the description instead, i.e. {0}, {1}, or {2}", `[${titleTranslated}](command:myext.command)`, `[${titleTranslated}](command:toSide:myext.command)`, `[${titleTranslated}](https://aka.ms)`), }, media: { type: 'object', diff --git a/src/vs/workbench/contrib/welcome/gettingStarted/common/gettingStartedContent.ts b/src/vs/workbench/contrib/welcome/gettingStarted/common/gettingStartedContent.ts index 5188d25939cf1..aa5fdc543fc01 100644 --- a/src/vs/workbench/contrib/welcome/gettingStarted/common/gettingStartedContent.ts +++ b/src/vs/workbench/contrib/welcome/gettingStarted/common/gettingStartedContent.ts @@ -118,6 +118,8 @@ export const startEntries: GettingStartedStartEntryContent = [ }, ]; +const Button = (title: string, href: string) => `[${title}](${href})`; + export const walkthroughs: GettingStartedWalkthroughContent = [ { id: 'Setup', @@ -131,14 +133,14 @@ export const walkthroughs: GettingStartedWalkthroughContent = [ { id: 'pickColorTheme', title: localize('gettingStarted.pickColor.title', "Choose the look you want"), - description: localize('gettingStarted.pickColor.description', "The right color palette helps you focus on your code, is easy on your eyes, and is simply more fun to use.\n[Browse Color Themes](command:workbench.action.selectTheme)"), + description: localize('gettingStarted.pickColor.description.interpolated', "The right color palette helps you focus on your code, is easy on your eyes, and is simply more fun to use.\n{0}", Button(localize('titleID', "Browse Color Themes"), 'command:workbench.action.selectTheme')), completionEvents: ['onSettingChanged:workbench.colorTheme'], media: { type: 'markdown', path: 'example_markdown_media', } }, { id: 'findLanguageExtensions', title: localize('gettingStarted.findLanguageExts.title', "Rich support for all your languages"), - description: localize('gettingStarted.findLanguageExts.description', "Code smarter with syntax highlighting, code completion, linting and debugging. While many languages are built-in, many more can be added as extensions.\n[Browse Language Extensions](command:workbench.extensions.action.showLanguageExtensions)"), + description: localize('gettingStarted.findLanguageExts.description.interpolated', "Code smarter with syntax highlighting, code completion, linting and debugging. While many languages are built-in, many more can be added as extensions.\n{0}", Button(localize('browseLangExts', "Browse Language Extensions"), 'command:workbench.extensions.action.showLanguageExtensions')), media: { type: 'image', altText: 'Language extensions', path: { dark: 'dark/languageExtensions.png', @@ -150,7 +152,7 @@ export const walkthroughs: GettingStartedWalkthroughContent = [ { id: 'commandPaletteTask', title: localize('gettingStarted.commandPalette.title', "One shortcut to access everything"), - description: localize('gettingStarted.commandPalette.description', "Commands Palette is the keyboard way to accomplish any task in VS Code. **Practice** by looking up your frequently used commands to save time and keep in the flow.\n[Open Command Palette](command:workbench.action.showCommands)\n__Try searching for 'view toggle'.__"), + description: localize('gettingStarted.commandPalette.description.interpolated', "Commands Palette is the keyboard way to accomplish any task in VS Code. **Practice** by looking up your frequently used commands to save time and keep in the flow.\n{0}\n__Try searching for 'view toggle'.__", Button(localize('commandPalette', "Open Command Palette"), 'command:workbench.action.showCommands')), media: { type: 'image', altText: 'Command Palette overlay for searching and executing commands.', path: { dark: 'dark/commandPalette.png', @@ -162,7 +164,7 @@ export const walkthroughs: GettingStartedWalkthroughContent = [ { id: 'workspaceTrust', title: localize('gettingStarted.workspaceTrust.title', "Safely browse and edit code"), - description: localize('gettingStarted.workspaceTrust.description', "[Workspace Trust](https://github.com/microsoft/vscode-docs/blob/workspaceTrust/docs/editor/workspace-trust.md) lets you decide whether your project folders should **allow or restrict** automatic code execution __(required for extensions, debugging, etc)__.\nOpening a file/folder will prompt to grant trust. You can always [enable trust](command:toSide:workbench.action.manageTrustedDomain) later."), + description: localize('gettingStarted.workspaceTrust.description.interpolated', "{0} lets you decide whether your project folders should **allow or restrict** automatic code execution __(required for extensions, debugging, etc)__.\nOpening a file/folder will prompt to grant trust. You can always {1} later.", Button(localize('workspaceTrust', "Workspace Trust"), 'https://github.com/microsoft/vscode-docs/blob/workspaceTrust/docs/editor/workspace-trust.md'), Button(localize('enableTrust', "enable trust"), 'command:toSide:workbench.action.manageTrustedDomain')), when: '!isWorkspaceTrusted && workspaceFolderCount == 0', media: { type: 'image', altText: 'Workspace Trust editor in Restricted mode and a primary button for switching to Trusted mode.', path: { @@ -175,7 +177,7 @@ export const walkthroughs: GettingStartedWalkthroughContent = [ { id: 'pickAFolderTask-Mac', title: localize('gettingStarted.setup.OpenFolder.title', "Open up your code"), - description: localize('gettingStarted.setup.OpenFolder.description', "You're all set to start coding. Open a project folder to get your files into VS Code.\n[Pick a Folder](command:workbench.action.files.openFileFolder)"), + description: localize('gettingStarted.setup.OpenFolder.description.interpolated', "You're all set to start coding. Open a project folder to get your files into VS Code.\n{0}", Button(localize('pickFolder', "Pick a Folder"), 'command:workbench.action.files.openFileFolder')), when: 'isMac && workspaceFolderCount == 0', media: { type: 'image', altText: 'Explorer view showing buttons for opening folder and cloning repository.', path: { @@ -188,7 +190,7 @@ export const walkthroughs: GettingStartedWalkthroughContent = [ { id: 'pickAFolderTask-Other', title: localize('gettingStarted.setup.OpenFolder.title', "Open up your code"), - description: localize('gettingStarted.setup.OpenFolder.description2', "You're all set to start coding. Open a project folder to get your files into VS Code.\n[Pick a Folder](command:workbench.action.files.openFolder)"), + description: localize('gettingStarted.setup.OpenFolder.description.interpolated', "You're all set to start coding. Open a project folder to get your files into VS Code.\n{0}", Button(localize('pickFolder', "Pick a Folder"), 'command:workbench.action.files.openFolder')), when: '!isMac && workspaceFolderCount == 0', media: { type: 'image', altText: 'Explorer view showing buttons for opening folder and cloning repository.', path: { @@ -201,7 +203,7 @@ export const walkthroughs: GettingStartedWalkthroughContent = [ { id: 'quickOpen', title: localize('gettingStarted.quickOpen.title', "Quickly navigate between your files"), - description: localize('gettingStarted.quickOpen.description', "Navigate between files in an instant with one keystroke. Tip: Open multiple files by pressing the right arrow key.\n[Quick Open a File](command:toSide:workbench.action.quickOpen)"), + description: localize('gettingStarted.quickOpen.description.interpolated', "Navigate between files in an instant with one keystroke. Tip: Open multiple files by pressing the right arrow key.\n{0}", Button(localize('quickOpen', "Quick Open a File"), 'command:toSide:workbench.action.quickOpen')), when: 'workspaceFolderCount != 0', media: { type: 'image', altText: 'Go to file in quick search.', path: { @@ -227,7 +229,7 @@ export const walkthroughs: GettingStartedWalkthroughContent = [ { id: 'playground', title: localize('gettingStarted.playground.title', "Redefine your editing skills"), - description: localize('gettingStarted.playground.description', "Want to code faster and smarter? Practice powerful code editing features in the interactive playground.\n[Open Interactive Playground](command:toSide:workbench.action.showInteractivePlayground)"), + description: localize('gettingStarted.playground.description.interpolated', "Want to code faster and smarter? Practice powerful code editing features in the interactive playground.\n{0}", Button(localize('openInteractivePlayground', "Open Interactive Playground"), 'command:toSide:workbench.action.showInteractivePlayground')), media: { type: 'image', altText: 'Interactive Playground.', path: { dark: 'dark/playground.png', @@ -239,7 +241,7 @@ export const walkthroughs: GettingStartedWalkthroughContent = [ { id: 'terminal', title: localize('gettingStarted.terminal.title', "Convenient built-in terminal"), - description: localize('gettingStarted.terminal.description', "Quickly run shell commands and monitor build output, right next to your code.\n[Show Terminal Panel](command:workbench.action.terminal.toggleTerminal)"), + description: localize('gettingStarted.terminal.description.interpolated', "Quickly run shell commands and monitor build output, right next to your code.\n{0}", Button(localize('showTerminal', "Show Terminal Panel"), 'command:workbench.action.terminal.toggleTerminal')), when: 'remoteName != codespaces && !terminalIsOpen', media: { type: 'image', altText: 'Integrated terminal running a few npm commands', path: { @@ -252,7 +254,7 @@ export const walkthroughs: GettingStartedWalkthroughContent = [ { id: 'extensions', title: localize('gettingStarted.extensions.title', "Limitless extensibility"), - description: localize('gettingStarted.extensions.description', "Extensions are VS Code's power-ups. They range from handy productivity hacks, expanding out-of-the-box features, to adding completely new capabilities.\n[Browse Recommended Extensions](command:workbench.extensions.action.showRecommendedExtensions)"), + description: localize('gettingStarted.extensions.description.interpolated', "Extensions are VS Code's power-ups. They range from handy productivity hacks, expanding out-of-the-box features, to adding completely new capabilities.\n{0}", Button(localize('browseRecommended', "Browse Recommended Extensions"), 'command:workbench.extensions.action.showRecommendedExtensions')), media: { type: 'image', altText: 'VS Code extension marketplace with featured language extensions', path: { dark: 'dark/extensions.png', @@ -264,7 +266,7 @@ export const walkthroughs: GettingStartedWalkthroughContent = [ { id: 'settings', title: localize('gettingStarted.settings.title', "Tune your settings"), - description: localize('gettingStarted.settings.description', "Tweak every aspect of VS Code and your extensions to your liking. Commonly used settings are listed first to get you started.\n[Tweak my Settings](command:toSide:workbench.action.openSettings)"), + description: localize('gettingStarted.settings.description.interpolated', "Tweak every aspect of VS Code and your extensions to your liking. Commonly used settings are listed first to get you started.\n{0}", Button(localize('tweakSettings', "Tweak my Settings"), 'command:toSide:workbench.action.openSettings')), media: { type: 'image', altText: 'VS Code Settings', path: { dark: 'dark/settings.png', @@ -276,7 +278,7 @@ export const walkthroughs: GettingStartedWalkthroughContent = [ { id: 'settingsSync', title: localize('gettingStarted.settingsSync.title', "Sync your stuff across devices"), - description: localize('gettingStarted.settingsSync.description', "Never lose the perfect VS Code setup! Settings Sync will back up and share settings, keybindings & extensions across several installations.\n[Enable Settings Sync](command:workbench.userDataSync.actions.turnOn)"), + description: localize('gettingStarted.settingsSync.description.interpolated', "Never lose the perfect VS Code setup! Settings Sync will back up and share settings, keybindings & extensions across several installations.\n{0}", Button(localize('enableSync', "Enable Settings Sync"), 'command:workbench.userDataSync.actions.turnOn')), when: 'syncStatus != uninitialized', completionEvents: ['onEvent:sync-enabled'], media: { @@ -290,7 +292,7 @@ export const walkthroughs: GettingStartedWalkthroughContent = [ { id: 'videoTutorial', title: localize('gettingStarted.videoTutorial.title', "Lean back and learn"), - description: localize('gettingStarted.videoTutorial.description', "Watch the first in a series of short & practical video tutorials for VS Code's key features.\n[Watch Tutorial](https://aka.ms/vscode-getting-started-video)"), + description: localize('gettingStarted.videoTutorial.description.interpolated', "Watch the first in a series of short & practical video tutorials for VS Code's key features.\n{0}", Button(localize('watch', "Watch Tutorial"), 'https://aka.ms/vscode-getting-started-video')), media: { type: 'image', altText: 'VS Code Settings', path: 'tutorialVideo.png' }, } ] @@ -308,7 +310,7 @@ export const walkthroughs: GettingStartedWalkthroughContent = [ { id: 'splitview', title: localize('gettingStarted.splitview.title', "Side by side editing"), - description: localize('gettingStarted.splitview.description', "Make the most of your screen estate by opening files side by side, vertically and horizontally.\n[Split Editor](command:workbench.action.splitEditor)"), + description: localize('gettingStarted.splitview.description.interpolated', "Make the most of your screen estate by opening files side by side, vertically and horizontally.\n{0}", Button(localize('splitEditor', "Split Editor"), 'command:workbench.action.splitEditor')), media: { type: 'image', altText: 'Multiple editors in split view.', path: { dark: 'dark/splitview.png', @@ -320,7 +322,7 @@ export const walkthroughs: GettingStartedWalkthroughContent = [ { id: 'debugging', title: localize('gettingStarted.debug.title', "Watch your code in action"), - description: localize('gettingStarted.debug.description', "Accelerate your edit, build, test, and debug loop by setting up a launch configuration.\n[Run your Project](command:workbench.action.debug.selectandstart)"), + description: localize('gettingStarted.debug.description.interpolated', "Accelerate your edit, build, test, and debug loop by setting up a launch configuration.\n{0}", Button(localize('runProject', "Run your Project"), 'command:workbench.action.debug.selectandstart')), when: 'workspaceFolderCount != 0', media: { type: 'image', altText: 'Run and debug view.', path: { @@ -333,7 +335,7 @@ export const walkthroughs: GettingStartedWalkthroughContent = [ { id: 'scmClone', title: localize('gettingStarted.scm.title', "Track your code with Git"), - description: localize('gettingStarted.scmClone.description', "Set up the built-in version control for your project to track your changes and collaborate with others.\n[Clone Repository](command:git.clone)"), + description: localize('gettingStarted.scmClone.description.interpolated', "Set up the built-in version control for your project to track your changes and collaborate with others.\n{0}", Button(localize('cloneRepo', "Clone Repository"), 'command:git.clone')), when: 'config.git.enabled && !git.missing && workspaceFolderCount == 0', media: { type: 'image', altText: 'Source Control view.', path: { @@ -346,7 +348,7 @@ export const walkthroughs: GettingStartedWalkthroughContent = [ { id: 'scmSetup', title: localize('gettingStarted.scm.title', "Track your code with Git"), - description: localize('gettingStarted.scmSetup.description', "Set up the built-in version control for your project to track your changes and collaborate with others.\n[Initialize Git Repository](command:git.init)"), + description: localize('gettingStarted.scmSetup.description.interpolated', "Set up the built-in version control for your project to track your changes and collaborate with others.\n{0}", Button(localize('initRepo', "Initialize Git Repository"), 'command:git.init')), when: 'config.git.enabled && !git.missing && workspaceFolderCount != 0 && gitOpenRepositoryCount == 0', media: { type: 'image', altText: 'Source Control view.', path: { @@ -359,7 +361,7 @@ export const walkthroughs: GettingStartedWalkthroughContent = [ { id: 'scm', title: localize('gettingStarted.scm.title', "Track your code with Git"), - description: localize('gettingStarted.scm.description', "No more looking up Git commands! Git and GitHub workflows are seamlessly integrated.\n[Open Source Control](command:workbench.view.scm)"), + description: localize('gettingStarted.scm.description.interpolated', "No more looking up Git commands! Git and GitHub workflows are seamlessly integrated.\n{0}", Button(localize('openSCM', "Open Source Control"), 'command:workbench.view.scm')), when: 'config.git.enabled && !git.missing && workspaceFolderCount != 0 && gitOpenRepositoryCount != 0 && activeViewlet != \'workbench.view.scm\'', media: { type: 'image', altText: 'Source Control view.', path: { @@ -373,7 +375,7 @@ export const walkthroughs: GettingStartedWalkthroughContent = [ id: 'tasks', title: localize('gettingStarted.tasks.title', "Automate your project tasks"), when: 'workspaceFolderCount != 0', - description: localize('gettingStarted.tasks.description', "Create tasks for your common workflows and enjoy the integrated experience of running scripts and automatically checking results.\n[Run Auto-detected Tasks](command:workbench.action.tasks.runTask)"), + description: localize('gettingStarted.tasks.description.interpolated', "Create tasks for your common workflows and enjoy the integrated experience of running scripts and automatically checking results.\n{0}", Button(localize('runTasks', "Run Auto-detected Tasks"), 'command:workbench.action.tasks.runTask')), media: { type: 'image', altText: 'Task runner.', path: { dark: 'dark/tasks.png', @@ -385,7 +387,7 @@ export const walkthroughs: GettingStartedWalkthroughContent = [ { id: 'shortcuts', title: localize('gettingStarted.shortcuts.title', "Customize your shortcuts"), - description: localize('gettingStarted.shortcuts.description', "Once you have discovered your favorite commands, create custom keyboard shortcuts for instant access.\n[Keyboard Shortcuts](command:toSide:workbench.action.openGlobalKeybindings)"), + description: localize('gettingStarted.shortcuts.description.interpolated', "Once you have discovered your favorite commands, create custom keyboard shortcuts for instant access.\n{0}", Button(localize('keyboardShortcuts', "Keyboard Shortcuts"), 'command:toSide:workbench.action.openGlobalKeybindings')), media: { type: 'image', altText: 'Interactive shortcuts.', path: { dark: 'dark/shortcuts.png', From c5e845182bf934ccbf8a3be3e48317757388ec59 Mon Sep 17 00:00:00 2001 From: Jackson Kearl Date: Tue, 8 Jun 2021 16:19:45 -0700 Subject: [PATCH 23/40] Dont use exp service for choosing first content behaviour (#125780) --- .../gettingStarted/browser/gettingStarted.ts | 45 +++++++------------ 1 file changed, 15 insertions(+), 30 deletions(-) diff --git a/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.ts b/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.ts index b38ca2cfec45c..94175cb868a30 100644 --- a/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.ts +++ b/src/vs/workbench/contrib/welcome/gettingStarted/browser/gettingStarted.ts @@ -5,7 +5,7 @@ import 'vs/css!./gettingStarted'; import { localize } from 'vs/nls'; -import { IInstantiationService, optional } from 'vs/platform/instantiation/common/instantiation'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IEditorInputSerializer, IEditorOpenContext } from 'vs/workbench/common/editor'; import { Disposable, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { assertIsDefined } from 'vs/base/common/types'; @@ -17,7 +17,7 @@ import { IThemeService, registerThemingParticipant, ThemeIcon } from 'vs/platfor import { welcomePageBackground, welcomePageProgressBackground, welcomePageProgressForeground, welcomePageTileBackground, welcomePageTileHoverBackground, welcomePageTileShadow } from 'vs/workbench/contrib/welcome/page/browser/welcomePageColors'; import { activeContrastBorder, buttonBackground, buttonForeground, buttonHoverBackground, contrastBorder, descriptionForeground, focusBorder, foreground, textLinkActiveForeground, textLinkForeground } from 'vs/platform/theme/common/colorRegistry'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { ITelemetryService, lastSessionDateStorageKey } from 'vs/platform/telemetry/common/telemetry'; +import { firstSessionDateStorageKey, ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement'; import { gettingStartedCheckedCodicon, gettingStartedUncheckedCodicon } from 'vs/workbench/contrib/welcome/gettingStarted/browser/gettingStartedIcons'; import { IOpenerService, matchesScheme } from 'vs/platform/opener/common/opener'; @@ -27,7 +27,6 @@ import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storag import { CancellationToken } from 'vs/base/common/cancellation'; import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ContextKeyExpr, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; -import { ITASExperimentService } from 'vs/workbench/services/experiment/common/experimentService'; import { IRecentFolder, IRecentlyOpened, IRecentWorkspace, isRecentFolder, isRecentWorkspace, IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { onUnexpectedError } from 'vs/base/common/errors'; @@ -103,7 +102,6 @@ export class GettingStartedPage extends EditorPane { private container: HTMLElement; private contextService: IContextKeyService; - private tasExperimentService?: ITASExperimentService; private previousSelection?: string; private recentlyOpened: Promise; private selectedStepElement?: HTMLDivElement; @@ -144,7 +142,6 @@ export class GettingStartedPage extends EditorPane { @IHostService private readonly hostService: IHostService, @IWebviewService private readonly webviewService: IWebviewService, @IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService, - @optional(ITASExperimentService) tasExperimentService: ITASExperimentService, ) { super(GettingStartedPage.ID, telemetryService, themeService, storageService); @@ -158,9 +155,6 @@ export class GettingStartedPage extends EditorPane { this.stepMediaComponent = $('.getting-started-media'); this.stepMediaComponent.id = generateUuid(); - - this.tasExperimentService = tasExperimentService; - this.contextService = this._register(contextService.createScoped(this.container)); inGettingStartedContext.bindTo(this.contextService).set(true); @@ -797,28 +791,19 @@ export class GettingStartedPage extends EditorPane { const someStepsComplete = this.gettingStartedCategories.some(categry => categry.content.type === 'steps' && categry.content.stepsComplete); if (!someStepsComplete && !this.hasScrolledToFirstCategory) { - const fistContentBehaviour = - !this.storageService.get(lastSessionDateStorageKey, StorageScope.GLOBAL) // isNewUser ? - ? 'openToFirstCategory' - : await Promise.race([ - this.tasExperimentService?.getTreatment<'index' | 'openToFirstCategory'>('GettingStartedFirstContent'), - new Promise<'index'>(resolve => setTimeout(() => resolve('index'), 1000)), - ]); - - if (this.gettingStartedCategories.some(category => category.content.type === 'steps' && category.content.stepsComplete)) { - this.setSlide('categories'); - return; - } else { - if (fistContentBehaviour === 'openToFirstCategory') { - const first = this.gettingStartedCategories.find(category => category.content.type === 'steps'); - this.hasScrolledToFirstCategory = true; - if (first) { - this.currentCategory = first; - this.editorInput.selectedCategory = this.currentCategory?.id; - this.buildCategorySlide(this.editorInput.selectedCategory); - this.setSlide('details'); - return; - } + const firstSessionDateString = this.storageService.get(firstSessionDateStorageKey, StorageScope.GLOBAL) || new Date().toUTCString(); + const daysSinceFirstSession = ((+new Date()) - (+new Date(firstSessionDateString))) / 1000 / 60 / 60 / 24; + const fistContentBehaviour = daysSinceFirstSession < 1 ? 'openToFirstCategory' : 'index'; + + if (fistContentBehaviour === 'openToFirstCategory') { + const first = this.gettingStartedCategories.find(category => category.content.type === 'steps'); + this.hasScrolledToFirstCategory = true; + if (first) { + this.currentCategory = first; + this.editorInput.selectedCategory = this.currentCategory?.id; + this.buildCategorySlide(this.editorInput.selectedCategory); + this.setSlide('details'); + return; } } } From f8b576c274b74b7d15743f60df951834ebde55bf Mon Sep 17 00:00:00 2001 From: SteVen Batten <6561887+sbatten@users.noreply.github.com> Date: Wed, 9 Jun 2021 02:22:13 -0700 Subject: [PATCH 24/40] trust the empty window by default (#125788) --- .../contrib/workspace/browser/workspace.contribution.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts b/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts index 89ee35a2fe081..4b589ac17b89d 100644 --- a/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts +++ b/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts @@ -637,7 +637,7 @@ Registry.as(ConfigurationExtensions.Configuration) }, [WORKSPACE_TRUST_EMPTY_WINDOW]: { type: 'boolean', - default: false, + default: true, included: !isWeb, markdownDescription: localize('workspace.trust.emptyWindow.description', "Controls whether or not the empty window is trusted by default within VS Code. When used with `#{0}#`, you can enable the full functionality of VS Code without prompting in an empty window.", WORKSPACE_TRUST_UNTRUSTED_FILES), scope: ConfigurationScope.APPLICATION From d5fbc9f45fa76fd58a88f7f478f680a4fbe10d7e Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Wed, 9 Jun 2021 11:59:07 +0200 Subject: [PATCH 25/40] fix localization strings with `command:`. For #125786 --- .../codeEditor/browser/saveParticipants.ts | 14 +++++++------ .../contrib/remote/browser/remoteExplorer.ts | 4 +++- .../contrib/remote/browser/remoteIndicator.ts | 6 +++++- .../browser/workspace.contribution.ts | 21 ++++++++++++++++--- 4 files changed, 34 insertions(+), 11 deletions(-) diff --git a/src/vs/workbench/contrib/codeEditor/browser/saveParticipants.ts b/src/vs/workbench/contrib/codeEditor/browser/saveParticipants.ts index 5f4725e8f5631..825a93c9fc29d 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/saveParticipants.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/saveParticipants.ts @@ -233,9 +233,10 @@ class FormatOnSaveParticipant implements ITextFileSaveParticipant { const nestedProgress = new Progress<{ displayName?: string, extensionId?: ExtensionIdentifier }>(provider => { progress.report({ message: localize( - 'formatting', - "Running '{0}' Formatter ([configure](command:workbench.action.openSettings?%5B%22editor.formatOnSave%22%5D)).", - provider.displayName || provider.extensionId && provider.extensionId.value || '???' + { key: 'formatting2', comment: ['[configure]({1}) is a link. Only translate `configure`. Do not change brackets and parentheses or {1}'] }, + "Running '{0}' Formatter ([configure]({1})).", + provider.displayName || provider.extensionId && provider.extensionId.value || '???', + 'command:workbench.action.openSettings?%5B%22editor.formatOnSave%22%5D' ) }); }); @@ -336,9 +337,10 @@ class CodeActionOnSaveParticipant implements ITextFileSaveParticipant { private _report(): void { progress.report({ message: localize( - 'codeaction.get', - "Getting code actions from '{0}' ([configure](command:workbench.action.openSettings?%5B%22editor.codeActionsOnSave%22%5D)).", - [...this._names].map(name => `'${name}'`).join(', ') + { key: 'codeaction.get2', comment: ['[configure]({1}) is a link. Only translate `configure`. Do not change brackets and parentheses or {1}'] }, + "Getting code actions from '{0}' ([configure]({1})).", + [...this._names].map(name => `'${name}'`).join(', '), + 'command:workbench.action.openSettings?%5B%22editor.codeActionsOnSave%22%5D' ) }); } diff --git a/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts b/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts index 33a5e367bc0b8..db88121bccbdd 100644 --- a/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts +++ b/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts @@ -314,7 +314,9 @@ class OnAutoForwardedAction extends Disposable { } private linkMessage() { - return nls.localize('remote.tunnelsView.notificationLink', "[See all forwarded ports](command:{0}.focus)", TunnelPanel.ID); + return nls.localize( + { key: 'remote.tunnelsView.notificationLink2', comment: ['[See all forwarded ports]({0}) is a link. Only translate `See all forwarded ports`. Do not change brackets and parentheses or {0}'] }, + "[See all forwarded ports]({0})", `command:${TunnelPanel.ID}.focus`); } private async showNotification(tunnel: RemoteTunnel) { diff --git a/src/vs/workbench/contrib/remote/browser/remoteIndicator.ts b/src/vs/workbench/contrib/remote/browser/remoteIndicator.ts index cd9414e6fa577..d14756a807d49 100644 --- a/src/vs/workbench/contrib/remote/browser/remoteIndicator.ts +++ b/src/vs/workbench/contrib/remote/browser/remoteIndicator.ts @@ -301,7 +301,11 @@ export class RemoteStatusIndicator extends Disposable implements IWorkbenchContr const workspaceLabel = this.getWorkspaceLabel(); if (workspaceLabel) { const toolTip: IMarkdownString = { - value: nls.localize('workspace.tooltip', "Virtual workspace on {0}\n\n[Some features](command:{1}) are not available for resources located on a virtual file system.", workspaceLabel, LIST_WORKSPACE_UNSUPPORTED_EXTENSIONS_COMMAND_ID), + value: nls.localize( + { key: 'workspace.tooltip2', comment: ['[abc]({1}) is a link. Only translate `Some features`. Do not change brackets and parentheses or {1}'] }, + "Virtual workspace on {0}\n\n[Some features]({1}) are not available for resources located on a virtual file system.", + workspaceLabel, `command:${LIST_WORKSPACE_UNSUPPORTED_EXTENSIONS_COMMAND_ID}` + ), isTrusted: true }; this.renderRemoteStatusIndicator(`$(remote) ${truncate(workspaceLabel, RemoteStatusIndicator.REMOTE_STATUS_LABEL_MAX_LENGTH)}`, toolTip); diff --git a/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts b/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts index 89ee35a2fe081..9969581e7ca6d 100644 --- a/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts +++ b/src/vs/workbench/contrib/workspace/browser/workspace.contribution.ts @@ -374,7 +374,12 @@ export class WorkspaceTrustUXHandler extends Disposable implements IWorkbenchCon ariaLabel = trusted ? localize('status.ariaTrustedWindow', "This window is trusted.") : localize('status.ariaUntrustedWindow', "Restricted Mode: Some features are disabled because this window is not trusted."); toolTip = trusted ? ariaLabel : { - value: localize('status.tooltipUntrustedWindow', "Running in Restricted Mode\n\n\Some [features are disabled](command:{0}) because this [window is not trusted](command:{1}).", LIST_WORKSPACE_UNSUPPORTED_EXTENSIONS_COMMAND_ID, MANAGE_TRUST_COMMAND_ID), + value: localize( + { key: 'status.tooltipUntrustedWindow2', comment: ['[abc]({n}) are links. Only translate `features are disabled` and `window is not trusted`. Do not change brackets and parentheses or {n}'] }, + "Running in Restricted Mode\n\nSome [features are disabled]({0}) because this [window is not trusted]({1}).", + `command:${LIST_WORKSPACE_UNSUPPORTED_EXTENSIONS_COMMAND_ID}`, + `command:${MANAGE_TRUST_COMMAND_ID}` + ), isTrusted: true, supportThemeIcons: true }; @@ -384,7 +389,12 @@ export class WorkspaceTrustUXHandler extends Disposable implements IWorkbenchCon ariaLabel = trusted ? localize('status.ariaTrustedFolder', "This folder is trusted.") : localize('status.ariaUntrustedFolder', "Restricted Mode: Some features are disabled because this folder is not trusted."); toolTip = trusted ? ariaLabel : { - value: localize('status.tooltipUntrustedFolder', "Running in Restricted Mode\n\n\Some [features are disabled](command:{0}) because this [folder is not trusted](command:{1}).", LIST_WORKSPACE_UNSUPPORTED_EXTENSIONS_COMMAND_ID, MANAGE_TRUST_COMMAND_ID), + value: localize( + { key: 'status.tooltipUntrustedFolder2', comment: ['[abc]({n}) are links. Only translate `features are disabled` and `folder is not trusted`. Do not change brackets and parentheses or {n}'] }, + "Running in Restricted Mode\n\nSome [features are disabled]({0}) because this [folder is not trusted]({1}).", + `command:${LIST_WORKSPACE_UNSUPPORTED_EXTENSIONS_COMMAND_ID}`, + `command:${MANAGE_TRUST_COMMAND_ID}` + ), isTrusted: true, supportThemeIcons: true }; @@ -394,7 +404,12 @@ export class WorkspaceTrustUXHandler extends Disposable implements IWorkbenchCon ariaLabel = trusted ? localize('status.ariaTrustedWorkspace', "This workspace is trusted.") : localize('status.ariaUntrustedWorkspace', "Restricted Mode: Some features are disabled because this workspace is not trusted."); toolTip = trusted ? ariaLabel : { - value: localize('status.tooltipUntrustedWorkspace', "Running in Restricted Mode\n\n\Some [features are disabled](command:{0}) because this [workspace is not trusted](command:{1}).", LIST_WORKSPACE_UNSUPPORTED_EXTENSIONS_COMMAND_ID, MANAGE_TRUST_COMMAND_ID), + value: localize( + { key: 'status.tooltipUntrustedWorkspace2', comment: ['[abc]({n}) are links. Only translate `features are disabled` and `workspace is not trusted`. Do not change brackets and parentheses or {n}'] }, + "Running in Restricted Mode\n\nSome [features are disabled]({0}) because this [workspace is not trusted]({1}).", + `command:${LIST_WORKSPACE_UNSUPPORTED_EXTENSIONS_COMMAND_ID}`, + `command:${MANAGE_TRUST_COMMAND_ID}` + ), isTrusted: true, supportThemeIcons: true }; From 33d504f8455b5c0ddf27d529739ca17bb634092d Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Wed, 9 Jun 2021 12:12:50 +0200 Subject: [PATCH 26/40] clarify nls comment --- src/vs/workbench/contrib/remote/browser/remoteIndicator.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/remote/browser/remoteIndicator.ts b/src/vs/workbench/contrib/remote/browser/remoteIndicator.ts index d14756a807d49..a1f3501b511fa 100644 --- a/src/vs/workbench/contrib/remote/browser/remoteIndicator.ts +++ b/src/vs/workbench/contrib/remote/browser/remoteIndicator.ts @@ -302,7 +302,7 @@ export class RemoteStatusIndicator extends Disposable implements IWorkbenchContr if (workspaceLabel) { const toolTip: IMarkdownString = { value: nls.localize( - { key: 'workspace.tooltip2', comment: ['[abc]({1}) is a link. Only translate `Some features`. Do not change brackets and parentheses or {1}'] }, + { key: 'workspace.tooltip2', comment: ['{0} is a remote location name, e.g. GitHub', '[Some features]({1}) is a link. Only translate `Some features`. Do not change brackets and parentheses or {1}'] }, "Virtual workspace on {0}\n\n[Some features]({1}) are not available for resources located on a virtual file system.", workspaceLabel, `command:${LIST_WORKSPACE_UNSUPPORTED_EXTENSIONS_COMMAND_ID}` ), From 6370d95598dc3ddcee45670dff3482e730f11485 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Fri, 11 Jun 2021 16:59:59 -0700 Subject: [PATCH 27/40] Set visibility of markdown cells before rendering it (#126099) Backports fix for #126056 to 1.57 For #126056 This was regressed when we made rendering potentially be async --- .../notebook/browser/view/renderers/webviewPreloads.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts index e68eac4a35cac..ec91e32c8f430 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts @@ -1071,7 +1071,7 @@ async function webviewPreloads(style: PreloadStyles, options: PreloadOptions, re } } - async function createMarkdownPreview(cellId: string, content: string, top: number): Promise { + async function createMarkdownPreview(cellId: string, content: string, top: number, visible: boolean): Promise { const container = document.getElementById('container')!; const cellContainer = document.createElement('div'); @@ -1084,6 +1084,7 @@ async function webviewPreloads(style: PreloadStyles, options: PreloadOptions, re cellContainer.id = cellId; cellContainer.classList.add('preview'); + cellContainer.style.visibility = visible ? 'visible' : 'hidden'; cellContainer.style.position = 'absolute'; cellContainer.style.top = top + 'px'; container.appendChild(cellContainer); @@ -1157,12 +1158,11 @@ async function webviewPreloads(style: PreloadStyles, options: PreloadOptions, re await Promise.all(update.map(async cell => { let container = document.getElementById(cell.cellId); if (container) { + container.style.visibility = cell.visible ? 'visible' : 'hidden'; await updateMarkdownPreview(container, cell.cellId, cell.content); } else { - container = await createMarkdownPreview(cell.cellId, cell.content, cell.offset); + container = await createMarkdownPreview(cell.cellId, cell.content, cell.offset, cell.visible); } - - container.style.visibility = cell.visible ? 'visible' : 'hidden'; })); } From ca66517cf901ddd7b1bc242af38727e3281d25bc Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 14 Jun 2021 10:46:56 +0200 Subject: [PATCH 28/40] Revert back to Electron `12.0.7` (#126026) * Revert "chore: bump electron@12.0.9" This reverts commit 286b643ecd231f66f3f2e67e1456f3c601838b46. * Revert "macOS - workaround fullscreen window regression (#125122)" This reverts commit a286059b90d42c797316c2a7c02ccbf6a679fa3f. --- .yarnrc | 2 +- cgmanifest.json | 4 ++-- package.json | 2 +- .../electron-main/windowsStateHandler.ts | 20 +++++-------------- yarn.lock | 8 ++++---- 5 files changed, 13 insertions(+), 23 deletions(-) diff --git a/.yarnrc b/.yarnrc index ba290809667b9..0b7e220665004 100644 --- a/.yarnrc +++ b/.yarnrc @@ -1,3 +1,3 @@ disturl "https://electronjs.org/headers" -target "12.0.9" +target "12.0.7" runtime "electron" diff --git a/cgmanifest.json b/cgmanifest.json index 22cbc50562c5b..474d6191ba53b 100644 --- a/cgmanifest.json +++ b/cgmanifest.json @@ -60,12 +60,12 @@ "git": { "name": "electron", "repositoryUrl": "https://github.com/electron/electron", - "commitHash": "30f82dd1cb8140ccb5c6a4960eef8e3b8c15eeba" + "commitHash": "8d55658bfa8b5983e1a90ad079c2e2ac91ee7af0" } }, "isOnlyProductionDependency": true, "license": "MIT", - "version": "12.0.9" + "version": "12.0.7" }, { "component": { diff --git a/package.json b/package.json index 3c2b3b89dc097..272d75f717376 100644 --- a/package.json +++ b/package.json @@ -125,7 +125,7 @@ "cssnano": "^4.1.11", "debounce": "^1.0.0", "deemon": "^1.4.0", - "electron": "12.0.9", + "electron": "12.0.7", "eslint": "6.8.0", "eslint-plugin-jsdoc": "^19.1.0", "event-stream": "3.3.4", diff --git a/src/vs/platform/windows/electron-main/windowsStateHandler.ts b/src/vs/platform/windows/electron-main/windowsStateHandler.ts index b24443601c2e5..1bdadb1261073 100644 --- a/src/vs/platform/windows/electron-main/windowsStateHandler.ts +++ b/src/vs/platform/windows/electron-main/windowsStateHandler.ts @@ -232,11 +232,9 @@ export class WindowsStateHandler extends Disposable { const windowConfig = this.configurationService.getValue('window'); // Window state is not from a previous session: only allow fullscreen if we inherit it or user wants fullscreen - // or to address a Electron issue on macOS (https://github.com/microsoft/vscode/issues/125122) let allowFullscreen: boolean; if (state.hasDefaultState) { - const configAllowsFullScreen = !!(windowConfig?.newWindowDimensions && ['fullscreen', 'inherit', 'offset'].indexOf(windowConfig.newWindowDimensions) >= 0); - allowFullscreen = configAllowsFullScreen || (isMacintosh && windowConfig?.nativeFullScreen !== false); + allowFullscreen = !!(windowConfig?.newWindowDimensions && ['fullscreen', 'inherit', 'offset'].indexOf(windowConfig.newWindowDimensions) >= 0); } // Window state is from a previous session: only allow fullscreen when we got updated or user wants to restore @@ -339,22 +337,14 @@ export class WindowsStateHandler extends Disposable { // Compute x/y based on display bounds // Note: important to use Math.round() because Electron does not seem to be too happy about // display coordinates that are not absolute numbers. - let state: INewWindowState = defaultWindowState(); + let state = defaultWindowState(); state.x = Math.round(displayToUse.bounds.x + (displayToUse.bounds.width / 2) - (state.width! / 2)); state.y = Math.round(displayToUse.bounds.y + (displayToUse.bounds.height / 2) - (state.height! / 2)); + // Check for newWindowDimensions setting and adjust accordingly const windowConfig = this.configurationService.getValue('window'); let ensureNoOverlap = true; - - // TODO@electron macOS: if the current window is fullscreen and native fullscreen - // is not disabled, always open a new window in fullscreen. This is a workaround - // for regression https://github.com/microsoft/vscode/issues/125122 - if (isMacintosh && windowConfig?.nativeFullScreen !== false && lastActive?.isFullScreen) { - state.mode = WindowMode.Fullscreen; - } - - // Adjust according to `newWindowDimensions` user setting - else if (windowConfig?.newWindowDimensions) { + if (windowConfig?.newWindowDimensions) { if (windowConfig.newWindowDimensions === 'maximized') { state.mode = WindowMode.Maximized; ensureNoOverlap = false; @@ -377,7 +367,7 @@ export class WindowsStateHandler extends Disposable { state = this.ensureNoOverlap(state); } - state.hasDefaultState = true; // flag as default state + (state as INewWindowState).hasDefaultState = true; // flag as default state return state; } diff --git a/yarn.lock b/yarn.lock index 2d5cec7e66e5a..9d031db1b718f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3001,10 +3001,10 @@ electron-to-chromium@^1.3.723: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.737.tgz#196f2e9656f4f3c31930750e1899c091b72d36b5" integrity sha512-P/B84AgUSQXaum7a8m11HUsYL8tj9h/Pt5f7Hg7Ty6bm5DxlFq+e5+ouHUoNQMsKDJ7u4yGfI8mOErCmSH9wyg== -electron@12.0.9: - version "12.0.9" - resolved "https://registry.yarnpkg.com/electron/-/electron-12.0.9.tgz#d582afa8f6fc0c429606f0961a4c89b376994823" - integrity sha512-p5aEt1tIh/PYjwN+6MHTc5HtW529XR9r4Qlj9PPcSb5ubkotSsS0BtWJoRPhDenSAN8sgHk3sbZLxXPJtdnRYA== +electron@12.0.7: + version "12.0.7" + resolved "https://registry.yarnpkg.com/electron/-/electron-12.0.7.tgz#e0fca2c8be34cb7da48c4d15cfb1d2ad666d2718" + integrity sha512-722TZNKDuLpEmj96AzTYFKHaJEH98xgOBH0aldStaPXI1xDFfb9SJQQuirvwFlkwG5OqQdz6Ne3OwwJ7Dbs5nQ== dependencies: "@electron/get" "^1.0.1" "@types/node" "^14.6.2" From b9f4ab00ba81360656e9951408a4896c69b38b4a Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 14 Jun 2021 10:47:22 +0200 Subject: [PATCH 29/40] linux - restore `--no-sandbox` for startup scripts (#126028) --- resources/linux/code-url-handler.desktop | 2 +- resources/linux/code.desktop | 4 ++-- src/vs/code/node/cli.ts | 6 +++++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/resources/linux/code-url-handler.desktop b/resources/linux/code-url-handler.desktop index 7106e0e0969be..b85525fbd042c 100644 --- a/resources/linux/code-url-handler.desktop +++ b/resources/linux/code-url-handler.desktop @@ -2,7 +2,7 @@ Name=@@NAME_LONG@@ - URL Handler Comment=Code Editing. Redefined. GenericName=Text Editor -Exec=@@EXEC@@ --open-url %U +Exec=@@EXEC@@ --no-sandbox --open-url %U Icon=@@ICON@@ Type=Application NoDisplay=true diff --git a/resources/linux/code.desktop b/resources/linux/code.desktop index ab3b79a011b77..62d6bfc47b469 100755 --- a/resources/linux/code.desktop +++ b/resources/linux/code.desktop @@ -2,7 +2,7 @@ Name=@@NAME_LONG@@ Comment=Code Editing. Redefined. GenericName=Text Editor -Exec=@@EXEC@@ --unity-launch %F +Exec=@@EXEC@@ --no-sandbox --unity-launch %F Icon=@@ICON@@ Type=Application StartupNotify=false @@ -14,5 +14,5 @@ Keywords=vscode; [Desktop Action new-empty-window] Name=New Empty Window -Exec=@@EXEC@@ --new-window %F +Exec=@@EXEC@@ --no-sandbox --new-window %F Icon=@@ICON@@ diff --git a/src/vs/code/node/cli.ts b/src/vs/code/node/cli.ts index 2e7b324ed1d1e..169b50ae77c29 100644 --- a/src/vs/code/node/cli.ts +++ b/src/vs/code/node/cli.ts @@ -15,7 +15,7 @@ import { isAbsolute, join } from 'vs/base/common/path'; import { whenDeleted, writeFileSync } from 'vs/base/node/pfs'; import { findFreePort } from 'vs/base/node/ports'; import { randomPort } from 'vs/base/common/ports'; -import { isWindows, IProcessEnvironment } from 'vs/base/common/platform'; +import { isLinux, isWindows, IProcessEnvironment } from 'vs/base/common/platform'; import type { ProfilingSession, Target } from 'v8-inspect-profiler'; import { isString } from 'vs/base/common/types'; import { hasStdinWithoutTty, stdinDataListener, getStdinFilePath, readFromStdin } from 'vs/platform/environment/node/stdin'; @@ -319,6 +319,10 @@ export async function main(argv: string[]): Promise { options['stdio'] = 'ignore'; } + if (isLinux) { + addArg(argv, '--no-sandbox'); // Electron 6 introduces a chrome-sandbox that requires root to run. This can fail. Disable sandbox via --no-sandbox + } + const child = spawn(process.execPath, argv.slice(2), options); if (args.wait && waitMarkerFilePath) { From 6bca69fc6fb2426fb56d07877c425a7cba00ca2e Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Mon, 14 Jun 2021 10:47:45 +0200 Subject: [PATCH 30/40] macos - restore Cmd+W to close window when no editors opened (#126045) --- .../electron-sandbox/actions/windowActions.ts | 4 +++- .../electron-sandbox/desktop.contribution.ts | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/electron-sandbox/actions/windowActions.ts b/src/vs/workbench/electron-sandbox/actions/windowActions.ts index e6dbac49746c5..67fd94f32dea7 100644 --- a/src/vs/workbench/electron-sandbox/actions/windowActions.ts +++ b/src/vs/workbench/electron-sandbox/actions/windowActions.ts @@ -27,9 +27,11 @@ import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegis export class CloseWindowAction extends Action2 { + static readonly ID = 'workbench.action.closeWindow'; + constructor() { super({ - id: 'workbench.action.closeWindow', + id: CloseWindowAction.ID, title: { value: localize('closeWindow', "Close Window"), mnemonicTitle: localize({ key: 'miCloseWindow', comment: ['&& denotes a mnemonic'] }, "Clos&&e Window"), diff --git a/src/vs/workbench/electron-sandbox/desktop.contribution.ts b/src/vs/workbench/electron-sandbox/desktop.contribution.ts index 01564b51c732b..59b1afc670988 100644 --- a/src/vs/workbench/electron-sandbox/desktop.contribution.ts +++ b/src/vs/workbench/electron-sandbox/desktop.contribution.ts @@ -23,6 +23,7 @@ import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } fr import { PartsSplash } from 'vs/workbench/electron-sandbox/splash'; import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle'; import { InstallShellScriptAction, UninstallShellScriptAction } from 'vs/workbench/electron-sandbox/actions/installActions'; +import { EditorsVisibleContext, SingleEditorGroupsContext } from 'vs/workbench/common/editor'; // Actions (function registerActions(): void { @@ -37,6 +38,19 @@ import { InstallShellScriptAction, UninstallShellScriptAction } from 'vs/workben registerAction2(QuickSwitchWindowAction); registerAction2(CloseWindowAction); + if (isMacintosh) { + // macOS: behave like other native apps that have documents + // but can run without a document opened and allow to close + // the window when the last document is closed + // (https://github.com/microsoft/vscode/issues/126042) + KeybindingsRegistry.registerKeybindingRule({ + id: CloseWindowAction.ID, + weight: KeybindingWeight.WorkbenchContrib, + when: ContextKeyExpr.and(EditorsVisibleContext.toNegated(), SingleEditorGroupsContext), + primary: KeyMod.CtrlCmd | KeyCode.KEY_W + }); + } + // Actions: Install Shell Script (macOS only) if (isMacintosh) { registerAction2(InstallShellScriptAction); From a16b9181915a6bc799c97be83493696f814c3d16 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 11 Jun 2021 11:20:18 -0700 Subject: [PATCH 31/40] Pass config to external terminal service The config service on the main process isn't complete which results in the terminal config being undefined if there are no user terminals settings set. Fixes #125985 --- .../common/externalTerminal.ts | 2 +- .../externalTerminalService.test.ts | 18 ++++---- .../node/externalTerminalService.ts | 46 ++++--------------- .../workbench/contrib/debug/node/terminals.ts | 7 ++- .../browser/externalTerminal.contribution.ts | 5 +- .../externalTerminal.contribution.ts | 11 +++-- 6 files changed, 33 insertions(+), 56 deletions(-) diff --git a/src/vs/platform/externalTerminal/common/externalTerminal.ts b/src/vs/platform/externalTerminal/common/externalTerminal.ts index 72d71f88520bb..df1a6e20a2eed 100644 --- a/src/vs/platform/externalTerminal/common/externalTerminal.ts +++ b/src/vs/platform/externalTerminal/common/externalTerminal.ts @@ -22,7 +22,7 @@ export interface ITerminalForPlatform { export interface IExternalTerminalService { readonly _serviceBrand: undefined; - openTerminal(path: string): Promise; + openTerminal(configuration: IExternalTerminalSettings, path: string): Promise; runInTerminal(title: string, cwd: string, args: string[], env: ITerminalEnvironment, settings: IExternalTerminalSettings): Promise; getDefaultTerminalForPlatforms(): Promise; } diff --git a/src/vs/platform/externalTerminal/electron-main/externalTerminalService.test.ts b/src/vs/platform/externalTerminal/electron-main/externalTerminalService.test.ts index a3acac5ce1352..86970909b5000 100644 --- a/src/vs/platform/externalTerminal/electron-main/externalTerminalService.test.ts +++ b/src/vs/platform/externalTerminal/electron-main/externalTerminalService.test.ts @@ -42,7 +42,7 @@ suite('ExternalTerminalService', () => { }; } }; - let testService = new WindowsExternalTerminalService(mockConfig); + let testService = new WindowsExternalTerminalService(); (testService).spawnTerminal( mockSpawner, mockConfig, @@ -67,7 +67,7 @@ suite('ExternalTerminalService', () => { } }; mockConfig.terminal.external.windowsExec = undefined; - let testService = new WindowsExternalTerminalService(mockConfig); + let testService = new WindowsExternalTerminalService(); (testService).spawnTerminal( mockSpawner, mockConfig, @@ -91,7 +91,7 @@ suite('ExternalTerminalService', () => { }; } }; - let testService = new WindowsExternalTerminalService(mockConfig); + let testService = new WindowsExternalTerminalService(); (testService).spawnTerminal( mockSpawner, mockConfig, @@ -115,7 +115,7 @@ suite('ExternalTerminalService', () => { return { on: (evt: any) => evt }; } }; - let testService = new WindowsExternalTerminalService(mockConfig); + let testService = new WindowsExternalTerminalService(); (testService).spawnTerminal( mockSpawner, mockConfig, @@ -137,7 +137,7 @@ suite('ExternalTerminalService', () => { return { on: (evt: any) => evt }; } }; - let testService = new WindowsExternalTerminalService(mockConfig); + let testService = new WindowsExternalTerminalService(); (testService).spawnTerminal( mockSpawner, mockConfig, @@ -160,7 +160,7 @@ suite('ExternalTerminalService', () => { }; } }; - let testService = new MacExternalTerminalService(mockConfig); + let testService = new MacExternalTerminalService(); (testService).spawnTerminal( mockSpawner, mockConfig, @@ -183,7 +183,7 @@ suite('ExternalTerminalService', () => { } }; mockConfig.terminal.external.osxExec = undefined; - let testService = new MacExternalTerminalService(mockConfig); + let testService = new MacExternalTerminalService(); (testService).spawnTerminal( mockSpawner, mockConfig, @@ -206,7 +206,7 @@ suite('ExternalTerminalService', () => { }; } }; - let testService = new LinuxExternalTerminalService(mockConfig); + let testService = new LinuxExternalTerminalService(); (testService).spawnTerminal( mockSpawner, mockConfig, @@ -230,7 +230,7 @@ suite('ExternalTerminalService', () => { } }; mockConfig.terminal.external.linuxExec = undefined; - let testService = new LinuxExternalTerminalService(mockConfig); + let testService = new LinuxExternalTerminalService(); (testService).spawnTerminal( mockSpawner, mockConfig, diff --git a/src/vs/platform/externalTerminal/node/externalTerminalService.ts b/src/vs/platform/externalTerminal/node/externalTerminalService.ts index a7ae827eee1c2..c90429f95092a 100644 --- a/src/vs/platform/externalTerminal/node/externalTerminalService.ts +++ b/src/vs/platform/externalTerminal/node/externalTerminalService.ts @@ -9,9 +9,7 @@ import * as processes from 'vs/base/node/processes'; import * as nls from 'vs/nls'; import * as pfs from 'vs/base/node/pfs'; import * as env from 'vs/base/common/platform'; -import { IExternalTerminalConfiguration, IExternalTerminalSettings, DEFAULT_TERMINAL_OSX, ITerminalForPlatform, IExternalTerminalMainService } from 'vs/platform/externalTerminal/common/externalTerminal'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { optional } from 'vs/platform/instantiation/common/instantiation'; +import { IExternalTerminalSettings, DEFAULT_TERMINAL_OSX, ITerminalForPlatform, IExternalTerminalMainService } from 'vs/platform/externalTerminal/common/externalTerminal'; import { FileAccess } from 'vs/base/common/network'; import { ITerminalEnvironment } from 'vs/platform/terminal/common/terminal'; import { sanitizeProcessEnvironment } from 'vs/base/common/processes'; @@ -31,20 +29,12 @@ export class WindowsExternalTerminalService extends ExternalTerminalService impl private static readonly CMD = 'cmd.exe'; private static _DEFAULT_TERMINAL_WINDOWS: string; - constructor( - @optional(IConfigurationService) private readonly _configurationService: IConfigurationService - ) { - super(); - } - - public openTerminal(cwd?: string): Promise { - const configuration = this._configurationService.getValue(); + public openTerminal(configuration: IExternalTerminalSettings, cwd?: string): Promise { return this.spawnTerminal(cp, configuration, processes.getWindowsShell(), cwd); } - public spawnTerminal(spawner: typeof cp, configuration: IExternalTerminalConfiguration, command: string, cwd?: string): Promise { - const terminalConfig = configuration.terminal.external; - const exec = terminalConfig?.windowsExec || WindowsExternalTerminalService.getDefaultTerminalWindows(); + public spawnTerminal(spawner: typeof cp, configuration: IExternalTerminalSettings, command: string, cwd?: string): Promise { + const exec = configuration.windowsExec || WindowsExternalTerminalService.getDefaultTerminalWindows(); // Make the drive letter uppercase on Windows (see #9448) if (cwd && cwd[1] === ':') { @@ -124,14 +114,7 @@ export class WindowsExternalTerminalService extends ExternalTerminalService impl export class MacExternalTerminalService extends ExternalTerminalService implements IExternalTerminalMainService { private static readonly OSASCRIPT = '/usr/bin/osascript'; // osascript is the AppleScript interpreter on OS X - constructor( - @optional(IConfigurationService) private readonly _configurationService: IConfigurationService - ) { - super(); - } - - public openTerminal(cwd?: string): Promise { - const configuration = this._configurationService.getValue(); + public openTerminal(configuration: IExternalTerminalSettings, cwd?: string): Promise { return this.spawnTerminal(cp, configuration, cwd); } @@ -199,9 +182,8 @@ export class MacExternalTerminalService extends ExternalTerminalService implemen }); } - spawnTerminal(spawner: typeof cp, configuration: IExternalTerminalConfiguration, cwd?: string): Promise { - const terminalConfig = configuration.terminal.external; - const terminalApp = terminalConfig?.osxExec || DEFAULT_TERMINAL_OSX; + spawnTerminal(spawner: typeof cp, configuration: IExternalTerminalSettings, cwd?: string): Promise { + const terminalApp = configuration.osxExec || DEFAULT_TERMINAL_OSX; return new Promise((c, e) => { const args = ['-a', terminalApp]; @@ -219,14 +201,7 @@ export class LinuxExternalTerminalService extends ExternalTerminalService implem private static readonly WAIT_MESSAGE = nls.localize('press.any.key', "Press any key to continue..."); - constructor( - @optional(IConfigurationService) private readonly _configurationService: IConfigurationService - ) { - super(); - } - - public openTerminal(cwd?: string): Promise { - const configuration = this._configurationService.getValue(); + public openTerminal(configuration: IExternalTerminalSettings, cwd?: string): Promise { return this.spawnTerminal(cp, configuration, cwd); } @@ -314,9 +289,8 @@ export class LinuxExternalTerminalService extends ExternalTerminalService implem return LinuxExternalTerminalService._DEFAULT_TERMINAL_LINUX_READY; } - spawnTerminal(spawner: typeof cp, configuration: IExternalTerminalConfiguration, cwd?: string): Promise { - const terminalConfig = configuration.terminal.external; - const execPromise = terminalConfig?.linuxExec ? Promise.resolve(terminalConfig.linuxExec) : LinuxExternalTerminalService.getDefaultTerminalLinuxReady(); + spawnTerminal(spawner: typeof cp, configuration: IExternalTerminalSettings, cwd?: string): Promise { + const execPromise = configuration.linuxExec ? Promise.resolve(configuration.linuxExec) : LinuxExternalTerminalService.getDefaultTerminalLinuxReady(); return new Promise((c, e) => { execPromise.then(exec => { diff --git a/src/vs/workbench/contrib/debug/node/terminals.ts b/src/vs/workbench/contrib/debug/node/terminals.ts index a4ef4b4c84f47..4155cf3bfdd18 100644 --- a/src/vs/workbench/contrib/debug/node/terminals.ts +++ b/src/vs/workbench/contrib/debug/node/terminals.ts @@ -8,7 +8,6 @@ import * as platform from 'vs/base/common/platform'; import { getDriveLetter } from 'vs/base/common/extpath'; import { LinuxExternalTerminalService, MacExternalTerminalService, WindowsExternalTerminalService } from 'vs/platform/externalTerminal/node/externalTerminalService'; import { IExternalTerminalService } from 'vs/platform/externalTerminal/common/externalTerminal'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ExtHostConfigProvider } from 'vs/workbench/api/common/extHostConfiguration'; @@ -36,11 +35,11 @@ let externalTerminalService: IExternalTerminalService | undefined = undefined; export function runInExternalTerminal(args: DebugProtocol.RunInTerminalRequestArguments, configProvider: ExtHostConfigProvider): Promise { if (!externalTerminalService) { if (platform.isWindows) { - externalTerminalService = new WindowsExternalTerminalService(undefined); + externalTerminalService = new WindowsExternalTerminalService(); } else if (platform.isMacintosh) { - externalTerminalService = new MacExternalTerminalService(undefined); + externalTerminalService = new MacExternalTerminalService(); } else if (platform.isLinux) { - externalTerminalService = new LinuxExternalTerminalService(undefined); + externalTerminalService = new LinuxExternalTerminalService(); } else { throw new Error('external terminals not supported on this platform'); } diff --git a/src/vs/workbench/contrib/externalTerminal/browser/externalTerminal.contribution.ts b/src/vs/workbench/contrib/externalTerminal/browser/externalTerminal.contribution.ts index d817ac6417005..daa8d8ec03a2c 100644 --- a/src/vs/workbench/contrib/externalTerminal/browser/externalTerminal.contribution.ts +++ b/src/vs/workbench/contrib/externalTerminal/browser/externalTerminal.contribution.ts @@ -42,7 +42,8 @@ CommandsRegistry.registerCommand({ return fileService.resolveAll(resources.map(r => ({ resource: r }))).then(async stats => { const targets = distinct(stats.filter(data => data.success)); // Always use integrated terminal when using a remote - const useIntegratedTerminal = remoteAgentService.getConnection() || configurationService.getValue().terminal.explorerKind === 'integrated'; + const config = configurationService.getValue(); + const useIntegratedTerminal = remoteAgentService.getConnection() || config.terminal.explorerKind === 'integrated'; if (useIntegratedTerminal) { // TODO: Use uri for cwd in createterminal const opened: { [path: string]: boolean } = {}; @@ -71,7 +72,7 @@ CommandsRegistry.registerCommand({ }); } else { distinct(targets.map(({ stat }) => stat!.isDirectory ? stat!.resource.fsPath : dirname(stat!.resource.fsPath))).forEach(cwd => { - terminalService!.openTerminal(cwd); + terminalService!.openTerminal(config.terminal.external, cwd); }); } }); diff --git a/src/vs/workbench/contrib/externalTerminal/electron-sandbox/externalTerminal.contribution.ts b/src/vs/workbench/contrib/externalTerminal/electron-sandbox/externalTerminal.contribution.ts index e63a96b7c60c4..b7acdba1aec5f 100644 --- a/src/vs/workbench/contrib/externalTerminal/electron-sandbox/externalTerminal.contribution.ts +++ b/src/vs/workbench/contrib/externalTerminal/electron-sandbox/externalTerminal.contribution.ts @@ -5,7 +5,7 @@ import * as nls from 'vs/nls'; import * as paths from 'vs/base/common/path'; -import { DEFAULT_TERMINAL_OSX, IExternalTerminalService } from 'vs/platform/externalTerminal/common/externalTerminal'; +import { DEFAULT_TERMINAL_OSX, IExternalTerminalService, IExternalTerminalSettings } from 'vs/platform/externalTerminal/common/externalTerminal'; import { MenuId, MenuRegistry } from 'vs/platform/actions/common/actions'; import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { KEYBINDING_CONTEXT_TERMINAL_NOT_FOCUSED } from 'vs/workbench/contrib/terminal/common/terminal'; @@ -17,6 +17,7 @@ import { IConfigurationRegistry, Extensions, ConfigurationScope } from 'vs/platf import { Registry } from 'vs/platform/registry/common/platform'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { IExternalTerminalMainService } from 'vs/platform/externalTerminal/electron-sandbox/externalTerminalMainService'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; const OPEN_NATIVE_CONSOLE_COMMAND_ID = 'workbench.action.terminal.openNativeConsole'; KeybindingsRegistry.registerCommandAndKeybindingRule({ @@ -28,18 +29,20 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ const historyService = accessor.get(IHistoryService); // Open external terminal in local workspaces const terminalService = accessor.get(IExternalTerminalService); + const configurationService = accessor.get(IConfigurationService); const root = historyService.getLastActiveWorkspaceRoot(Schemas.file); + const config = configurationService.getValue('terminal.external'); if (root) { - terminalService.openTerminal(root.fsPath); + terminalService.openTerminal(config, root.fsPath); } else { // Opens current file's folder, if no folder is open in editor const activeFile = historyService.getLastActiveFile(Schemas.file); if (activeFile) { - terminalService.openTerminal(paths.dirname(activeFile.fsPath)); + terminalService.openTerminal(config, paths.dirname(activeFile.fsPath)); } else { const pathService = accessor.get(IPathService); const userHome = await pathService.userHome(); - terminalService.openTerminal(userHome.fsPath); + terminalService.openTerminal(config, userHome.fsPath); } } } From d21d7d9d3e8383e4e2f9431f10dabc29629908ec Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com> Date: Mon, 14 Jun 2021 17:30:16 +0200 Subject: [PATCH 32/40] Port fix #126057 (#126215) --- .../workspaces/common/workspaceTrust.ts | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/vs/workbench/services/workspaces/common/workspaceTrust.ts b/src/vs/workbench/services/workspaces/common/workspaceTrust.ts index 97a83689a8596..f3a1ae0150480 100644 --- a/src/vs/workbench/services/workspaces/common/workspaceTrust.ts +++ b/src/vs/workbench/services/workspaces/common/workspaceTrust.ts @@ -126,15 +126,17 @@ export class WorkspaceTrustManagementService extends Disposable implements IWork private registerListeners(): void { // Resolve the workspace uris and resolve the initialization promise - this.resolveCanonicalWorkspaceUris().then(async () => { - this._initialized = true; - await this.updateWorkspaceTrust(); - - this._workspaceResolvedPromiseResolve(); - if (!this.environmentService.remoteAuthority) { - this._workspaceTrustInitializedPromiseResolve(); - } - }); + this.resolveCanonicalWorkspaceUris() + .then(async () => { + this._initialized = true; + await this.updateWorkspaceTrust(); + }) + .finally(() => { + this._workspaceResolvedPromiseResolve(); + if (!this.environmentService.remoteAuthority) { + this._workspaceTrustInitializedPromiseResolve(); + } + }); // Remote - resolve remote authority if (this.environmentService.remoteAuthority) { @@ -142,7 +144,8 @@ export class WorkspaceTrustManagementService extends Disposable implements IWork .then(async result => { this._remoteAuthority = result; await this.updateWorkspaceTrust(); - + }) + .finally(() => { this._workspaceTrustInitializedPromiseResolve(); }); } From 92c259a77f51ac23e25efd18e8f6217359cd541a Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Mon, 14 Jun 2021 14:35:43 -0500 Subject: [PATCH 33/40] Update package.json (#126283) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 272d75f717376..6ac7da8e3b104 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "code-oss-dev", - "version": "1.57.0", + "version": "1.57.1", "distro": "90b97e4e10fb8a1ab3cd4846f4dc56bfea8ea620", "author": { "name": "Microsoft Corporation" From 3300069a2b7f14f5c5e4165e0452a21c0e637b24 Mon Sep 17 00:00:00 2001 From: Andrea Mah Date: Mon, 14 Jun 2021 13:34:41 -0600 Subject: [PATCH 34/40] separated editor scroll info by type and consume entry on access --- .../src/features/preview.ts | 2 +- .../src/features/previewManager.ts | 4 +-- .../src/util/topmostLineMonitor.ts | 28 +++++++++++++------ 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/extensions/markdown-language-features/src/features/preview.ts b/extensions/markdown-language-features/src/features/preview.ts index fb3fbeca1832a..0f16361338b5f 100644 --- a/extensions/markdown-language-features/src/features/preview.ts +++ b/extensions/markdown-language-features/src/features/preview.ts @@ -531,7 +531,7 @@ export class StaticMarkdownPreview extends Disposable implements ManagedMarkdown })); this._register(this.preview.onScroll((scrollInfo) => { - topmostLineMonitor.setPreviousEditorLine(scrollInfo); + topmostLineMonitor.setPreviousStaticEditorLine(scrollInfo); })); this._register(topmostLineMonitor.onDidChanged(event => { diff --git a/extensions/markdown-language-features/src/features/previewManager.ts b/extensions/markdown-language-features/src/features/previewManager.ts index 7f30abb1c84d6..4cf55fa9d39eb 100644 --- a/extensions/markdown-language-features/src/features/previewManager.ts +++ b/extensions/markdown-language-features/src/features/previewManager.ts @@ -81,7 +81,7 @@ export class MarkdownPreviewManager extends Disposable implements vscode.Webview // When at a markdown file, apply existing scroll settings if (textEditor && textEditor.document && isMarkdownFile(textEditor.document)) { - const line = this._topmostLineMonitor.getPreviousEditorLineByUri(textEditor.document.uri); + const line = this._topmostLineMonitor.getPreviousStaticEditorLineByUri(textEditor.document.uri); if (line) { scrollEditorToLine(line, textEditor); } @@ -172,7 +172,7 @@ export class MarkdownPreviewManager extends Disposable implements vscode.Webview document: vscode.TextDocument, webview: vscode.WebviewPanel ): Promise { - const lineNumber = this._topmostLineMonitor.getPreviousEditorLineByUri(document.uri); + const lineNumber = this._topmostLineMonitor.getPreviousTextEditorLineByUri(document.uri); const preview = StaticMarkdownPreview.revive( document.uri, webview, diff --git a/extensions/markdown-language-features/src/util/topmostLineMonitor.ts b/extensions/markdown-language-features/src/util/topmostLineMonitor.ts index 62f5b5c194b1b..f2e0e2061ca67 100644 --- a/extensions/markdown-language-features/src/util/topmostLineMonitor.ts +++ b/extensions/markdown-language-features/src/util/topmostLineMonitor.ts @@ -16,15 +16,15 @@ export class TopmostLineMonitor extends Disposable { private readonly pendingUpdates = new Map(); private readonly throttle = 50; - private previousEditorInfo = new Map(); - public isPrevEditorCustom = false; + private previousTextEditorInfo = new Map(); + private previousStaticEditorInfo = new Map(); constructor() { super(); if (vscode.window.activeTextEditor) { const line = getVisibleLine(vscode.window.activeTextEditor); - this.setPreviousEditorLine({ uri: vscode.window.activeTextEditor.document.uri, line: line ?? 0 }); + this.setPreviousTextEditorLine({ uri: vscode.window.activeTextEditor.document.uri, line: line ?? 0 }); } this._register(vscode.window.onDidChangeTextEditorVisibleRanges(event => { @@ -32,7 +32,7 @@ export class TopmostLineMonitor extends Disposable { const line = getVisibleLine(event.textEditor); if (typeof line === 'number') { this.updateLine(event.textEditor.document.uri, line); - this.setPreviousEditorLine({ uri: event.textEditor.document.uri, line: line }); + this.setPreviousTextEditorLine({ uri: event.textEditor.document.uri, line: line }); } } })); @@ -41,12 +41,24 @@ export class TopmostLineMonitor extends Disposable { private readonly _onChanged = this._register(new vscode.EventEmitter<{ readonly resource: vscode.Uri, readonly line: number }>()); public readonly onDidChanged = this._onChanged.event; - public setPreviousEditorLine(scrollLocation: LastScrollLocation): void { - this.previousEditorInfo.set(scrollLocation.uri.toString(), scrollLocation); + public setPreviousStaticEditorLine(scrollLocation: LastScrollLocation): void { + this.previousStaticEditorInfo.set(scrollLocation.uri.toString(), scrollLocation); } - public getPreviousEditorLineByUri(resource: vscode.Uri): number | undefined { - const scrollLoc = this.previousEditorInfo.get(resource.toString()); + public getPreviousStaticEditorLineByUri(resource: vscode.Uri): number | undefined { + const scrollLoc = this.previousStaticEditorInfo.get(resource.toString()); + this.previousStaticEditorInfo.delete(resource.toString()); + return scrollLoc?.line; + } + + + public setPreviousTextEditorLine(scrollLocation: LastScrollLocation): void { + this.previousTextEditorInfo.set(scrollLocation.uri.toString(), scrollLocation); + } + + public getPreviousTextEditorLineByUri(resource: vscode.Uri): number | undefined { + const scrollLoc = this.previousTextEditorInfo.get(resource.toString()); + this.previousTextEditorInfo.delete(resource.toString()); return scrollLoc?.line; } From 45c13db21951b8e1af762aa38378b0d8c9e12569 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Tue, 15 Jun 2021 23:10:00 +0200 Subject: [PATCH 35/40] Do not auto-trigger suggest when typing exactly the inline suggestion Co-authored-by: Henning Dieterichs --- .../inlineCompletions/ghostTextController.ts | 5 +++- src/vs/editor/contrib/suggest/suggestModel.ts | 27 +++++++++++++++++++ .../contrib/suggest/test/suggestModel.test.ts | 7 +++-- 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/src/vs/editor/contrib/inlineCompletions/ghostTextController.ts b/src/vs/editor/contrib/inlineCompletions/ghostTextController.ts index 9c8bc623d9ef7..e226aca73b826 100644 --- a/src/vs/editor/contrib/inlineCompletions/ghostTextController.ts +++ b/src/vs/editor/contrib/inlineCompletions/ghostTextController.ts @@ -19,7 +19,7 @@ import { ContextKeyExpr, IContextKeyService, RawContextKey } from 'vs/platform/c import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; export class GhostTextController extends Disposable { - public static readonly inlineSuggestionVisible = new RawContextKey('inlineSuggestionVisible ', false, nls.localize('inlineSuggestionVisible', "Whether an inline suggestion is visible")); + public static readonly inlineSuggestionVisible = new RawContextKey('inlineSuggestionVisible', false, nls.localize('inlineSuggestionVisible', "Whether an inline suggestion is visible")); public static readonly inlineSuggestionHasIndentation = new RawContextKey('inlineSuggestionHasIndentation', false, nls.localize('inlineSuggestionHasIndentation', "Whether the inline suggestion starts with whitespace")); static ID = 'editor.contrib.ghostTextController'; @@ -50,6 +50,9 @@ export class GhostTextController extends Disposable { if (e.hasChanged(EditorOption.suggest)) { this.updateModelController(); } + if (e.hasChanged(EditorOption.inlineSuggest)) { + this.updateModelController(); + } })); this.updateModelController(); } diff --git a/src/vs/editor/contrib/suggest/suggestModel.ts b/src/vs/editor/contrib/suggest/suggestModel.ts index 1880ef1bd9d1f..7089173d95471 100644 --- a/src/vs/editor/contrib/suggest/suggestModel.ts +++ b/src/vs/editor/contrib/suggest/suggestModel.ts @@ -24,6 +24,8 @@ import { isLowSurrogate, isHighSurrogate, getLeadingWhitespace } from 'vs/base/c import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { ILogService } from 'vs/platform/log/common/log'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; export interface ICancelEvent { readonly retrigger: boolean; @@ -95,6 +97,20 @@ export const enum State { Auto = 2 } +function shouldPreventQuickSuggest(contextKeyService: IContextKeyService, configurationService: IConfigurationService): boolean { + return ( + Boolean(contextKeyService.getContextKeyValue('inlineSuggestionVisible')) + && !Boolean(configurationService.getValue('editor.inlineSuggest.allowQuickSuggestions')) + ); +} + +function shouldPreventSuggestOnTriggerCharacters(contextKeyService: IContextKeyService, configurationService: IConfigurationService): boolean { + return ( + Boolean(contextKeyService.getContextKeyValue('inlineSuggestionVisible')) + && !Boolean(configurationService.getValue('editor.inlineSuggest.allowSuggestOnTriggerCharacters')) + ); +} + export class SuggestModel implements IDisposable { private readonly _toDispose = new DisposableStore(); @@ -123,6 +139,8 @@ export class SuggestModel implements IDisposable { @IClipboardService private readonly _clipboardService: IClipboardService, @ITelemetryService private readonly _telemetryService: ITelemetryService, @ILogService private readonly _logService: ILogService, + @IContextKeyService private readonly _contextKeyService: IContextKeyService, + @IConfigurationService private readonly _configurationService: IConfigurationService, ) { this._currentSelection = this._editor.getSelection() || new Selection(1, 1, 1, 1); @@ -213,6 +231,10 @@ export class SuggestModel implements IDisposable { const checkTriggerCharacter = (text?: string) => { + if (shouldPreventSuggestOnTriggerCharacters(this._contextKeyService, this._configurationService)) { + return; + } + if (!text) { // came here from the compositionEnd-event const position = this._editor.getPosition()!; @@ -351,6 +373,11 @@ export class SuggestModel implements IDisposable { } } + if (shouldPreventQuickSuggest(this._contextKeyService, this._configurationService)) { + // do not trigger quick suggestions if inline suggestions are shown + return; + } + // we made it till here -> trigger now this.trigger({ auto: true, shy: false }); diff --git a/src/vs/editor/contrib/suggest/test/suggestModel.test.ts b/src/vs/editor/contrib/suggest/test/suggestModel.test.ts index a17fa48850bf6..882e001e73526 100644 --- a/src/vs/editor/contrib/suggest/test/suggestModel.test.ts +++ b/src/vs/editor/contrib/suggest/test/suggestModel.test.ts @@ -31,11 +31,12 @@ import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerServ import { ISuggestMemoryService } from 'vs/editor/contrib/suggest/suggestMemory'; import { ITextModel } from 'vs/editor/common/model'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { MockKeybindingService } from 'vs/platform/keybinding/test/common/mockKeybindingService'; +import { MockKeybindingService, MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService'; import { createTextModel } from 'vs/editor/test/common/editorTestUtils'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; import { mock } from 'vs/base/test/common/mock'; import { NullLogService } from 'vs/platform/log/common/log'; +import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; function createMockEditor(model: TextModel): ITestCodeEditor { @@ -204,7 +205,9 @@ suite('SuggestModel - TriggerAndCancelOracle', function () { } }, NullTelemetryService, - new NullLogService() + new NullLogService(), + new MockContextKeyService(), + new TestConfigurationService() ); disposables.push(oracle, editor); From 08bca485860ff8d32d318c7901afb14a91a76f48 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Wed, 16 Jun 2021 16:11:08 +0200 Subject: [PATCH 36/40] Fix race that causes auto port forwarding setting to be ignored (#126481) * Fix race in proc based port finding * Check port auto forward setting after waiting Fixes microsoft/vscode-remote-release#5208 --- .../contrib/remote/browser/remoteExplorer.ts | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts b/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts index db88121bccbdd..0ba9d54a78e57 100644 --- a/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts +++ b/src/vs/workbench/contrib/remote/browser/remoteExplorer.ts @@ -488,7 +488,15 @@ class ProcAutomaticPortForwarding extends Disposable { ) { super(); this.notifier = new OnAutoForwardedAction(notificationService, remoteExplorerService, openerService, externalOpenerService, tunnelService, hostService, logService); - this._register(configurationService.onDidChangeConfiguration(async (e) => { + this.initialize(); + } + + private async initialize() { + if (!this.remoteExplorerService.tunnelModel.environmentTunnelsSet) { + await new Promise(resolve => this.remoteExplorerService.tunnelModel.onEnvironmentTunnelsSet(() => resolve())); + } + + this._register(this.configurationService.onDidChangeConfiguration(async (e) => { if (e.affectsConfiguration(PORT_AUTO_FORWARD_SETTING)) { await this.startStopCandidateListener(); } @@ -524,14 +532,13 @@ class ProcAutomaticPortForwarding extends Disposable { this.portsFeatures.dispose(); } - if (!this.remoteExplorerService.tunnelModel.environmentTunnelsSet) { - await new Promise(resolve => this.remoteExplorerService.tunnelModel.onEnvironmentTunnelsSet(() => resolve())); - } - // Capture list of starting candidates so we don't auto forward them later. await this.setInitialCandidates(); - this.candidateListener = this._register(this.remoteExplorerService.tunnelModel.onCandidatesChanged(this.handleCandidateUpdate, this)); + // Need to check the setting again, since it may have changed while we waited for the initial candidates to be set. + if (this.configurationService.getValue(PORT_AUTO_FORWARD_SETTING)) { + this.candidateListener = this._register(this.remoteExplorerService.tunnelModel.onCandidatesChanged(this.handleCandidateUpdate, this)); + } } private async setInitialCandidates() { From d95f6de445f52d5f61d4470c9d3749e9faebde3b Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 17 Jun 2021 12:36:52 +0200 Subject: [PATCH 37/40] - migrate only from active window - respect old value while reading --- .../editor/browser/editorOverrideService.ts | 37 ++++++++++++++++--- 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/services/editor/browser/editorOverrideService.ts b/src/vs/workbench/services/editor/browser/editorOverrideService.ts index d0eec2dba448b..939aa018b5269 100644 --- a/src/vs/workbench/services/editor/browser/editorOverrideService.ts +++ b/src/vs/workbench/services/editor/browser/editorOverrideService.ts @@ -22,6 +22,8 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; +import { IHostService } from 'vs/workbench/services/host/browser/host'; +import { ILogService } from 'vs/platform/log/common/log'; interface IContributedEditorInput extends IEditorInput { viewType?: string; @@ -56,13 +58,20 @@ export class EditorOverrideService extends Disposable implements IEditorOverride @INotificationService private readonly notificationService: INotificationService, @ITelemetryService private readonly telemetryService: ITelemetryService, @IStorageService private readonly storageService: IStorageService, - @IExtensionService private readonly extensionService: IExtensionService + @IExtensionService private readonly extensionService: IExtensionService, + @IHostService private readonly hostService: IHostService, + @ILogService private readonly logService: ILogService, ) { super(); // Read in the cache on statup this.cache = new Set(JSON.parse(this.storageService.get(EditorOverrideService.overrideCacheStorageID, StorageScope.GLOBAL, JSON.stringify([])))); this.storageService.remove(EditorOverrideService.overrideCacheStorageID, StorageScope.GLOBAL); - this.convertOldAssociationFormat(); + this.hostService.hadLastFocus().then(hadLastFocus => { + if (!hadLastFocus) { + return; + } + this.convertOldAssociationFormat(); + }); this._register(this.storageService.onWillSaveState(() => { // We want to store the glob patterns we would activate on, this allows us to know if we need to await the ext host on startup for opening a resource @@ -75,8 +84,10 @@ export class EditorOverrideService extends Disposable implements IEditorOverride }); // When the setting changes we want to ensure that it is properly converted - this._register(this.configurationService.onDidChangeConfiguration(() => { - this.convertOldAssociationFormat(); + this._register(this.configurationService.onDidChangeConfiguration((e) => { + if (e.affectsConfiguration(editorsAssociationsSettingId)) { + this.convertOldAssociationFormat(); + } })); } @@ -177,7 +188,7 @@ export class EditorOverrideService extends Disposable implements IEditorOverride } private convertOldAssociationFormat(): void { - const rawAssociations = this.configurationService.getValue(editorsAssociationsSettingId) || []; + const rawAssociations = this.configurationService.getValue(editorsAssociationsSettingId) || {}; // If it's not an array, then it's the new format if (!Array.isArray(rawAssociations)) { return; @@ -189,11 +200,25 @@ export class EditorOverrideService extends Disposable implements IEditorOverride newSettingObject[association.filenamePattern] = association.viewType; } } + this.logService.info(`Migrating ${editorsAssociationsSettingId}`); this.configurationService.updateValue(editorsAssociationsSettingId, newSettingObject); } private getAllUserAssociations(): EditorAssociations { - const rawAssociations = this.configurationService.getValue<{ [fileNamePattern: string]: string }>(editorsAssociationsSettingId) || []; + let rawAssociations = this.configurationService.getValue(editorsAssociationsSettingId) || {}; + + // If it's an array then it is old format + if (Array.isArray(rawAssociations)) { + // Make the correctly formatted object + const newValue = Object.create(null); + for (const association of rawAssociations) { + if (association.filenamePattern) { + newValue[association.filenamePattern] = association.viewType; + } + } + rawAssociations = newValue; + } + let associations = []; for (const [key, value] of Object.entries(rawAssociations)) { const association: EditorAssociation = { From 3f4baf46c6fe7a99c41e1b618290b27ce807e84a Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 17 Jun 2021 14:01:18 +0200 Subject: [PATCH 38/40] move focus check while converting --- .../editor/browser/editorOverrideService.ts | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/vs/workbench/services/editor/browser/editorOverrideService.ts b/src/vs/workbench/services/editor/browser/editorOverrideService.ts index 939aa018b5269..5d87f892e2a6e 100644 --- a/src/vs/workbench/services/editor/browser/editorOverrideService.ts +++ b/src/vs/workbench/services/editor/browser/editorOverrideService.ts @@ -66,12 +66,7 @@ export class EditorOverrideService extends Disposable implements IEditorOverride // Read in the cache on statup this.cache = new Set(JSON.parse(this.storageService.get(EditorOverrideService.overrideCacheStorageID, StorageScope.GLOBAL, JSON.stringify([])))); this.storageService.remove(EditorOverrideService.overrideCacheStorageID, StorageScope.GLOBAL); - this.hostService.hadLastFocus().then(hadLastFocus => { - if (!hadLastFocus) { - return; - } - this.convertOldAssociationFormat(); - }); + this.convertOldAssociationFormat(); this._register(this.storageService.onWillSaveState(() => { // We want to store the glob patterns we would activate on, this allows us to know if we need to await the ext host on startup for opening a resource @@ -188,20 +183,25 @@ export class EditorOverrideService extends Disposable implements IEditorOverride } private convertOldAssociationFormat(): void { - const rawAssociations = this.configurationService.getValue(editorsAssociationsSettingId) || {}; - // If it's not an array, then it's the new format - if (!Array.isArray(rawAssociations)) { - return; - } - let newSettingObject = Object.create(null); - // Make the correctly formatted object from the array and then set that object - for (const association of rawAssociations) { - if (association.filenamePattern) { - newSettingObject[association.filenamePattern] = association.viewType; + this.hostService.hadLastFocus().then(hadLastFocus => { + if (!hadLastFocus) { + return; } - } - this.logService.info(`Migrating ${editorsAssociationsSettingId}`); - this.configurationService.updateValue(editorsAssociationsSettingId, newSettingObject); + const rawAssociations = this.configurationService.getValue(editorsAssociationsSettingId) || {}; + // If it's not an array, then it's the new format + if (!Array.isArray(rawAssociations)) { + return; + } + let newSettingObject = Object.create(null); + // Make the correctly formatted object from the array and then set that object + for (const association of rawAssociations) { + if (association.filenamePattern) { + newSettingObject[association.filenamePattern] = association.viewType; + } + } + this.logService.info(`Migrating ${editorsAssociationsSettingId}`); + this.configurationService.updateValue(editorsAssociationsSettingId, newSettingObject); + }); } private getAllUserAssociations(): EditorAssociations { From f0607e90e04d894978be723b605292ade406ea7a Mon Sep 17 00:00:00 2001 From: Teffen Ellis Date: Mon, 26 Jul 2021 19:53:03 -0400 Subject: [PATCH 39/40] Flesh out lib/vscode migration. WIP --- .eslintignore | 5 + .eslintrc.json | 2 + .gitignore | 3 +- .vscode/settings.json | 6 + build/gulpfile.reh.js | 2 + build/hygiene.js | 14 +- build/lib/extensions.ts | 2 +- build/lib/node.js | 4 +- build/lib/node.ts | 6 +- build/lib/util.js | 2 + build/lib/util.ts | 5 +- build/package.json | 9 +- build/yarn.lock | 938 +++--------------- coder.js | 71 ++ .../github-authentication/src/githubServer.ts | 3 +- extensions/postinstall.js | 3 + package.json | 5 + src/vs/base/common/ipc.d.ts | 137 +++ src/vs/base/common/network.ts | 7 +- src/vs/base/common/platform.ts | 12 + src/vs/base/common/processes.ts | 1 + src/vs/base/common/product.ts | 3 + src/vs/base/common/util.ts | 64 ++ src/vs/base/node/languagePacks.js | 5 +- src/vs/base/node/proxy_agent.ts | 85 ++ src/vs/base/parts/ipc/common/ipc.net.ts | 5 + src/vs/code/browser/workbench/workbench.ts | 93 +- src/vs/platform/environment/common/argv.ts | 2 + .../environment/common/environment.ts | 3 + .../environment/common/environmentService.ts | 14 + src/vs/platform/environment/node/argv.ts | 3 + .../node/extensionsScanner.ts | 10 +- src/vs/platform/product/common/product.ts | 7 + .../remote/browser/browserSocketFactory.ts | 3 +- .../remote/common/remoteAgentConnection.ts | 4 +- src/vs/platform/storage/common/storage.ts | 25 +- src/vs/server/channel.ts | 564 +++++++++++ src/vs/server/connection.ts | 244 +++++ src/vs/server/entry.ts | 89 ++ src/vs/server/fork.js | 8 + src/vs/server/insights.ts | 129 +++ src/vs/server/ipc.ts | 66 ++ src/vs/server/marketplace.ts | 178 ++++ src/vs/server/nls.ts | 93 ++ src/vs/server/protocol.ts | 158 +++ src/vs/server/server.ts | 318 ++++++ src/vs/server/uriTransformer.ts | 58 ++ src/vs/server/util.ts | 11 + .../api/browser/mainThreadStorage.ts | 5 +- src/vs/workbench/api/node/extHostCLIServer.ts | 7 + src/vs/workbench/browser/client.ts | 171 ++++ .../browser/parts/dialogs/dialogHandler.ts | 5 +- src/vs/workbench/browser/web.main.ts | 4 + src/vs/workbench/common/resources.ts | 6 +- .../extensions/browser/extensionsViewlet.ts | 43 +- .../contrib/files/browser/explorerViewlet.ts | 8 +- .../page/browser/vs_code_welcome_page.ts | 18 +- .../welcome/page/browser/welcomePage.ts | 2 +- .../environment/browser/environmentService.ts | 27 +- .../browser/extensionEnablementService.ts | 2 +- .../common/extensionManagementService.ts | 6 + .../node/extensionHostProcessSetup.ts | 11 +- .../browser/keyboardLayoutService.ts | 3 + .../browser/localizationsService.ts | 27 + yarn.lock | 193 +++- 65 files changed, 3092 insertions(+), 925 deletions(-) create mode 100644 coder.js create mode 100644 src/vs/base/common/ipc.d.ts create mode 100644 src/vs/base/common/util.ts create mode 100644 src/vs/base/node/proxy_agent.ts create mode 100644 src/vs/server/channel.ts create mode 100644 src/vs/server/connection.ts create mode 100644 src/vs/server/entry.ts create mode 100644 src/vs/server/fork.js create mode 100644 src/vs/server/insights.ts create mode 100644 src/vs/server/ipc.ts create mode 100644 src/vs/server/marketplace.ts create mode 100644 src/vs/server/nls.ts create mode 100644 src/vs/server/protocol.ts create mode 100644 src/vs/server/server.ts create mode 100644 src/vs/server/uriTransformer.ts create mode 100644 src/vs/server/util.ts create mode 100644 src/vs/workbench/browser/client.ts create mode 100644 src/vs/workbench/services/localizations/browser/localizationsService.ts diff --git a/.eslintignore b/.eslintignore index 8b93a4199e5d7..f9c117426c757 100644 --- a/.eslintignore +++ b/.eslintignore @@ -16,3 +16,8 @@ **/extensions/markdown-language-features/notebook-out/** **/extensions/typescript-basics/test/colorize-fixtures/** **/extensions/**/dist/** +# These are code-server code symlinks. +src/vs/base/common/util.ts +src/vs/base/common/ipc.d.ts +src/vs/base/node/proxy_agent.ts +src/vs/server/uriTransformer.ts diff --git a/.eslintrc.json b/.eslintrc.json index a54964c17b673..97d31c1771295 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -802,10 +802,12 @@ "target": "**/vs/server/**", "restrictions": [ "vs/nls", + "**/vs/code/**/{common,server,browser,node,electron-sandbox,electron-browser}/**", "**/vs/base/**/{common,node}/**", "**/vs/base/parts/**/{common,node}/**", "**/vs/platform/**/{common,node}/**", "**/vs/workbench/**/{common,node}/**", + "**/vs/workbench/workbench.web.api", "**/vs/server/**", "*" // node modules ] diff --git a/.gitignore b/.gitignore index 11a7486bf533c..ed42d401d9cd8 100644 --- a/.gitignore +++ b/.gitignore @@ -7,7 +7,8 @@ node_modules/ extensions/**/dist/ /out*/ /extensions/**/out/ -src/vs/server +# NOTE@coder: remove to provide our own server +# src/vs/server resources/server build/node_modules coverage/ diff --git a/.vscode/settings.json b/.vscode/settings.json index a97841683c0ef..d0ffadd1d5d69 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -84,6 +84,12 @@ "editor.defaultFormatter": "vscode.typescript-language-features", "editor.formatOnSave": true, }, + "typescript.format.insertSpaceAfterConstructor": false, + "javascript.format.insertSpaceAfterConstructor": false, + "javascript.format.insertSpaceBeforeFunctionParenthesis": false, + "typescript.format.insertSpaceBeforeFunctionParenthesis": false, + "typescript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": false, + "javascript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": false, "typescript.tsc.autoDetect": "off", "notebook.experimental.useMarkdownRenderer": true, "testing.autoRun.mode": "rerun", diff --git a/build/gulpfile.reh.js b/build/gulpfile.reh.js index 387a54cbbfea9..0704ab70e9d19 100644 --- a/build/gulpfile.reh.js +++ b/build/gulpfile.reh.js @@ -42,6 +42,8 @@ BUILD_TARGETS.forEach(({ platform, arch }) => { }); function getNodeVersion() { + // NOTE@coder: Fix version due to .yarnrc removal. + return process.versions.node; const yarnrc = fs.readFileSync(path.join(REPO_ROOT, 'remote', '.yarnrc'), 'utf8'); const target = /^target "(.*)"$/m.exec(yarnrc)[1]; return target; diff --git a/build/hygiene.js b/build/hygiene.js index 9d6756dbc86d7..024d12c0c2616 100644 --- a/build/hygiene.js +++ b/build/hygiene.js @@ -19,6 +19,18 @@ const copyrightHeaderLines = [ ' *--------------------------------------------------------------------------------------------*/', ]; +/** + * @remark While this helps delineate Coder's additions to the upstream project, + * this notice should be examined within the context of the application. + * Code from both maintainers often overlaps. + */ +const coderCopyrightHeaderLines = [ + '/*---------------------------------------------------------------------------------------------', + ' * Copyright (c) Coder Technologies. All rights reserved.', + ' * Licensed under the MIT License. See License.txt in the project root for license information.', + ' *--------------------------------------------------------------------------------------------*/', +]; + function hygiene(some, linting = true) { const gulpeslint = require('gulp-eslint'); const tsfmt = require('typescript-formatter'); @@ -62,7 +74,7 @@ function hygiene(some, linting = true) { const lines = file.__lines; for (let i = 0; i < copyrightHeaderLines.length; i++) { - if (lines[i] !== copyrightHeaderLines[i]) { + if (lines[i] !== copyrightHeaderLines[i] && lines[i] !== coderCopyrightHeaderLines[i]) { console.error(file.relative + ': Missing or bad copyright statement'); errorCount++; break; diff --git a/build/lib/extensions.ts b/build/lib/extensions.ts index 6c55569b97313..9281bb19e20b1 100644 --- a/build/lib/extensions.ts +++ b/build/lib/extensions.ts @@ -67,7 +67,7 @@ function fromLocal(extensionPath: string, forWeb: boolean): Stream { if (isWebPacked) { input = updateExtensionPackageJSON(input, (data: any) => { delete data.scripts; - delete data.dependencies; + // https://github.com/cdr/code-server/pull/2041#issuecomment-685910322 delete data.devDependencies; if (data.main) { data.main = data.main.replace('/out/', /dist/); diff --git a/build/lib/node.js b/build/lib/node.js index e727aff832396..6e735f2cdb29e 100644 --- a/build/lib/node.js +++ b/build/lib/node.js @@ -8,8 +8,8 @@ const path = require("path"); const fs = require("fs"); const root = path.dirname(path.dirname(__dirname)); const yarnrcPath = path.join(root, 'remote', '.yarnrc'); -const yarnrc = fs.readFileSync(yarnrcPath, 'utf8'); -const version = /^target\s+"([^"]+)"$/m.exec(yarnrc)[1]; +// NOTE@coder: Fix version due to .yarnrc removal. +const version = process.versions.node; const platform = process.platform; const arch = platform === 'darwin' ? 'x64' : process.arch; const node = platform === 'win32' ? 'node.exe' : 'node'; diff --git a/build/lib/node.ts b/build/lib/node.ts index 6ac45ebb1f89c..96fa624ad30a2 100644 --- a/build/lib/node.ts +++ b/build/lib/node.ts @@ -4,13 +4,11 @@ *--------------------------------------------------------------------------------------------*/ import * as path from 'path'; -import * as fs from 'fs'; const root = path.dirname(path.dirname(__dirname)); -const yarnrcPath = path.join(root, 'remote', '.yarnrc'); -const yarnrc = fs.readFileSync(yarnrcPath, 'utf8'); -const version = /^target\s+"([^"]+)"$/m.exec(yarnrc)![1]; +// NOTE@coder: Fix version due to .yarnrc removal. +const version = process.versions.node; const platform = process.platform; const arch = platform === 'darwin' ? 'x64' : process.arch; diff --git a/build/lib/util.js b/build/lib/util.js index 8d0294e4cebc0..b58fb754d2bb8 100644 --- a/build/lib/util.js +++ b/build/lib/util.js @@ -269,6 +269,8 @@ function streamToPromise(stream) { } exports.streamToPromise = streamToPromise; function getElectronVersion() { + // NOTE@coder: Fix version due to .yarnrc removal. + return process.versions.node; const yarnrc = fs.readFileSync(path.join(root, '.yarnrc'), 'utf8'); const target = /^target "(.*)"$/m.exec(yarnrc)[1]; return target; diff --git a/build/lib/util.ts b/build/lib/util.ts index c0a0d9619d736..2c64a4bfe64b9 100644 --- a/build/lib/util.ts +++ b/build/lib/util.ts @@ -336,7 +336,6 @@ export function streamToPromise(stream: NodeJS.ReadWriteStream): Promise { } export function getElectronVersion(): string { - const yarnrc = fs.readFileSync(path.join(root, '.yarnrc'), 'utf8'); - const target = /^target "(.*)"$/m.exec(yarnrc)![1]; - return target; + // NOTE@coder: Fix version due to .yarnrc removal. + return process.versions.node; } diff --git a/build/package.json b/build/package.json index 6e12a9c4abc8e..69a210e5e57bb 100644 --- a/build/package.json +++ b/build/package.json @@ -3,8 +3,6 @@ "version": "1.0.0", "license": "MIT", "devDependencies": { - "@azure/cosmos": "^3.9.3", - "@azure/storage-blob": "^12.4.0", "@types/ansi-colors": "^3.2.0", "@types/azure": "0.9.19", "@types/byline": "^4.2.32", @@ -37,12 +35,10 @@ "@typescript-eslint/experimental-utils": "~2.13.0", "@typescript-eslint/parser": "^3.3.0", "applicationinsights": "1.0.8", - "azure-storage": "^2.1.0", "byline": "^5.0.0", "colors": "^1.4.0", "commander": "^7.0.0", - "electron-osx-sign": "^0.4.16", - "esbuild": "^0.12.1", + "esbuild": "^0.12.6", "fs-extra": "^9.1.0", "got": "11.8.1", "iconv-lite-umd": "0.6.8", @@ -50,10 +46,9 @@ "mime": "^1.4.1", "mkdirp": "^1.0.4", "p-limit": "^3.1.0", - "plist": "^3.0.1", "source-map": "0.6.1", "typescript": "^4.4.0-dev.20210528", - "vsce": "1.48.0", + "vsce": "1.88.0", "vscode-universal": "deepak1556/universal#61454d96223b774c53cda10f72c2098c0ce02d58" }, "scripts": { diff --git a/build/yarn.lock b/build/yarn.lock index 07536a575ace9..b324d5bfa7b0d 100644 --- a/build/yarn.lock +++ b/build/yarn.lock @@ -2,112 +2,6 @@ # yarn lockfile v1 -"@azure/abort-controller@^1.0.0": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@azure/abort-controller/-/abort-controller-1.0.2.tgz#822405c966b2aec16fb62c1b19d37eaccf231995" - integrity sha512-XUyTo+bcyxHEf+jlN2MXA7YU9nxVehaubngHV1MIZZaqYmZqykkoeAz/JMMEeR7t3TcyDwbFa3Zw8BZywmIx4g== - dependencies: - tslib "^2.0.0" - -"@azure/core-asynciterator-polyfill@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@azure/core-asynciterator-polyfill/-/core-asynciterator-polyfill-1.0.0.tgz#dcccebb88406e5c76e0e1d52e8cc4c43a68b3ee7" - integrity sha512-kmv8CGrPfN9SwMwrkiBK9VTQYxdFQEGe0BmQk+M8io56P9KNzpAxcWE/1fxJj7uouwN4kXF0BHW8DNlgx+wtCg== - -"@azure/core-auth@^1.1.3": - version "1.1.4" - resolved "https://registry.yarnpkg.com/@azure/core-auth/-/core-auth-1.1.4.tgz#af9a334acf3cb9c49e6013e6caf6dc9d43476030" - integrity sha512-+j1embyH1jqf04AIfJPdLafd5SC1y6z1Jz4i+USR1XkTp6KM8P5u4/AjmWMVoEQdM/M29PJcRDZcCEWjK9S1bw== - dependencies: - "@azure/abort-controller" "^1.0.0" - tslib "^2.0.0" - -"@azure/core-http@^1.2.0": - version "1.2.2" - resolved "https://registry.yarnpkg.com/@azure/core-http/-/core-http-1.2.2.tgz#a6f7717184fd2657d3acabd1d64dfdc0bd531ce3" - integrity sha512-9eu2OcbR7e44gqBy4U1Uv8NTWgLIMwKXMEGgO2MahsJy5rdTiAhs5fJHQffPq8uX2MFh21iBODwO9R/Xlov88A== - dependencies: - "@azure/abort-controller" "^1.0.0" - "@azure/core-auth" "^1.1.3" - "@azure/core-tracing" "1.0.0-preview.9" - "@azure/logger" "^1.0.0" - "@opentelemetry/api" "^0.10.2" - "@types/node-fetch" "^2.5.0" - "@types/tunnel" "^0.0.1" - form-data "^3.0.0" - node-fetch "^2.6.0" - process "^0.11.10" - tough-cookie "^4.0.0" - tslib "^2.0.0" - tunnel "^0.0.6" - uuid "^8.3.0" - xml2js "^0.4.19" - -"@azure/core-lro@^1.0.2": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@azure/core-lro/-/core-lro-1.0.3.tgz#1ddfb4ecdb81ce87b5f5d972ffe2acbbc46e524e" - integrity sha512-Py2crJ84qx1rXkzIwfKw5Ni4WJuzVU7KAF6i1yP3ce8fbynUeu8eEWS4JGtSQgU7xv02G55iPDROifmSDbxeHA== - dependencies: - "@azure/abort-controller" "^1.0.0" - "@azure/core-http" "^1.2.0" - events "^3.0.0" - tslib "^2.0.0" - -"@azure/core-paging@^1.1.1": - version "1.1.3" - resolved "https://registry.yarnpkg.com/@azure/core-paging/-/core-paging-1.1.3.tgz#3587c9898a0530cacb64bab216d7318468aa5efc" - integrity sha512-his7Ah40ThEYORSpIAwuh6B8wkGwO/zG7gqVtmSE4WAJ46e36zUDXTKReUCLBDc6HmjjApQQxxcRFy5FruG79A== - dependencies: - "@azure/core-asynciterator-polyfill" "^1.0.0" - -"@azure/core-tracing@1.0.0-preview.9": - version "1.0.0-preview.9" - resolved "https://registry.yarnpkg.com/@azure/core-tracing/-/core-tracing-1.0.0-preview.9.tgz#84f3b85572013f9d9b85e1e5d89787aa180787eb" - integrity sha512-zczolCLJ5QG42AEPQ+Qg9SRYNUyB+yZ5dzof4YEc+dyWczO9G2sBqbAjLB7IqrsdHN2apkiB2oXeDKCsq48jug== - dependencies: - "@opencensus/web-types" "0.0.7" - "@opentelemetry/api" "^0.10.2" - tslib "^2.0.0" - -"@azure/cosmos@^3.9.3": - version "3.9.3" - resolved "https://registry.yarnpkg.com/@azure/cosmos/-/cosmos-3.9.3.tgz#7e95ff92e5c3e9da7e8316bc50c9cc928be6c1d6" - integrity sha512-1mh8a6LAIykz24tJvQpafXiABUfq+HSAZBFJVZXea0Rd0qG8Ia9z8AK9FtPbC1nPvDC2RID2mRIjJvYbxRM/BA== - dependencies: - "@types/debug" "^4.1.4" - debug "^4.1.1" - fast-json-stable-stringify "^2.0.0" - jsbi "^3.1.3" - node-abort-controller "^1.0.4" - node-fetch "^2.6.0" - priorityqueuejs "^1.0.0" - semaphore "^1.0.5" - tslib "^2.0.0" - universal-user-agent "^6.0.0" - uuid "^8.3.0" - -"@azure/logger@^1.0.0": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@azure/logger/-/logger-1.0.1.tgz#19b333203d1b2931353d8879e814b64a7274837a" - integrity sha512-QYQeaJ+A5x6aMNu8BG5qdsVBnYBop9UMwgUvGihSjf1PdZZXB+c/oMdM2ajKwzobLBh9e9QuMQkN9iL+IxLBLA== - dependencies: - tslib "^2.0.0" - -"@azure/storage-blob@^12.4.0": - version "12.4.0" - resolved "https://registry.yarnpkg.com/@azure/storage-blob/-/storage-blob-12.4.0.tgz#7127ddd9f413105e2c3688691bc4c6245d0806b3" - integrity sha512-OnhVSoKD1HzBB79/rFzPbC4w9TdzFXeoOwkX+aIu3rb8qvN0VaqvUqZXSrBCyG2LcLyVkY4MPCJQBrmEUm9kvw== - dependencies: - "@azure/abort-controller" "^1.0.0" - "@azure/core-http" "^1.2.0" - "@azure/core-lro" "^1.0.2" - "@azure/core-paging" "^1.1.1" - "@azure/core-tracing" "1.0.0-preview.9" - "@azure/logger" "^1.0.0" - "@opentelemetry/api" "^0.10.2" - events "^3.0.0" - tslib "^2.0.0" - "@malept/cross-spawn-promise@^1.1.0": version "1.1.1" resolved "https://registry.yarnpkg.com/@malept/cross-spawn-promise/-/cross-spawn-promise-1.1.1.tgz#504af200af6b98e198bce768bc1730c6936ae01d" @@ -115,23 +9,6 @@ dependencies: cross-spawn "^7.0.1" -"@opencensus/web-types@0.0.7": - version "0.0.7" - resolved "https://registry.yarnpkg.com/@opencensus/web-types/-/web-types-0.0.7.tgz#4426de1fe5aa8f624db395d2152b902874f0570a" - integrity sha512-xB+w7ZDAu3YBzqH44rCmG9/RlrOmFuDPt/bpf17eJr8eZSrLt7nc7LnWdxM9Mmoj/YKMHpxRg28txu3TcpiL+g== - -"@opentelemetry/api@^0.10.2": - version "0.10.2" - resolved "https://registry.yarnpkg.com/@opentelemetry/api/-/api-0.10.2.tgz#9647b881f3e1654089ff7ea59d587b2d35060654" - integrity sha512-GtpMGd6vkzDMYcpu2t9LlhEgMy/SzBwRnz48EejlRArYqZzqSzAsKmegUK7zHgl+EOIaK9mKHhnRaQu3qw20cA== - dependencies: - "@opentelemetry/context-base" "^0.10.2" - -"@opentelemetry/context-base@^0.10.2": - version "0.10.2" - resolved "https://registry.yarnpkg.com/@opentelemetry/context-base/-/context-base-0.10.2.tgz#55bea904b2b91aa8a8675df9eaba5961bddb1def" - integrity sha512-hZNKjKOYsckoOEgBziGMnBcX0M7EtstnCmwz5jZUOUYwlZ+/xxX6z3jPu1XVO2Jivk0eLfuP9GP+vFD49CMetw== - "@sindresorhus/is@^4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.0.0.tgz#2ff674e9611b45b528896d820d3d7a812de2f0e4" @@ -191,7 +68,7 @@ resolved "https://registry.yarnpkg.com/@types/debounce/-/debounce-1.0.0.tgz#417560200331e1bb84d72da85391102c2fcd61b7" integrity sha1-QXVgIAMx4buE1y2oU5EQLC/NYbc= -"@types/debug@^4.1.4", "@types/debug@^4.1.5": +"@types/debug@^4.1.5": version "4.1.5" resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.5.tgz#b14efa8852b7768d898906613c23f688713e02cd" integrity sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ== @@ -358,14 +235,6 @@ resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-8.2.0.tgz#3eb56d13a1de1d347ecb1957c6860c911704bc44" integrity sha512-/Sge3BymXo4lKc31C8OINJgXLaw+7vL1/L1pGiBNpGrBiT8FQiaFpSYV0uhTaG4y78vcMBTMFsWaHDvuD+xGzQ== -"@types/node-fetch@^2.5.0": - version "2.5.8" - resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.8.tgz#e199c835d234c7eb0846f6618012e558544ee2fb" - integrity sha512-fbjI6ja0N5ZA8TV53RUqzsKNkl9fv8Oj3T7zxW7FGv1GSH7gwJaNF8dzCjrqKaxKeUpTz4yT1DaJFq/omNpGfw== - dependencies: - "@types/node" "*" - form-data "^3.0.0" - "@types/node@*": version "8.0.51" resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.51.tgz#b31d716fb8d58eeb95c068a039b9b6292817d5fb" @@ -447,13 +316,6 @@ resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-2.3.2.tgz#e0d481d8bb282ad8a8c9e100ceb72c995fb5e709" integrity sha512-vOVmaruQG5EatOU/jM6yU2uCp3Lz6mK1P5Ztu4iJjfM4SVHU9XYktPUQtKlIXuahqXHdEyUarMrBEwg5Cwu+bA== -"@types/tunnel@^0.0.1": - version "0.0.1" - resolved "https://registry.yarnpkg.com/@types/tunnel/-/tunnel-0.0.1.tgz#0d72774768b73df26f25df9184273a42da72b19c" - integrity sha512-AOqu6bQu5MSWwYvehMXLukFHnupHrpZ8nvgae5Ggie9UwzDR1CCwoXgSSWNZJuyOlCdfdsWMA5F2LlmvyoTv8A== - dependencies: - "@types/node" "*" - "@types/underscore@^1.8.9": version "1.8.9" resolved "https://registry.yarnpkg.com/@types/underscore/-/underscore-1.8.9.tgz#fef41f800cd23db1b4f262ddefe49cd952d82323" @@ -564,15 +426,12 @@ dependencies: eslint-visitor-keys "^1.1.0" -ajv@^6.12.3: - version "6.12.6" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" - integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== dependencies: - fast-deep-equal "^3.1.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" + color-convert "^1.9.0" applicationinsights@1.0.8: version "1.0.8" @@ -602,77 +461,24 @@ asar@^3.0.3: optionalDependencies: "@types/glob" "^7.1.1" -asn1@~0.2.3: - version "0.2.4" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" - integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== - dependencies: - safer-buffer "~2.1.0" - -assert-plus@1.0.0, assert-plus@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= - -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= - at-least-node@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== -aws-sign2@~0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" - integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= - -aws4@^1.8.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" - integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== - -azure-storage@^2.1.0: - version "2.10.3" - resolved "https://registry.yarnpkg.com/azure-storage/-/azure-storage-2.10.3.tgz#c5966bf929d87587d78f6847040ea9a4b1d4a50a" - integrity sha512-IGLs5Xj6kO8Ii90KerQrrwuJKexLgSwYC4oLWmc11mzKe7Jt2E5IVg+ZQ8K53YWZACtVTMBNO3iGuA+4ipjJxQ== - dependencies: - browserify-mime "~1.2.9" - extend "^3.0.2" - json-edm-parser "0.1.2" - md5.js "1.3.4" - readable-stream "~2.0.0" - request "^2.86.0" - underscore "~1.8.3" - uuid "^3.0.0" - validator "~9.4.1" - xml2js "0.2.8" - xmlbuilder "^9.0.7" +azure-devops-node-api@^10.2.2: + version "10.2.2" + resolved "https://registry.yarnpkg.com/azure-devops-node-api/-/azure-devops-node-api-10.2.2.tgz#9f557e622dd07bbaa9bd5e7e84e17c761e2151b2" + integrity sha512-4TVv2X7oNStT0vLaEfExmy3J4/CzfuXolEcQl/BRUmvGySqKStTG2O55/hUQ0kM7UJlZBLgniM0SBq4d/WkKow== + dependencies: + tunnel "0.0.6" + typed-rest-client "^1.8.4" balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= -base64-js@^1.2.3: - version "1.3.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1" - integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g== - -bcrypt-pbkdf@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" - integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= - dependencies: - tweetnacl "^0.14.3" - -bluebird@^3.5.0: - version "3.7.2" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" - integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== - boolbase@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" @@ -686,24 +492,6 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" -browserify-mime@~1.2.9: - version "1.2.9" - resolved "https://registry.yarnpkg.com/browserify-mime/-/browserify-mime-1.2.9.tgz#aeb1af28de6c0d7a6a2ce40adb68ff18422af31f" - integrity sha1-rrGvKN5sDXpqLOQK22j/GEIq8x8= - -buffer-alloc-unsafe@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" - integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg== - -buffer-alloc@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec" - integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow== - dependencies: - buffer-alloc-unsafe "^1.1.0" - buffer-fill "^1.0.0" - buffer-crc32@~0.2.3: version "0.2.13" resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" @@ -714,11 +502,6 @@ buffer-equal@1.0.0: resolved "https://registry.yarnpkg.com/buffer-equal/-/buffer-equal-1.0.0.tgz#59616b498304d556abd466966b22eeda3eca5fbe" integrity sha1-WWFrSYME1Var1GaWayLu2j7KX74= -buffer-fill@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" - integrity sha1-+PeLdniYiO858gXNY39o5wISKyw= - byline@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/byline/-/byline-5.0.0.tgz#741c5216468eadc457b03410118ad77de8c1ddb1" @@ -742,10 +525,22 @@ cacheable-request@^7.0.1: normalize-url "^4.1.0" responselike "^2.0.0" -caseless@~0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" - integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= +call-bind@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" + integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + +chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" cheerio@^1.0.0-rc.1: version "1.0.0-rc.2" @@ -771,6 +566,18 @@ clone-response@^1.0.2: dependencies: mimic-response "^1.0.0" +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + colors@1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" @@ -781,13 +588,6 @@ colors@^1.4.0: resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== -combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: - version "1.0.8" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" - integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== - dependencies: - delayed-stream "~1.0.0" - commander@2.9.0: version "2.9.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" @@ -795,36 +595,26 @@ commander@2.9.0: dependencies: graceful-readlink ">= 1.0.0" -commander@^2.8.1: - version "2.19.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" - integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg== - commander@^5.0.0: version "5.1.0" resolved "https://registry.yarnpkg.com/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae" integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg== +commander@^6.1.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c" + integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA== + commander@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/commander/-/commander-7.0.0.tgz#3e2bbfd8bb6724760980988fb5b22b7ee6b71ab2" integrity sha512-ovx/7NkTrnPuIV8sqk/GjUIIM1+iUQeqA3ye2VNpq9sVoiZsooObWlQy+OPWGI17GDaEoybuAGJm6U8yC077BA== -compare-version@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/compare-version/-/compare-version-0.1.2.tgz#0162ec2d9351f5ddd59a9202cba935366a725080" - integrity sha1-AWLsLZNR9d3VmpICy6k1NmpyUIA= - concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= -core-util-is@1.0.2, core-util-is@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= - cross-spawn@^7.0.1: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" @@ -849,20 +639,6 @@ css-what@2.1: resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.2.tgz#c0876d9d0480927d7d4920dcd72af3595649554d" integrity sha512-wan8dMWQ0GUeF7DGEPVjhHemVW/vy6xUYmFzRY8RYqgA0JtXC9rJmbScBjqSu6dg9q0lwPQy6ZAmJVr3PPTvqQ== -dashdash@^1.12.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= - dependencies: - assert-plus "^1.0.0" - -debug@^2.6.8: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - debug@^4.1.1, debug@^4.3.1: version "4.3.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" @@ -882,11 +658,6 @@ defer-to-connect@^2.0.0: resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.0.tgz#83d6b199db041593ac84d781b5222308ccf4c2c1" integrity sha512-bYL2d05vOSf1JEZNx5vSAtPuBMkX8K9EUutg7zlKvTqKXHt7RhWJFbmd7qakVuf13i+IkGmp6FwSsONOf6VYIg== -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= - denodeify@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/denodeify/-/denodeify-1.2.1.tgz#3a36287f5034e699e7577901052c2e6c94251631" @@ -960,26 +731,6 @@ domutils@^1.5.1: dom-serializer "0" domelementtype "1" -ecc-jsbn@~0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" - integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= - dependencies: - jsbn "~0.1.0" - safer-buffer "^2.1.0" - -electron-osx-sign@^0.4.16: - version "0.4.16" - resolved "https://registry.yarnpkg.com/electron-osx-sign/-/electron-osx-sign-0.4.16.tgz#0be8e579b2d9fa4c12d2a21f063898294b3434aa" - integrity sha512-ziMWfc3NmQlwnWLW6EaZq8nH2BWVng/atX5GWsGwhexJYpdW6hsg//MkAfRTRx1kR3Veiqkeiog1ibkbA4x0rg== - dependencies: - bluebird "^3.5.0" - compare-version "^0.1.2" - debug "^2.6.8" - isbinaryfile "^3.0.2" - minimist "^1.2.0" - plist "^3.0.1" - end-of-stream@^1.1.0: version "1.4.4" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" @@ -992,10 +743,20 @@ entities@^1.1.1, entities@~1.1.1: resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w== -esbuild@^0.12.1: - version "0.12.1" - resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.12.1.tgz#f652d5b3b9432dbb42fc2c034ddd62360296e03d" - integrity sha512-WfQ00MKm/Y4ysz1u9PCUAsV66k5lbrcEvS6aG9jhBIavpB94FBdaWeBkaZXxCZB4w+oqh+j4ozJFWnnFprOXbg== +entities@~2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.3.tgz#5c487e5742ab93c15abb5da22759b8590ec03b7f" + integrity sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ== + +esbuild@^0.12.6: + version "0.12.16" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.12.16.tgz#c397144ce13b445a6ead9c1f747da11f79ec5e67" + integrity sha512-XqI9cXP2bmQ6MREIqrYBb13KfYFSERsV1+e5jSVWps8dNlLZK+hln7d0mznzDIpfISsg/AgQW0DW3kSInXWhrg== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= eslint-scope@^5.0.0: version "5.0.0" @@ -1029,36 +790,6 @@ estraverse@^4.1.0, estraverse@^4.1.1: resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== -events@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/events/-/events-3.2.0.tgz#93b87c18f8efcd4202a461aec4dfc0556b639379" - integrity sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg== - -extend@^3.0.2, extend@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" - integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== - -extsprintf@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" - integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= - -extsprintf@^1.2.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" - integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= - -fast-deep-equal@^3.1.1: - version "3.1.3" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" - integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== - -fast-json-stable-stringify@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" - integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== - fd-slicer@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" @@ -1066,29 +797,6 @@ fd-slicer@~1.1.0: dependencies: pend "~1.2.0" -forever-agent@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= - -form-data@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.0.tgz#31b7e39c85f1355b7139ee0c647cf0de7f83c682" - integrity sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.8" - mime-types "^2.1.12" - -form-data@~2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" - integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.6" - mime-types "^2.1.12" - fs-extra@^9.0.1, fs-extra@^9.1.0: version "9.1.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" @@ -1104,6 +812,20 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +get-intrinsic@^1.0.2: + version "1.1.1" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" + integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + get-stream@^5.1.0: version "5.2.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" @@ -1111,13 +833,6 @@ get-stream@^5.1.0: dependencies: pump "^3.0.0" -getpass@^0.1.1: - version "0.1.7" - resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= - dependencies: - assert-plus "^1.0.0" - glob@^7.0.6: version "7.1.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" @@ -1169,27 +884,22 @@ graceful-fs@^4.1.6, graceful-fs@^4.2.0: resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" integrity sha1-TK+tdrxi8C+gObL5Tpo906ORpyU= -har-schema@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" - integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= -har-validator@~5.1.3: - version "5.1.5" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd" - integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w== - dependencies: - ajv "^6.12.3" - har-schema "^2.0.0" +has-symbols@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423" + integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== -hash-base@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" - integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== dependencies: - inherits "^2.0.4" - readable-stream "^3.6.0" - safe-buffer "^5.2.0" + function-bind "^1.1.1" htmlparser2@^3.9.1: version "3.10.0" @@ -1208,15 +918,6 @@ http-cache-semantics@^4.0.0: resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390" integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ== -http-signature@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" - integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= - dependencies: - assert-plus "^1.0.0" - jsprim "^1.2.2" - sshpk "^1.7.0" - http2-wrapper@^1.0.0-beta.5.2: version "1.0.0-beta.5.2" resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-1.0.0-beta.5.2.tgz#8b923deb90144aea65cf834b016a340fc98556f3" @@ -1238,7 +939,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.1, inherits@^2.0.4, inherits@~2.0.1: +inherits@2, inherits@^2.0.1: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -1260,70 +961,16 @@ is-glob@^4.0.1: dependencies: is-extglob "^2.1.1" -is-typedarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= - -isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= - -isbinaryfile@^3.0.2: - version "3.0.3" - resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-3.0.3.tgz#5d6def3edebf6e8ca8cae9c30183a804b5f8be80" - integrity sha512-8cJBL5tTd2OS0dM4jz07wQd5g0dCCqIhUxPIGtZfa5L6hWlvV5MHTITy/DBAsF+Oe2LS1X3krBUhNwaGUWpWxw== - dependencies: - buffer-alloc "^1.2.0" - isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= -isstream@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= - -jsbi@^3.1.3: - version "3.1.4" - resolved "https://registry.yarnpkg.com/jsbi/-/jsbi-3.1.4.tgz#9654dd02207a66a4911b4e4bb74265bc2cbc9dd0" - integrity sha512-52QRRFSsi9impURE8ZUbzAMCLjPm4THO7H2fcuIvaaeFTbSysvkodbQQXIVsNgq/ypDbq6dJiuGKL0vZ/i9hUg== - -jsbn@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= - json-buffer@3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== -json-edm-parser@0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/json-edm-parser/-/json-edm-parser-0.1.2.tgz#1e60b0fef1bc0af67bc0d146dfdde5486cd615b4" - integrity sha1-HmCw/vG8CvZ7wNFG393lSGzWFbQ= - dependencies: - jsonparse "~1.2.0" - -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - -json-schema@0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" - integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= - -json-stringify-safe@~5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= - jsonc-parser@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-2.3.0.tgz#7c7fc988ee1486d35734faaaa866fadb00fa91ee" @@ -1338,21 +985,6 @@ jsonfile@^6.0.1: optionalDependencies: graceful-fs "^4.1.6" -jsonparse@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.2.0.tgz#5c0c5685107160e72fe7489bddea0b44c2bc67bd" - integrity sha1-XAxWhRBxYOcv50ib3eoLRMK8Z70= - -jsprim@^1.2.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" - integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= - dependencies: - assert-plus "1.0.0" - extsprintf "1.3.0" - json-schema "0.2.3" - verror "1.10.0" - keyv@^4.0.0: version "4.0.3" resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.0.3.tgz#4f3aa98de254803cafcd2896734108daa35e4254" @@ -1360,6 +992,11 @@ keyv@^4.0.0: dependencies: json-buffer "3.0.1" +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + linkify-it@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-2.0.3.tgz#d94a4648f9b1c179d64fa97291268bdb6ce9434f" @@ -1372,7 +1009,7 @@ lodash.unescape@4.0.1: resolved "https://registry.yarnpkg.com/lodash.unescape/-/lodash.unescape-4.0.1.tgz#bf2249886ce514cda112fae9218cdc065211fc9c" integrity sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw= -lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.15: +lodash@^4.15.0, lodash@^4.17.15: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -1389,42 +1026,22 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" -markdown-it@^8.3.1: - version "8.4.2" - resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-8.4.2.tgz#386f98998dc15a37722aa7722084f4020bdd9b54" - integrity sha512-GcRz3AWTqSUphY3vsUqQSFMbgR38a4Lh3GWlHRh/7MRwz8mcu9n2IO7HOh+bXHrR9kOPDl5RNCaEsrneb+xhHQ== +markdown-it@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-10.0.0.tgz#abfc64f141b1722d663402044e43927f1f50a8dc" + integrity sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg== dependencies: argparse "^1.0.7" - entities "~1.1.1" + entities "~2.0.0" linkify-it "^2.0.0" mdurl "^1.0.1" uc.micro "^1.0.5" -md5.js@1.3.4: - version "1.3.4" - resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.4.tgz#e9bdbde94a20a5ac18b04340fc5764d5b09d901d" - integrity sha1-6b296UogpawYsENA/Fdk1bCdkB0= - dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - mdurl@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4= -mime-db@1.45.0: - version "1.45.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.45.0.tgz#cceeda21ccd7c3a745eba2decd55d4b73e7879ea" - integrity sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w== - -mime-types@^2.1.12, mime-types@~2.1.19: - version "2.1.28" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.28.tgz#1160c4757eab2c5363888e005273ecf79d2a0ecd" - integrity sha512-0TO2yJ5YHYr7M2zzT7gDU1tbwHxEUWBCLt0lscSNpcdAfFyJOVEpRYNS7EXVcTLNj/25QO8gulHC5JtTzSE2UQ== - dependencies: - mime-db "1.45.0" - mime@^1.3.4: version "1.4.1" resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" @@ -1452,21 +1069,11 @@ minimatch@3.0.4, minimatch@^3.0.3, minimatch@^3.0.4: dependencies: brace-expansion "^1.1.7" -minimist@^1.2.0: - version "1.2.3" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.3.tgz#3db5c0765545ab8637be71f333a104a965a9ca3f" - integrity sha512-+bMdgqjMN/Z77a6NlY/I3U5LlRDbnmaAk6lDveAPKwSpcPM4tKAuYsvYF8xjhOPXhOYGe/73vVLVez5PW+jqhw== - mkdirp@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= - ms@2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" @@ -1477,16 +1084,6 @@ mute-stream@~0.0.4: resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= -node-abort-controller@^1.0.4: - version "1.1.0" - resolved "https://registry.yarnpkg.com/node-abort-controller/-/node-abort-controller-1.1.0.tgz#8a734a631b022af29963be7245c1483cbb9e070d" - integrity sha512-dEYmUqjtbivotqjraOe8UvhT/poFfog1BQRNsZm/MSEDDESk2cQ1tvD8kGyuN07TM/zoW+n42odL8zTeJupYdQ== - -node-fetch@^2.6.0: - version "2.6.1" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" - integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== - normalize-url@^4.1.0: version "4.5.0" resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.0.tgz#453354087e6ca96957bd8f5baf753f5982142129" @@ -1499,10 +1096,10 @@ nth-check@~1.0.1: dependencies: boolbase "~1.0.0" -oauth-sign@~0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" - integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== +object-inspect@^1.9.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.11.0.tgz#9dceb146cedd4148a0d9e51ab88d34cf509922b1" + integrity sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg== once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" @@ -1570,40 +1167,6 @@ pend@~1.2.0: resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA= -performance-now@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" - integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= - -plist@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/plist/-/plist-3.0.1.tgz#a9b931d17c304e8912ef0ba3bdd6182baf2e1f8c" - integrity sha512-GpgvHHocGRyQm74b6FWEZZVRroHKE1I0/BTjAmySaohK+cUn+hZpbqXkc3KWgW3gQYkqcQej35FohcT0FRlkRQ== - dependencies: - base64-js "^1.2.3" - xmlbuilder "^9.0.7" - xmldom "0.1.x" - -priorityqueuejs@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/priorityqueuejs/-/priorityqueuejs-1.0.0.tgz#2ee4f23c2560913e08c07ce5ccdd6de3df2c5af8" - integrity sha1-LuTyPCVgkT4IwHzlzN1t498sWvg= - -process-nextick-args@~1.0.6: - version "1.0.7" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" - integrity sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M= - -process@^0.11.10: - version "0.11.10" - resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" - integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= - -psl@^1.1.28, psl@^1.1.33: - version "1.8.0" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" - integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== - pump@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" @@ -1612,20 +1175,12 @@ pump@^3.0.0: end-of-stream "^1.1.0" once "^1.3.1" -punycode@^2.1.0, punycode@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== - -q@^1.0.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" - integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= - -qs@~6.5.2: - version "6.5.2" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" - integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== +qs@^6.9.1: + version "6.10.1" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.1.tgz#4931482fa8d647a5aab799c5271d2133b981fb6a" + integrity sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg== + dependencies: + side-channel "^1.0.4" quick-lru@^5.1.1: version "5.1.1" @@ -1648,53 +1203,6 @@ readable-stream@^3.0.6: string_decoder "^1.1.1" util-deprecate "^1.0.1" -readable-stream@^3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" - integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== - dependencies: - inherits "^2.0.3" - string_decoder "^1.1.1" - util-deprecate "^1.0.1" - -readable-stream@~2.0.0: - version "2.0.6" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" - integrity sha1-j5A0HmilPMySh4jaz80Rs265t44= - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "~1.0.0" - process-nextick-args "~1.0.6" - string_decoder "~0.10.x" - util-deprecate "~1.0.1" - -request@^2.86.0: - version "2.88.2" - resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" - integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.8.0" - caseless "~0.12.0" - combined-stream "~1.0.6" - extend "~3.0.2" - forever-agent "~0.6.1" - form-data "~2.3.2" - har-validator "~5.1.3" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.19" - oauth-sign "~0.9.0" - performance-now "^2.1.0" - qs "~6.5.2" - safe-buffer "^5.1.2" - tough-cookie "~2.5.0" - tunnel-agent "^0.6.0" - uuid "^3.3.2" - resolve-alpn@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/resolve-alpn/-/resolve-alpn-1.0.0.tgz#745ad60b3d6aff4b4a48e01b8c0bdc70959e0e8c" @@ -1707,36 +1215,11 @@ responselike@^2.0.0: dependencies: lowercase-keys "^2.0.0" -safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - safe-buffer@~5.1.0: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" - integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== - -sax@0.5.x: - version "0.5.8" - resolved "https://registry.yarnpkg.com/sax/-/sax-0.5.8.tgz#d472db228eb331c2506b0e8c15524adb939d12c1" - integrity sha1-1HLbIo6zMcJQaw6MFVJK25OdEsE= - -sax@>=0.6.0: - version "1.2.4" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" - integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== - -semaphore@^1.0.5: - version "1.1.0" - resolved "https://registry.yarnpkg.com/semaphore/-/semaphore-1.1.0.tgz#aaad8b86b20fe8e9b32b16dc2ee682a8cd26a8aa" - integrity sha512-O4OZEaNtkMd/K0i6js9SL+gqy0ZCBMgUvlSqHKi4IBdjhe7wB8pwztUk1BbZ1fmrvpwFrPbHzqd2w5pTcJH6LA== - semver@^5.1.0, semver@^5.3.0: version "5.6.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" @@ -1766,6 +1249,15 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + source-map@0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" @@ -1776,21 +1268,6 @@ sprintf-js@~1.0.2: resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= -sshpk@^1.7.0: - version "1.16.1" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" - integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== - dependencies: - asn1 "~0.2.3" - assert-plus "^1.0.0" - bcrypt-pbkdf "^1.0.0" - dashdash "^1.12.0" - ecc-jsbn "~0.1.1" - getpass "^0.1.1" - jsbn "~0.1.0" - safer-buffer "^2.0.2" - tweetnacl "~0.14.0" - string_decoder@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" @@ -1798,10 +1275,12 @@ string_decoder@^1.1.1: dependencies: safe-buffer "~5.1.0" -string_decoder@~0.10.x: - version "0.10.31" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" - integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" tmp@0.0.29: version "0.0.29" @@ -1810,33 +1289,11 @@ tmp@0.0.29: dependencies: os-tmpdir "~1.0.1" -tough-cookie@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.0.0.tgz#d822234eeca882f991f0f908824ad2622ddbece4" - integrity sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg== - dependencies: - psl "^1.1.33" - punycode "^2.1.1" - universalify "^0.1.2" - -tough-cookie@~2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" - integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== - dependencies: - psl "^1.1.28" - punycode "^2.1.1" - tslib@^1.8.1: version "1.9.3" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" integrity sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ== -tslib@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.0.3.tgz#8e0741ac45fc0c226e58a17bfc3e64b9bc6ca61c" - integrity sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ== - tsutils@^3.17.1: version "3.17.1" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759" @@ -1844,35 +1301,19 @@ tsutils@^3.17.1: dependencies: tslib "^1.8.1" -tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= - dependencies: - safe-buffer "^5.0.1" - -tunnel@0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/tunnel/-/tunnel-0.0.4.tgz#2d3785a158c174c9a16dc2c046ec5fc5f1742213" - integrity sha1-LTeFoVjBdMmhbcLARuxfxfF0IhM= - -tunnel@^0.0.6: +tunnel@0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c" integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg== -tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.5" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" - integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= - -typed-rest-client@^0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/typed-rest-client/-/typed-rest-client-0.9.0.tgz#f768cc0dc3f4e950f06e04825c36b3e7834aa1f2" - integrity sha1-92jMDcP06VDwbgSCXDaz54NKofI= +typed-rest-client@^1.8.4: + version "1.8.4" + resolved "https://registry.yarnpkg.com/typed-rest-client/-/typed-rest-client-1.8.4.tgz#ba3fb788e5b9322547406392533f12d660a5ced6" + integrity sha512-MyfKKYzk3I6/QQp6e1T50py4qg+c+9BzOEl2rBmQIpStwNUoqQ73An+Tkfy9YuV7O+o2mpVVJpe+fH//POZkbg== dependencies: - tunnel "0.0.4" - underscore "1.8.3" + qs "^6.9.1" + tunnel "0.0.6" + underscore "^1.12.1" typescript@^4.1.3: version "4.1.3" @@ -1889,83 +1330,40 @@ uc.micro@^1.0.1, uc.micro@^1.0.5: resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.5.tgz#0c65f15f815aa08b560a61ce8b4db7ffc3f45376" integrity sha512-JoLI4g5zv5qNyT09f4YAvEZIIV1oOjqnewYg5D38dkQljIzpPT296dbIGvKro3digYI1bkb7W6EP1y4uDlmzLg== -underscore@1.8.3, underscore@~1.8.3: - version "1.8.3" - resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.8.3.tgz#4f3fb53b106e6097fcf9cb4109f2a5e9bdfa5022" - integrity sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI= - -underscore@^1.8.3: - version "1.9.1" - resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.9.1.tgz#06dce34a0e68a7babc29b365b8e74b8925203961" - integrity sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg== - -universal-user-agent@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-6.0.0.tgz#3381f8503b251c0d9cd21bc1de939ec9df5480ee" - integrity sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w== - -universalify@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" - integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== +underscore@^1.12.1: + version "1.13.1" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.13.1.tgz#0c1c6bd2df54b6b69f2314066d65b6cde6fcf9d1" + integrity sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g== universalify@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== -uri-js@^4.2.2: - version "4.4.1" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" - integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== - dependencies: - punycode "^2.1.0" - url-join@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/url-join/-/url-join-1.1.0.tgz#741c6c2f4596c4830d6718460920d0c92202dc78" integrity sha1-dBxsL0WWxIMNZxhGCSDQySIC3Hg= -util-deprecate@^1.0.1, util-deprecate@~1.0.1: +util-deprecate@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= -uuid@^3.0.0, uuid@^3.3.2: - version "3.4.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" - integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== - -uuid@^8.3.0: - version "8.3.1" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.1.tgz#2ba2e6ca000da60fce5a196954ab241131e05a31" - integrity sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg== - -validator@~9.4.1: - version "9.4.1" - resolved "https://registry.yarnpkg.com/validator/-/validator-9.4.1.tgz#abf466d398b561cd243050112c6ff1de6cc12663" - integrity sha512-YV5KjzvRmSyJ1ee/Dm5UED0G+1L4GZnLN3w6/T+zZm8scVua4sOhYKWTUrKa0H/tMiJyO9QLHMPN+9mB/aMunA== - -verror@1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= - dependencies: - assert-plus "^1.0.0" - core-util-is "1.0.2" - extsprintf "^1.2.0" - -vsce@1.48.0: - version "1.48.0" - resolved "https://registry.yarnpkg.com/vsce/-/vsce-1.48.0.tgz#31c1a4c6909c3b8bdc48b3d32cc8c8e94c7113a2" - integrity sha512-1qJn6QLRTu26FIvvMbK/gzHLLdxJVTg9CUTSnCjJHObCCF5CQ0F3FUv7t+5cT7i0J5v5YljrsRY09u7dPBcEnA== +vsce@1.88.0: + version "1.88.0" + resolved "https://registry.yarnpkg.com/vsce/-/vsce-1.88.0.tgz#748dc9f75996d97a5953408848c56c4c1b4dca6b" + integrity sha512-FS5ou3G+WRnPPr/tWVs8b/jVzeDacgZHy/y7/QQW7maSPFEAmRt2bFGUJtJVEUDLBqtDm/3VGMJ7D31cF2U1tw== dependencies: + azure-devops-node-api "^10.2.2" + chalk "^2.4.2" cheerio "^1.0.0-rc.1" - commander "^2.8.1" + commander "^6.1.0" denodeify "^1.2.1" glob "^7.0.6" - lodash "^4.17.10" - markdown-it "^8.3.1" + leven "^3.1.0" + lodash "^4.17.15" + markdown-it "^10.0.0" mime "^1.3.4" minimatch "^3.0.3" osenv "^0.1.3" @@ -1973,8 +1371,8 @@ vsce@1.48.0: read "^1.0.7" semver "^5.1.0" tmp "0.0.29" + typed-rest-client "^1.8.4" url-join "^1.1.0" - vso-node-api "6.1.2-preview" yauzl "^2.3.1" yazl "^2.2.2" @@ -1992,16 +1390,6 @@ vscode-universal@deepak1556/universal#61454d96223b774c53cda10f72c2098c0ce02d58: fs-extra "^9.0.1" typescript "^4.1.3" -vso-node-api@6.1.2-preview: - version "6.1.2-preview" - resolved "https://registry.yarnpkg.com/vso-node-api/-/vso-node-api-6.1.2-preview.tgz#aab3546df2451ecd894e071bb99b5df19c5fa78f" - integrity sha1-qrNUbfJFHs2JTgcbuZtd8Zxfp48= - dependencies: - q "^1.0.1" - tunnel "0.0.4" - typed-rest-client "^0.9.0" - underscore "^1.8.3" - which@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" @@ -2014,41 +1402,11 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= -xml2js@0.2.8: - version "0.2.8" - resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.2.8.tgz#9b81690931631ff09d1957549faf54f4f980b3c2" - integrity sha1-m4FpCTFjH/CdGVdUn69U9PmAs8I= - dependencies: - sax "0.5.x" - -xml2js@^0.4.19: - version "0.4.23" - resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66" - integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug== - dependencies: - sax ">=0.6.0" - xmlbuilder "~11.0.0" - xmlbuilder@>=11.0.1: version "15.1.1" resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-15.1.1.tgz#9dcdce49eea66d8d10b42cae94a79c3c8d0c2ec5" integrity sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg== -xmlbuilder@^9.0.7: - version "9.0.7" - resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d" - integrity sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0= - -xmlbuilder@~11.0.0: - version "11.0.1" - resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" - integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== - -xmldom@0.1.x: - version "0.1.31" - resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.31.tgz#b76c9a1bd9f0a9737e5a72dc37231cf38375e2ff" - integrity sha512-yS2uJflVQs6n+CyjHoaBmVSqIDevTAWrzMmjG1Gc7h1qQ7uVozNhEPJAwZXWyGQ/Gafo3fCwrcaokezLPupVyQ== - yallist@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" diff --git a/coder.js b/coder.js new file mode 100644 index 0000000000000..e487491df8258 --- /dev/null +++ b/coder.js @@ -0,0 +1,71 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Coder Technologies. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +// This must be ran from VS Code's root. +const gulp = require('gulp'); +const path = require('path'); +const _ = require('underscore'); +const buildfile = require('./src/buildfile'); +const common = require('./build/lib/optimize'); +const util = require('./build/lib/util'); + +const vscodeEntryPoints = _.flatten([ + buildfile.entrypoint('vs/workbench/workbench.web.api'), + buildfile.entrypoint('vs/server/entry'), + buildfile.base, + buildfile.workbenchWeb, + buildfile.workerExtensionHost, + buildfile.workerNotebook, + buildfile.keyboardMaps, + // See ./src/vs/workbench/buildfile.desktop.js + buildfile.entrypoint('vs/platform/files/node/watcher/unix/watcherApp'), + buildfile.entrypoint('vs/platform/files/node/watcher/nsfw/watcherApp'), + buildfile.entrypoint(`vs/platform/terminal/node/ptyHostMain`), + buildfile.entrypoint('vs/workbench/services/extensions/node/extensionHostProcess'), +]); + +// See ./build/gulpfile.vscode.js +const vscodeResources = [ + 'out-build/vs/server/fork.js', + '!out-build/vs/server/doc/**', + 'out-build/vs/workbench/services/extensions/worker/extensionHostWorkerMain.js', + 'out-build/bootstrap.js', + 'out-build/bootstrap-fork.js', + 'out-build/bootstrap-amd.js', + 'out-build/bootstrap-node.js', + 'out-build/vs/**/*.{svg,png,html,ttf,jpg}', + '!out-build/vs/code/browser/workbench/*.html', + '!out-build/vs/code/electron-browser/**', + 'out-build/vs/base/common/performance.js', + 'out-build/vs/base/node/languagePacks.js', + 'out-build/vs/base/browser/ui/codicons/codicon/**', + 'out-build/vs/base/node/userDataPath.js', + 'out-build/vs/workbench/browser/media/*-theme.css', + 'out-build/vs/workbench/contrib/debug/**/*.json', + 'out-build/vs/workbench/contrib/externalTerminal/**/*.scpt', + 'out-build/vs/workbench/contrib/webview/browser/pre/*.js', + 'out-build/vs/**/markdown.css', + 'out-build/vs/workbench/contrib/tasks/**/*.json', + 'out-build/vs/platform/files/**/*.md', + '!**/test/**' +]; + +gulp.task('optimize', gulp.series( + util.rimraf('out-vscode'), + common.optimizeTask({ + src: 'out-build', + entryPoints: vscodeEntryPoints, + resources: vscodeResources, + loaderConfig: common.loaderConfig(), + out: 'out-vscode', + inlineAmdImages: true, + bundleInfo: undefined + }), +)); + +gulp.task('minify', gulp.series( + util.rimraf('out-vscode-min'), + common.minifyTask('out-vscode') +)); diff --git a/extensions/github-authentication/src/githubServer.ts b/extensions/github-authentication/src/githubServer.ts index f675507c4dd39..33ee47e63162e 100644 --- a/extensions/github-authentication/src/githubServer.ts +++ b/extensions/github-authentication/src/githubServer.ts @@ -15,7 +15,8 @@ import { AuthProviderType } from './github'; const localize = nls.loadMessageBundle(); export const NETWORK_ERROR = 'network error'; -const AUTH_RELAY_SERVER = 'vscode-auth.github.com'; +// NOTE@coder: use our own auth relay (the commented one is microsoft's, not ours) +const AUTH_RELAY_SERVER = 'auth.code-server.dev'; // const AUTH_RELAY_STAGING_SERVER = 'client-auth-staging-14a768b.herokuapp.com'; class UriEventHandler extends vscode.EventEmitter implements vscode.UriHandler { diff --git a/extensions/postinstall.js b/extensions/postinstall.js index da4fa3e9d0443..654f6dbfdeb4a 100644 --- a/extensions/postinstall.js +++ b/extensions/postinstall.js @@ -24,6 +24,9 @@ function processRoot() { rimraf.sync(filePath); } } + + // NOTE@coder: Delete .bin so it doesn't contain broken symlinks that trip up nfpm. + rimraf.sync(path.join(__dirname, 'node_modules', '.bin')); } function processLib() { diff --git a/package.json b/package.json index 6ac7da8e3b104..8b362dc39b79d 100644 --- a/package.json +++ b/package.json @@ -57,6 +57,8 @@ "extensions-ci": "node --max_old_space_size=4095 ./node_modules/gulp/bin/gulp.js extensions-ci" }, "dependencies": { + "@types/proxy-from-env": "^1.0.1", + "@types/tar-stream": "^2.2.1", "applicationinsights": "1.0.8", "chokidar": "3.5.1", "graceful-fs": "4.2.6", @@ -71,8 +73,11 @@ "native-watchdog": "1.3.0", "node-pty": "0.11.0-beta7", "nsfw": "2.1.2", + "proxy-agent": "^4.0.1", + "proxy-from-env": "^1.1.0", "spdlog": "^0.13.0", "sudo-prompt": "9.2.1", + "tar-stream": "^2.2.0", "tas-client-umd": "0.1.4", "v8-inspect-profiler": "^0.0.20", "vscode-oniguruma": "1.5.1", diff --git a/src/vs/base/common/ipc.d.ts b/src/vs/base/common/ipc.d.ts new file mode 100644 index 0000000000000..984bf1664cb50 --- /dev/null +++ b/src/vs/base/common/ipc.d.ts @@ -0,0 +1,137 @@ +/** + * External interfaces for integration into code-server over IPC. + * This file exists in two locations: + * - typings/ipc.d.ts + * - lib/vscode/src/typings/ipc.d.ts + * The second is a symlink to the first. + */ +export interface Options { + authed: boolean + base: string + csStaticBase: string + disableUpdateCheck: boolean + logLevel: number +} + +export interface InitMessage { + type: 'init' + id: string + options: VscodeOptions +} + +export type Query = { [key: string]: string | string[] | undefined | Query | Query[] } + +export interface SocketMessage { + type: 'socket' + query: Query + permessageDeflate: boolean +} + +export interface CliMessage { + type: 'cli' + args: Args +} + +export interface OpenCommandPipeArgs { + type: 'open' + fileURIs?: string[] + folderURIs: string[] + forceNewWindow?: boolean + diffMode?: boolean + addMode?: boolean + gotoLineMode?: boolean + forceReuseWindow?: boolean + waitMarkerFilePath?: string +} + +export type CodeServerMessage = InitMessage | SocketMessage | CliMessage + +export interface ReadyMessage { + type: 'ready' +} + +export interface OptionsMessage { + id: string + type: 'options' + options: WorkbenchOptions +} + +export type VscodeMessage = ReadyMessage | OptionsMessage + +export interface StartPath { + url: string + workspace: boolean +} + +export interface Args { + 'user-data-dir'?: string + + 'enable-proposed-api'?: string[] + 'extensions-dir'?: string + 'builtin-extensions-dir'?: string + 'extra-extensions-dir'?: string[] + 'extra-builtin-extensions-dir'?: string[] + 'ignore-last-opened'?: boolean + + locale?: string + + log?: string + verbose?: boolean + + _: string[] +} + +export interface VscodeOptions { + readonly args: Args + readonly remoteAuthority: string + readonly startPath?: StartPath +} + +export interface VscodeOptionsMessage extends VscodeOptions { + readonly id: string +} + +export interface UriComponents { + readonly scheme: string + readonly authority: string + readonly path: string + readonly query: string + readonly fragment: string +} + +export interface NLSConfiguration { + locale: string + availableLanguages: { + [key: string]: string + } + pseudo?: boolean + _languagePackSupport?: boolean +} + +export interface WorkbenchOptions { + readonly workbenchWebConfiguration: { + readonly remoteAuthority?: string + readonly folderUri?: UriComponents + readonly workspaceUri?: UriComponents + readonly logLevel?: number + readonly workspaceProvider?: { + payload: [['userDataPath', string], ['enableProposedApi', string]] + } + } + readonly remoteUserDataUri: UriComponents + readonly productConfiguration: { + codeServerVersion?: string + readonly extensionsGallery?: { + readonly serviceUrl: string + readonly itemUrl: string + readonly controlUrl: string + readonly recommendationsUrl: string + } + } + readonly nlsConfiguration: NLSConfiguration + readonly commit: string +} + +export interface WorkbenchOptionsMessage { + id: string +} diff --git a/src/vs/base/common/network.ts b/src/vs/base/common/network.ts index d5bacc79d2d8c..c990c88e095fa 100644 --- a/src/vs/base/common/network.ts +++ b/src/vs/base/common/network.ts @@ -126,16 +126,17 @@ class RemoteAuthoritiesImpl { if (host && host.indexOf(':') !== -1) { host = `[${host}]`; } - const port = this._ports[authority]; + // const port = this._ports[authority]; const connectionToken = this._connectionTokens[authority]; let query = `path=${encodeURIComponent(uri.path)}`; if (typeof connectionToken === 'string') { query += `&tkn=${encodeURIComponent(connectionToken)}`; } + // NOTE@coder: Changed this to work against the current path. return URI.from({ scheme: platform.isWeb ? this._preferredWebSchema : Schemas.vscodeRemoteResource, - authority: `${host}:${port}`, - path: `/vscode-remote-resource`, + authority: window.location.host, + path: `${window.location.pathname.replace(/\/+$/, '')}/vscode-remote-resource`, query }); } diff --git a/src/vs/base/common/platform.ts b/src/vs/base/common/platform.ts index 512775eaddc69..2453c8fd24f45 100644 --- a/src/vs/base/common/platform.ts +++ b/src/vs/base/common/platform.ts @@ -101,6 +101,18 @@ if (typeof navigator === 'object' && !isElectronRenderer) { _isWeb = true; _locale = navigator.language; _language = _locale; + + // NOTE@coder: Make languages work. + const el = typeof document !== 'undefined' && document.getElementById('vscode-remote-nls-configuration'); + const rawNlsConfig = el && el.getAttribute('data-settings'); + if (rawNlsConfig) { + try { + const nlsConfig: NLSConfig = JSON.parse(rawNlsConfig); + _locale = nlsConfig.locale; + _translationsConfigFile = nlsConfig._translationsConfigFile; + _language = nlsConfig.availableLanguages['*'] || LANGUAGE_DEFAULT; + } catch (error) { /* Oh well. */ } + } } // Native environment diff --git a/src/vs/base/common/processes.ts b/src/vs/base/common/processes.ts index 6c52c3f9ce2bf..6b84dbedbf57a 100644 --- a/src/vs/base/common/processes.ts +++ b/src/vs/base/common/processes.ts @@ -111,6 +111,7 @@ export function sanitizeProcessEnvironment(env: IProcessEnvironment, ...preserve /^VSCODE_.+$/, /^SNAP(|_.*)$/, /^GDK_PIXBUF_.+$/, + /^CODE_SERVER_.+$/, ]; const envKeys = Object.keys(env); envKeys diff --git a/src/vs/base/common/product.ts b/src/vs/base/common/product.ts index a301b50683c18..8ede7fbdfd6b9 100644 --- a/src/vs/base/common/product.ts +++ b/src/vs/base/common/product.ts @@ -31,6 +31,9 @@ export type ExtensionVirtualWorkspaceSupport = { }; export interface IProductConfiguration { + // NOTE@coder: add codeServerVersion + readonly codeServerVersion?: string; + readonly version: string; readonly date?: string; readonly quality?: string; diff --git a/src/vs/base/common/util.ts b/src/vs/base/common/util.ts new file mode 100644 index 0000000000000..338db5a2fdea4 --- /dev/null +++ b/src/vs/base/common/util.ts @@ -0,0 +1,64 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Coder Technologies. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +/** + * Base options included on every page. + */ +export interface Options { + base: string + csStaticBase: string + logLevel: number +} + +/** + * Remove extra slashes in a URL. + */ +export const normalize = (url: string, keepTrailing = false): string => { + return url.replace(/\/\/+/g, "/").replace(/\/+$/, keepTrailing ? "/" : "") +} + +/** + * Resolve a relative base against the window location. This is used for + * anything that doesn't work with a relative path. + */ +export const resolveBase = (base?: string): string => { + // After resolving the base will either start with / or be an empty string. + if (!base || base.startsWith("/")) { + return base ?? "" + } + const parts = location.pathname.split("/") + parts[parts.length - 1] = base + const url = new URL(location.origin + "/" + parts.join("/")) + return normalize(url.pathname) +} + +/** + * Get options embedded in the HTML or query params. + */ +export const getOptions = (): T => { + let options: T + try { + options = JSON.parse(document.getElementById("coder-options")!.getAttribute("data-settings")!) + } catch (error) { + options = {} as T + } + + // You can also pass options in stringified form to the options query + // variable. Options provided here will override the ones in the options + // element. + const params = new URLSearchParams(location.search) + const queryOpts = params.get("options") + if (queryOpts) { + options = { + ...options, + ...JSON.parse(queryOpts), + } + } + + options.base = resolveBase(options.base) + options.csStaticBase = resolveBase(options.csStaticBase) + + return options +} diff --git a/src/vs/base/node/languagePacks.js b/src/vs/base/node/languagePacks.js index 5c14fade87895..0899cab4ed150 100644 --- a/src/vs/base/node/languagePacks.js +++ b/src/vs/base/node/languagePacks.js @@ -73,7 +73,10 @@ function getLanguagePackConfigurations(userDataPath) { const configFile = path.join(userDataPath, 'languagepacks.json'); try { - return nodeRequire(configFile); + // NOTE@coder: Swapped require with readFile since require is cached and + // we don't restart the server-side portion of code-server when the + // language changes. + return JSON.parse(fs.readFileSync(configFile, 'utf8')); } catch (err) { // Do nothing. If we can't read the file we have no // language pack config. diff --git a/src/vs/base/node/proxy_agent.ts b/src/vs/base/node/proxy_agent.ts new file mode 100644 index 0000000000000..495634bdc7652 --- /dev/null +++ b/src/vs/base/node/proxy_agent.ts @@ -0,0 +1,85 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Coder Technologies. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as http from "http" +import * as proxyAgent from "proxy-agent" +import * as proxyFromEnv from "proxy-from-env" + +/** + * This file has nothing to do with the code-server proxy. + * It is to support $HTTP_PROXY, $HTTPS_PROXY and $NO_PROXY. + * + * - https://github.com/cdr/code-server/issues/124 + * - https://www.npmjs.com/package/proxy-agent + * - https://www.npmjs.com/package/proxy-from-env + * + * This file exists in two locations: + * - src/node/proxy_agent.ts + * - lib/vscode/src/vs/base/node/proxy_agent.ts + * The second is a symlink to the first. + */ + +/** + * monkeyPatch patches the node http,https modules to route all requests through the + * agent we get from the proxy-agent package. + * + * This approach only works if there is no code specifying an explicit agent when making + * a request. + * + * None of our code ever passes in a explicit agent to the http,https modules. + * VS Code's does sometimes but only when a user sets the http.proxy configuration. + * See https://code.visualstudio.com/docs/setup/network#_legacy-proxy-server-support + * + * Even if they do, it's probably the same proxy so we should be fine! And those knobs + * are deprecated anyway. + */ +export function monkeyPatch(inVSCode: boolean): void { + if (shouldEnableProxy()) { + const http = require("http") + const https = require("https") + + // If we do not pass in a proxy URL, proxy-agent will get the URL from the environment. + // See https://www.npmjs.com/package/proxy-from-env. + // Also see shouldEnableProxy. + const pa = newProxyAgent(inVSCode) + http.globalAgent = pa + https.globalAgent = pa + } +} + +function newProxyAgent(inVSCode: boolean): http.Agent { + // The reasoning for this split is that VS Code's build process does not have + // esModuleInterop enabled but the code-server one does. As a result depending on where + // we execute, we either have a default attribute or we don't. + // + // I can't enable esModuleInterop in VS Code's build process as it breaks and spits out + // a huge number of errors. And we can't use require as otherwise the modules won't be + // included in the final product. + if (inVSCode) { + return new (proxyAgent as any)() + } else { + return new (proxyAgent as any).default() + } +} + +// If they have $NO_PROXY set to example.com then this check won't work! +// But that's drastically unlikely. +function shouldEnableProxy(): boolean { + let shouldEnable = false + + const httpProxy = proxyFromEnv.getProxyForUrl(`http://example.com`) + if (httpProxy) { + shouldEnable = true + console.debug(`using $HTTP_PROXY ${httpProxy}`) + } + + const httpsProxy = proxyFromEnv.getProxyForUrl(`https://example.com`) + if (httpsProxy) { + shouldEnable = true + console.debug(`using $HTTPS_PROXY ${httpsProxy}`) + } + + return shouldEnable +} diff --git a/src/vs/base/parts/ipc/common/ipc.net.ts b/src/vs/base/parts/ipc/common/ipc.net.ts index aad4fb4e92a28..7d9459c1c2407 100644 --- a/src/vs/base/parts/ipc/common/ipc.net.ts +++ b/src/vs/base/parts/ipc/common/ipc.net.ts @@ -747,6 +747,11 @@ export class PersistentProtocol implements IMessagePassingProtocol { return this._socket; } + // NOTE@coder: add setSocket + public setSocket(socket: ISocket) { + this._socket = socket; + } + public getMillisSinceLastIncomingData(): number { return Date.now() - this._socketReader.lastReadTime; } diff --git a/src/vs/code/browser/workbench/workbench.ts b/src/vs/code/browser/workbench/workbench.ts index 9c222a0048ec3..033924a7743a2 100644 --- a/src/vs/code/browser/workbench/workbench.ts +++ b/src/vs/code/browser/workbench/workbench.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IWorkbenchConstructionOptions, create, ICredentialsProvider, IURLCallbackProvider, IWorkspaceProvider, IWorkspace, IWindowIndicator, IHomeIndicator, IProductQualityChangeHandler, ISettingsSyncOptions } from 'vs/workbench/workbench.web.api'; +import { IWorkbenchConstructionOptions, create, ICredentialsProvider, IURLCallbackProvider, IWorkspaceProvider, IWorkspace, IWindowIndicator, IProductQualityChangeHandler, ISettingsSyncOptions } from 'vs/workbench/workbench.web.api'; import { URI, UriComponents } from 'vs/base/common/uri'; import { Event, Emitter } from 'vs/base/common/event'; import { generateUuid } from 'vs/base/common/uuid'; @@ -17,7 +17,6 @@ import { isStandalone } from 'vs/base/browser/browser'; import { localize } from 'vs/nls'; import { Schemas } from 'vs/base/common/network'; import product from 'vs/platform/product/common/product'; -import { parseLogLevel } from 'vs/platform/log/common/log'; function doCreateUri(path: string, queryValues: Map): URI { let query: string | undefined = undefined; @@ -37,6 +36,15 @@ function doCreateUri(path: string, queryValues: Map): URI { return URI.parse(window.location.href).with({ path, query }); } +/** + * NOTE@coder: Add this function. + * Encode a path for opening via the folder or workspace query parameter. This + * preserves slashes so it can be edited by hand more easily. + */ +export const encodePath = (path: string): string => { + return path.split('/').map((p) => encodeURIComponent(p)).join('/'); +}; + interface ICredential { service: string; account: string; @@ -316,12 +324,18 @@ class WorkspaceProvider implements IWorkspaceProvider { // Folder else if (isFolderToOpen(workspace)) { - targetHref = `${document.location.origin}${document.location.pathname}?${WorkspaceProvider.QUERY_PARAM_FOLDER}=${encodeURIComponent(workspace.folderUri.toString())}`; + const target = workspace.folderUri.scheme === Schemas.vscodeRemote + ? encodePath(workspace.folderUri.path) + : encodeURIComponent(workspace.folderUri.toString()); + targetHref = `${document.location.origin}${document.location.pathname}?${WorkspaceProvider.QUERY_PARAM_FOLDER}=${target}`; } // Workspace else if (isWorkspaceToOpen(workspace)) { - targetHref = `${document.location.origin}${document.location.pathname}?${WorkspaceProvider.QUERY_PARAM_WORKSPACE}=${encodeURIComponent(workspace.workspaceUri.toString())}`; + const target = workspace.workspaceUri.scheme === Schemas.vscodeRemote + ? encodePath(workspace.workspaceUri.path) + : encodeURIComponent(workspace.workspaceUri.toString()); + targetHref = `${document.location.origin}${document.location.pathname}?${WorkspaceProvider.QUERY_PARAM_WORKSPACE}=${target}`; } // Append payload if any @@ -403,7 +417,6 @@ class WindowIndicator implements IWindowIndicator { } (function () { - // Find config by checking for DOM const configElement = document.getElementById('vscode-workbench-web-configuration'); const configElementAttribute = configElement ? configElement.getAttribute('data-settings') : undefined; @@ -411,51 +424,27 @@ class WindowIndicator implements IWindowIndicator { throw new Error('Missing web configuration element'); } - const config: IWorkbenchConstructionOptions & { folderUri?: UriComponents, workspaceUri?: UriComponents } = JSON.parse(configElementAttribute); + const config: IWorkbenchConstructionOptions & { folderUri?: UriComponents, workspaceUri?: UriComponents } = { + webviewEndpoint: `${window.location.origin}${window.location.pathname.replace(/\/+$/, '')}/webview`, + ...JSON.parse(configElementAttribute), + }; + + // Strip the protocol from the authority if it exists. + const normalizeAuthority = (authority: string): string => authority.replace(/^https?:\/\//, ''); + if (config.remoteAuthority) { + (config as any).remoteAuthority = normalizeAuthority(config.remoteAuthority); + } + if (config.workspaceUri && config.workspaceUri.authority) { + config.workspaceUri.authority = normalizeAuthority(config.workspaceUri.authority); + } + if (config.folderUri && config.folderUri.authority) { + config.folderUri.authority = normalizeAuthority(config.folderUri.authority); + } // Find workspace to open and payload let foundWorkspace = false; let workspace: IWorkspace; - let payload = Object.create(null); - let logLevel: string | undefined = undefined; - - const query = new URL(document.location.href).searchParams; - query.forEach((value, key) => { - switch (key) { - - // Folder - case WorkspaceProvider.QUERY_PARAM_FOLDER: - workspace = { folderUri: URI.parse(value) }; - foundWorkspace = true; - break; - - // Workspace - case WorkspaceProvider.QUERY_PARAM_WORKSPACE: - workspace = { workspaceUri: URI.parse(value) }; - foundWorkspace = true; - break; - - // Empty - case WorkspaceProvider.QUERY_PARAM_EMPTY_WINDOW: - workspace = undefined; - foundWorkspace = true; - break; - - // Payload - case WorkspaceProvider.QUERY_PARAM_PAYLOAD: - try { - payload = JSON.parse(value); - } catch (error) { - console.error(error); // possible invalid JSON - } - break; - - // Log level - case 'logLevel': - logLevel = value; - break; - } - }); + let payload = config.workspaceProvider?.payload || Object.create(null); // If no workspace is provided through the URL, check for config attribute from server if (!foundWorkspace) { @@ -471,13 +460,6 @@ class WindowIndicator implements IWindowIndicator { // Workspace Provider const workspaceProvider = new WorkspaceProvider(workspace, payload); - // Home Indicator - const homeIndicator: IHomeIndicator = { - href: 'https://github.com/microsoft/vscode', - icon: 'code', - title: localize('home', "Home") - }; - // Window indicator (unless connected to a remote) let windowIndicator: WindowIndicator | undefined = undefined; if (!workspaceProvider.hasRemote()) { @@ -520,12 +502,7 @@ class WindowIndicator implements IWindowIndicator { // Finally create workbench create(document.body, { ...config, - developmentOptions: { - logLevel: logLevel ? parseLogLevel(logLevel) : undefined, - ...config.developmentOptions - }, settingsSyncOptions, - homeIndicator, windowIndicator, productQualityChangeHandler, workspaceProvider, diff --git a/src/vs/platform/environment/common/argv.ts b/src/vs/platform/environment/common/argv.ts index ded07ffcd9e5d..08a4afa55ba15 100644 --- a/src/vs/platform/environment/common/argv.ts +++ b/src/vs/platform/environment/common/argv.ts @@ -39,6 +39,8 @@ export interface NativeParsedArgs { 'extensions-dir'?: string; 'extensions-download-dir'?: string; 'builtin-extensions-dir'?: string; + 'extra-extensions-dir'?: string[]; // NOTE@coder: added extra extensions dir + 'extra-builtin-extensions-dir'?: string[]; // NOTE@coder: added extra builtin extensions dir extensionDevelopmentPath?: string[]; // undefined or array of 1 or more local paths or URIs extensionTestsPath?: string; // either a local path or a URI extensionDevelopmentKind?: string[]; diff --git a/src/vs/platform/environment/common/environment.ts b/src/vs/platform/environment/common/environment.ts index 77efaac3fbaff..f5d5fd956db88 100644 --- a/src/vs/platform/environment/common/environment.ts +++ b/src/vs/platform/environment/common/environment.ts @@ -124,6 +124,9 @@ export interface INativeEnvironmentService extends IEnvironmentService { extensionsPath: string; extensionsDownloadPath: string; builtinExtensionsPath: string; + // NOTE@coder: add extraExtensionPaths/extraBuiltinExtensionPaths + extraExtensionPaths: string[]; + extraBuiltinExtensionPaths: string[]; // --- smoke test support driverHandle?: string; diff --git a/src/vs/platform/environment/common/environmentService.ts b/src/vs/platform/environment/common/environmentService.ts index 70e06765c6970..03650810378f0 100644 --- a/src/vs/platform/environment/common/environmentService.ts +++ b/src/vs/platform/environment/common/environmentService.ts @@ -15,6 +15,7 @@ import { URI } from 'vs/base/common/uri'; import { ExtensionKind } from 'vs/platform/extensions/common/extensions'; import { env } from 'vs/base/common/process'; + export interface INativeEnvironmentPaths { /** @@ -157,6 +158,19 @@ export abstract class AbstractNativeEnvironmentService implements INativeEnviron return joinPath(this.userHome, this.productService.dataFolderName, 'extensions').fsPath; } + /** + * NOTE@coder: add extraExtensionPaths and extraBuiltinExtensionPaths + */ + @memoize + get extraExtensionPaths(): string[] { + return (this._args['extra-extensions-dir'] || []).map((p) => resolve(p)); + } + + @memoize + get extraBuiltinExtensionPaths(): string[] { + return (this._args['extra-builtin-extensions-dir'] || []).map((p) => resolve(p)); + } + @memoize get extensionDevelopmentLocationURI(): URI[] | undefined { const extensionDevelopmentPaths = this.args.extensionDevelopmentPath; diff --git a/src/vs/platform/environment/node/argv.ts b/src/vs/platform/environment/node/argv.ts index 238098af3a062..6b65cf668fd99 100644 --- a/src/vs/platform/environment/node/argv.ts +++ b/src/vs/platform/environment/node/argv.ts @@ -52,6 +52,9 @@ export const OPTIONS: OptionDescriptions> = { 'extensions-dir': { type: 'string', deprecates: 'extensionHomePath', cat: 'e', args: 'dir', description: localize('extensionHomePath', "Set the root path for extensions.") }, 'extensions-download-dir': { type: 'string' }, 'builtin-extensions-dir': { type: 'string' }, + // NOTE@coder: add extra-extensions-dir and extra-builtin-extensions-dir + 'extra-extensions-dir': { type: 'string[]', cat: 'o', description: 'Path to an extra user extension directory.' }, + 'extra-builtin-extensions-dir': { type: 'string[]', cat: 'o', description: 'Path to an extra builtin extension directory.' }, 'list-extensions': { type: 'boolean', cat: 'e', description: localize('listExtensions', "List the installed extensions.") }, 'show-versions': { type: 'boolean', cat: 'e', description: localize('showVersions', "Show versions of installed extensions, when using --list-extensions.") }, 'category': { type: 'string', cat: 'e', description: localize('category', "Filters installed extensions by provided category, when using --list-extensions."), args: 'category' }, diff --git a/src/vs/platform/extensionManagement/node/extensionsScanner.ts b/src/vs/platform/extensionManagement/node/extensionsScanner.ts index f489f82362ba5..bd49ee29bdb91 100644 --- a/src/vs/platform/extensionManagement/node/extensionsScanner.ts +++ b/src/vs/platform/extensionManagement/node/extensionsScanner.ts @@ -97,7 +97,7 @@ export class ExtensionsScanner extends Disposable { } async scanAllUserExtensions(): Promise { - return this.scanExtensionsInDir(this.extensionsPath, ExtensionType.User); + return this.scanExtensionsInDirs([this.extensionsPath, ...this.environmentService.extraExtensionPaths], ExtensionType.User); } async extractUserExtension(identifierWithVersion: ExtensionIdentifierWithVersion, zipPath: string, token: CancellationToken): Promise { @@ -273,6 +273,7 @@ export class ExtensionsScanner extends Disposable { return [...systemExtensions, ...devSystemExtensions]; } + private async scanExtensionsInDir(dir: string, type: ExtensionType): Promise { const limiter = new Limiter(10); const stat = await this.fileService.resolve(URI.file(dir)); @@ -313,7 +314,7 @@ export class ExtensionsScanner extends Disposable { } private async scanDefaultSystemExtensions(): Promise { - const result = await this.scanExtensionsInDir(this.systemExtensionsPath, ExtensionType.System); + const result = await this.scanExtensionsInDirs([this.systemExtensionsPath, ...this.environmentService.extraBuiltinExtensionPaths], ExtensionType.System); this.logService.trace('Scanned system extensions:', result.length); return result; } @@ -417,4 +418,9 @@ export class ExtensionsScanner extends Disposable { } }); } + + private async scanExtensionsInDirs(dirs: string[], type: ExtensionType): Promise { + const results = await Promise.all(dirs.map((path) => this.scanExtensionsInDir(path, type))); + return results.reduce((flat, current) => flat.concat(current), []); + } } diff --git a/src/vs/platform/product/common/product.ts b/src/vs/platform/product/common/product.ts index 4a0b94187d631..0735d29d9f00b 100644 --- a/src/vs/platform/product/common/product.ts +++ b/src/vs/platform/product/common/product.ts @@ -73,6 +73,13 @@ else { ], }); } + + // NOTE@coder: Add the ability to inject settings from the server. + const el = document.getElementById('vscode-remote-product-configuration'); + const rawProductConfiguration = el && el.getAttribute('data-settings'); + if (rawProductConfiguration) { + Object.assign(product, JSON.parse(rawProductConfiguration)); + } } export default product; diff --git a/src/vs/platform/remote/browser/browserSocketFactory.ts b/src/vs/platform/remote/browser/browserSocketFactory.ts index 2f343e841ab99..60bf97572f8e4 100644 --- a/src/vs/platform/remote/browser/browserSocketFactory.ts +++ b/src/vs/platform/remote/browser/browserSocketFactory.ts @@ -208,7 +208,8 @@ export class BrowserSocketFactory implements ISocketFactory { } connect(host: string, port: number, query: string, callback: IConnectCallback): void { - const socket = this._webSocketFactory.create(`ws://${/:/.test(host) ? `[${host}]` : host}:${port}/?${query}&skipWebSocketFrames=false`); + // NOTE@coder: Modified to work against the current path. + const socket = this._webSocketFactory.create(`${window.location.protocol === 'https:' ? 'wss' : 'ws'}://${window.location.host}${window.location.pathname}?${query}&skipWebSocketFrames=false`); const errorListener = socket.onError((err) => callback(err, undefined)); socket.onOpen(() => { errorListener.dispose(); diff --git a/src/vs/platform/remote/common/remoteAgentConnection.ts b/src/vs/platform/remote/common/remoteAgentConnection.ts index 41475982dd398..e36cc6be53691 100644 --- a/src/vs/platform/remote/common/remoteAgentConnection.ts +++ b/src/vs/platform/remote/common/remoteAgentConnection.ts @@ -229,7 +229,9 @@ async function connectToRemoteExtensionHostAgent(options: ISimpleConnectionOptio let socket: ISocket; try { - socket = await createSocket(options.logService, options.socketFactory, options.host, options.port, `reconnectionToken=${options.reconnectionToken}&reconnection=${options.reconnectionProtocol ? 'true' : 'false'}`, timeoutCancellationToken); + // NOTE@coder: Add connection type to the socket. This is so they can be + // distinguished by the backend. + socket = await createSocket(options.logService, options.socketFactory, options.host, options.port, `type=${connectionTypeToString(connectionType)}&reconnectionToken=${options.reconnectionToken}&reconnection=${options.reconnectionProtocol ? 'true' : 'false'}`, timeoutCancellationToken); } catch (error) { options.logService.error(`${logPrefix} socketFactory.connect() failed or timed out. Error:`); options.logService.error(error); diff --git a/src/vs/platform/storage/common/storage.ts b/src/vs/platform/storage/common/storage.ts index faecb2618ea52..4dc61721d815a 100644 --- a/src/vs/platform/storage/common/storage.ts +++ b/src/vs/platform/storage/common/storage.ts @@ -105,8 +105,10 @@ export interface IStorageService { * * @param target allows to define the target of the storage operation * to either the current machine or user. + * + * NOTE@coder: Add a promise so extensions can await storage writes. */ - store(key: string, value: string | boolean | number | undefined | null, scope: StorageScope, target: StorageTarget): void; + store(key: string, value: string | boolean | number | undefined | null, scope: StorageScope, target: StorageTarget): Promise | void; /** * Delete an element stored under the provided key from storage. @@ -333,46 +335,49 @@ export abstract class AbstractStorageService extends Disposable implements IStor return this.getStorage(scope)?.getNumber(key, fallbackValue); } - store(key: string, value: string | boolean | number | undefined | null, scope: StorageScope, target: StorageTarget): void { + // NOTE@coder: Make a promise so extensions can await storage writes. + store(key: string, value: string | boolean | number | undefined | null, scope: StorageScope, target: StorageTarget): Promise | void { // We remove the key for undefined/null values if (isUndefinedOrNull(value)) { this.remove(key, scope); - return; + return Promise.resolve(); } // Update our datastructures but send events only after - this.withPausedEmitters(() => { + return this.withPausedEmitters(() => { // Update key-target map this.updateKeyTarget(key, scope, target); // Store actual value - this.getStorage(scope)?.set(key, value); + return this.getStorage(scope)?.set(key, value); }); } - remove(key: string, scope: StorageScope): void { + // NOTE@coder: Make a promise so extensions can await the storage write. + remove(key: string, scope: StorageScope): Promise | void { // Update our datastructures but send events only after - this.withPausedEmitters(() => { + return this.withPausedEmitters(() => { // Update key-target map this.updateKeyTarget(key, scope, undefined); // Remove actual key - this.getStorage(scope)?.delete(key); + return this.getStorage(scope)?.delete(key); }); } - private withPausedEmitters(fn: Function): void { + // NOTE@coder: Return the function's return so extensions can await the storage write. + private withPausedEmitters(fn: () => T): T { // Pause emitters this._onDidChangeValue.pause(); this._onDidChangeTarget.pause(); try { - fn(); + return fn(); } finally { // Resume emitters diff --git a/src/vs/server/channel.ts b/src/vs/server/channel.ts new file mode 100644 index 0000000000000..a93b95b9eb1e5 --- /dev/null +++ b/src/vs/server/channel.ts @@ -0,0 +1,564 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Coder Technologies. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as os from 'os'; +import * as path from 'path'; +import { VSBuffer } from 'vs/base/common/buffer'; +import { CancellationTokenSource } from 'vs/base/common/cancellation'; +import { Emitter, Event } from 'vs/base/common/event'; +import { IDisposable } from 'vs/base/common/lifecycle'; +import * as platform from 'vs/base/common/platform'; +import * as resources from 'vs/base/common/resources'; +import { ReadableStreamEventPayload } from 'vs/base/common/stream'; +import { URI, UriComponents } from 'vs/base/common/uri'; +import { transformOutgoingURIs } from 'vs/base/common/uriIpc'; +import { IServerChannel } from 'vs/base/parts/ipc/common/ipc'; +import { IDiagnosticInfo } from 'vs/platform/diagnostics/common/diagnostics'; +import { INativeEnvironmentService } from 'vs/platform/environment/common/environment'; +import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; +import { FileDeleteOptions, FileOpenOptions, FileOverwriteOptions, FileReadStreamOptions, FileType, FileWriteOptions, IStat, IWatchOptions } from 'vs/platform/files/common/files'; +import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider'; +import { ConsoleLogger, ILogService } from 'vs/platform/log/common/log'; +import product from 'vs/platform/product/common/product'; +import { IRemoteAgentEnvironment, RemoteAgentConnectionContext } from 'vs/platform/remote/common/remoteAgentEnvironment'; +import { ITelemetryData, ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { IShellLaunchConfig, ITerminalEnvironment } from 'vs/platform/terminal/common/terminal'; +import { getTranslations } from 'vs/server/nls'; +import { getUriTransformer } from 'vs/server/util'; +import { IFileChangeDto } from 'vs/workbench/api/common/extHost.protocol'; +import { IEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable'; +import { MergedEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariableCollection'; +import { deserializeEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariableShared'; +import * as terminal from 'vs/workbench/contrib/terminal/common/remoteTerminalChannel'; +import * as terminalEnvironment from 'vs/workbench/contrib/terminal/common/terminalEnvironment'; +import { AbstractVariableResolverService } from 'vs/workbench/services/configurationResolver/common/variableResolver'; +import { ExtensionScanner, ExtensionScannerInput } from 'vs/workbench/services/extensions/node/extensionPoints'; +import { PtyHostService } from 'vs/platform/terminal/node/ptyHostService'; + +const logger = new ConsoleLogger(); + +/** + * Extend the file provider to allow unwatching. + */ +class Watcher extends DiskFileSystemProvider { + public readonly watches = new Map(); + + public override dispose(): void { + this.watches.forEach((w) => w.dispose()); + this.watches.clear(); + super.dispose(); + } + + public _watch(req: number, resource: URI, opts: IWatchOptions): void { + this.watches.set(req, this.watch(resource, opts)); + } + + public unwatch(req: number): void { + this.watches.get(req)!.dispose(); + this.watches.delete(req); + } +} + +export class FileProviderChannel implements IServerChannel, IDisposable { + private readonly provider: DiskFileSystemProvider; + private readonly watchers = new Map(); + + public constructor( + private readonly environmentService: INativeEnvironmentService, + private readonly logService: ILogService, + ) { + this.provider = new DiskFileSystemProvider(this.logService); + } + + public listen(context: RemoteAgentConnectionContext, event: string, args?: any): Event { + switch (event) { + case 'filechange': return this.filechange(context, args[0]); + case 'readFileStream': return this.readFileStream(args[0], args[1]); + } + + throw new Error(`Invalid listen '${event}'`); + } + + private filechange(context: RemoteAgentConnectionContext, session: string): Event { + const emitter = new Emitter({ + onFirstListenerAdd: () => { + const provider = new Watcher(this.logService); + this.watchers.set(session, provider); + const transformer = getUriTransformer(context.remoteAuthority); + provider.onDidChangeFile((events) => { + emitter.fire(events.map((event) => ({ + ...event, + resource: transformer.transformOutgoing(event.resource), + }))); + }); + provider.onDidErrorOccur((event) => this.logService.error(event)); + }, + onLastListenerRemove: () => { + this.watchers.get(session)!.dispose(); + this.watchers.delete(session); + }, + }); + + return emitter.event; + } + + private readFileStream(resource: UriComponents, opts: FileReadStreamOptions): Event> { + const cts = new CancellationTokenSource(); + const fileStream = this.provider.readFileStream(this.transform(resource), opts, cts.token); + const emitter = new Emitter>({ + onFirstListenerAdd: () => { + fileStream.on('data', (data) => emitter.fire(VSBuffer.wrap(data))); + fileStream.on('error', (error) => emitter.fire(error)); + fileStream.on('end', () => emitter.fire('end')); + }, + onLastListenerRemove: () => cts.cancel(), + }); + + return emitter.event; + } + + public call(_: unknown, command: string, args?: any): Promise { + switch (command) { + case 'stat': return this.stat(args[0]); + case 'open': return this.open(args[0], args[1]); + case 'close': return this.close(args[0]); + case 'read': return this.read(args[0], args[1], args[2]); + case 'readFile': return this.readFile(args[0]); + case 'write': return this.write(args[0], args[1], args[2], args[3], args[4]); + case 'writeFile': return this.writeFile(args[0], args[1], args[2]); + case 'delete': return this.delete(args[0], args[1]); + case 'mkdir': return this.mkdir(args[0]); + case 'readdir': return this.readdir(args[0]); + case 'rename': return this.rename(args[0], args[1], args[2]); + case 'copy': return this.copy(args[0], args[1], args[2]); + case 'watch': return this.watch(args[0], args[1], args[2], args[3]); + case 'unwatch': return this.unwatch(args[0], args[1]); + } + + throw new Error(`Invalid call '${command}'`); + } + + public dispose(): void { + this.watchers.forEach((w) => w.dispose()); + this.watchers.clear(); + } + + private async stat(resource: UriComponents): Promise { + return this.provider.stat(this.transform(resource)); + } + + private async open(resource: UriComponents, opts: FileOpenOptions): Promise { + return this.provider.open(this.transform(resource), opts); + } + + private async close(fd: number): Promise { + return this.provider.close(fd); + } + + private async read(fd: number, pos: number, length: number): Promise<[VSBuffer, number]> { + const buffer = VSBuffer.alloc(length); + const bytesRead = await this.provider.read(fd, pos, buffer.buffer, 0, length); + return [buffer, bytesRead]; + } + + private async readFile(resource: UriComponents): Promise { + return VSBuffer.wrap(await this.provider.readFile(this.transform(resource))); + } + + private write(fd: number, pos: number, buffer: VSBuffer, offset: number, length: number): Promise { + return this.provider.write(fd, pos, buffer.buffer, offset, length); + } + + private writeFile(resource: UriComponents, buffer: VSBuffer, opts: FileWriteOptions): Promise { + return this.provider.writeFile(this.transform(resource), buffer.buffer, opts); + } + + private async delete(resource: UriComponents, opts: FileDeleteOptions): Promise { + return this.provider.delete(this.transform(resource), opts); + } + + private async mkdir(resource: UriComponents): Promise { + return this.provider.mkdir(this.transform(resource)); + } + + private async readdir(resource: UriComponents): Promise<[string, FileType][]> { + return this.provider.readdir(this.transform(resource)); + } + + private async rename(resource: UriComponents, target: UriComponents, opts: FileOverwriteOptions): Promise { + return this.provider.rename(this.transform(resource), URI.from(target), opts); + } + + private copy(resource: UriComponents, target: UriComponents, opts: FileOverwriteOptions): Promise { + return this.provider.copy(this.transform(resource), URI.from(target), opts); + } + + private async watch(session: string, req: number, resource: UriComponents, opts: IWatchOptions): Promise { + this.watchers.get(session)!._watch(req, this.transform(resource), opts); + } + + private async unwatch(session: string, req: number): Promise { + this.watchers.get(session)!.unwatch(req); + } + + private transform(resource: UriComponents): URI { + // Used for walkthrough content. + if (/^\/static[^/]*\//.test(resource.path)) { + return URI.file(this.environmentService.appRoot + resource.path.replace(/^\/static[^/]*\//, '/')); + // Used by the webview service worker to load resources. + } else if (resource.path === '/vscode-resource' && resource.query) { + try { + const query = JSON.parse(resource.query); + if (query.requestResourcePath) { + return URI.file(query.requestResourcePath); + } + } catch (error) { /* Carry on. */ } + } + return URI.from(resource); + } +} + +// See ../../workbench/services/remote/common/remoteAgentEnvironmentChannel.ts +export class ExtensionEnvironmentChannel implements IServerChannel { + public constructor( + private readonly environment: INativeEnvironmentService, + private readonly log: ILogService, + private readonly telemetry: ITelemetryService, + private readonly connectionToken: string, + ) { } + + public listen(_: unknown, event: string): Event { + throw new Error(`Invalid listen '${event}'`); + } + + public async call(context: any, command: string, args: any): Promise { + switch (command) { + case 'getEnvironmentData': + return transformOutgoingURIs( + await this.getEnvironmentData(), + getUriTransformer(context.remoteAuthority), + ); + case 'scanExtensions': + return transformOutgoingURIs( + await this.scanExtensions(args.language), + getUriTransformer(context.remoteAuthority), + ); + case 'getDiagnosticInfo': return this.getDiagnosticInfo(); + case 'disableTelemetry': return this.disableTelemetry(); + case 'logTelemetry': return this.logTelemetry(args.eventName, args.data); + case 'flushTelemetry': return this.flushTelemetry(); + } + throw new Error(`Invalid call '${command}'`); + } + + private async getEnvironmentData(): Promise { + return { + pid: process.pid, + connectionToken: this.connectionToken, + appRoot: URI.file(this.environment.appRoot), + settingsPath: this.environment.settingsResource, + logsPath: URI.file(this.environment.logsPath), + extensionsPath: URI.file(this.environment.extensionsPath!), + extensionHostLogsPath: URI.file(path.join(this.environment.logsPath, 'extension-host')), + globalStorageHome: this.environment.globalStorageHome, + workspaceStorageHome: this.environment.workspaceStorageHome, + userHome: this.environment.userHome, + useHostProxy: false, + os: platform.OS, + marks: [] + }; + } + + private async scanExtensions(language: string): Promise { + const translations = await getTranslations(language, this.environment.userDataPath); + + const scanMultiple = (isBuiltin: boolean, isUnderDevelopment: boolean, paths: string[]): Promise => { + return Promise.all(paths.map((path) => { + return ExtensionScanner.scanExtensions(new ExtensionScannerInput( + product.version, + product.date, + product.commit, + language, + !!process.env.VSCODE_DEV, + path, + isBuiltin, + isUnderDevelopment, + translations, + ), this.log); + })); + }; + + const scanBuiltin = async (): Promise => { + return scanMultiple(true, false, [this.environment.builtinExtensionsPath, ...this.environment.extraBuiltinExtensionPaths]); + }; + + const scanInstalled = async (): Promise => { + return scanMultiple(false, true, [this.environment.extensionsPath!, ...this.environment.extraExtensionPaths]); + }; + + return Promise.all([scanBuiltin(), scanInstalled()]).then((allExtensions) => { + const uniqueExtensions = new Map(); + allExtensions.forEach((multipleExtensions) => { + multipleExtensions.forEach((extensions) => { + extensions.forEach((extension) => { + const id = ExtensionIdentifier.toKey(extension.identifier); + if (uniqueExtensions.has(id)) { + const oldPath = uniqueExtensions.get(id)!.extensionLocation.fsPath; + const newPath = extension.extensionLocation.fsPath; + this.log.warn(`${oldPath} has been overridden ${newPath}`); + } + uniqueExtensions.set(id, extension); + }); + }); + }); + return Array.from(uniqueExtensions.values()); + }); + } + + private getDiagnosticInfo(): Promise { + throw new Error('not implemented'); + } + + private async disableTelemetry(): Promise { + this.telemetry.setEnabled(false); + } + + private async logTelemetry(eventName: string, data: ITelemetryData): Promise { + this.telemetry.publicLog(eventName, data); + } + + private async flushTelemetry(): Promise { + // We always send immediately at the moment. + } +} + +// Reference: - ../../workbench/api/common/extHostDebugService.ts +class VariableResolverService extends AbstractVariableResolverService { + constructor( + remoteAuthority: string, + args: terminal.ICreateTerminalProcessArguments, + env: platform.IProcessEnvironment, + ) { + super({ + getFolderUri: (name: string): URI | undefined => { + const folder = args.workspaceFolders.find((f) => f.name === name); + return folder && URI.revive(folder.uri); + }, + getWorkspaceFolderCount: (): number => { + return args.workspaceFolders.length; + }, + // In ../../workbench/contrib/terminal/common/remoteTerminalChannel.ts it + // looks like there are `config:` entries which must be for this? Not sure + // how/if the URI comes into play though. + getConfigurationValue: (_: URI, section: string): string | undefined => { + return args.resolvedVariables[`config:${section}`]; + }, + getAppRoot: (): string | undefined => { + return (args.resolverEnv && args.resolverEnv['VSCODE_CWD']) || env['VSCODE_CWD'] || process.cwd(); + }, + getExecPath: (): string | undefined => { + // Assuming that resolverEnv is just for use in the resolver and not for + // the terminal itself. + return (args.resolverEnv && args.resolverEnv['VSCODE_EXEC_PATH']) || env['VSCODE_EXEC_PATH']; + }, + // This is just a guess; this is the only file-related thing we're sent + // and none of these resolver methods seem to get called so I don't know + // how to test. + getFilePath: (): string | undefined => { + const resource = transformIncoming(remoteAuthority, args.activeFileResource); + if (!resource) { + return undefined; + } + // See ../../editor/standalone/browser/simpleServices.ts; + // `BaseConfigurationResolverService` calls `getUriLabel` from there. + if (resource.scheme === 'file') { + return resource.fsPath; + } + return resource.path; + }, + // It looks like these are set here although they aren't on the types: + // ../../workbench/contrib/terminal/common/remoteTerminalChannel.ts + getSelectedText: (): string | undefined => { + return args.resolvedVariables.selectedText; + }, + getLineNumber: (): string | undefined => { + return args.resolvedVariables.selectedText; + }, + }, undefined, Promise.resolve(env)); + } +} + +export class TerminalProviderChannel implements IServerChannel, IDisposable { + public constructor( + private readonly logService: ILogService, + private readonly ptyService: PtyHostService, + ) { } + + public listen(_: RemoteAgentConnectionContext, event: string, args: any): Event { + logger.trace('TerminalProviderChannel:listen', event, args); + + switch (event) { + case '$onPtyHostExitEvent': return this.ptyService.onPtyHostExit || Event.None; + case '$onPtyHostStartEvent': return this.ptyService.onPtyHostStart || Event.None; + case '$onPtyHostUnresponsiveEvent': return this.ptyService.onPtyHostUnresponsive || Event.None; + case '$onPtyHostResponsiveEvent': return this.ptyService.onPtyHostResponsive || Event.None; + case '$onPtyHostRequestResolveVariablesEvent': return this.ptyService.onPtyHostRequestResolveVariables || Event.None; + case '$onProcessDataEvent': return this.ptyService.onProcessData; + case '$onProcessExitEvent': return this.ptyService.onProcessExit; + case '$onProcessReadyEvent': return this.ptyService.onProcessReady; + case '$onProcessReplayEvent': return this.ptyService.onProcessReplay; + case '$onProcessTitleChangedEvent': return this.ptyService.onProcessTitleChanged; + case '$onProcessShellTypeChangedEvent': return this.ptyService.onProcessShellTypeChanged; + case '$onProcessOverrideDimensionsEvent': return this.ptyService.onProcessOverrideDimensions; + case '$onProcessResolvedShellLaunchConfigEvent': return this.ptyService.onProcessResolvedShellLaunchConfig; + case '$onProcessOrphanQuestion': return this.ptyService.onProcessOrphanQuestion; + // NOTE@asher: I think this must have something to do with running + // commands on the terminal that will do things in VS Code but we + // already have that functionality via a socket so I'm not sure what + // this is for. + // NOTE: VSCODE_IPC_HOOK_CLI is now missing, perhaps this is meant to + // replace that in some way. + case '$onExecuteCommand': return Event.None; + } + + throw new Error(`Invalid listen '${event}'`); + } + + public call(context: RemoteAgentConnectionContext, command: string, args: any): Promise { + logger.trace('TerminalProviderChannel:call', command, args); + + switch (command) { + case '$restartPtyHost': return this.ptyService.restartPtyHost(); + case '$createProcess': return this.createProcess(context.remoteAuthority, args); + case '$attachToProcess': return this.ptyService.attachToProcess(args[0]); + case '$start': return this.ptyService.start(args[0]); + case '$input': return this.ptyService.input(args[0], args[1]); + case '$acknowledgeDataEvent': return this.ptyService.acknowledgeDataEvent(args[0], args[1]); + case '$shutdown': return this.ptyService.shutdown(args[0], args[1]); + case '$resize': return this.ptyService.resize(args[0], args[1], args[2]); + case '$getInitialCwd': return this.ptyService.getInitialCwd(args[0]); + case '$getCwd': return this.ptyService.getCwd(args[0]); + case '$sendCommandResult': return this.sendCommandResult(args[0], args[1], args[2], args[3]); + case '$orphanQuestionReply': return this.ptyService.orphanQuestionReply(args[0]); + case '$listProcesses': return this.ptyService.listProcesses(); + case '$setTerminalLayoutInfo': return this.ptyService.setTerminalLayoutInfo(args); + case '$getTerminalLayoutInfo': return this.ptyService.getTerminalLayoutInfo(args); + case '$getEnvironment': return this.ptyService.getEnvironment(); + case '$getDefaultSystemShell': return this.ptyService.getDefaultSystemShell(args[0]); + case '$reduceConnectionGraceTime': return this.ptyService.reduceConnectionGraceTime(); + case '$updateTitle': return this.ptyService.updateTitle(args[0], args[1], args[2]); + case '$getProfiles': return this.ptyService.getProfiles(args[0], args[1], args[2]); + case '$acceptPtyHostResolvedVariables': return this.ptyService.acceptPtyHostResolvedVariables(args[0], args[1]); + } + + throw new Error(`Invalid call '${command}'`); + } + + public async dispose(): Promise { + // Nothing at the moment. + } + + // References: - ../../workbench/api/node/extHostTerminalService.ts + // - ../../workbench/contrib/terminal/browser/terminalProcessManager.ts + private async createProcess(remoteAuthority: string, args: terminal.ICreateTerminalProcessArguments): Promise { + const shellLaunchConfig: IShellLaunchConfig = { + name: args.shellLaunchConfig.name, + executable: args.shellLaunchConfig.executable, + args: args.shellLaunchConfig.args, + // TODO: Should we transform if it's a string as well? The incoming + // transform only takes `UriComponents` so I suspect it's not necessary. + cwd: typeof args.shellLaunchConfig.cwd !== 'string' + ? transformIncoming(remoteAuthority, args.shellLaunchConfig.cwd) + : args.shellLaunchConfig.cwd, + env: args.shellLaunchConfig.env, + }; + + const activeWorkspaceUri = transformIncoming(remoteAuthority, args.activeWorkspaceFolder?.uri); + const activeWorkspace = activeWorkspaceUri && args.activeWorkspaceFolder ? { + ...args.activeWorkspaceFolder, + uri: activeWorkspaceUri, + toResource: (relativePath: string) => resources.joinPath(activeWorkspaceUri, relativePath), + } : undefined; + + const resolverService = new VariableResolverService(remoteAuthority, args, process.env); + const resolver = terminalEnvironment.createVariableResolver(activeWorkspace, process.env, resolverService); + + shellLaunchConfig.cwd = terminalEnvironment.getCwd( + shellLaunchConfig, + os.homedir(), + resolver, + activeWorkspaceUri, + args.configuration['terminal.integrated.cwd'], + this.logService, + ); + + // Use instead of `terminal.integrated.env.${platform}` to make types work. + const getEnvFromConfig = (): ITerminalEnvironment => { + if (platform.isWindows) { + return args.configuration['terminal.integrated.env.windows']; + } else if (platform.isMacintosh) { + return args.configuration['terminal.integrated.env.osx']; + } + return args.configuration['terminal.integrated.env.linux']; + }; + + // ptyHostService calls getEnvironment in the ptyHost process it creates, + // which uses that process's environment. The process spawned doesn't have + // VSCODE_IPC_HOOK_CLI in its env, so we add it here. + const getEnvironment = async (): Promise => { + const env = await this.ptyService.getEnvironment(); + env.VSCODE_IPC_HOOK_CLI = process.env['VSCODE_IPC_HOOK_CLI']!; + return env; + }; + + const env = terminalEnvironment.createTerminalEnvironment( + shellLaunchConfig, + getEnvFromConfig(), + resolver, + product.version, + args.configuration['terminal.integrated.detectLocale'], + await getEnvironment() + ); + + // Apply extension environment variable collections to the environment. + if (!shellLaunchConfig.strictEnv) { + // They come in an array and in serialized format. + const envVariableCollections = new Map(); + for (const [k, v] of args.envVariableCollections) { + envVariableCollections.set(k, { map: deserializeEnvironmentVariableCollection(v) }); + } + const mergedCollection = new MergedEnvironmentVariableCollection(envVariableCollections); + mergedCollection.applyToProcessEnvironment(env); + } + + const persistentTerminalId = await this.ptyService.createProcess( + shellLaunchConfig, + shellLaunchConfig.cwd, + args.cols, + args.rows, + env, + process.env as platform.IProcessEnvironment, // Environment used for findExecutable + false, // windowsEnableConpty + args.shouldPersistTerminal, + args.workspaceId, + args.workspaceName, + ); + + return { + persistentTerminalId, + resolvedShellLaunchConfig: shellLaunchConfig, + }; + } + + private async sendCommandResult(_id: number, _reqId: number, _isError: boolean, _payload: any): Promise { + // NOTE: Not required unless we implement the matching event, see above. + throw new Error('not implemented'); + } +} + +function transformIncoming(remoteAuthority: string, uri: UriComponents | undefined): URI | undefined { + const transformer = getUriTransformer(remoteAuthority); + return uri ? URI.revive(transformer.transformIncoming(uri)) : uri; +} diff --git a/src/vs/server/connection.ts b/src/vs/server/connection.ts new file mode 100644 index 0000000000000..4d2fb53755a15 --- /dev/null +++ b/src/vs/server/connection.ts @@ -0,0 +1,244 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Coder Technologies. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as cp from 'child_process'; +import { VSBuffer } from 'vs/base/common/buffer'; +import { Emitter } from 'vs/base/common/event'; +import { FileAccess } from 'vs/base/common/network'; +import { INativeEnvironmentService } from 'vs/platform/environment/common/environment'; +import { ConsoleLogger } from 'vs/platform/log/common/log'; +import { IRemoteExtensionHostStartParams } from 'vs/platform/remote/common/remoteAgentConnection'; +import { getNlsConfiguration } from 'vs/server/nls'; +import { Protocol } from 'vs/server/protocol'; +import { IExtHostReadyMessage } from 'vs/workbench/services/extensions/common/extensionHostProtocol'; + +export abstract class Connection { + private readonly _onClose = new Emitter(); + /** + * Fire when the connection is closed (not just disconnected). This should + * only happen when the connection is offline and old or has an error. + */ + public readonly onClose = this._onClose.event; + private disposed = false; + private _offline: number | undefined; + + protected readonly logger: ConsoleLogger; + + public constructor( + protected readonly protocol: Protocol, + public readonly name: string, + ) { + this.logger = new ConsoleLogger(); + + this.logger.debug('Connecting...'); + this.onClose(() => this.logger.debug('Closed')); + } + + public get offline(): number | undefined { + return this._offline; + } + + public reconnect(protocol: Protocol): void { + this.logger.debug(`${this.protocol.options.reconnectionToken} Reconnecting...`); + this._offline = undefined; + this.doReconnect(protocol); + } + + public dispose(reason?: string): void { + this.logger.debug(`${this.protocol.options.reconnectionToken} Disposing...`, reason); + if (!this.disposed) { + this.disposed = true; + this.doDispose(); + this._onClose.fire(); + } + } + + protected setOffline(): void { + this.logger.debug('Disconnected'); + if (!this._offline) { + this._offline = Date.now(); + } + } + + /** + * Set up the connection on a new socket. + */ + protected abstract doReconnect(protcol: Protocol): void; + + /** + * Dispose/destroy everything permanently. + */ + protected abstract doDispose(): void; +} + +/** + * Used for all the IPC channels. + */ +export class ManagementConnection extends Connection { + public constructor(protocol: Protocol) { + super(protocol, 'management'); + protocol.onDidDispose(() => this.dispose()); // Explicit close. + protocol.onSocketClose(() => this.setOffline()); // Might reconnect. + protocol.sendMessage({ type: 'ok' }); + } + + protected doDispose(): void { + this.protocol.destroy(); + } + + protected doReconnect(protocol: Protocol): void { + protocol.sendMessage({ type: 'ok' }); + this.protocol.beginAcceptReconnection(protocol.getSocket(), protocol.readEntireBuffer()); + this.protocol.endAcceptReconnection(); + protocol.dispose(); + } +} + +interface DisconnectedMessage { + type: 'VSCODE_EXTHOST_DISCONNECTED'; +} + +interface ConsoleMessage { + type: '__$console'; + // See bootstrap-fork.js#L135. + severity: 'log' | 'warn' | 'error'; + arguments: any[]; +} + +type ExtHostMessage = DisconnectedMessage | ConsoleMessage | IExtHostReadyMessage; + +export class ExtensionHostConnection extends Connection { + private process?: cp.ChildProcess; + + public constructor( + protocol: Protocol, + private readonly params: IRemoteExtensionHostStartParams, + private readonly environment: INativeEnvironmentService, + ) { + super(protocol, 'exthost'); + + protocol.sendMessage({ debugPort: this.params.port }); + const buffer = protocol.readEntireBuffer(); + const inflateBytes = protocol.inflateBytes; + protocol.dispose(); + protocol.getUnderlyingSocket().pause(); + + this.spawn(buffer, inflateBytes).then((p) => this.process = p); + } + + protected doDispose(): void { + this.protocol.destroy(); + if (this.process) { + this.process.kill(); + } + } + + protected doReconnect(protocol: Protocol): void { + protocol.sendMessage({ debugPort: this.params.port }); + const buffer = protocol.readEntireBuffer(); + const inflateBytes = protocol.inflateBytes; + protocol.dispose(); + protocol.getUnderlyingSocket().pause(); + this.protocol.setSocket(protocol.getSocket()); + + this.sendInitMessage(buffer, inflateBytes); + } + + private sendInitMessage(buffer: VSBuffer, inflateBytes: Uint8Array | undefined): void { + if (!this.process) { + throw new Error('Tried to initialize VS Code before spawning'); + } + + this.logger.debug('Sending socket'); + + // TODO: Do something with the debug port. + this.process.send({ + type: 'VSCODE_EXTHOST_IPC_SOCKET', + initialDataChunk: Buffer.from(buffer.buffer).toString('base64'), + skipWebSocketFrames: this.protocol.options.skipWebSocketFrames, + permessageDeflate: this.protocol.options.permessageDeflate, + inflateBytes: inflateBytes ? Buffer.from(inflateBytes).toString('base64') : undefined, + }, this.protocol.getUnderlyingSocket()); + } + + private async spawn(buffer: VSBuffer, inflateBytes: Uint8Array | undefined): Promise { + this.logger.debug('Getting NLS configuration...'); + const config = await getNlsConfiguration(this.params.language, this.environment.userDataPath); + this.logger.debug('Spawning extension host...'); + const proc = cp.fork( + FileAccess.asFileUri('bootstrap-fork', require).fsPath, + [ + // While not technically necessary, adding --type makes it easier to + // tell which process bootstrap-fork is executing. Can also do `pkill -f + // extensionHost`. Other spawns in the VS Code codebase behave + // similarly. + '--type=extensionHost', + // We can't use the symlinked uriTransformer in this same directory + // because it gets compiled into AMD syntax and this path is imported + // using Node's native require. + `--uriTransformerPath=${FileAccess.asFileUri('vs/server/uriTransformer.js', require).fsPath}` + ], + { + env: { + ...process.env, + VSCODE_AMD_ENTRYPOINT: 'vs/workbench/services/extensions/node/extensionHostProcess', + VSCODE_PIPE_LOGGING: 'true', + VSCODE_VERBOSE_LOGGING: 'true', + VSCODE_EXTHOST_WILL_SEND_SOCKET: 'true', + VSCODE_HANDLES_UNCAUGHT_ERRORS: 'true', + VSCODE_LOG_STACK: 'false', + VSCODE_LOG_LEVEL: process.env.LOG_LEVEL, + VSCODE_NLS_CONFIG: JSON.stringify(config), + VSCODE_PARENT_PID: String(process.pid), + }, + silent: true, + }, + ); + + proc.on('error', (error) => { + this.logger.error(`${this.protocol.options.reconnectionToken} Exited unexpectedly`, error); + this.dispose(); + }); + proc.on('exit', (code) => { + this.logger.debug(`${this.protocol.options.reconnectionToken} Exited`, code); + this.dispose(); + }); + if (proc.stdout && proc.stderr) { + proc.stdout.setEncoding('utf8').on('data', (d) => this.logger.info(d)); + proc.stderr.setEncoding('utf8').on('data', (d) => this.logger.error(d)); + } + + proc.on('message', (event: ExtHostMessage) => { + switch (event.type) { + case '__$console': + switch (event.severity) { + case 'log': + this.logger.info('console', event.arguments); + break; + case 'warn': + this.logger.warn('console', event.arguments); + break; + default: + this.logger.error('console', event.arguments); + } + break; + case 'VSCODE_EXTHOST_DISCONNECTED': + this.logger.debug('Got disconnected message'); + this.setOffline(); + break; + case 'VSCODE_EXTHOST_IPC_READY': + this.logger.debug('Handshake completed'); + this.sendInitMessage(buffer, inflateBytes); + break; + default: + this.logger.error('Unexpected message', event); + break; + } + }); + + this.logger.debug('Waiting for handshake...'); + return proc; + } +} diff --git a/src/vs/server/entry.ts b/src/vs/server/entry.ts new file mode 100644 index 0000000000000..868f8c7c63db9 --- /dev/null +++ b/src/vs/server/entry.ts @@ -0,0 +1,89 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Coder Technologies. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { setUnexpectedErrorHandler } from 'vs/base/common/errors'; +import * as proxyAgent from 'vs/base/node/proxy_agent'; +import { CodeServerMessage, VscodeMessage } from 'vs/base/common/ipc'; +import { enableCustomMarketplace } from 'vs/server/marketplace'; +import { Vscode } from 'vs/server/server'; +import { ConsoleMainLogger } from 'vs/platform/log/common/log'; + +const logger = new ConsoleMainLogger(); + +setUnexpectedErrorHandler((error) => { + logger.warn('Uncaught error', error instanceof Error ? error.message : error); +}); +enableCustomMarketplace(); +proxyAgent.monkeyPatch(true); + +/** + * Ensure we control when the process exits. + */ +const exit = process.exit; +process.exit = function (code?: number) { + logger.warn(`process.exit() was prevented: ${code || 'unknown code'}.`); +} as (code?: number) => never; + +// Kill VS Code if the parent process dies. +if (typeof process.env.CODE_SERVER_PARENT_PID !== 'undefined') { + const parentPid = parseInt(process.env.CODE_SERVER_PARENT_PID, 10); + setInterval(() => { + try { + process.kill(parentPid, 0); // Throws an exception if the process doesn't exist anymore. + } catch (e) { + exit(); + } + }, 5000); +} else { + logger.error('no parent process'); + exit(1); +} + +const vscode = new Vscode(); +const send = (message: VscodeMessage): void => { + if (!process.send) { + throw new Error('not spawned with IPC'); + } + process.send(message); +}; + +// Wait for the init message then start up VS Code. Subsequent messages will +// return new workbench options without starting a new instance. +process.on('message', async (message: CodeServerMessage, socket) => { + logger.debug('got message from code-server', message.type); + logger.trace('code-server message content', message); + switch (message.type) { + case 'init': + try { + const options = await vscode.initialize(message.options); + send({ type: 'options', id: message.id, options }); + } catch (error) { + logger.error(error.message); + logger.error(error.stack); + exit(1); + } + break; + case 'cli': + try { + await vscode.cli(message.args); + exit(0); + } catch (error) { + logger.error(error.message); + logger.error(error.stack); + exit(1); + } + break; + case 'socket': + vscode.handleWebSocket(socket, message.query, message.permessageDeflate); + break; + } +}); +if (!process.send) { + logger.error('not spawned with IPC'); + exit(1); +} else { + // This lets the parent know the child is ready to receive messages. + send({ type: 'ready' }); +} diff --git a/src/vs/server/fork.js b/src/vs/server/fork.js new file mode 100644 index 0000000000000..915d9d8313572 --- /dev/null +++ b/src/vs/server/fork.js @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Coder Technologies. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +// This must be a JS file otherwise when it gets compiled it turns into AMD +// syntax which will not work without the right loader. +require('../../bootstrap-amd').load('vs/server/entry'); diff --git a/src/vs/server/insights.ts b/src/vs/server/insights.ts new file mode 100644 index 0000000000000..db9a65c7dfbbc --- /dev/null +++ b/src/vs/server/insights.ts @@ -0,0 +1,129 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Coder Technologies. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as appInsights from 'applicationinsights'; +import * as https from 'https'; +import * as http from 'http'; +import * as os from 'os'; + +class Channel { + public get _sender() { + throw new Error('unimplemented'); + } + public get _buffer() { + throw new Error('unimplemented'); + } + + public setUseDiskRetryCaching(): void { + throw new Error('unimplemented'); + } + public send(): void { + throw new Error('unimplemented'); + } + public triggerSend(): void { + throw new Error('unimplemented'); + } +} + +export class TelemetryClient { + public context: any = undefined; + public commonProperties: any = undefined; + public config: any = {}; + + public channel: any = new Channel(); + + public addTelemetryProcessor(): void { + throw new Error('unimplemented'); + } + + public clearTelemetryProcessors(): void { + throw new Error('unimplemented'); + } + + public runTelemetryProcessors(): void { + throw new Error('unimplemented'); + } + + public trackTrace(): void { + throw new Error('unimplemented'); + } + + public trackMetric(): void { + throw new Error('unimplemented'); + } + + public trackException(): void { + throw new Error('unimplemented'); + } + + public trackRequest(): void { + throw new Error('unimplemented'); + } + + public trackDependency(): void { + throw new Error('unimplemented'); + } + + public track(): void { + throw new Error('unimplemented'); + } + + public trackNodeHttpRequestSync(): void { + throw new Error('unimplemented'); + } + + public trackNodeHttpRequest(): void { + throw new Error('unimplemented'); + } + + public trackNodeHttpDependency(): void { + throw new Error('unimplemented'); + } + + public trackEvent(options: appInsights.Contracts.EventTelemetry): void { + if (!options.properties) { + options.properties = {}; + } + if (!options.measurements) { + options.measurements = {}; + } + + try { + const cpus = os.cpus(); + options.measurements.cores = cpus.length; + options.properties['common.cpuModel'] = cpus[0].model; + } catch (error) { } + + try { + options.measurements.memoryFree = os.freemem(); + options.measurements.memoryTotal = os.totalmem(); + } catch (error) { } + + try { + options.properties['common.shell'] = os.userInfo().shell; + options.properties['common.release'] = os.release(); + options.properties['common.arch'] = os.arch(); + } catch (error) { } + + try { + const url = process.env.TELEMETRY_URL || 'https://v1.telemetry.coder.com/track'; + const request = (/^http:/.test(url) ? http : https).request(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + }); + request.on('error', () => { /* We don't care. */ }); + request.write(JSON.stringify(options)); + request.end(); + } catch (error) { } + } + + public flush(options: { callback: (v: string) => void }): void { + if (options.callback) { + options.callback(''); + } + } +} diff --git a/src/vs/server/ipc.ts b/src/vs/server/ipc.ts new file mode 100644 index 0000000000000..3a56d24edfb78 --- /dev/null +++ b/src/vs/server/ipc.ts @@ -0,0 +1,66 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Coder Technologies. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as cp from 'child_process'; +import { Emitter } from 'vs/base/common/event'; + +enum ControlMessage { + okToChild = 'ok>', + okFromChild = 'ok<', +} + +interface RelaunchMessage { + type: 'relaunch'; + version: string; +} + +export type Message = RelaunchMessage; + +class IpcMain { + protected readonly _onMessage = new Emitter(); + public readonly onMessage = this._onMessage.event; + + public handshake(child?: cp.ChildProcess): Promise { + return new Promise((resolve, reject) => { + const target = child || process; + if (!target.send) { + throw new Error('Not spawned with IPC enabled'); + } + target.on('message', (message) => { + if (message === child ? ControlMessage.okFromChild : ControlMessage.okToChild) { + target.removeAllListeners(); + target.on('message', (msg) => this._onMessage.fire(msg)); + if (child) { + target.send!(ControlMessage.okToChild); + } + resolve(); + } + }); + if (child) { + child.once('error', reject); + child.once('exit', (code) => { + const error = new Error(`Unexpected exit with code ${code}`); + (error as any).code = code; + reject(error); + }); + } else { + target.send(ControlMessage.okFromChild); + } + }); + } + + public relaunch(version: string): void { + this.send({ type: 'relaunch', version }); + } + + private send(message: Message): void { + if (!process.send) { + throw new Error('Not a child process with IPC enabled'); + } + process.send(message); + } +} + +export const ipcMain = new IpcMain(); diff --git a/src/vs/server/marketplace.ts b/src/vs/server/marketplace.ts new file mode 100644 index 0000000000000..355e443d01382 --- /dev/null +++ b/src/vs/server/marketplace.ts @@ -0,0 +1,178 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Coder Technologies. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as fs from 'fs'; +import * as path from 'path'; +import * as tarStream from 'tar-stream'; +import * as util from 'util'; +import { CancellationToken } from 'vs/base/common/cancellation'; +import * as vszip from 'vs/base/node/zip'; +import * as nls from 'vs/nls'; +import product from 'vs/platform/product/common/product'; +import { IProductConfiguration } from 'vs/workbench/workbench.web.api'; + +// We will be overriding these, so keep a reference to the original. +const vszipExtract = vszip.extract; +const vszipBuffer = vszip.buffer; + +export const tar = async (tarPath: string, files: vszip.IFile[]): Promise => { + const pack = tarStream.pack(); + const chunks: Buffer[] = []; + const ended = new Promise((resolve) => { + pack.on('end', () => resolve(Buffer.concat(chunks))); + }); + pack.on('data', (chunk: Buffer) => chunks.push(chunk)); + for (let i = 0; i < files.length; i++) { + const file = files[i]; + pack.entry({ name: file.path }, file.contents); + } + pack.finalize(); + await util.promisify(fs.writeFile)(tarPath, await ended); + return tarPath; +}; + +export const extract = async (archivePath: string, extractPath: string, options: vszip.IExtractOptions = {}, token: CancellationToken): Promise => { + try { + await extractTar(archivePath, extractPath, options, token); + } catch (error) { + if (error.toString().includes('Invalid tar header')) { + await vszipExtract(archivePath, extractPath, options, token); + } + } +}; + +export const buffer = (targetPath: string, filePath: string): Promise => { + return new Promise(async (resolve, reject) => { + try { + let done: boolean = false; + await extractAssets(targetPath, new RegExp(filePath), (assetPath: string, data: Buffer) => { + if (path.normalize(assetPath) === path.normalize(filePath)) { + done = true; + resolve(data); + } + }); + if (!done) { + throw new Error('couldn\'t find asset ' + filePath); + } + } catch (error) { + if (error.toString().includes('Invalid tar header')) { + vszipBuffer(targetPath, filePath).then(resolve).catch(reject); + } else { + reject(error); + } + } + }); +}; + +const extractAssets = async (tarPath: string, match: RegExp, callback: (path: string, data: Buffer) => void): Promise => { + return new Promise((resolve, reject): void => { + const extractor = tarStream.extract(); + const fail = (error: Error) => { + extractor.destroy(); + reject(error); + }; + extractor.once('error', fail); + extractor.on('entry', async (header, stream, next) => { + const name = header.name; + if (match.test(name)) { + extractData(stream).then((data) => { + callback(name, data); + next(); + }).catch(fail); + } else { + stream.on('end', () => next()); + stream.resume(); // Just drain it. + } + }); + extractor.on('finish', resolve); + fs.createReadStream(tarPath).pipe(extractor); + }); +}; + +const extractData = (stream: NodeJS.ReadableStream): Promise => { + return new Promise((resolve, reject): void => { + const fileData: Buffer[] = []; + stream.on('error', reject); + stream.on('end', () => resolve(Buffer.concat(fileData))); + stream.on('data', (data) => fileData.push(data)); + }); +}; + +const extractTar = async (tarPath: string, targetPath: string, options: vszip.IExtractOptions = {}, token: CancellationToken): Promise => { + return new Promise((resolve, reject): void => { + const sourcePathRegex = new RegExp(options.sourcePath ? `^${options.sourcePath}` : ''); + const extractor = tarStream.extract(); + const fail = (error: Error) => { + extractor.destroy(); + reject(error); + }; + extractor.once('error', fail); + extractor.on('entry', async (header, stream, next) => { + const nextEntry = (): void => { + stream.on('end', () => next()); + stream.resume(); + }; + + const rawName = path.normalize(header.name); + if (token.isCancellationRequested || !sourcePathRegex.test(rawName)) { + return nextEntry(); + } + + const fileName = rawName.replace(sourcePathRegex, ''); + const targetFileName = path.join(targetPath, fileName); + if (/\/$/.test(fileName)) { + /* + NOTE:@coder: they removed mkdirp in favor of fs.promises + See commit: https://github.com/microsoft/vscode/commit/a0d76bb9834b63a02fba8017a6306511fe1ab4fe#diff-2bf233effbb62ea789bb7c4739d222a43ccd97ed9f1219f75bb07e9dee91c1a7 + 3/11/21 @jsjoeio + */ + return fs.promises.mkdir(targetFileName, { recursive: true }).then(nextEntry); + } + + const dirName = path.dirname(fileName); + const targetDirName = path.join(targetPath, dirName); + if (targetDirName.indexOf(targetPath) !== 0) { + return fail(new Error(nls.localize('invalid file', 'Error extracting {0}. Invalid file.', fileName))); + } + + /* + NOTE:@coder: they removed mkdirp in favor of fs.promises + See commit: https://github.com/microsoft/vscode/commit/a0d76bb9834b63a02fba8017a6306511fe1ab4fe#diff-2bf233effbb62ea789bb7c4739d222a43ccd97ed9f1219f75bb07e9dee91c1a7 + 3/11/21 @jsjoeio + */ + await fs.promises.mkdir(targetDirName, { recursive: true }); + + const fstream = fs.createWriteStream(targetFileName, { mode: header.mode }); + fstream.once('close', () => next()); + fstream.once('error', fail); + stream.pipe(fstream); + }); + extractor.once('finish', resolve); + fs.createReadStream(tarPath).pipe(extractor); + }); +}; + +/** + * Override original functionality so we can use a custom marketplace with + * either tars or zips. + */ +export const enableCustomMarketplace = (): void => { + const extensionsGallery: IProductConfiguration['extensionsGallery'] = { + serviceUrl: process.env.SERVICE_URL || 'https://extensions.coder.com/api', + itemUrl: process.env.ITEM_URL || '', + controlUrl: '', + recommendationsUrl: '', + ...(product.extensionsGallery || {}), + }; + + // Workaround for readonly property. + Object.assign(product, { extensionsGallery }); + + const target = vszip as typeof vszip; + + target.zip = tar; + target.extract = extract; + target.buffer = buffer; +}; diff --git a/src/vs/server/nls.ts b/src/vs/server/nls.ts new file mode 100644 index 0000000000000..4b16cc37c31a4 --- /dev/null +++ b/src/vs/server/nls.ts @@ -0,0 +1,93 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Coder Technologies. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as fs from 'fs'; +import * as path from 'path'; +import * as util from 'util'; +import { FileAccess } from 'vs/base/common/network'; +import * as lp from 'vs/base/node/languagePacks'; +import product from 'vs/platform/product/common/product'; +import { Translations } from 'vs/workbench/services/extensions/common/extensionPoints'; + +const configurations = new Map>(); +const metadataPath = path.join(FileAccess.asFileUri('', require).fsPath, 'nls.metadata.json'); + +export const isInternalConfiguration = (config: lp.NLSConfiguration): config is lp.InternalNLSConfiguration => { + return config && !!(config)._languagePackId; +}; + +const DefaultConfiguration = { + locale: 'en', + availableLanguages: {}, +}; + +export const getNlsConfiguration = async (locale: string, userDataPath: string): Promise => { + const id = `${locale}: ${userDataPath}`; + if (!configurations.has(id)) { + configurations.set(id, new Promise(async (resolve) => { + const config = product.commit && await util.promisify(fs.exists)(metadataPath) + ? await lp.getNLSConfiguration(product.commit, userDataPath, metadataPath, locale) + : DefaultConfiguration; + if (isInternalConfiguration(config)) { + config._languagePackSupport = true; + } + // If the configuration has no results keep trying since code-server + // doesn't restart when a language is installed so this result would + // persist (the plugin might not be installed yet or something). + if (config.locale !== 'en' && config.locale !== 'en-us' && Object.keys(config.availableLanguages).length === 0) { + configurations.delete(id); + } + resolve(config); + })); + } + return configurations.get(id)!; +}; + +export const getTranslations = async (locale: string, userDataPath: string): Promise => { + const config = await getNlsConfiguration(locale, userDataPath); + if (isInternalConfiguration(config)) { + try { + return JSON.parse(await util.promisify(fs.readFile)(config._translationsConfigFile, 'utf8')); + } catch (error) { /* Nothing yet. */ } + } + return {}; +}; + +export const getLocaleFromConfig = async (userDataPath: string): Promise => { + const files = ['locale.json', 'argv.json']; + for (let i = 0; i < files.length; ++i) { + try { + const localeConfigUri = path.join(userDataPath, 'User', files[i]); + const content = stripComments(await util.promisify(fs.readFile)(localeConfigUri, 'utf8')); + return JSON.parse(content).locale; + } catch (error) { /* Ignore. */ } + } + return 'en'; +}; + +// Taken from src/main.js in the main VS Code source. +const stripComments = (content: string): string => { + const regexp = /('(?:[^\\']*(?:\\.)?)*')|('(?:[^\\']*(?:\\.)?)*')|(\/\*(?:\r?\n|.)*?\*\/)|(\/{2,}.*?(?:(?:\r?\n)|$))/g; + + return content.replace(regexp, (match, _m1, _m2, m3, m4) => { + // Only one of m1, m2, m3, m4 matches + if (m3) { + // A block comment. Replace with nothing + return ''; + } else if (m4) { + // A line comment. If it ends in \r?\n then keep it. + const length_1 = m4.length; + if (length_1 > 2 && m4[length_1 - 1] === '\n') { + return m4[length_1 - 2] === '\r' ? '\r\n' : '\n'; + } + else { + return ''; + } + } else { + // We match a string + return match; + } + }); +}; diff --git a/src/vs/server/protocol.ts b/src/vs/server/protocol.ts new file mode 100644 index 0000000000000..89b860307351d --- /dev/null +++ b/src/vs/server/protocol.ts @@ -0,0 +1,158 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Coder Technologies. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as net from 'net'; +import { VSBuffer } from 'vs/base/common/buffer'; +import { PersistentProtocol } from 'vs/base/parts/ipc/common/ipc.net'; +import { NodeSocket, WebSocketNodeSocket } from 'vs/base/parts/ipc/node/ipc.net'; +import { ConsoleLogger, LogLevel } from 'vs/platform/log/common/log'; +import { AuthRequest, ConnectionTypeRequest, HandshakeMessage } from 'vs/platform/remote/common/remoteAgentConnection'; + +export interface SocketOptions { + /** The token is how we identify and connect to existing sessions. */ + readonly reconnectionToken: string; + /** Specifies that the client is trying to reconnect. */ + readonly reconnection: boolean; + /** If true assume this is not a web socket (always false for code-server). */ + readonly skipWebSocketFrames: boolean; + /** Whether to support compression (web socket only). */ + readonly permessageDeflate?: boolean; + /** + * Seed zlib with these bytes (web socket only). If parts of inflating was + * done in a different zlib instance we need to pass all those bytes into zlib + * otherwise the inflate might hit an inflated portion referencing a distance + * too far back. + */ + readonly inflateBytes?: VSBuffer; +} + +export class Protocol extends PersistentProtocol { + private readonly logger: ConsoleLogger; + + public constructor(socket: net.Socket, public readonly options: SocketOptions) { + super( + options.skipWebSocketFrames + ? new NodeSocket(socket) + : new WebSocketNodeSocket( + new NodeSocket(socket), + options.permessageDeflate || false, + options.inflateBytes || null, + // Always record inflate bytes if using permessage-deflate. + options.permessageDeflate || false, + ), + ); + + this.logger = new ConsoleLogger(LogLevel.Info); + } + + public getUnderlyingSocket(): net.Socket { + const socket = this.getSocket(); + return socket instanceof NodeSocket + ? socket.socket + : (socket as WebSocketNodeSocket).socket.socket; + } + + /** + * Perform a handshake to get a connection request. + */ + public handshake(): Promise { + this.logger.debug('Initiating handshake...'); + + return new Promise((resolve, reject) => { + const cleanup = () => { + handler.dispose(); + onClose.dispose(); + clearTimeout(timeout); + }; + + const onClose = this.onSocketClose(() => { + cleanup(); + this.logger.debug('Handshake failed'); + reject(new Error('Protocol socket closed unexpectedly')); + }); + + const timeout = setTimeout(() => { + cleanup(); + this.logger.debug('Handshake timed out'); + reject(new Error('Protocol handshake timed out')); + }, 10000); // Matches the client timeout. + + const handler = this.onControlMessage((rawMessage) => { + try { + const raw = rawMessage.toString(); + this.logger.trace('Got message', raw); + const message = JSON.parse(raw); + switch (message.type) { + case 'auth': + return this.authenticate(message); + case 'connectionType': + cleanup(); + this.logger.debug('Handshake completed'); + return resolve(message); + default: + throw new Error('Unrecognized message type'); + } + } catch (error) { + cleanup(); + reject(error); + } + }); + + // Kick off the handshake in case we missed the client's opening shot. + // TODO: Investigate why that message seems to get lost. + this.authenticate(); + }); + } + + /** + * TODO: This ignores the authentication process entirely for now. + */ + private authenticate(_?: AuthRequest): void { + this.sendMessage({ type: 'sign', data: '' }); + } + + /** + * TODO: implement. + */ + public tunnel(): void { + throw new Error('Tunnel is not implemented yet'); + } + + /** + * Send a handshake message. In the case of the extension host it should just + * send a debug port. + */ + public sendMessage(message: HandshakeMessage | { debugPort?: number | null }): void { + this.sendControl(VSBuffer.fromString(JSON.stringify(message))); + } + + /** + * Disconnect and dispose everything including the underlying socket. + */ + public destroy(reason?: string): void { + try { + if (reason) { + this.sendMessage({ type: 'error', reason }); + } + // If still connected try notifying the client. + this.sendDisconnect(); + } catch (error) { + // I think the write might fail if already disconnected. + this.logger.warn(error.message || error); + } + this.dispose(); // This disposes timers and socket event handlers. + this.getSocket().dispose(); // This will destroy() the socket. + } + + /** + * Get inflateBytes from the current socket. + */ + public get inflateBytes(): Uint8Array | undefined { + const socket = this.getSocket(); + return socket instanceof WebSocketNodeSocket + ? socket.recordedInflateBytes.buffer + : undefined; + } +} diff --git a/src/vs/server/server.ts b/src/vs/server/server.ts new file mode 100644 index 0000000000000..92d3486966e41 --- /dev/null +++ b/src/vs/server/server.ts @@ -0,0 +1,318 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Coder Technologies. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { promises as fs } from 'fs'; +import * as net from 'net'; +import { hostname, release } from 'os'; +import * as path from 'path'; +import { Emitter } from 'vs/base/common/event'; +import { Schemas } from 'vs/base/common/network'; +import { URI } from 'vs/base/common/uri'; +import { getMachineId } from 'vs/base/node/id'; +import { ClientConnectionEvent, IPCServer, IServerChannel, ProxyChannel } from 'vs/base/parts/ipc/common/ipc'; +import { main } from 'vs/code/node/cliProcessMain'; +import { Query, VscodeOptions, WorkbenchOptions } from 'vs/base/common/ipc'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { ConfigurationService } from 'vs/platform/configuration/common/configurationService'; +import { ExtensionHostDebugBroadcastChannel } from 'vs/platform/debug/common/extensionHostDebugIpc'; +import { NativeParsedArgs } from 'vs/platform/environment/common/argv'; +import { IEnvironmentService, INativeEnvironmentService } from 'vs/platform/environment/common/environment'; +import { NativeEnvironmentService } from 'vs/platform/environment/node/environmentService'; +import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService'; +import { IExtensionGalleryService, IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { ExtensionManagementChannel } from 'vs/platform/extensionManagement/common/extensionManagementIpc'; +import { ExtensionManagementService } 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'; +import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; +import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService'; +import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; +import { ILocalizationsService } from 'vs/platform/localizations/common/localizations'; +import { LocalizationsService } from 'vs/platform/localizations/node/localizations'; +import { ConsoleLogger, ConsoleMainLogger, getLogLevel, ILoggerService, ILogService, MultiplexLogService } from 'vs/platform/log/common/log'; +import { LogLevelChannel } from 'vs/platform/log/common/logIpc'; +import { LoggerService } from 'vs/platform/log/node/loggerService'; +import { SpdLogLogger } from 'vs/platform/log/node/spdlogLog'; +import product from 'vs/platform/product/common/product'; +import { IProductService } from 'vs/platform/product/common/productService'; +import { ConnectionType, ConnectionTypeRequest } from 'vs/platform/remote/common/remoteAgentConnection'; +import { RemoteAgentConnectionContext } from 'vs/platform/remote/common/remoteAgentEnvironment'; +import { IRequestService } from 'vs/platform/request/common/request'; +import { RequestChannel } from 'vs/platform/request/common/requestIpc'; +import { RequestService } from 'vs/platform/request/node/requestService'; +import ErrorTelemetry from 'vs/platform/telemetry/node/errorTelemetry'; +import { resolveCommonProperties } from 'vs/platform/telemetry/common/commonProperties'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { TelemetryLogAppender } from 'vs/platform/telemetry/common/telemetryLogAppender'; +import { TelemetryService } from 'vs/platform/telemetry/common/telemetryService'; +import { combinedAppender, NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils'; +import { AppInsightsAppender } from 'vs/platform/telemetry/node/appInsightsAppender'; +import { ExtensionEnvironmentChannel, FileProviderChannel, TerminalProviderChannel } from 'vs/server/channel'; +import { Connection, ExtensionHostConnection, ManagementConnection } from 'vs/server/connection'; +import { TelemetryClient } from 'vs/server/insights'; +import { getLocaleFromConfig, getNlsConfiguration } from 'vs/server/nls'; +import { Protocol } from 'vs/server/protocol'; +import { getUriTransformer } from 'vs/server/util'; +import { REMOTE_TERMINAL_CHANNEL_NAME } from 'vs/workbench/contrib/terminal/common/remoteTerminalChannel'; +import { REMOTE_FILE_SYSTEM_CHANNEL_NAME } from 'vs/workbench/services/remote/common/remoteAgentFileSystemChannel'; +import { RemoteExtensionLogFileName } from 'vs/workbench/services/remote/common/remoteAgentService'; +import { PtyHostService } from 'vs/platform/terminal/node/ptyHostService'; +import { LogsDataCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/logsDataCleaner'; + +const commit = product.commit || 'development'; +const logger = new ConsoleMainLogger(); + +export class Vscode { + public readonly _onDidClientConnect = new Emitter(); + public readonly onDidClientConnect = this._onDidClientConnect.event; + private readonly ipc = new IPCServer(this.onDidClientConnect); + + private readonly maxExtraOfflineConnections = 0; + private readonly connections = new Map>(); + + private readonly services = new ServiceCollection(); + private servicesPromise?: Promise; + + public async cli(args: NativeParsedArgs): Promise { + return main(args); + } + + public async initialize(options: VscodeOptions): Promise { + const transformer = getUriTransformer(options.remoteAuthority); + if (!this.servicesPromise) { + this.servicesPromise = this.initializeServices(options.args); + } + await this.servicesPromise; + const environment = this.services.get(IEnvironmentService) as INativeEnvironmentService; + const startPath = options.startPath; + const parseUrl = (url: string): URI => { + // This might be a fully-specified URL or just a path. + try { + return URI.parse(url, true); + } catch (error) { + return URI.from({ + scheme: Schemas.vscodeRemote, + authority: options.remoteAuthority, + path: url, + }); + } + }; + return { + workbenchWebConfiguration: { + workspaceUri: startPath && startPath.workspace ? parseUrl(startPath.url) : undefined, + folderUri: startPath && !startPath.workspace ? parseUrl(startPath.url) : undefined, + remoteAuthority: options.remoteAuthority, + logLevel: getLogLevel(environment), + workspaceProvider: { + payload: [ + ['userDataPath', environment.userDataPath], + ['enableProposedApi', JSON.stringify(options.args['enable-proposed-api'] || [])] + ], + }, + }, + remoteUserDataUri: transformer.transformOutgoing(URI.file(environment.userDataPath)), + productConfiguration: product, + nlsConfiguration: await getNlsConfiguration(environment.args.locale || await getLocaleFromConfig(environment.userDataPath), environment.userDataPath), + commit, + }; + } + + public async handleWebSocket(socket: net.Socket, query: Query, permessageDeflate: boolean): Promise { + if (!query.reconnectionToken) { + throw new Error('Reconnection token is missing from query parameters'); + } + const protocol = new Protocol(socket, { + reconnectionToken: query.reconnectionToken, + reconnection: query.reconnection === 'true', + skipWebSocketFrames: query.skipWebSocketFrames === 'true', + permessageDeflate, + }); + try { + await this.connect(await protocol.handshake(), protocol); + } catch (error) { + protocol.destroy(error.message); + } + return true; + } + + private async connect(message: ConnectionTypeRequest, protocol: Protocol): Promise { + if (product.commit && message.commit !== product.commit) { + logger.warn(`Version mismatch (${message.commit} instead of ${product.commit})`); + } + + switch (message.desiredConnectionType) { + case ConnectionType.ExtensionHost: + case ConnectionType.Management: + // Initialize connection map for this type of connection. + if (!this.connections.has(message.desiredConnectionType)) { + this.connections.set(message.desiredConnectionType, new Map()); + } + const connections = this.connections.get(message.desiredConnectionType)!; + + const token = protocol.options.reconnectionToken; + let connection = connections.get(token); + if (protocol.options.reconnection && connection) { + return connection.reconnect(protocol); + } + + // This probably means the process restarted so the session was lost + // while the browser remained open. + if (protocol.options.reconnection) { + throw new Error(`Unable to reconnect; session no longer exists (${token})`); + } + + // This will probably never happen outside a chance collision. + if (connection) { + throw new Error('Unable to connect; token is already in use'); + } + + // Now that the initial exchange has completed we can create the actual + // connection on top of the protocol then send it to whatever uses it. + if (message.desiredConnectionType === ConnectionType.Management) { + // The management connection is used by firing onDidClientConnect + // which makes the IPC server become aware of the connection. + connection = new ManagementConnection(protocol); + this._onDidClientConnect.fire({ + protocol, + onDidClientDisconnect: connection.onClose, + }); + } else { + // The extension host connection is used by spawning an extension host + // and passing the socket into it. + connection = new ExtensionHostConnection( + protocol, + { + language: 'en', + ...message.args, + }, + this.services.get(IEnvironmentService) as INativeEnvironmentService, + ); + } + connections.set(token, connection); + connection.onClose(() => connections.delete(token)); + + this.disposeOldOfflineConnections(connections); + logger.debug(`${connections.size} active ${connection.name} connection(s)`); + break; + case ConnectionType.Tunnel: + return protocol.tunnel(); + default: + throw new Error(`Unrecognized connection type ${message.desiredConnectionType}`); + } + } + + private disposeOldOfflineConnections(connections: Map): void { + const offline = Array.from(connections.values()) + .filter((connection) => typeof connection.offline !== 'undefined'); + for (let i = 0, max = offline.length - this.maxExtraOfflineConnections; i < max; ++i) { + offline[i].dispose('old'); + } + } + + // References: + // ../../electron-browser/sharedProcess/sharedProcessMain.ts#L148 + // ../../../code/electron-main/app.ts + private async initializeServices(args: NativeParsedArgs): Promise { + const productService = { _serviceBrand: undefined, ...product }; + const environmentService = new NativeEnvironmentService(args, productService); + + await Promise.all([ + environmentService.extensionsPath, + environmentService.logsPath, + environmentService.globalStorageHome.fsPath, + environmentService.workspaceStorageHome.fsPath, + ...environmentService.extraExtensionPaths, + ...environmentService.extraBuiltinExtensionPaths, + ].map((p) => fs.mkdir(p, { recursive: true }).catch((error) => { + logger.warn(error.message || error); + }))); + + const logService = new MultiplexLogService([ + new ConsoleLogger(getLogLevel(environmentService)), + new SpdLogLogger(RemoteExtensionLogFileName, path.join(environmentService.logsPath, `${RemoteExtensionLogFileName}.log`), false, getLogLevel(environmentService)) + ]); + const fileService = new FileService(logService); + fileService.registerProvider(Schemas.file, new DiskFileSystemProvider(logService)); + + const loggerService = new LoggerService(logService, fileService); + + const piiPaths = [ + path.join(environmentService.userDataPath, 'clp'), // Language packs. + environmentService.appRoot, + environmentService.extensionsPath, + environmentService.builtinExtensionsPath, + ...environmentService.extraExtensionPaths, + ...environmentService.extraBuiltinExtensionPaths, + ]; + + this.ipc.registerChannel('logger', new LogLevelChannel(logService)); + this.ipc.registerChannel(ExtensionHostDebugBroadcastChannel.ChannelName, new ExtensionHostDebugBroadcastChannel()); + + this.services.set(ILogService, logService); + this.services.set(IEnvironmentService, environmentService); + this.services.set(INativeEnvironmentService, environmentService); + this.services.set(ILoggerService, loggerService); + + const configurationService = new ConfigurationService(environmentService.settingsResource, fileService); + await configurationService.initialize(); + this.services.set(IConfigurationService, configurationService); + + this.services.set(IRequestService, new SyncDescriptor(RequestService)); + this.services.set(IFileService, fileService); + this.services.set(IProductService, productService); + + const machineId = await getMachineId(); + + await new Promise((resolve) => { + const instantiationService = new InstantiationService(this.services); + + instantiationService.invokeFunction((accessor) => { + instantiationService.createInstance(LogsDataCleaner); + + let telemetryService: ITelemetryService; + + if (!environmentService.isExtensionDevelopment && !environmentService.disableTelemetry && !!productService.enableTelemetry) { + telemetryService = new TelemetryService({ + appender: combinedAppender( + new AppInsightsAppender('code-server', null, () => new TelemetryClient() as any), + new TelemetryLogAppender(accessor.get(ILoggerService), environmentService) + ), + sendErrorTelemetry: true, + commonProperties: resolveCommonProperties( + fileService, release(), hostname(), process.arch, commit, product.version, machineId, + undefined, environmentService.installSourcePath, 'code-server', + ), + piiPaths, + }, configurationService); + } else { + telemetryService = NullTelemetryService; + } + + this.services.set(ITelemetryService, telemetryService); + + this.services.set(IExtensionManagementService, new SyncDescriptor(ExtensionManagementService)); + this.services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryService)); + this.services.set(ILocalizationsService, new SyncDescriptor(LocalizationsService)); + + this.ipc.registerChannel('extensions', new ExtensionManagementChannel( + accessor.get(IExtensionManagementService), + (context) => getUriTransformer(context.remoteAuthority), + )); + this.ipc.registerChannel('remoteextensionsenvironment', new ExtensionEnvironmentChannel( + environmentService, logService, telemetryService, '', + )); + this.ipc.registerChannel('request', new RequestChannel(accessor.get(IRequestService))); + this.ipc.registerChannel('localizations', >ProxyChannel.fromService(accessor.get(ILocalizationsService))); + this.ipc.registerChannel(REMOTE_FILE_SYSTEM_CHANNEL_NAME, new FileProviderChannel(environmentService, logService)); + + const ptyHostService = new PtyHostService({ GraceTime: 60000, ShortGraceTime: 6000 }, configurationService, logService, telemetryService); + this.ipc.registerChannel(REMOTE_TERMINAL_CHANNEL_NAME, new TerminalProviderChannel(logService, ptyHostService)); + + resolve(new ErrorTelemetry(telemetryService)); + }); + }); + } +} diff --git a/src/vs/server/uriTransformer.ts b/src/vs/server/uriTransformer.ts new file mode 100644 index 0000000000000..61183f7cebe68 --- /dev/null +++ b/src/vs/server/uriTransformer.ts @@ -0,0 +1,58 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Coder Technologies. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +// In a bit of a hack, this file is stored in two places +// - src/node/uri_transformer.ts +// - lib/vscode/src/vs/server/uriTransformer.ts + +import { IRawURITransformer, UriParts } from 'vs/base/common/uriIpc' + +// The reason for this is that we need a CommonJS-compiled +// version of this file to supply as a command line argument +// to extensionHostProcessSetup.ts; but we also need to include +// it ourselves cleanly in `lib/vscode/src/vs/server`. + +// @oxy: Could not figure out how to compile as a CommonJS module +// in the same tree as VSCode, which is why I came up with the solution +// of storing it in two places. + +class RawURITransformer implements IRawURITransformer { + constructor(private readonly authority: string) { } + + transformIncoming(uri: UriParts): UriParts { + switch (uri.scheme) { + case "vscode-remote": + return { scheme: "file", path: uri.path } + default: + return uri + } + } + + transformOutgoing(uri: UriParts): UriParts { + switch (uri.scheme) { + case "file": + return { scheme: "vscode-remote", authority: this.authority, path: uri.path } + default: + return uri + } + } + + transformOutgoingScheme(scheme: string): string { + switch (scheme) { + case "file": + return "vscode-remote" + default: + return scheme + } + } +} + +// Using `export =` is deliberate. +// See lib/vscode/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts; +// they include the file directly with a node require and expect a function as `module.exports`. +// `export =` in TypeScript is equivalent to `module.exports =` in vanilla JS. +export = function rawURITransformerFactory(authority: string) { + return new RawURITransformer(authority) +} diff --git a/src/vs/server/util.ts b/src/vs/server/util.ts new file mode 100644 index 0000000000000..0aea1ee82860c --- /dev/null +++ b/src/vs/server/util.ts @@ -0,0 +1,11 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Coder Technologies. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { URITransformer } from 'vs/base/common/uriIpc'; +import rawURITransformerFactory = require('vs/server/uriTransformer'); + +export const getUriTransformer = (remoteAuthority: string): URITransformer => { + return new URITransformer(rawURITransformerFactory(remoteAuthority)); +}; diff --git a/src/vs/workbench/api/browser/mainThreadStorage.ts b/src/vs/workbench/api/browser/mainThreadStorage.ts index 5cb658e91d1c6..8fd15e86f9f8f 100644 --- a/src/vs/workbench/api/browser/mainThreadStorage.ts +++ b/src/vs/workbench/api/browser/mainThreadStorage.ts @@ -62,12 +62,13 @@ export class MainThreadStorage implements MainThreadStorageShape { return JSON.parse(jsonValue); } - $setValue(shared: boolean, key: string, value: object): Promise { + async $setValue(shared: boolean, key: string, value: object): Promise { let jsonValue: string; try { jsonValue = JSON.stringify(value); // Extension state is synced separately through extensions - this._storageService.store(key, jsonValue, shared ? StorageScope.GLOBAL : StorageScope.WORKSPACE, StorageTarget.MACHINE); + // NOTE@coder: Wait for the actual storage write. + await this._storageService.store(key, jsonValue, shared ? StorageScope.GLOBAL : StorageScope.WORKSPACE, StorageTarget.MACHINE); } catch (err) { return Promise.reject(err); } diff --git a/src/vs/workbench/api/node/extHostCLIServer.ts b/src/vs/workbench/api/node/extHostCLIServer.ts index 6177f03c80fd1..ee509b68f1899 100644 --- a/src/vs/workbench/api/node/extHostCLIServer.ts +++ b/src/vs/workbench/api/node/extHostCLIServer.ts @@ -11,6 +11,8 @@ import { IWindowOpenable, IOpenWindowOptions } from 'vs/platform/windows/common/ import { URI } from 'vs/base/common/uri'; import { hasWorkspaceFileExtension } from 'vs/platform/workspaces/common/workspaces'; import { ILogService } from 'vs/platform/log/common/log'; +import { tmpdir } from 'os'; +import { join } from 'vs/base/common/path'; export interface OpenCommandPipeArgs { type: 'open'; @@ -67,6 +69,11 @@ export class CLIServerBase { } private async setup(): Promise { + // NOTE@coder: Write this out so we can get the most recent path. + fs.promises.writeFile(join(tmpdir(), 'vscode-ipc'), this._ipcHandlePath).catch((error) => { + this.logService.error(error); + }); + try { this._server.listen(this.ipcHandlePath); this._server.on('error', err => this.logService.error(err)); diff --git a/src/vs/workbench/browser/client.ts b/src/vs/workbench/browser/client.ts new file mode 100644 index 0000000000000..84718dcbc811d --- /dev/null +++ b/src/vs/workbench/browser/client.ts @@ -0,0 +1,171 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Coder Technologies. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as path from 'vs/base/common/path'; +import { Options } from 'vs/base/common/ipc'; +import { localize } from 'vs/nls'; +import { MenuId, MenuRegistry } from 'vs/platform/actions/common/actions'; +import { CommandsRegistry } from 'vs/platform/commands/common/commands'; +import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; +import { ILogService } from 'vs/platform/log/common/log'; +import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; +import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; +import { getOptions } from 'vs/base/common/util'; +import 'vs/workbench/contrib/localizations/browser/localizations.contribution'; // eslint-disable-line code-import-patterns +import 'vs/workbench/services/localizations/browser/localizationsService'; + +/** + * All client-side customization to VS Code should live in this file when + * possible. + */ + +const options = getOptions(); + +/** + * This is called by vs/workbench/browser/web.main.ts after the workbench has + * been initialized so we can initialize our own client-side code. + */ +export const initialize = async (services: ServiceCollection): Promise => { + const event = new CustomEvent('ide-ready'); + window.dispatchEvent(event); + + if (parent) { + // Tell the parent loading has completed. + parent.postMessage({ event: 'loaded' }, '*'); + + // Proxy or stop proxing events as requested by the parent. + const listeners = new Map void>(); + window.addEventListener('message', (parentEvent) => { + const eventName = parentEvent.data.bind || parentEvent.data.unbind; + if (eventName) { + const oldListener = listeners.get(eventName); + if (oldListener) { + document.removeEventListener(eventName, oldListener); + } + } + + if (parentEvent.data.bind && parentEvent.data.prop) { + const listener = (event: Event) => { + parent.postMessage({ + event: parentEvent.data.event, + [parentEvent.data.prop]: event[parentEvent.data.prop as keyof Event] + }, window.location.origin); + }; + listeners.set(parentEvent.data.bind, listener); + document.addEventListener(parentEvent.data.bind, listener); + } + }); + } + + if (!window.isSecureContext) { + (services.get(INotificationService) as INotificationService).notify({ + severity: Severity.Warning, + message: 'code-server is being accessed over an insecure domain. Web views, the clipboard, and other functionality will not work as expected.', + actions: { + primary: [{ + id: 'understand', + label: 'I understand', + tooltip: '', + class: undefined, + enabled: true, + checked: true, + dispose: () => undefined, + run: () => { + return Promise.resolve(); + } + }], + } + }); + } + + const logService = (services.get(ILogService) as ILogService); + const storageService = (services.get(IStorageService) as IStorageService); + const updateCheckEndpoint = path.join(options.base, '/update/check'); + const getUpdate = async (): Promise => { + logService.debug('Checking for update...'); + + const response = await fetch(updateCheckEndpoint, { + headers: { 'Accept': 'application/json' }, + }); + if (!response.ok) { + throw new Error(response.statusText); + } + const json = await response.json(); + if (json.error) { + throw new Error(json.error); + } + if (json.isLatest) { + return; + } + + const lastNoti = storageService.getNumber('csLastUpdateNotification', StorageScope.GLOBAL); + if (lastNoti) { + // Only remind them again after 1 week. + const timeout = 1000 * 60 * 60 * 24 * 7; + const threshold = lastNoti + timeout; + if (Date.now() < threshold) { + return; + } + } + + storageService.store('csLastUpdateNotification', Date.now(), StorageScope.GLOBAL, StorageTarget.MACHINE); + (services.get(INotificationService) as INotificationService).notify({ + severity: Severity.Info, + message: `[code-server v${json.latest}](https://github.com/cdr/code-server/releases/tag/v${json.latest}) has been released!`, + }); + }; + + const updateLoop = (): void => { + getUpdate().catch((error) => { + logService.debug(`failed to check for update: ${error}`); + }).finally(() => { + // Check again every 6 hours. + setTimeout(updateLoop, 1000 * 60 * 60 * 6); + }); + }; + + if (!options.disableUpdateCheck) { + updateLoop(); + } + + // This will be used to set the background color while VS Code loads. + const theme = storageService.get('colorThemeData', StorageScope.GLOBAL); + if (theme) { + localStorage.setItem('colorThemeData', theme); + } + + // Use to show or hide logout commands and menu options. + const contextKeyService = (services.get(IContextKeyService) as IContextKeyService); + contextKeyService.createKey('code-server.authed', options.authed); + + // Add a logout command. + const logoutEndpoint = path.join(options.base, '/logout') + `?base=${options.base}`; + const LOGOUT_COMMAND_ID = 'code-server.logout'; + CommandsRegistry.registerCommand( + LOGOUT_COMMAND_ID, + () => { + window.location.href = logoutEndpoint; + }, + ); + + // Add logout to command palette. + MenuRegistry.appendMenuItem(MenuId.CommandPalette, { + command: { + id: LOGOUT_COMMAND_ID, + title: localize('logout', "Log out") + }, + when: ContextKeyExpr.has('code-server.authed') + }); + + // Add logout to the (web-only) home menu. + MenuRegistry.appendMenuItem(MenuId.MenubarHomeMenu, { + command: { + id: LOGOUT_COMMAND_ID, + title: localize('logout', "Log out") + }, + when: ContextKeyExpr.has('code-server.authed') + }); +}; diff --git a/src/vs/workbench/browser/parts/dialogs/dialogHandler.ts b/src/vs/workbench/browser/parts/dialogs/dialogHandler.ts index 84c51a948ad9a..2defb9ee22cac 100644 --- a/src/vs/workbench/browser/parts/dialogs/dialogHandler.ts +++ b/src/vs/workbench/browser/parts/dialogs/dialogHandler.ts @@ -144,11 +144,12 @@ export class BrowserDialogHandler implements IDialogHandler { async about(): Promise { const detailString = (useAgo: boolean): string => { return localize('aboutDetail', - "Version: {0}\nCommit: {1}\nDate: {2}\nBrowser: {3}", + "code-server: v{4}\n VS Code: v{0}\nCommit: {1}\nDate: {2}\nBrowser: {3}", this.productService.version || 'Unknown', this.productService.commit || 'Unknown', this.productService.date ? `${this.productService.date}${useAgo ? ' (' + fromNow(new Date(this.productService.date), true) + ')' : ''}` : 'Unknown', - navigator.userAgent + navigator.userAgent, + this.productService.codeServerVersion || 'Unknown', ); }; diff --git a/src/vs/workbench/browser/web.main.ts b/src/vs/workbench/browser/web.main.ts index ef1a454bf1c27..5e03179dd48a2 100644 --- a/src/vs/workbench/browser/web.main.ts +++ b/src/vs/workbench/browser/web.main.ts @@ -64,6 +64,7 @@ import { WorkspaceTrustManagementService } from 'vs/workbench/services/workspace import { IWorkspaceTrustManagementService } from 'vs/platform/workspace/common/workspaceTrust'; import { HTMLFileSystemProvider } from 'vs/platform/files/browser/htmlFileSystemProvider'; import { IOpenerService } from 'vs/platform/opener/common/opener'; +import { initialize } from './client'; class BrowserMain extends Disposable { @@ -96,6 +97,9 @@ class BrowserMain extends Disposable { // Startup const instantiationService = workbench.startup(); + // NOTE@coder: initialize our additions + await initialize(services.serviceCollection); + // Window this._register(instantiationService.createInstance(BrowserWindow)); diff --git a/src/vs/workbench/common/resources.ts b/src/vs/workbench/common/resources.ts index f99661f7ea790..79eb43d845f5c 100644 --- a/src/vs/workbench/common/resources.ts +++ b/src/vs/workbench/common/resources.ts @@ -16,6 +16,7 @@ import { ParsedExpression, IExpression, parse } from 'vs/base/common/glob'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; import { withNullAsUndefined } from 'vs/base/common/types'; +import { Schemas } from 'vs/base/common/network'; export class ResourceContextKey extends Disposable implements IContextKey { @@ -75,7 +76,10 @@ export class ResourceContextKey extends Disposable implements IContextKey { if (!ResourceContextKey._uriEquals(this._resourceKey.get(), value)) { this._contextKeyService.bufferChangeEvents(() => { this._resourceKey.set(value); - this._schemeKey.set(value ? value.scheme : null); + // NOTE@coder: this is to get Git context actions to show up + // See issue #1140 / commit 7e4a73ce2d19eee08ceea25113debefeb8ac27e2 + // TODO@oxy: Codespaces has this working alright without this patch - investigate why we need this and remove it. + this._schemeKey.set(value ? (value.scheme === Schemas.vscodeRemote ? Schemas.file : value.scheme) : null); this._filenameKey.set(value ? basename(value) : null); this._dirnameKey.set(value ? dirname(value).fsPath : null); this._pathKey.set(value ? value.fsPath : null); diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts b/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts index 9cba26e468397..82e67722ad471 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts @@ -27,7 +27,7 @@ import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/ import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import Severity from 'vs/base/common/severity'; import { IActivityService, NumberBadge } from 'vs/workbench/services/activity/common/activity'; -import { IThemeService } from 'vs/platform/theme/common/themeService'; +import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IViewsRegistry, IViewDescriptor, Extensions, ViewContainer, IViewDescriptorService, IAddedViewDescriptorRef } from 'vs/workbench/common/views'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; @@ -60,6 +60,7 @@ import { isIOS, isWeb } from 'vs/base/common/platform'; import { installLocalInRemoteIcon } from 'vs/workbench/contrib/extensions/browser/extensionsIcons'; import { registerAction2, Action2, MenuId } from 'vs/platform/actions/common/actions'; import { WorkspaceTrustContext } from 'vs/workbench/services/workspaces/common/workspaceTrust'; +import { textLinkForeground } from 'vs/platform/theme/common/colorRegistry'; const SearchMarketplaceExtensionsContext = new RawContextKey('searchMarketplaceExtensions', false); const SearchIntalledExtensionsContext = new RawContextKey('searchInstalledExtensions', false); @@ -525,6 +526,46 @@ export class ExtensionsViewPaneContainer extends ViewPaneContainer implements IE overlay.style.backgroundColor = overlayBackgroundColor; hide(overlay); + // NOTE@coder this UI element helps users understand the extension marketplace divergence + const extensionHelperLocalStorageKey = 'coder.extension-help-message'; + + if (localStorage.getItem(extensionHelperLocalStorageKey) === null) { + const helperHeader = append(this.root, $('.header')); + helperHeader.id = 'codeServerMarketplaceHelper'; + helperHeader.style.height = 'auto'; + helperHeader.style.fontWeight = '600'; + helperHeader.style.padding = 'padding: 5px 16px'; + helperHeader.style.position = 'relative'; + + const helperText = append(helperHeader, $('div')); + + + // We call this function because it gives us access to the current theme + // Then we can apply the link color to the links in the helper header + registerThemingParticipant((theme) => { + const linkColor = theme.getColor(textLinkForeground); + + append(helperText, $('div', { style: 'margin-bottom: 8px;' }, + $('p', { style: 'margin-bottom: 0; display: flex; align-items: center' }, + $('span', { class: 'codicon codicon-warning', style: 'margin-right: 2px; color: #C4A103' }), + 'WARNING'), + $('p', { style: 'margin-top: 0; margin-bottom: 4px' }, + 'These extensions are not official. Find additional open-source extensions', + $('a', { style: `color: ${linkColor}`, href: 'https://open-vsx.org/', target: '_blank' }, 'here'), + '. See ', + $('a', { style: `color: ${linkColor}`, href: 'https://github.com/cdr/code-server/blob/master/docs/FAQ.md#differences-compared-to-vs-code', target: '_blank' }, 'docs'), + '.' + ))); + }); + + const dismiss = append(helperHeader, $('span', { style: `display: 'block'; textAlign: 'right'; cursor: 'pointer';`, tabindex: '0' }, 'Dismiss')); + + dismiss.onclick = () => { + helperHeader.remove(); + localStorage.setItem(extensionHelperLocalStorageKey, 'viewed'); + }; + } + const header = append(this.root, $('.header')); const placeholder = localize('searchExtensions', "Search Extensions in Marketplace"); diff --git a/src/vs/workbench/contrib/files/browser/explorerViewlet.ts b/src/vs/workbench/contrib/files/browser/explorerViewlet.ts index f752b8790e5a2..3e91e275941c4 100644 --- a/src/vs/workbench/contrib/files/browser/explorerViewlet.ts +++ b/src/vs/workbench/contrib/files/browser/explorerViewlet.ts @@ -303,9 +303,15 @@ viewsRegistry.registerViewWelcomeContent(EmptyView.ID, { order: 1 }); +// NOTE@coder: +// We use OpenFolderAction.ID instead of commandId +// because for some reason, the command openFileFolder +// does not work as expected and causes the "Open Folder" +// command to not work +// See: https://github.com/cdr/code-server/issues/3457 viewsRegistry.registerViewWelcomeContent(EmptyView.ID, { content: localize({ key: 'noFolderHelp', comment: ['Please do not translate the word "commmand", it is part of our internal syntax which must not change'] }, - "You have not yet opened a folder.\n[Open Folder](command:{0})", commandId), + "You have not yet opened a folder.\n[Open Folder](command:{0})", OpenFolderAction.ID), when: ContextKeyExpr.or(ContextKeyExpr.and(WorkbenchStateContext.notEqualsTo('workspace'), RemoteNameContext.isEqualTo('')), ContextKeyExpr.and(WorkbenchStateContext.notEqualsTo('workspace'), IsWebContext)), group: ViewContentGroups.Open, order: 1 diff --git a/src/vs/workbench/contrib/welcome/page/browser/vs_code_welcome_page.ts b/src/vs/workbench/contrib/welcome/page/browser/vs_code_welcome_page.ts index a405271ac1c1c..c32048e7df18c 100644 --- a/src/vs/workbench/contrib/welcome/page/browser/vs_code_welcome_page.ts +++ b/src/vs/workbench/contrib/welcome/page/browser/vs_code_welcome_page.ts @@ -5,13 +5,14 @@ import { escape } from 'vs/base/common/strings'; import { localize } from 'vs/nls'; +import product from 'vs/platform/product/common/product'; export default () => `

${escape(localize('welcomePage.vscode', "Visual Studio Code"))}

-

${escape(localize({ key: 'welcomePage.editingEvolved', comment: ['Shown as subtitle on the Welcome page.'] }, "Editing evolved"))}

+

VS Code v${product.version}

+
+

code-server ${escape(localize('welcomePage.help', "Help"))}

+ +

${escape(localize('welcomePage.help', "Help"))}

    diff --git a/src/vs/workbench/contrib/welcome/page/browser/welcomePage.ts b/src/vs/workbench/contrib/welcome/page/browser/welcomePage.ts index 0824a9edbbb3e..a8f5d76bda394 100644 --- a/src/vs/workbench/contrib/welcome/page/browser/welcomePage.ts +++ b/src/vs/workbench/contrib/welcome/page/browser/welcomePage.ts @@ -365,7 +365,7 @@ class WelcomePage extends Disposable { const prodName = container.querySelector('.welcomePage .title .caption') as HTMLElement; if (prodName) { - prodName.textContent = this.productService.nameLong; + prodName.textContent = `code-server v${this.productService.codeServerVersion}`; } recentlyOpened.then(({ workspaces }) => { diff --git a/src/vs/workbench/services/environment/browser/environmentService.ts b/src/vs/workbench/services/environment/browser/environmentService.ts index 00b781462ea29..536a4e8f372c6 100644 --- a/src/vs/workbench/services/environment/browser/environmentService.ts +++ b/src/vs/workbench/services/environment/browser/environmentService.ts @@ -120,8 +120,26 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment @memoize get logFile(): URI { return joinPath(this.options.logsPath, 'window.log'); } + // NOTE@coder: Use the same path in // ../../../../platform/environment/node/environmentService.ts + // and don't use the user data scheme. This solves two problems: + // 1. Extensions running in the browser (like Vim) might use these paths + // directly instead of using the file service and most likely can't write + // to `/User` on disk. + // 2. Settings will be stored in the file system instead of in browser + // storage. Using browser storage makes sharing or seeding settings + // between browsers difficult. We may want to revisit this once/if we get + // settings sync. @memoize - get userRoamingDataHome(): URI { return URI.file('/User').with({ scheme: Schemas.userData }); } + get userRoamingDataHome(): URI { return joinPath(URI.file(this.userDataPath).with({ scheme: Schemas.vscodeRemote }), 'User'); } + + @memoize + get userDataPath(): string { + const dataPath = this.payload?.get('userDataPath'); + if (!dataPath) { + throw new Error('userDataPath was not provided to environment service'); + } + return dataPath; + } @memoize get settingsResource(): URI { return joinPath(this.userRoamingDataHome, 'settings.json'); } @@ -317,7 +335,12 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment extensionHostDebugEnvironment.params.port = parseInt(value); break; case 'enableProposedApi': - extensionHostDebugEnvironment.extensionEnabledProposedApi = []; + try { + extensionHostDebugEnvironment.extensionEnabledProposedApi = JSON.parse(value); + } catch (error) { + console.error(error); + extensionHostDebugEnvironment.extensionEnabledProposedApi = []; + } break; } } diff --git a/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts b/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts index 521ab664f825d..06a8083eeb00d 100644 --- a/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts +++ b/src/vs/workbench/services/extensionManagement/browser/extensionEnablementService.ts @@ -263,7 +263,7 @@ export class ExtensionEnablementService extends Disposable implements IWorkbench } } } - return true; + return false; // NOTE@coder: Don't disable anything by extensionKind. } return false; } diff --git a/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts b/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts index e4921e4e0a3a6..9921920689924 100644 --- a/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts +++ b/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts @@ -26,6 +26,7 @@ import { IUserDataAutoSyncEnablementService, IUserDataSyncResourceEnablementServ import { Promises } from 'vs/base/common/async'; import { IWorkspaceTrustRequestService } from 'vs/platform/workspace/common/workspaceTrust'; import { IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService'; +import { isWeb } from 'vs/base/common/platform'; export class ExtensionManagementService extends Disposable implements IWorkbenchExtensionManagementService { @@ -307,6 +308,11 @@ export class ExtensionManagementService extends Disposable implements IWorkbench } } + // NOTE@coder: Fall back to installing on the remote server on web. + if (isWeb && this.extensionManagementServerService.remoteExtensionManagementServer) { + return this.extensionManagementServerService.remoteExtensionManagementServer; + } + // Local server can accept any extension. So return local server if not compatible server found. return this.extensionManagementServerService.localExtensionManagementServer; } diff --git a/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts b/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts index a0baef2503403..ed44762939e06 100644 --- a/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts +++ b/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts @@ -22,6 +22,7 @@ import { exists } from 'vs/base/node/pfs'; import { realpath } from 'vs/base/node/extpath'; import { IHostUtils } from 'vs/workbench/api/common/extHostExtensionService'; import { RunOnceScheduler } from 'vs/base/common/async'; +import * as proxyAgent from 'vs/base/node/proxy_agent'; import 'vs/workbench/api/common/extHost.common.services'; import 'vs/workbench/api/node/extHost.node.services'; @@ -137,8 +138,11 @@ function _createExtHostProtocol(): Promise { // Wait for rich client to reconnect protocol.onSocketClose(() => { - // The socket has closed, let's give the renderer a certain amount of time to reconnect - disconnectRunner1.schedule(); + // NOTE@coder: Inform the server so we can manage offline + // connections there instead. Our goal is to persist connections + // forever (to a reasonable point) to account for things like + // hibernating overnight. + process.send!({ type: 'VSCODE_EXTHOST_DISCONNECTED' }); }); } } @@ -312,6 +316,9 @@ function connectToRenderer(protocol: IMessagePassingProtocol): Promise { + // NOTE@coder: add proxy agent patch + proxyAgent.monkeyPatch(true); + performance.mark(`code/extHost/willConnectToRenderer`); const protocol = await createExtHostProtocol(); performance.mark(`code/extHost/didConnectToRenderer`); diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayoutService.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayoutService.ts index 6d71a818bbeaf..0fcefe306e617 100644 --- a/src/vs/workbench/services/keybinding/browser/keyboardLayoutService.ts +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayoutService.ts @@ -406,6 +406,9 @@ export class BrowserKeyboardMapperFactoryBase { // } // return null; + }).catch(() => { + // NOTE@coder: It looks like the intention was to catch this error but + // a try/catch won't do it when using promises without `await`. }); } catch { // getLayoutMap can throw if invoked from a nested browsing context diff --git a/src/vs/workbench/services/localizations/browser/localizationsService.ts b/src/vs/workbench/services/localizations/browser/localizationsService.ts new file mode 100644 index 0000000000000..a47d340aaa0a0 --- /dev/null +++ b/src/vs/workbench/services/localizations/browser/localizationsService.ts @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Coder Technologies. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +// NOTE@coder: This appears to fix localization as of v1.58.2 +// However, upstream diverges from this behavior: +// https://github.com/microsoft/vscode/commit/3ef4aa861a38a1aac95e3f560e073fe98929ddda + +import { ProxyChannel } from 'vs/base/parts/ipc/common/ipc'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { ILocalizationsService } from 'vs/platform/localizations/common/localizations'; +import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; + +// @ts-ignore: interface is implemented via proxy +export class LocalizationsService implements ILocalizationsService { + + declare readonly _serviceBrand: undefined; + + constructor( + @IRemoteAgentService remoteAgentService: IRemoteAgentService, + ) { + return ProxyChannel.toService(remoteAgentService.getConnection()!.getChannel('localizations')); + } +} + +registerSingleton(ILocalizationsService, LocalizationsService, true); diff --git a/yarn.lock b/yarn.lock index 9d031db1b718f..55e1b578ab4dd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -509,6 +509,13 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.37.tgz#a3dd8da4eb84a996c36e331df98d82abd76b516e" integrity sha512-XYmBiy+ohOR4Lh5jE379fV2IU+6Jn4g5qASinhitfyO71b/sCo6MKsMLF5tc7Zf2CE8hViVQyYSobJNke8OvUw== +"@types/proxy-from-env@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@types/proxy-from-env/-/proxy-from-env-1.0.1.tgz#b5f3e99230ca4518af196c18267055fc51f892b7" + integrity sha512-luG++TFHyS61eKcfkR1CVV6a1GMNXDjtqEQIIfaSHax75xp0HU3SlezjOi1yqubJwrG8e9DeW59n6wTblIDwFg== + dependencies: + "@types/node" "*" + "@types/q@^1.5.1": version "1.5.4" resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.4.tgz#15925414e0ad2cd765bfef58842f7e26a7accb24" @@ -534,6 +541,13 @@ resolved "https://registry.yarnpkg.com/@types/tapable/-/tapable-1.0.4.tgz#b4ffc7dc97b498c969b360a41eee247f82616370" integrity sha512-78AdXtlhpCHT0K3EytMpn4JNxaf5tbqbLcbIRoQIHzpTIyjpxLQKRoxU55ujBXAtg3Nl2h/XWvfDa9dsMOd0pQ== +"@types/tar-stream@^2.2.1": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@types/tar-stream/-/tar-stream-2.2.1.tgz#7cb4516fe6d1a926a37b7733905c50885718e7ad" + integrity sha512-zhcfACZ4HavArMutfAB1/ApfSx44kNF2zyytU4mbO1dGCT/y9kL2IZwRDRyYYtBUxW6LRparZpLoX8i67b6IZw== + dependencies: + "@types/node" "*" + "@types/trusted-types@^1.0.6": version "1.0.6" resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-1.0.6.tgz#569b8a08121d3203398290d602d84d73c8dcf5da" @@ -892,7 +906,7 @@ agent-base@^4.3.0: dependencies: es6-promisify "^5.0.0" -agent-base@^6.0.2: +agent-base@^6.0.0, agent-base@^6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== @@ -1281,6 +1295,13 @@ assign-symbols@^1.0.0: resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= +ast-types@^0.13.2: + version "0.13.4" + resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.13.4.tgz#ee0d77b343263965ecc3fb62da16e7222b2b6782" + integrity sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w== + dependencies: + tslib "^2.0.1" + astral-regex@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" @@ -1683,7 +1704,7 @@ builtin-status-codes@^3.0.0: resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug= -bytes@^3.0.0: +bytes@3.1.0, bytes@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== @@ -2793,6 +2814,15 @@ define-property@^2.0.2: is-descriptor "^1.0.2" isobject "^3.0.1" +degenerator@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/degenerator/-/degenerator-2.2.0.tgz#49e98c11fa0293c5b26edfbb52f15729afcdb254" + integrity sha512-aiQcQowF01RxFI4ZLFMpzyotbQonhNpBao6dkI8JPk5a+hmSjR5ErHp2CQySmQe8os3VBqLCIh87nDBgZXvsmg== + dependencies: + ast-types "^0.13.2" + escodegen "^1.8.1" + esprima "^4.0.0" + delayed-stream@0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-0.0.6.tgz#a2646cb7ec3d5d7774614670a7a65de0c173edbc" @@ -2808,6 +2838,11 @@ delegates@^1.0.0: resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= + deprecation@^2.0.0, deprecation@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919" @@ -3221,6 +3256,18 @@ escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.3, escape-string-regexp@^ resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= +escodegen@^1.8.1: + version "1.14.3" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503" + integrity sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw== + dependencies: + esprima "^4.0.1" + estraverse "^4.2.0" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.6.1" + eslint-plugin-jsdoc@^19.1.0: version "19.1.0" resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-19.1.0.tgz#fcc17f0378fdd6ee1c847a79b7211745cb05d014" @@ -3373,7 +3420,7 @@ espree@^6.1.2: acorn-jsx "^5.2.0" eslint-visitor-keys "^1.1.0" -esprima@^4.0.0: +esprima@^4.0.0, esprima@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== @@ -3392,7 +3439,7 @@ esrecurse@^4.1.0, esrecurse@^4.3.0: dependencies: estraverse "^5.2.0" -estraverse@^4.1.1: +estraverse@^4.1.1, estraverse@^4.2.0: version "4.3.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== @@ -4108,7 +4155,7 @@ get-stream@^5.1.0: dependencies: pump "^3.0.0" -get-uri@^3.0.2: +get-uri@3, get-uri@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/get-uri/-/get-uri-3.0.2.tgz#f0ef1356faabc70e1f9404fa3b66b2ba9bfc725c" integrity sha512-+5s0SJbGoyiJTZZ2JTpFPLMPSch72KEqGOTvQsBqg0RBWvwhWUSYZFAtz3TPW0GXJuLBJPts1E241iHg+VRfhg== @@ -4811,6 +4858,17 @@ http-cache-semantics@^4.0.0: resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390" integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ== +http-errors@1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" + integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw== + dependencies: + depd "~1.1.2" + inherits "2.0.4" + setprototypeof "1.1.1" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + http-proxy-agent@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz#e4821beef5b2142a2026bd73926fe537631c5405" @@ -4819,7 +4877,7 @@ http-proxy-agent@^2.1.0: agent-base "4" debug "3.1.0" -http-proxy-agent@^4.0.1: +http-proxy-agent@^4.0.0, http-proxy-agent@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== @@ -4842,6 +4900,14 @@ https-browserify@^1.0.0: resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= +https-proxy-agent@5, https-proxy-agent@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" + integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA== + dependencies: + agent-base "6" + debug "4" + https-proxy-agent@^2.2.3: version "2.2.4" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b" @@ -4858,14 +4924,6 @@ https-proxy-agent@^4.0.0: agent-base "5" debug "4" -https-proxy-agent@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" - integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA== - dependencies: - agent-base "6" - debug "4" - husky@^0.13.1: version "0.13.4" resolved "https://registry.yarnpkg.com/husky/-/husky-0.13.4.tgz#48785c5028de3452a51c48c12c4f94b2124a1407" @@ -4881,18 +4939,18 @@ iconv-lite-umd@0.6.8: resolved "https://registry.yarnpkg.com/iconv-lite-umd/-/iconv-lite-umd-0.6.8.tgz#5ad310ec126b260621471a2d586f7f37b9958ec0" integrity sha512-zvXJ5gSwMC9JD3wDzH8CoZGc1pbiJn12Tqjk8BXYCnYz3hYL5GRjHW8LEykjXhV9WgNGI4rgpgHcbIiBfrRq6A== -iconv-lite@^0.4.19: - version "0.4.19" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" - integrity sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ== - -iconv-lite@^0.4.24: +iconv-lite@0.4.24, iconv-lite@^0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== dependencies: safer-buffer ">= 2.1.2 < 3" +iconv-lite@^0.4.19: + version "0.4.19" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" + integrity sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ== + icss-utils@^4.0.0, icss-utils@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-4.1.1.tgz#21170b53789ee27447c2f47dd683081403f9a467" @@ -4986,7 +5044,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -6499,6 +6557,11 @@ neo-async@^2.5.0, neo-async@^2.6.1: resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== +netmask@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/netmask/-/netmask-2.0.2.tgz#8b01a07644065d536383835823bc52004ebac5e7" + integrity sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg== + next-tick@1, next-tick@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb" @@ -6852,7 +6915,7 @@ optimist@0.3.5: dependencies: wordwrap "~0.0.2" -optionator@^0.8.2, optionator@^0.8.3: +optionator@^0.8.1, optionator@^0.8.2, optionator@^0.8.3: version "0.8.3" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== @@ -6997,6 +7060,30 @@ p-try@^2.0.0: resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== +pac-proxy-agent@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/pac-proxy-agent/-/pac-proxy-agent-4.1.0.tgz#66883eeabadc915fc5e95457324cb0f0ac78defb" + integrity sha512-ejNgYm2HTXSIYX9eFlkvqFp8hyJ374uDf0Zq5YUAifiSh1D6fo+iBivQZirGvVv8dCYUsLhmLBRhlAYvBKI5+Q== + dependencies: + "@tootallnate/once" "1" + agent-base "6" + debug "4" + get-uri "3" + http-proxy-agent "^4.0.1" + https-proxy-agent "5" + pac-resolver "^4.1.0" + raw-body "^2.2.0" + socks-proxy-agent "5" + +pac-resolver@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pac-resolver/-/pac-resolver-4.2.0.tgz#b82bcb9992d48166920bc83c7542abb454bd9bdd" + integrity sha512-rPACZdUyuxT5Io/gFKUeeZFfE5T7ve7cAkE5TUZRRfuKP0u5Hocwe48X7ZEm6mYB+bTB0Qf+xlVlA/RM/i6RCQ== + dependencies: + degenerator "^2.2.0" + ip "^1.1.5" + netmask "^2.0.1" + pako@~1.0.5: version "1.0.11" resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" @@ -7722,7 +7809,21 @@ proto-list@~1.2.1: resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" integrity sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk= -proxy-from-env@^1.1.0: +proxy-agent@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/proxy-agent/-/proxy-agent-4.0.1.tgz#326c3250776c7044cd19655ccbfadf2e065a045c" + integrity sha512-ODnQnW2jc/FUVwHHuaZEfN5otg/fMbvMxz9nMSUQfJ9JU7q2SZvSULSsjLloVgJOiv9yhc8GlNMKc4GkFmcVEA== + dependencies: + agent-base "^6.0.0" + debug "4" + http-proxy-agent "^4.0.0" + https-proxy-agent "^5.0.0" + lru-cache "^5.1.1" + pac-proxy-agent "^4.1.0" + proxy-from-env "^1.0.0" + socks-proxy-agent "^5.0.0" + +proxy-from-env@^1.0.0, proxy-from-env@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== @@ -7867,6 +7968,16 @@ randomfill@^1.0.3: randombytes "^2.0.5" safe-buffer "^5.1.0" +raw-body@^2.2.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.1.tgz#30ac82f98bb5ae8c152e67149dac8d55153b168c" + integrity sha512-9WmIKF6mkvA0SLmA2Knm9+qj89e+j1zqgyn8aXGd7+nAduPoqgI9lO57SAZNn/Byzo5P7JhXTyg9PzaJbH73bA== + dependencies: + bytes "3.1.0" + http-errors "1.7.3" + iconv-lite "0.4.24" + unpipe "1.0.0" + rc@^1.2.7: version "1.2.8" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" @@ -8483,6 +8594,11 @@ setimmediate@^1.0.4: resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= +setprototypeof@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" + integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== + sha.js@^2.4.0, sha.js@^2.4.8: version "2.4.11" resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" @@ -8603,6 +8719,15 @@ snapdragon@^0.8.1: source-map-resolve "^0.5.0" use "^3.1.0" +socks-proxy-agent@5: + version "5.0.1" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-5.0.1.tgz#032fb583048a29ebffec2e6a73fca0761f48177e" + integrity sha512-vZdmnjb9a2Tz6WEQVIurybSwElwPxMZaIc7PzqbJTrezcKNznv6giT7J7tZDZ1BojVaa1jvO/UiUdhDVB0ACoQ== + dependencies: + agent-base "^6.0.2" + debug "4" + socks "^2.3.3" + socks-proxy-agent@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-5.0.0.tgz#7c0f364e7b1cf4a7a437e71253bed72e9004be60" @@ -8809,6 +8934,11 @@ static-extend@^0.1.1: define-property "^0.2.5" object-copy "^0.1.0" +"statuses@>= 1.5.0 < 2": + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= + stream-browserify@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b" @@ -9148,7 +9278,7 @@ tar-fs@^2.0.0: pump "^3.0.0" tar-stream "^2.1.4" -tar-stream@^2.1.4: +tar-stream@^2.1.4, tar-stream@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== @@ -9396,6 +9526,11 @@ to-through@^2.0.0: dependencies: through2 "^2.0.3" +toidentifier@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" + integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== + tough-cookie@~2.4.3: version "2.4.3" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" @@ -9461,6 +9596,11 @@ tslib@^1.9.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== +tslib@^2.0.1: + version "2.3.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e" + integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg== + tsutils@^3.17.1: version "3.17.1" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759" @@ -9643,6 +9783,11 @@ universalify@^0.1.0: resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== +unpipe@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= + unquote@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/unquote/-/unquote-1.1.1.tgz#8fded7324ec6e88a0ff8b905e7c098cdc086d544" From d78f2cec6ba2bd08389d4556ba0a5f32c3a43c05 Mon Sep 17 00:00:00 2001 From: Teffen Ellis Date: Tue, 27 Jul 2021 17:33:12 -0400 Subject: [PATCH 40/40] Fix issues surrounding IPC interfaces. Update names. --- src/vs/base/common/ipc.d.ts | 17 +++--- src/vs/base/common/uriServer.ts | 45 ++++++++++++++ src/vs/server/channel.ts | 10 ++-- src/vs/server/entry.ts | 9 +-- src/vs/server/server.ts | 15 +++-- src/vs/server/uriTransformer.ts | 58 ------------------- src/vs/server/util.ts | 11 ---- src/vs/workbench/browser/client.ts | 4 +- .../node/extensionHostProcessSetup.ts | 8 +-- 9 files changed, 79 insertions(+), 98 deletions(-) create mode 100644 src/vs/base/common/uriServer.ts delete mode 100644 src/vs/server/uriTransformer.ts delete mode 100644 src/vs/server/util.ts diff --git a/src/vs/base/common/ipc.d.ts b/src/vs/base/common/ipc.d.ts index 984bf1664cb50..5bd7beca09cb8 100644 --- a/src/vs/base/common/ipc.d.ts +++ b/src/vs/base/common/ipc.d.ts @@ -1,11 +1,12 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Coder Technologies. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + /** * External interfaces for integration into code-server over IPC. - * This file exists in two locations: - * - typings/ipc.d.ts - * - lib/vscode/src/typings/ipc.d.ts - * The second is a symlink to the first. */ -export interface Options { +export interface CodeServerConfiguration { authed: boolean base: string csStaticBase: string @@ -16,7 +17,7 @@ export interface Options { export interface InitMessage { type: 'init' id: string - options: VscodeOptions + options: VscodeInitializationOptions } export type Query = { [key: string]: string | string[] | undefined | Query | Query[] } @@ -81,13 +82,13 @@ export interface Args { _: string[] } -export interface VscodeOptions { +export interface VscodeInitializationOptions { readonly args: Args readonly remoteAuthority: string readonly startPath?: StartPath } -export interface VscodeOptionsMessage extends VscodeOptions { +export interface VscodeInitializationOptionsMessage extends VscodeInitializationOptions { readonly id: string } diff --git a/src/vs/base/common/uriServer.ts b/src/vs/base/common/uriServer.ts new file mode 100644 index 0000000000000..7e59775e213e2 --- /dev/null +++ b/src/vs/base/common/uriServer.ts @@ -0,0 +1,45 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Coder Technologies. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IRawURITransformer, UriParts, URITransformer } from 'vs/base/common/uriIpc'; + +class RawURITransformer implements IRawURITransformer { + constructor(private readonly authority: string) { } + + transformIncoming(uri: UriParts): UriParts { + switch (uri.scheme) { + case 'vscode-remote': + return { scheme: 'file', path: uri.path }; + default: + return uri; + } + } + + transformOutgoing(uri: UriParts): UriParts { + switch (uri.scheme) { + case 'file': + return { scheme: 'vscode-remote', authority: this.authority, path: uri.path }; + default: + return uri; + } + } + + transformOutgoingScheme(scheme: string): string { + switch (scheme) { + case 'file': + return 'vscode-remote'; + default: + return scheme; + } + } +} + +/** + * Convenience function, given that a server's raw URI transformer is often wrapped + * by VSCode's `URITransformer`. + */ +export function createServerURITransformer(authority: string) { + return new URITransformer(new RawURITransformer(authority)); +} diff --git a/src/vs/server/channel.ts b/src/vs/server/channel.ts index a93b95b9eb1e5..f9bb92ef8daff 100644 --- a/src/vs/server/channel.ts +++ b/src/vs/server/channel.ts @@ -26,7 +26,6 @@ import { IRemoteAgentEnvironment, RemoteAgentConnectionContext } from 'vs/platfo import { ITelemetryData, ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IShellLaunchConfig, ITerminalEnvironment } from 'vs/platform/terminal/common/terminal'; import { getTranslations } from 'vs/server/nls'; -import { getUriTransformer } from 'vs/server/util'; import { IFileChangeDto } from 'vs/workbench/api/common/extHost.protocol'; import { IEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable'; import { MergedEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariableCollection'; @@ -36,6 +35,7 @@ import * as terminalEnvironment from 'vs/workbench/contrib/terminal/common/termi import { AbstractVariableResolverService } from 'vs/workbench/services/configurationResolver/common/variableResolver'; import { ExtensionScanner, ExtensionScannerInput } from 'vs/workbench/services/extensions/node/extensionPoints'; import { PtyHostService } from 'vs/platform/terminal/node/ptyHostService'; +import { createServerURITransformer } from 'vs/base/common/uriServer'; const logger = new ConsoleLogger(); @@ -86,7 +86,7 @@ export class FileProviderChannel implements IServerChannel { const provider = new Watcher(this.logService); this.watchers.set(session, provider); - const transformer = getUriTransformer(context.remoteAuthority); + const transformer = createServerURITransformer(context.remoteAuthority); provider.onDidChangeFile((events) => { emitter.fire(events.map((event) => ({ ...event, @@ -238,12 +238,12 @@ export class ExtensionEnvironmentChannel implements IServerChannel { case 'getEnvironmentData': return transformOutgoingURIs( await this.getEnvironmentData(), - getUriTransformer(context.remoteAuthority), + createServerURITransformer(context.remoteAuthority), ); case 'scanExtensions': return transformOutgoingURIs( await this.scanExtensions(args.language), - getUriTransformer(context.remoteAuthority), + createServerURITransformer(context.remoteAuthority), ); case 'getDiagnosticInfo': return this.getDiagnosticInfo(); case 'disableTelemetry': return this.disableTelemetry(); @@ -559,6 +559,6 @@ export class TerminalProviderChannel implements IServerChannel { if (!process.send) { throw new Error('not spawned with IPC'); @@ -57,8 +57,9 @@ process.on('message', async (message: CodeServerMessage, socket) => { switch (message.type) { case 'init': try { - const options = await vscode.initialize(message.options); - send({ type: 'options', id: message.id, options }); + const workbenchOptions = await vscode.initialize(message.options); + + send({ type: 'options', id: message.id, options: workbenchOptions }); } catch (error) { logger.error(error.message); logger.error(error.stack); diff --git a/src/vs/server/server.ts b/src/vs/server/server.ts index 92d3486966e41..de9c4eb5d3a04 100644 --- a/src/vs/server/server.ts +++ b/src/vs/server/server.ts @@ -13,7 +13,7 @@ import { URI } from 'vs/base/common/uri'; import { getMachineId } from 'vs/base/node/id'; import { ClientConnectionEvent, IPCServer, IServerChannel, ProxyChannel } from 'vs/base/parts/ipc/common/ipc'; import { main } from 'vs/code/node/cliProcessMain'; -import { Query, VscodeOptions, WorkbenchOptions } from 'vs/base/common/ipc'; +import { Query, VscodeInitializationOptions, WorkbenchOptions } from 'vs/base/common/ipc'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ConfigurationService } from 'vs/platform/configuration/common/configurationService'; import { ExtensionHostDebugBroadcastChannel } from 'vs/platform/debug/common/extensionHostDebugIpc'; @@ -55,17 +55,20 @@ import { Connection, ExtensionHostConnection, ManagementConnection } from 'vs/se import { TelemetryClient } from 'vs/server/insights'; import { getLocaleFromConfig, getNlsConfiguration } from 'vs/server/nls'; import { Protocol } from 'vs/server/protocol'; -import { getUriTransformer } from 'vs/server/util'; import { REMOTE_TERMINAL_CHANNEL_NAME } from 'vs/workbench/contrib/terminal/common/remoteTerminalChannel'; import { REMOTE_FILE_SYSTEM_CHANNEL_NAME } from 'vs/workbench/services/remote/common/remoteAgentFileSystemChannel'; import { RemoteExtensionLogFileName } from 'vs/workbench/services/remote/common/remoteAgentService'; import { PtyHostService } from 'vs/platform/terminal/node/ptyHostService'; import { LogsDataCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/logsDataCleaner'; +import { createServerURITransformer } from 'vs/base/common/uriServer'; const commit = product.commit || 'development'; const logger = new ConsoleMainLogger(); -export class Vscode { +/** + * Handles client connections to a VSCode instance via IPC. + */ +export class VscodeServer { public readonly _onDidClientConnect = new Emitter(); public readonly onDidClientConnect = this._onDidClientConnect.event; private readonly ipc = new IPCServer(this.onDidClientConnect); @@ -80,8 +83,8 @@ export class Vscode { return main(args); } - public async initialize(options: VscodeOptions): Promise { - const transformer = getUriTransformer(options.remoteAuthority); + public async initialize(options: VscodeInitializationOptions): Promise { + const transformer = createServerURITransformer(options.remoteAuthority); if (!this.servicesPromise) { this.servicesPromise = this.initializeServices(options.args); } @@ -299,7 +302,7 @@ export class Vscode { this.ipc.registerChannel('extensions', new ExtensionManagementChannel( accessor.get(IExtensionManagementService), - (context) => getUriTransformer(context.remoteAuthority), + (context) => createServerURITransformer(context.remoteAuthority), )); this.ipc.registerChannel('remoteextensionsenvironment', new ExtensionEnvironmentChannel( environmentService, logService, telemetryService, '', diff --git a/src/vs/server/uriTransformer.ts b/src/vs/server/uriTransformer.ts deleted file mode 100644 index 61183f7cebe68..0000000000000 --- a/src/vs/server/uriTransformer.ts +++ /dev/null @@ -1,58 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Coder Technologies. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -// In a bit of a hack, this file is stored in two places -// - src/node/uri_transformer.ts -// - lib/vscode/src/vs/server/uriTransformer.ts - -import { IRawURITransformer, UriParts } from 'vs/base/common/uriIpc' - -// The reason for this is that we need a CommonJS-compiled -// version of this file to supply as a command line argument -// to extensionHostProcessSetup.ts; but we also need to include -// it ourselves cleanly in `lib/vscode/src/vs/server`. - -// @oxy: Could not figure out how to compile as a CommonJS module -// in the same tree as VSCode, which is why I came up with the solution -// of storing it in two places. - -class RawURITransformer implements IRawURITransformer { - constructor(private readonly authority: string) { } - - transformIncoming(uri: UriParts): UriParts { - switch (uri.scheme) { - case "vscode-remote": - return { scheme: "file", path: uri.path } - default: - return uri - } - } - - transformOutgoing(uri: UriParts): UriParts { - switch (uri.scheme) { - case "file": - return { scheme: "vscode-remote", authority: this.authority, path: uri.path } - default: - return uri - } - } - - transformOutgoingScheme(scheme: string): string { - switch (scheme) { - case "file": - return "vscode-remote" - default: - return scheme - } - } -} - -// Using `export =` is deliberate. -// See lib/vscode/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts; -// they include the file directly with a node require and expect a function as `module.exports`. -// `export =` in TypeScript is equivalent to `module.exports =` in vanilla JS. -export = function rawURITransformerFactory(authority: string) { - return new RawURITransformer(authority) -} diff --git a/src/vs/server/util.ts b/src/vs/server/util.ts deleted file mode 100644 index 0aea1ee82860c..0000000000000 --- a/src/vs/server/util.ts +++ /dev/null @@ -1,11 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Coder Technologies. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { URITransformer } from 'vs/base/common/uriIpc'; -import rawURITransformerFactory = require('vs/server/uriTransformer'); - -export const getUriTransformer = (remoteAuthority: string): URITransformer => { - return new URITransformer(rawURITransformerFactory(remoteAuthority)); -}; diff --git a/src/vs/workbench/browser/client.ts b/src/vs/workbench/browser/client.ts index 84718dcbc811d..5cf3ddf6be5fa 100644 --- a/src/vs/workbench/browser/client.ts +++ b/src/vs/workbench/browser/client.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as path from 'vs/base/common/path'; -import { Options } from 'vs/base/common/ipc'; +import { CodeServerConfiguration } from 'vs/base/common/ipc'; import { localize } from 'vs/nls'; import { MenuId, MenuRegistry } from 'vs/platform/actions/common/actions'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; @@ -22,7 +22,7 @@ import 'vs/workbench/services/localizations/browser/localizationsService'; * possible. */ -const options = getOptions(); +const options = getOptions(); /** * This is called by vs/workbench/browser/web.main.ts after the workbench has diff --git a/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts b/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts index ed44762939e06..ca8ea8106e2ad 100644 --- a/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts +++ b/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts @@ -17,7 +17,8 @@ import { IInitData } from 'vs/workbench/api/common/extHost.protocol'; import { MessageType, createMessageOfType, isMessageOfType, IExtHostSocketMessage, IExtHostReadyMessage, IExtHostReduceGraceTimeMessage, ExtensionHostExitCode } from 'vs/workbench/services/extensions/common/extensionHostProtocol'; import { ExtensionHostMain, IExitFn } from 'vs/workbench/services/extensions/common/extensionHostMain'; import { VSBuffer } from 'vs/base/common/buffer'; -import { IURITransformer, URITransformer, IRawURITransformer } from 'vs/base/common/uriIpc'; +import { IURITransformer } from 'vs/base/common/uriIpc'; +import { createServerURITransformer } from 'vs/base/common/uriServer'; import { exists } from 'vs/base/node/pfs'; import { realpath } from 'vs/base/node/extpath'; import { IHostUtils } from 'vs/workbench/api/common/extHostExtensionService'; @@ -339,11 +340,10 @@ export async function startExtensionHostProcess(): Promise { // Attempt to load uri transformer let uriTransformer: IURITransformer | null = null; + if (initData.remote.authority && args.uriTransformerPath) { try { - const rawURITransformerFactory = require.__$__nodeRequire(args.uriTransformerPath); - const rawURITransformer = rawURITransformerFactory(initData.remote.authority); - uriTransformer = new URITransformer(rawURITransformer); + uriTransformer = createServerURITransformer(initData.remote.authority); } catch (e) { console.error(e); }