diff --git a/README.md b/README.md index cecb3f6b..3a6500a9 100644 --- a/README.md +++ b/README.md @@ -184,11 +184,14 @@ Additionally, 25 packages that include the vscode version of some services (with - Running terminals - Running vscode extensions (not web-compatible) - and probably more? - This library exports a `vscode-ext-host-server` bin to start the remote agent + + Another package `@codingame/monaco-vscode-server` is published, which expose a `vscode-ext-host-server` bin to start the remote agent - **Accessibility**: `@codingame/monaco-vscode-accessibility-service-override` - Register accessibility helpers - **Workspace trust**: `@codingame/monaco-vscode-workspace-trust-service-override` - Ask user it they trust the current workspace, disable some features if not +- **Extension Gallery**: `@codingame/monaco-vscode-extension-gallery-service-override` + - Support for the VSCode marketplace, it allows to install extensions from the marketplace. Usage: ```typescript diff --git a/demo/package-lock.json b/demo/package-lock.json index bc6045c3..9b5247fd 100644 --- a/demo/package-lock.json +++ b/demo/package-lock.json @@ -32,6 +32,7 @@ "@codingame/monaco-vscode-emmet-default-extension": "file:../dist/default-extension-emmet", "@codingame/monaco-vscode-environment-service-override": "file:../dist/service-override-environment", "@codingame/monaco-vscode-extension-editing-default-extension": "file:../dist/default-extension-extension-editing", + "@codingame/monaco-vscode-extension-gallery-service-override": "file:../dist/service-override-extension-gallery", "@codingame/monaco-vscode-extensions-service-override": "file:../dist/service-override-extensions", "@codingame/monaco-vscode-files-service-override": "file:../dist/service-override-files", "@codingame/monaco-vscode-fsharp-default-extension": "file:../dist/default-extension-fsharp", @@ -1002,6 +1003,15 @@ "vscode": "npm:@codingame/monaco-vscode-api@^0.0.0-semantic-release" } }, + "../dist/service-override-extension-gallery": { + "name": "@codingame/monaco-vscode-extension-gallery-service-override", + "version": "0.0.0-semantic-release", + "license": "MIT", + "dependencies": { + "monaco-editor": "0.44.0", + "vscode": "npm:@codingame/monaco-vscode-api@^0.0.0-semantic-release" + } + }, "../dist/service-override-extensions": { "name": "@codingame/monaco-vscode-extensions-service-override", "version": "0.0.0-semantic-release", @@ -1484,6 +1494,10 @@ "resolved": "../dist/default-extension-extension-editing", "link": true }, + "node_modules/@codingame/monaco-vscode-extension-gallery-service-override": { + "resolved": "../dist/service-override-extension-gallery", + "link": true + }, "node_modules/@codingame/monaco-vscode-extensions-service-override": { "resolved": "../dist/service-override-extensions", "link": true diff --git a/demo/package.json b/demo/package.json index 3db80911..ab60ed24 100644 --- a/demo/package.json +++ b/demo/package.json @@ -12,7 +12,7 @@ "build": "tsc --noEmit && vite --config vite.config.ts build", "build:github": "tsc --noEmit && vite --config vite.github-page.config.ts build && touch dist/.nojekyll", "start:debugServer": "node --loader ts-node/esm src/debugServer.ts", - "start:extHostServer": "vscode-ext-host-server --without-connection-token" + "start:extHostServer": "WEB_ENDPOINT_URL_TEMPLATE=http://localhost:5173/ vscode-ext-host-server --without-connection-token" }, "devDependencies": { "@codingame/monaco-vscode-rollup-vsix-plugin": "file:../dist/rollup-vsix-plugin", @@ -49,6 +49,7 @@ "@codingame/monaco-vscode-editor-service-override": "file:../dist/service-override-editor", "@codingame/monaco-vscode-emmet-default-extension": "file:../dist/default-extension-emmet", "@codingame/monaco-vscode-environment-service-override": "file:../dist/service-override-environment", + "@codingame/monaco-vscode-extension-gallery-service-override": "file:../dist/service-override-extension-gallery", "@codingame/monaco-vscode-extension-editing-default-extension": "file:../dist/default-extension-extension-editing", "@codingame/monaco-vscode-extensions-service-override": "file:../dist/service-override-extensions", "@codingame/monaco-vscode-files-service-override": "file:../dist/service-override-files", diff --git a/demo/src/features/remoteExtension.ts b/demo/src/features/remoteExtension.ts index 3b039370..293bfbca 100644 --- a/demo/src/features/remoteExtension.ts +++ b/demo/src/features/remoteExtension.ts @@ -7,5 +7,5 @@ declare global { } if (window.rootDirectory != null) { - registerRemoteExtension(`${window.rootDirectory}/src/features/remoteExtensionExample/`) + void registerRemoteExtension(`${window.rootDirectory}/src/features/remoteExtensionExample/`) } diff --git a/demo/src/features/remoteExtensionExample/package.json b/demo/src/features/remoteExtensionExample/package.json index 2055817f..d97208ba 100644 --- a/demo/src/features/remoteExtensionExample/package.json +++ b/demo/src/features/remoteExtensionExample/package.json @@ -4,7 +4,7 @@ "version": "1.0.0", "activationEvents": ["*"], "engines": { - "vscode": "*" + "vscode": "^1.77.0" }, "l10n": "./l10n", "main": "./main.js", diff --git a/demo/src/setup.ts b/demo/src/setup.ts index e6b153b9..fe08b9d7 100644 --- a/demo/src/setup.ts +++ b/demo/src/setup.ts @@ -9,6 +9,7 @@ import getTextmateServiceOverride from '@codingame/monaco-vscode-textmate-servic import getThemeServiceOverride from '@codingame/monaco-vscode-theme-service-override' import getLanguagesServiceOverride from '@codingame/monaco-vscode-languages-service-override' import getAudioCueServiceOverride from '@codingame/monaco-vscode-audio-cue-service-override' +import getExtensionGalleryServiceOverride from '@codingame/monaco-vscode-extension-gallery-service-override' import getViewsServiceOverride, { isEditorPartVisible, Parts, @@ -84,13 +85,19 @@ await Promise.all([ folders: [{ path: '/tmp' }] - })) + })), + initFile(monaco.Uri.file('/tmp/.vscode/extensions.json'), `{ + "recommendations": [ + "vscodevim.vim" + ] +}`) ]) // Override services await initializeMonacoService({ ...getLogServiceOverride(), ...getExtensionServiceOverride(toWorkerConfig(ExtensionHostWorker)), + ...getExtensionGalleryServiceOverride({ webOnly: false }), ...getModelServiceOverride(), ...getNotificationServiceOverride(), ...getDialogsServiceOverride(), @@ -140,6 +147,16 @@ await initializeMonacoService({ }, developmentOptions: { logLevel: LogLevel.Info // Default value + }, + productConfiguration: { + extensionsGallery: { + serviceUrl: 'https://open-vsx.org/vscode/gallery', + itemUrl: 'https://open-vsx.org/vscode/item', + resourceUrlTemplate: 'https://open-vsx.org/vscode/unpkg/{publisher}/{name}/{version}/{path}', + controlUrl: '', + nlsBaseUrl: '', + publisherUrl: '' + } } }) diff --git a/demo/vite.config.ts b/demo/vite.config.ts index 0e1d88b1..37151795 100644 --- a/demo/vite.config.ts +++ b/demo/vite.config.ts @@ -19,7 +19,7 @@ export default defineConfig({ apply: 'serve', configureServer: server => { server.middlewares.use((_req, res, next) => { - res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp') + res.setHeader('Cross-Origin-Embedder-Policy', 'credentialless') res.setHeader('Cross-Origin-Opener-Policy', 'same-origin') res.setHeader('Cross-Origin-Resource-Policy', 'cross-origin') next() @@ -59,7 +59,7 @@ export default defineConfig({ // These 2 lines prevent vite from reloading the whole page when starting a worker (so 2 times in a row after cleaning the vite cache - for the editor then the textmate workers) // it's mainly empirical and probably not the best way, fix me if you find a better way - 'monaco-editor/esm/vs/nls.js', 'monaco-editor/esm/vs/editor/editor.worker.js', 'vscode-textmate', 'vscode-oniguruma', '@vscode/vscode-languagedetection', + 'monaco-editor/esm/vs/nls.js', 'monaco-editor/esm/vs/editor/editor.worker.js', 'vscode-textmate', 'vscode-oniguruma', '@vscode/vscode-languagedetection', 'vscode-semver', ...(await glob('monaco-editor/esm/vs/**/common/**/*.js', { cwd: path.resolve(__dirname, '../node_modules') })) ], exclude: [], diff --git a/package-lock.json b/package-lock.json index 26799bce..341274be 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,6 +26,7 @@ "node-pty": "1.1.0-beta1", "vscode-oniguruma": "1.7.0", "vscode-regexpp": "^3.1.0", + "vscode-semver": "npm:semver@=5.5.0", "vscode-textmate": "9.0.0", "xterm": "5.4.0-beta.27", "xterm-addon-canvas": "0.6.0-beta.27", @@ -58,6 +59,7 @@ "@types/node": "^18.17.15", "@types/semver": "^7.5.5", "@types/vscode": "~1.83.0", + "@types/vscode-semver": "npm:@types/semver@=5.5.0", "@types/yauzl": "^2.10.3", "@typescript-eslint/eslint-plugin": "^6.11.0", "@typescript-eslint/parser": "^6.11.0", @@ -3012,6 +3014,13 @@ "integrity": "sha512-3mUtHqLAVz9hegut9au4xehuBrzRE3UJiQMpoEHkNl6XHliihO7eATx2BMHs0odsmmrwjJrlixx/Pte6M3ygDQ==", "dev": true }, + "node_modules/@types/vscode-semver": { + "name": "@types/semver", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-5.5.0.tgz", + "integrity": "sha512-41qEJgBH/TWgo5NFSvBCJ1qkoi3Q6ONSF2avrHq1LVEZfYpdHmj0y9SuTK+u9ZhG1sYQKBL1AWXKyLWP4RaUoQ==", + "dev": true + }, "node_modules/@types/which": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/which/-/which-3.0.0.tgz", @@ -9519,6 +9528,15 @@ "url": "https://github.com/sponsors/mysticatea" } }, + "node_modules/vscode-semver": { + "name": "semver", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", + "bin": { + "semver": "bin/semver" + } + }, "node_modules/vscode-textmate": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-9.0.0.tgz", diff --git a/package.json b/package.json index 9e68f4f3..e093ed7a 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "compile-default-extensions": "NODE_OPTIONS=--max_old_space_size=8192 rollup --config rollup/rollup.default-extensions.ts --configPlugin 'typescript={tsconfig: `tsconfig.rollup-config-default-extensions.json`}'", "compile-language-packs": "NODE_OPTIONS=--max_old_space_size=8192 rollup --config rollup/rollup.language-packs.ts --configPlugin 'typescript={tsconfig: `tsconfig.rollup-config-language-packs.json`}'", "clean": "rm -rf dist/", - "compile-server": "rollup --config rollup/rollup.server.config.ts --configPlugin 'typescript={tsconfig: `tsconfig.rollup-config-server.json`, include: [`./rollup/rollup.server.config.ts`, `./rollup/rollup-metadata-plugin.ts`]}'", + "compile-server": "rollup --config rollup/rollup.server.config.ts --configPlugin 'typescript={tsconfig: `tsconfig.rollup-config-server.json`, include: [`./rollup/rollup.server.config.ts`, `./rollup/rollup-metadata-plugin.ts`]}' --vscode-version ${npm_package_config_vscode_version} --vscode-ref ${npm_package_config_vscode_ref}", "compile-treemending-script": "rollup --config rollup/rollup.treemending-script.config.ts --configPlugin 'typescript={tsconfig: `tsconfig.rollup-config-treemending-script.json`, include: [`./rollup/rollup.treemending-script.config.ts`, `./rollup/rollup-metadata-plugin.ts`]}'", "compile-rollup-plugins": "rollup --config rollup/rollup.rollup-plugins.config.ts --configPlugin 'typescript={tsconfig: `tsconfig.rollup-config-plugins.json`, include: [`./rollup/rollup.rollup-plugins.config.ts`, `./rollup/rollup-metadata-plugin.ts`]}'", "copy-monaco-editor": "cp -R node_modules/monaco-editor dist/ && (cd dist/monaco-editor; change-package-name \"@codingame/monaco-editor-treemended\")", @@ -57,6 +57,7 @@ "@types/mime-types": "^2.1.4", "@types/node": "^18.17.15", "@types/semver": "^7.5.5", + "@types/vscode-semver": "npm:@types/semver@=5.5.0", "@types/vscode": "~1.83.0", "@types/yauzl": "^2.10.3", "@typescript-eslint/eslint-plugin": "^6.11.0", @@ -112,6 +113,7 @@ "node-pty": "1.1.0-beta1", "vscode-oniguruma": "1.7.0", "vscode-regexpp": "^3.1.0", + "vscode-semver": "npm:semver@=5.5.0", "vscode-textmate": "9.0.0", "xterm": "5.4.0-beta.27", "xterm-addon-canvas": "0.6.0-beta.27", diff --git a/rollup/rollup.config.ts b/rollup/rollup.config.ts index 1a35b41a..30d222dd 100644 --- a/rollup/rollup.config.ts +++ b/rollup/rollup.config.ts @@ -496,6 +496,7 @@ const workerGroups: Record = { const externals = Object.keys({ ...pkg.dependencies }) const external: rollup.ExternalOption = (source) => { + if (source === 'semver' || source.startsWith('semver')) return true if (source.includes('tas-client-umd')) return true if (source.startsWith(MONACO_EDITOR_DIR) || source.startsWith('monaco-editor/')) { return true diff --git a/rollup/rollup.server.config.ts b/rollup/rollup.server.config.ts index 8cfacd67..772e023c 100644 --- a/rollup/rollup.server.config.ts +++ b/rollup/rollup.server.config.ts @@ -4,6 +4,7 @@ import typescript from '@rollup/plugin-typescript' import commonjs from '@rollup/plugin-commonjs' import json from '@rollup/plugin-json' import { PackageJson } from 'type-fest' +import replace from '@rollup/plugin-replace' import * as path from 'path' import { fileURLToPath } from 'url' import metadataPlugin from './rollup-metadata-plugin.js' @@ -15,72 +16,84 @@ const BASE_DIR = path.resolve(__dirname, '..') const TSCONFIG = path.resolve(BASE_DIR, 'tsconfig.rollup.json') const externals = Object.keys(pkg.dependencies) -const config: rollup.RollupOptions = { - cache: false, - external: (source) => { - if (source === 'graceful-fs' || source === 'xterm-headless') { - // commonjs module - return false - } - return externals.some(external => source === external || source.startsWith(`${external}/`)) - }, - output: [{ - format: 'esm', - dir: 'dist/server', - entryFileNames: '[name].js', - chunkFileNames: '[name].js', - banner: (module) => module.isEntry ? '#!/usr/bin/env node' : '' - }], - input: { - server: 'src/server/server.ts', - 'bootstrap-fork': 'src/server/bootstrap-fork.ts' - }, - plugins: [ - json({ - compact: true, - namedExports: false, - preferConst: false - }), - commonjs({ - ignoreDynamicRequires: true - }), - nodeResolve({ - extensions: EXTENSIONS, - modulePaths: ['vscode/src'], - browser: false, - preferBuiltins: true - }), - typescript({ - noEmitOnError: true, - tsconfig: TSCONFIG, - compilerOptions: { - outDir: 'dist/server' +export default (args: Record): rollup.RollupOptions => { + const vscodeVersion = args['vscode-version'] + delete args['vscode-version'] + const vscodeRef = args['vscode-ref'] + delete args['vscode-ref'] + if (vscodeVersion == null) { + throw new Error('Vscode version is mandatory') + } + return rollup.defineConfig({ + cache: false, + external: (source) => { + if (source === 'graceful-fs' || source === 'xterm-headless') { + // commonjs module + return false } - }), - metadataPlugin({ - handle (_, dependencies) { - const packageJson: PackageJson = { - name: '@codingame/monaco-vscode-server', - ...Object.fromEntries(Object.entries(pkg).filter(([key]) => ['version', 'keywords', 'author', 'license', 'repository', 'type'].includes(key))), - private: false, - description: `VSCode server designed to be used with ${pkg.name}`, - bin: { - 'vscode-ext-host-server': './server.js' - }, - dependencies: { - vscode: `npm:${pkg.name}@^${pkg.version}`, - ...Object.fromEntries(Object.entries(pkg.dependencies).filter(([key]) => dependencies.has(key))) + return externals.some(external => source === external || source.startsWith(`${external}/`)) + }, + output: [{ + format: 'esm', + dir: 'dist/server', + entryFileNames: '[name].js', + chunkFileNames: '[name].js', + banner: (module) => module.isEntry ? '#!/usr/bin/env node' : '' + }], + input: { + server: 'src/server/server.ts', + 'bootstrap-fork': 'src/server/bootstrap-fork.ts' + }, + plugins: [ + replace({ + VSCODE_VERSION: JSON.stringify(vscodeVersion), + VSCODE_REF: JSON.stringify(vscodeRef), + preventAssignment: true + }), + json({ + compact: true, + namedExports: false, + preferConst: false + }), + commonjs({ + ignoreDynamicRequires: true + }), + nodeResolve({ + extensions: EXTENSIONS, + modulePaths: ['vscode/src'], + browser: false, + preferBuiltins: true + }), + typescript({ + noEmitOnError: true, + tsconfig: TSCONFIG, + compilerOptions: { + outDir: 'dist/server' + } + }), + metadataPlugin({ + handle (_, dependencies) { + const packageJson: PackageJson = { + name: '@codingame/monaco-vscode-server', + ...Object.fromEntries(Object.entries(pkg).filter(([key]) => ['version', 'keywords', 'author', 'license', 'repository', 'type'].includes(key))), + private: false, + description: `VSCode server designed to be used with ${pkg.name}`, + bin: { + 'vscode-ext-host-server': './server.js' + }, + dependencies: { + vscode: `npm:${pkg.name}@^${pkg.version}`, + ...Object.fromEntries(Object.entries(pkg.dependencies).filter(([key]) => dependencies.has(key))) + } } + this.emitFile({ + fileName: 'package.json', + needsCodeReference: false, + source: JSON.stringify(packageJson, null, 2), + type: 'asset' + }) } - this.emitFile({ - fileName: 'package.json', - needsCodeReference: false, - source: JSON.stringify(packageJson, null, 2), - type: 'asset' - }) - } - }) - ] + }) + ] + }) } - -export default config diff --git a/scripts/vscode.patch b/scripts/vscode.patch index e93fba06..15f78f23 100644 --- a/scripts/vscode.patch +++ b/scripts/vscode.patch @@ -542,6 +542,19 @@ index d8cefb6df67..a94fca911ea 100644 import { IProcessEnvironment } from 'vs/base/common/platform'; import { localize } from 'vs/nls'; import { NativeParsedArgs } from 'vs/platform/environment/common/argv'; +diff --git a/src/vs/platform/extensionResourceLoader/browser/extensionResourceLoaderService.ts b/src/vs/platform/extensionResourceLoader/browser/extensionResourceLoaderService.ts +index c766318f30f..58c3000cbd3 100644 +--- a/src/vs/platform/extensionResourceLoader/browser/extensionResourceLoaderService.ts ++++ b/src/vs/platform/extensionResourceLoader/browser/extensionResourceLoaderService.ts +@@ -14,7 +14,7 @@ import { ILogService } from 'vs/platform/log/common/log'; + import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; + import { AbstractExtensionResourceLoaderService, IExtensionResourceLoaderService } from 'vs/platform/extensionResourceLoader/common/extensionResourceLoader'; + +-class ExtensionResourceLoaderService extends AbstractExtensionResourceLoaderService { ++export class ExtensionResourceLoaderService extends AbstractExtensionResourceLoaderService { + + declare readonly _serviceBrand: undefined; + diff --git a/src/vs/platform/files/node/diskFileSystemProvider.ts b/src/vs/platform/files/node/diskFileSystemProvider.ts index e22cfe1b45e..b48c1babf86 100644 --- a/src/vs/platform/files/node/diskFileSystemProvider.ts @@ -955,7 +968,7 @@ index b83a462131d..5555f431ba0 100644 performance.mark('code/extHost/didInitAPI'); diff --git a/src/vs/workbench/api/worker/extensionHostWorker.ts b/src/vs/workbench/api/worker/extensionHostWorker.ts -index 6e6f8845da5..48462781c2a 100644 +index 6e6f8845da5..80a3a9f0095 100644 --- a/src/vs/workbench/api/worker/extensionHostWorker.ts +++ b/src/vs/workbench/api/worker/extensionHostWorker.ts @@ -15,7 +15,6 @@ import * as performance from 'vs/base/common/performance'; @@ -1052,7 +1065,7 @@ index 6e6f8845da5..48462781c2a 100644 + private notFound = false; + override open(method: string, url: string | URL, async?: boolean, username?: string | null, password?: string | null): void { + const transformedUrl = asWorkerBrowserUrl(url); -+ this.notFound = transformedUrl.startsWith('extension:'); ++ this.notFound = transformedUrl.startsWith('extension-file:'); + return super.open(method, transformedUrl, async ?? true, username, password); + } + override send(body?: Document | XMLHttpRequestBodyInit | null | undefined): void { @@ -1442,10 +1455,54 @@ index a860270eca9..0ef927948db 100644 if (this.element && this._messagePort) { this._messagePort.postMessage({ channel, args: data }, transferable); diff --git a/src/vs/workbench/services/extensions/browser/extensionService.ts b/src/vs/workbench/services/extensions/browser/extensionService.ts -index 25885c7c4f9..ec1beb2c951 100644 +index 25885c7c4f9..2d220cbe1ad 100644 --- a/src/vs/workbench/services/extensions/browser/extensionService.ts +++ b/src/vs/workbench/services/extensions/browser/extensionService.ts -@@ -212,16 +212,16 @@ export class ExtensionService extends AbstractExtensionService implements IExten +@@ -42,8 +42,10 @@ import { IUserDataInitializationService } from 'vs/workbench/services/userData/b + import { IUserDataProfileService } from 'vs/workbench/services/userDataProfile/common/userDataProfile'; + + export class ExtensionService extends AbstractExtensionService implements IExtensionService { +- + constructor( ++ extensionsProposedApi: ExtensionsProposedApi, ++ extensionHostFactory: IExtensionHostFactory, ++ extensionHostKindPicker: IExtensionHostKindPicker, + @IInstantiationService instantiationService: IInstantiationService, + @INotificationService notificationService: INotificationService, + @IBrowserWorkbenchEnvironmentService private readonly _browserEnvironmentService: IBrowserWorkbenchEnvironmentService, +@@ -67,21 +69,10 @@ export class ExtensionService extends AbstractExtensionService implements IExten + @IRemoteExplorerService private readonly _remoteExplorerService: IRemoteExplorerService, + @IDialogService dialogService: IDialogService, + ) { +- const extensionsProposedApi = instantiationService.createInstance(ExtensionsProposedApi); +- const extensionHostFactory = new BrowserExtensionHostFactory( +- extensionsProposedApi, +- () => this._scanWebExtensions(), +- () => this._getExtensionRegistrySnapshotWhenReady(), +- instantiationService, +- remoteAgentService, +- remoteAuthorityResolverService, +- extensionEnablementService, +- logService +- ); + super( + extensionsProposedApi, + extensionHostFactory, +- new BrowserExtensionHostKindPicker(logService), ++ extensionHostKindPicker, + instantiationService, + notificationService, + _browserEnvironmentService, +@@ -129,7 +120,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten + this._register(this._fileService.registerProvider(Schemas.https, provider)); + } + +- private async _scanWebExtensions(): Promise { ++ protected async _scanWebExtensions(): Promise { + const system: IExtensionDescription[] = [], user: IExtensionDescription[] = [], development: IExtensionDescription[] = []; + try { + await Promise.all([ +@@ -212,16 +203,16 @@ export class ExtensionService extends AbstractExtensionService implements IExten } } @@ -1467,7 +1524,7 @@ index 25885c7c4f9..ec1beb2c951 100644 @ILogService private readonly _logService: ILogService, ) { } -@@ -248,7 +248,7 @@ class BrowserExtensionHostFactory implements IExtensionHostFactory { +@@ -248,7 +239,7 @@ class BrowserExtensionHostFactory implements IExtensionHostFactory { } } @@ -1476,6 +1533,79 @@ index 25885c7c4f9..ec1beb2c951 100644 return { getInitData: async (): Promise => { if (isInitialStart) { +@@ -345,4 +336,71 @@ export class BrowserExtensionHostKindPicker implements IExtensionHostKindPicker + } + } + +-registerSingleton(IExtensionService, ExtensionService, InstantiationType.Eager); ++export class BrowserExtensionService extends ExtensionService { ++ constructor( ++ @IInstantiationService instantiationService: IInstantiationService, ++ @INotificationService notificationService: INotificationService, ++ @IBrowserWorkbenchEnvironmentService browserEnvironmentService: IBrowserWorkbenchEnvironmentService, ++ @ITelemetryService telemetryService: ITelemetryService, ++ @IWorkbenchExtensionEnablementService extensionEnablementService: IWorkbenchExtensionEnablementService, ++ @IFileService fileService: IFileService, ++ @IProductService productService: IProductService, ++ @IWorkbenchExtensionManagementService extensionManagementService: IWorkbenchExtensionManagementService, ++ @IWorkspaceContextService contextService: IWorkspaceContextService, ++ @IConfigurationService configurationService: IConfigurationService, ++ @IExtensionManifestPropertiesService extensionManifestPropertiesService: IExtensionManifestPropertiesService, ++ @IWebExtensionsScannerService webExtensionsScannerService: IWebExtensionsScannerService, ++ @ILogService logService: ILogService, ++ @IRemoteAgentService remoteAgentService: IRemoteAgentService, ++ @IRemoteExtensionsScannerService remoteExtensionsScannerService: IRemoteExtensionsScannerService, ++ @ILifecycleService lifecycleService: ILifecycleService, ++ @IRemoteAuthorityResolverService remoteAuthorityResolverService: IRemoteAuthorityResolverService, ++ @IUserDataInitializationService userDataInitializationService: IUserDataInitializationService, ++ @IUserDataProfileService userDataProfileService: IUserDataProfileService, ++ @IWorkspaceTrustManagementService workspaceTrustManagementService: IWorkspaceTrustManagementService, ++ @IRemoteExplorerService remoteExplorerService: IRemoteExplorerService, ++ @IDialogService dialogService: IDialogService, ++ ) { ++ const extensionsProposedApi = instantiationService.createInstance(ExtensionsProposedApi); ++ const extensionHostFactory = new BrowserExtensionHostFactory( ++ extensionsProposedApi, ++ () => this._scanWebExtensions(), ++ () => this._getExtensionRegistrySnapshotWhenReady(), ++ instantiationService, ++ remoteAgentService, ++ remoteAuthorityResolverService, ++ extensionEnablementService, ++ logService ++ ); ++ super( ++ extensionsProposedApi, ++ extensionHostFactory, ++ new BrowserExtensionHostKindPicker(logService), ++ instantiationService, ++ notificationService, ++ browserEnvironmentService, ++ telemetryService, ++ extensionEnablementService, ++ fileService, ++ productService, ++ extensionManagementService, ++ contextService, ++ configurationService, ++ extensionManifestPropertiesService, ++ webExtensionsScannerService, ++ logService, ++ remoteAgentService, ++ remoteExtensionsScannerService, ++ lifecycleService, ++ remoteAuthorityResolverService, ++ userDataInitializationService, ++ userDataProfileService, ++ workspaceTrustManagementService, ++ remoteExplorerService, ++ dialogService ++ ); ++ } ++} ++ ++ ++registerSingleton(IExtensionService, BrowserExtensionService, InstantiationType.Eager); diff --git a/src/vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts b/src/vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts index a7ce017ab9f..fd873470224 100644 --- a/src/vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts @@ -1675,6 +1805,19 @@ index f4707432371..7c5cdde39cc 100644 declare _serviceBrand: undefined; +diff --git a/src/vs/workbench/services/remote/common/remoteExtensionsScanner.ts b/src/vs/workbench/services/remote/common/remoteExtensionsScanner.ts +index a466cc1f3a1..09f6a40eb26 100644 +--- a/src/vs/workbench/services/remote/common/remoteExtensionsScanner.ts ++++ b/src/vs/workbench/services/remote/common/remoteExtensionsScanner.ts +@@ -16,7 +16,7 @@ import { ILogService } from 'vs/platform/log/common/log'; + import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; + import { IActiveLanguagePackService } from 'vs/workbench/services/localization/common/locale'; + +-class RemoteExtensionsScannerService implements IRemoteExtensionsScannerService { ++export class RemoteExtensionsScannerService implements IRemoteExtensionsScannerService { + + declare readonly _serviceBrand: undefined; + diff --git a/src/vs/workbench/services/textMate/browser/backgroundTokenization/textMateWorkerTokenizerController.ts b/src/vs/workbench/services/textMate/browser/backgroundTokenization/textMateWorkerTokenizerController.ts index 850b58e1e6c..2eb835fa2b6 100644 --- a/src/vs/workbench/services/textMate/browser/backgroundTokenization/textMateWorkerTokenizerController.ts @@ -1843,6 +1986,19 @@ index ad67fb4f422..fadf86cece5 100644 // ensure to limit buffer for guessing due to https://github.com/aadsm/jschardet/issues/53 const limitedBuffer = buffer.slice(0, AUTO_ENCODING_GUESS_MAX_BYTES); +diff --git a/src/vs/workbench/services/userDataProfile/common/remoteUserDataProfiles.ts b/src/vs/workbench/services/userDataProfile/common/remoteUserDataProfiles.ts +index d3ef612836b..0d0fb8d2862 100644 +--- a/src/vs/workbench/services/userDataProfile/common/remoteUserDataProfiles.ts ++++ b/src/vs/workbench/services/userDataProfile/common/remoteUserDataProfiles.ts +@@ -25,7 +25,7 @@ export interface IRemoteUserDataProfilesService { + getRemoteProfile(localProfile: IUserDataProfile): Promise; + } + +-class RemoteUserDataProfilesService extends Disposable implements IRemoteUserDataProfilesService { ++export class RemoteUserDataProfilesService extends Disposable implements IRemoteUserDataProfilesService { + + readonly _serviceBrand: undefined; + diff --git a/src/vs/workbench/services/workspaces/browser/abstractWorkspaceEditingService.ts b/src/vs/workbench/services/workspaces/browser/abstractWorkspaceEditingService.ts index 4653e395be9..1eccfce4bf4 100644 --- a/src/vs/workbench/services/workspaces/browser/abstractWorkspaceEditingService.ts diff --git a/src/extensions.ts b/src/extensions.ts index eb8e3310..0e25d570 100644 --- a/src/extensions.ts +++ b/src/extensions.ts @@ -13,8 +13,8 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ import { parse } from 'vs/base/common/json' import { IFileService } from 'vs/platform/files/common/files' import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation' -import { IExtensionWithExtHostKind, SimpleExtensionService, getLocalExtHostExtensionService } from './service-override/extensions' -import { registerExtensionFile } from './service-override/files' +import { IExtensionWithExtHostKind, ExtensionServiceOverride, getLocalExtHostExtensionService } from './service-override/extensions' +import { CustomSchemas, registerExtensionFile } from './service-override/files' import { setDefaultApi } from './api' import { getService } from './services' import { ExtensionManifestTranslator } from './tools/l10n' @@ -79,7 +79,7 @@ interface ExtensionDelta { toRemove: IExtension[] } const deltaExtensions = throttle(async ({ toAdd, toRemove }: ExtensionDelta) => { - const extensionService = await getService(IExtensionService) as SimpleExtensionService + const extensionService = await getService(IExtensionService) as ExtensionServiceOverride await extensionService.deltaExtensions(toAdd, toRemove) }, (a, b) => ({ toAdd: [...a.toAdd, ...b.toAdd], toRemove: [...a.toRemove, ...b.toRemove] }), 0) @@ -99,7 +99,7 @@ export function registerExtension (manifest: IExtensionManifest, extHostKind?: E export function registerExtension (manifest: IExtensionManifest, extHostKind?: ExtensionHostKind, { builtin = manifest.publisher === 'vscode', path = '/' }: RegisterExtensionParams = {}): RegisterExtensionResult { const disposableStore = new DisposableStore() const id = getExtensionId(manifest.publisher, manifest.name) - const location = URI.from({ scheme: 'extension', authority: id, path }) + const location = URI.from({ scheme: CustomSchemas.extensionFile, authority: id, path }) const addExtensionPromise = (async () => { const remoteAuthority = (await getService(IWorkbenchEnvironmentService)).remoteAuthority diff --git a/src/missing-services.ts b/src/missing-services.ts index c9c20826..6d6636d8 100644 --- a/src/missing-services.ts +++ b/src/missing-services.ts @@ -55,7 +55,7 @@ import { IEditSessionIdentityService } from 'vs/platform/workspace/common/editSe import { IWorkspaceEditingService } from 'vs/workbench/services/workspaces/common/workspaceEditing' import { ITimerService } from 'vs/workbench/services/timer/browser/timerService' import { IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/common/extensions' -import { EnablementState, IWorkbenchExtensionEnablementService, IWorkbenchExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement' +import { EnablementState, IExtensionManagementServerService, IWebExtensionsScannerService, IWorkbenchExtensionEnablementService, IWorkbenchExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement' import { ITunnelService } from 'vs/platform/tunnel/common/tunnel' import { IWorkingCopyBackupService } from 'vs/workbench/services/workingCopy/common/workingCopyBackup' import { IWorkingCopyService, WorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService' @@ -78,9 +78,8 @@ import { IEditorResolverService } from 'vs/workbench/services/editor/common/edit import { AbstractLifecycleService } from 'vs/workbench/services/lifecycle/common/lifecycleService' import { IOutputChannel, IOutputChannelDescriptor, IOutputService } from 'vs/workbench/services/output/common/output' import { IOutputChannelModelService, OutputChannelModelService } from 'vs/workbench/contrib/output/common/outputChannelModelService' -import { AbstractExtensionResourceLoaderService, IExtensionResourceLoaderService } from 'vs/platform/extensionResourceLoader/common/extensionResourceLoader' -import { IStorageService } from 'vs/platform/storage/common/storage' -import { IConfigurationService } from 'vs/platform/configuration/common/configuration' +import { IExtensionResourceLoaderService } from 'vs/platform/extensionResourceLoader/common/extensionResourceLoader' +import { ExtensionResourceLoaderService } from 'vs/platform/extensionResourceLoader/browser/extensionResourceLoaderService' import { IHoverService } from 'vs/workbench/services/hover/browser/hover' import { IExplorerService } from 'vs/workbench/contrib/files/browser/files' import { ExtensionStorageService, IExtensionStorageService } from 'vs/platform/extensionManagement/common/extensionStorage' @@ -93,7 +92,7 @@ import { IBreadcrumbsService } from 'vs/workbench/browser/parts/editor/breadcrum import { IOutlineService } from 'vs/workbench/services/outline/browser/outline' import { IUpdateService, State } from 'vs/platform/update/common/update' import { IStatusbarService } from 'vs/workbench/services/statusbar/browser/statusbar' -import { IExtensionGalleryService, IExtensionManagementService, ILocalExtension } from 'vs/platform/extensionManagement/common/extensionManagement' +import { IExtensionGalleryService, IExtensionManagementService, IExtensionTipsService, IGlobalExtensionEnablementService, ILocalExtension } from 'vs/platform/extensionManagement/common/extensionManagement' import { IModelService } from 'vs/editor/common/services/model' import { IDetachedTerminalInstance, ITerminalEditorService, ITerminalGroupService, ITerminalInstance, ITerminalInstanceService, ITerminalService, TerminalConnectionState } from 'vs/workbench/contrib/terminal/browser/terminal' import { ITerminalProfileResolverService, ITerminalProfileService } from 'vs/workbench/contrib/terminal/common/terminal' @@ -104,7 +103,7 @@ import { IEnvironmentVariableService } from 'vs/workbench/contrib/terminal/commo import { ITerminalQuickFixService } from 'vs/workbench/contrib/terminalContrib/quickFix/browser/quickFix' import { IPreferencesSearchService } from 'vs/workbench/contrib/preferences/common/preferences' import { AccountStatus, IUserDataSyncWorkbenchService } from 'vs/workbench/services/userDataSync/common/userDataSync' -import { IUserDataSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSync' +import { IUserDataAutoSyncService, IUserDataSyncEnablementService } from 'vs/platform/userDataSync/common/userDataSync' import { IKeybindingEditingService } from 'vs/workbench/services/keybinding/common/keybindingEditing' import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService' import { ISearchHistoryService } from 'vs/workbench/contrib/search/common/searchHistoryService' @@ -128,7 +127,7 @@ import { IEditorDropService } from 'vs/workbench/services/editor/browser/editorD import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver' import { ExternalUriOpenerService, IExternalUriOpenerService } from 'vs/workbench/contrib/externalUriOpener/common/externalUriOpenerService' import { IAccessibleViewService } from 'vs/workbench/contrib/accessibility/browser/accessibleView' -import { IExtension, IRelaxedExtensionDescription } from 'vs/platform/extensions/common/extensions' +import { IBuiltinExtensionsScannerService, IExtension, IRelaxedExtensionDescription } from 'vs/platform/extensions/common/extensions' import { IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService' import { IRemoteExtensionsScannerService } from 'vs/platform/remote/common/remoteExtensionsScanner' import { BrowserURLService } from 'vs/workbench/services/url/browser/urlService' @@ -171,10 +170,17 @@ import { BrowserHostService } from 'vs/workbench/services/host/browser/browserHo import { IBannerService } from 'vs/workbench/services/banner/browser/bannerService' import { ITitleService } from 'vs/workbench/services/title/common/titleService' import { IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents' +import { IActiveLanguagePackService, ILocaleService } from 'vs/workbench/services/localization/common/locale' import { joinPath } from 'vs/base/common/resources' +import { IExtensionIgnoredRecommendationsService, IExtensionRecommendationsService } from 'vs/workbench/services/extensionRecommendations/common/extensionRecommendations' +import { IIgnoredExtensionsManagementService } from 'vs/platform/userDataSync/common/ignoredExtensions' +import { IExtensionRecommendationNotificationService } from 'vs/platform/extensionRecommendations/common/extensionRecommendations' +import { IWorkspaceExtensionsConfigService } from 'vs/workbench/services/extensionRecommendations/common/workspaceExtensionsConfig' +import { IRemoteUserDataProfilesService } from 'vs/workbench/services/userDataProfile/common/remoteUserDataProfiles' +import { IExtensionBisectService } from 'vs/workbench/services/extensionManagement/browser/extensionBisect' +import { IUserDataSyncAccountService } from 'vs/platform/userDataSync/common/userDataSyncAccount' import { unsupported } from './tools' import { getBuiltInExtensionTranslationsUris } from './l10n' - class NullLoggerService extends AbstractLoggerService { constructor () { super(LogLevel.Info, URI.file('logs.log')) @@ -424,6 +430,7 @@ registerSingleton(IProductService, class ProductService implements IProductServi version = VSCODE_VERSION commit = VSCODE_REF + quality = 'oss' nameShort = 'Code - OSS Dev' nameLong = 'Code - OSS Dev' applicationName = 'code-oss' @@ -435,6 +442,13 @@ registerSingleton(IProductService, class ProductService implements IProductServi serverApplicationName = 'code-server-oss' }, InstantiationType.Eager) +registerSingleton(IExtensionTipsService, class ExtensionTipsService implements IExtensionTipsService { + readonly _serviceBrand = undefined + getConfigBasedTips = async () => [] + getImportantExecutableBasedTips = async () => [] + getOtherExecutableBasedTips = async () => [] +}, InstantiationType.Eager) + registerSingleton(ILanguageStatusService, class LanguageStatusServiceImpl implements ILanguageStatusService { declare _serviceBrand: undefined @@ -939,6 +953,93 @@ registerSingleton(IExtensionsWorkbenchService, class ExtensionsWorkbenchService toggleExtensionIgnoredToSync = unsupported }, InstantiationType.Eager) +registerSingleton(IExtensionManagementServerService, class ExtensionManagementServerService implements IExtensionManagementServerService { + _serviceBrand = undefined + localExtensionManagementServer = null + remoteExtensionManagementServer = null + webExtensionManagementServer = null + + getExtensionManagementServer (_extension: IExtension) { + return null + } + + getExtensionInstallLocation (_extension: IExtension) { + return null + } +}, InstantiationType.Eager) + +registerSingleton(IExtensionRecommendationsService, class ExtensionRecommendationsService implements IExtensionRecommendationsService { + _serviceBrand: undefined + onDidChangeRecommendations = Event.None + getAllRecommendationsWithReason = () => ({}) + getImportantRecommendations = async () => [] + getOtherRecommendations = async () => [] + getFileBasedRecommendations = () => [] + getExeBasedRecommendations = async () => ({ important: [], others: [] }) + getConfigBasedRecommendations = async () => ({ important: [], others: [] }) + getWorkspaceRecommendations = async () => [] + getKeymapRecommendations = () => [] + getLanguageRecommendations = () => [] + getRemoteRecommendations = () => [] +}, InstantiationType.Eager) +registerSingleton(IUserDataAutoSyncService, class UserDataAutoSyncService implements IUserDataAutoSyncService { + _serviceBrand: undefined + readonly onError = Event.None + turnOn = unsupported + turnOff = unsupported + triggerSync = unsupported +}, InstantiationType.Eager) + +registerSingleton(IIgnoredExtensionsManagementService, class IgnoredExtensionsManagementService implements IIgnoredExtensionsManagementService { + _serviceBrand: undefined + getIgnoredExtensions = () => [] + hasToNeverSyncExtension = () => false + hasToAlwaysSyncExtension = () => false + updateIgnoredExtensions = unsupported + updateSynchronizedExtensions = unsupported +}, InstantiationType.Eager) + +registerSingleton(IExtensionRecommendationNotificationService, class ExtensionRecommendationNotificationService implements IExtensionRecommendationNotificationService { + _serviceBrand: undefined + readonly ignoredRecommendations: string[] = [] + hasToIgnoreRecommendationNotifications = () => false + promptImportantExtensionsInstallNotification = unsupported + promptWorkspaceRecommendations = unsupported +}, InstantiationType.Eager) + +registerSingleton(IWebExtensionsScannerService, class WebExtensionsScannerService implements IWebExtensionsScannerService { + _serviceBrand: undefined + scanSystemExtensions = async () => [] + scanUserExtensions = async () => [] + scanExtensionsUnderDevelopment = async () => [] + scanExistingExtension = async () => null + addExtension = unsupported + addExtensionFromGallery = unsupported + removeExtension = async () => {} + copyExtensions = async () => {} + updateMetadata = unsupported + scanExtensionManifest = async () => null +}, InstantiationType.Eager) + +registerSingleton(IExtensionIgnoredRecommendationsService, class ExtensionIgnoredRecommendationsService implements IExtensionIgnoredRecommendationsService { + _serviceBrand: undefined + onDidChangeIgnoredRecommendations = Event.None + ignoredRecommendations = [] + onDidChangeGlobalIgnoredRecommendation = Event.None + globalIgnoredRecommendations = [] + toggleGlobalIgnoredRecommendation = unsupported +}, InstantiationType.Eager) + +registerSingleton(IWorkspaceExtensionsConfigService, class WorkspaceExtensionsConfigService implements IWorkspaceExtensionsConfigService { + _serviceBrand: undefined + onDidChangeExtensionsConfigs = Event.None + getExtensionsConfigs = unsupported + getRecommendations = unsupported + getUnwantedRecommendations = unsupported + toggleRecommendation = unsupported + toggleUnwantedRecommendation = unsupported +}, InstantiationType.Eager) + registerSingleton(IWorkbenchExtensionEnablementService, class WorkbenchExtensionEnablementService implements IWorkbenchExtensionEnablementService { _serviceBrand: undefined onEnablementChanged = Event.None @@ -1074,25 +1175,14 @@ registerSingleton(IOutputService, class OutputService implements IOutputService }, InstantiationType.Delayed) registerSingleton(IOutputChannelModelService, OutputChannelModelService, InstantiationType.Delayed) -class SimpleExtensionResourceLoaderService extends AbstractExtensionResourceLoaderService { - // required for injection - // eslint-disable-next-line @typescript-eslint/no-useless-constructor - constructor ( - @IFileService fileService: IFileService, - @IStorageService storageService: IStorageService, - @IProductService productService: IProductService, - @IEnvironmentService environmentService: IEnvironmentService, - @IConfigurationService configurationService: IConfigurationService - ) { - super(fileService, storageService, productService, environmentService, configurationService) - } +registerSingleton(IExtensionResourceLoaderService, ExtensionResourceLoaderService, InstantiationType.Eager) - async readExtensionResource (uri: URI): Promise { - const result = await this._fileService.readFile(uri) - return result.value.toString() +registerSingleton(IBuiltinExtensionsScannerService, class BuiltinExtensionsScannerService implements IBuiltinExtensionsScannerService { + _serviceBrand: undefined + scanBuiltinExtensions () { + return Promise.resolve([]) } -} -registerSingleton(IExtensionResourceLoaderService, SimpleExtensionResourceLoaderService, InstantiationType.Eager) +}, InstantiationType.Eager) registerSingleton(IHoverService, class HoverService implements IHoverService { showAndFocusLastHover = unsupported @@ -1123,6 +1213,22 @@ registerSingleton(IExplorerService, class ExplorerService implements IExplorerSe registerSingleton(IExtensionStorageService, ExtensionStorageService, InstantiationType.Delayed) +registerSingleton(IGlobalExtensionEnablementService, class GlobalExtensionEnablementService implements IGlobalExtensionEnablementService { + _serviceBrand: undefined + onDidChangeEnablement = Event.None + getDisabledExtensions () { + return [] + } + + enableExtension () { + return Promise.resolve(true) + } + + disableExtension () { + return Promise.resolve(true) + } +}, InstantiationType.Delayed) + registerSingleton(ILanguagePackService, class LanguagePackService implements ILanguagePackService { _serviceBrand: undefined async getAvailableLanguages (): Promise { @@ -1689,6 +1795,15 @@ registerSingleton(IWebviewViewService, class WebviewService implements IWebviewV resolve = unsupported }, InstantiationType.Delayed) +registerSingleton(ILocaleService, class LocaleService implements ILocaleService { + _serviceBrand: undefined + setLocale = unsupported + + clearLocalePreference () { + return Promise.resolve() + } +}, InstantiationType.Delayed) + registerSingleton(IWebviewWorkbenchService, class WebviewWorkbenchService implements IWebviewWorkbenchService { _serviceBrand: undefined get iconManager () { @@ -1927,6 +2042,39 @@ registerSingleton(IInteractiveDocumentService, class InteractiveDocumentService willRemoveInteractiveDocument = unsupported }, InstantiationType.Delayed) +registerSingleton(IActiveLanguagePackService, class ActiveLanguagePackService implements IActiveLanguagePackService { + readonly _serviceBrand: undefined + getExtensionIdProvidingCurrentLocale () { + return Promise.resolve(undefined) + } +}, InstantiationType.Eager) + +registerSingleton(IRemoteUserDataProfilesService, class RemoteUserDataProfilesService implements IRemoteUserDataProfilesService { + _serviceBrand: undefined + getRemoteProfiles = async () => [] + getRemoteProfile = unsupported +}, InstantiationType.Eager) + +registerSingleton(IExtensionBisectService, class ExtensionBisectService implements IExtensionBisectService { + _serviceBrand: undefined + isDisabledByBisect = () => false + isActive = false + disabledCount = 0 + start = unsupported + next = unsupported + reset = unsupported +}, InstantiationType.Eager) +registerSingleton(IUserDataSyncAccountService, class UserDataSyncAccountService implements IUserDataSyncAccountService { + _serviceBrand: undefined + + readonly onTokenFailed = Event.None + readonly account = undefined + readonly onDidChangeAccount = Event.None + updateAccount (): Promise { + return Promise.resolve() + } +}, InstantiationType.Eager) + registerSingleton(IInlineChatService, class InlineChatService implements IInlineChatService { onDidChangeProviders = Event.None _serviceBrand: undefined diff --git a/src/override/vs/base/common/semver/semver.ts b/src/override/vs/base/common/semver/semver.ts index 44de371f..cb7ee45b 100644 --- a/src/override/vs/base/common/semver/semver.ts +++ b/src/override/vs/base/common/semver/semver.ts @@ -1,5 +1 @@ -export const gte = (): boolean => false -export const gt = (): boolean => false -export const lt = (): boolean => false -export const lte = (): boolean => false -export const valid = (): boolean => false +export { gte, gt, lt, lte, valid, eq, rcompare } from 'vscode-semver' diff --git a/src/server/server-main.ts b/src/server/server-main.ts new file mode 100644 index 00000000..7952ad43 --- /dev/null +++ b/src/server/server-main.ts @@ -0,0 +1,127 @@ +import './server-assets' +import type { IServerAPI } from 'vs/server/node/remoteExtensionHostAgentServer' +import { createServer } from 'vs/server/node/server.main.js' +import { buildHelpMessage, buildVersionMessage, parseArgs } from 'vs/platform/environment/node/argv' +import { ServerParsedArgs, serverOptions } from 'vs/server/node/serverEnvironmentService' +import product from 'vs/platform/product/common/product' +import { AddressInfo, ListenOptions, Socket } from 'net' +import http from 'http' + +export async function start (options: ListenOptions): Promise { + let _remoteExtensionHostAgentServer: IServerAPI | null = null + let _remoteExtensionHostAgentServerPromise: Promise | null = null + const getRemoteExtensionHostAgentServer = (): Promise => { + if (_remoteExtensionHostAgentServerPromise == null) { + _remoteExtensionHostAgentServerPromise = createServer(address).then(server => { + _remoteExtensionHostAgentServer = server + return server + }) + } + return _remoteExtensionHostAgentServerPromise + } + + let address: AddressInfo | string | null = null + const server = http.createServer(async (req, res) => { + const remoteExtensionHostAgentServer = await getRemoteExtensionHostAgentServer() + return remoteExtensionHostAgentServer.handleRequest(req, res) + }) + server.on('upgrade', async (req, socket) => { + const remoteExtensionHostAgentServer = await getRemoteExtensionHostAgentServer() + return remoteExtensionHostAgentServer.handleUpgrade(req, socket) + }) + server.on('error', async (err) => { + const remoteExtensionHostAgentServer = await getRemoteExtensionHostAgentServer() + return remoteExtensionHostAgentServer.handleServerError(err) + }) + + server.listen(options, async () => { + address = server.address() + if (address === null) { + throw new Error('Unexpected server address') + } + + // eslint-disable-next-line no-console + console.log(`Server bound to ${typeof address === 'string' ? address : `${address.address}:${address.port} (${address.family})`}`) + + await getRemoteExtensionHostAgentServer() + }) + + process.on('exit', () => { + server.close() + if (_remoteExtensionHostAgentServer != null) { + _remoteExtensionHostAgentServer.dispose() + } + }) +} + +function parseRange (strRange: string) { + const match = strRange.match(/^(\d+)-(\d+)$/) + if (match != null) { + const start = parseInt(match[1]!, 10); const end = parseInt(match[2]!, 10) + if (start > 0 && start <= end && end <= 65535) { + return { start, end } + } + } + return undefined +} + +async function findFreePort (host: string, start: number, end: number) { + const testPort = (port: number) => { + return new Promise((resolve) => { + const server = http.createServer() + server.listen(port, host, () => { + server.close() + resolve(true) + }).on('error', () => { + resolve(false) + }) + }) + } + for (let port = start; port <= end; port++) { + if (await testPort(port)) { + return port + } + } + return undefined +} + +async function parsePort (host: string, strPort: string | undefined) { + if (strPort != null) { + let range + if (strPort.match(/^\d+$/) != null) { + return parseInt(strPort, 10) + } else if ((range = parseRange(strPort)) != null) { + const port = await findFreePort(host, range.start, range.end) + if (port !== undefined) { + return port + } + // Remote-SSH extension relies on this exact port error message, treat as an API + console.warn(`--port: Could not find free port in range: ${range.start} - ${range.end} (inclusive).`) + process.exit(1) + } else { + console.warn(`--port "${strPort}" is not a valid number or range. Ranges must be in the form 'from-to' with 'from' an integer larger than 0 and not larger than 'end'.`) + process.exit(1) + } + } + return 8000 +} + +const parsedArgs = parseArgs(process.argv.slice(2), serverOptions) +if (parsedArgs.help) { + const serverOptionsWithoutExtensionManagement = Object.fromEntries(Object.entries(serverOptions).filter(([, def]) => def.cat !== 'e')) + // eslint-disable-next-line no-console + console.log(buildHelpMessage(product.nameLong, 'vscode-ext-host-server', product.version, serverOptionsWithoutExtensionManagement, { noInputFiles: true, noPipe: true })) +} else if (parsedArgs.version) { + // eslint-disable-next-line no-console + console.log(buildVersionMessage(product.version, product.commit)) +} else { + const host = parsedArgs.host ?? 'localhost' + + const nodeListenOptions = ( + parsedArgs['socket-path'] != null + ? { path: parsedArgs['socket-path'] } + : { host, port: await parsePort(host, parsedArgs.port) } + ) + + void start(nodeListenOptions) +} diff --git a/src/server/server.ts b/src/server/server.ts index 7952ad43..212a6f97 100644 --- a/src/server/server.ts +++ b/src/server/server.ts @@ -1,127 +1,45 @@ -import './server-assets' -import type { IServerAPI } from 'vs/server/node/remoteExtensionHostAgentServer' -import { createServer } from 'vs/server/node/server.main.js' -import { buildHelpMessage, buildVersionMessage, parseArgs } from 'vs/platform/environment/node/argv' -import { ServerParsedArgs, serverOptions } from 'vs/server/node/serverEnvironmentService' -import product from 'vs/platform/product/common/product' -import { AddressInfo, ListenOptions, Socket } from 'net' -import http from 'http' - -export async function start (options: ListenOptions): Promise { - let _remoteExtensionHostAgentServer: IServerAPI | null = null - let _remoteExtensionHostAgentServerPromise: Promise | null = null - const getRemoteExtensionHostAgentServer = (): Promise => { - if (_remoteExtensionHostAgentServerPromise == null) { - _remoteExtensionHostAgentServerPromise = createServer(address).then(server => { - _remoteExtensionHostAgentServer = server - return server - }) - } - return _remoteExtensionHostAgentServerPromise - } - - let address: AddressInfo | string | null = null - const server = http.createServer(async (req, res) => { - const remoteExtensionHostAgentServer = await getRemoteExtensionHostAgentServer() - return remoteExtensionHostAgentServer.handleRequest(req, res) - }) - server.on('upgrade', async (req, socket) => { - const remoteExtensionHostAgentServer = await getRemoteExtensionHostAgentServer() - return remoteExtensionHostAgentServer.handleUpgrade(req, socket) - }) - server.on('error', async (err) => { - const remoteExtensionHostAgentServer = await getRemoteExtensionHostAgentServer() - return remoteExtensionHostAgentServer.handleServerError(err) - }) - - server.listen(options, async () => { - address = server.address() - if (address === null) { - throw new Error('Unexpected server address') - } - - // eslint-disable-next-line no-console - console.log(`Server bound to ${typeof address === 'string' ? address : `${address.address}:${address.port} (${address.family})`}`) - - await getRemoteExtensionHostAgentServer() - }) - - process.on('exit', () => { - server.close() - if (_remoteExtensionHostAgentServer != null) { - _remoteExtensionHostAgentServer.dispose() - } - }) +import { IProductService } from 'vs/platform/product/common/productService' +import * as fs from 'fs/promises' +import * as path from 'path' +import { fileURLToPath } from 'url' +import VSCODE_PACKAGE_JSON from '../../vscode/package.json' assert { type: 'json' } + +const thisWithVSCodeParams = globalThis as typeof globalThis & { + _VSCODE_PRODUCT_JSON: Partial + _VSCODE_PACKAGE_JSON: { version: string } } -function parseRange (strRange: string) { - const match = strRange.match(/^(\d+)-(\d+)$/) - if (match != null) { - const start = parseInt(match[1]!, 10); const end = parseInt(match[2]!, 10) - if (start > 0 && start <= end && end <= 65535) { - return { start, end } - } - } - return undefined +const WEB_ENDPOINT_URL_TEMPLATE = process.env.WEB_ENDPOINT_URL_TEMPLATE +if (WEB_ENDPOINT_URL_TEMPLATE == null) { + console.warn('No WEB_ENDPOINT_URL_TEMPLATE env variable set, the client won\'t be able to load server extension files') } -async function findFreePort (host: string, start: number, end: number) { - const testPort = (port: number) => { - return new Promise((resolve) => { - const server = http.createServer() - server.listen(port, host, () => { - server.close() - resolve(true) - }).on('error', () => { - resolve(false) - }) - }) - } - for (let port = start; port <= end; port++) { - if (await testPort(port)) { - return port - } +// Initialize the product information for the server, including the extension gallery URL. +thisWithVSCodeParams._VSCODE_PRODUCT_JSON = { + quality: 'oss', + commit: VSCODE_REF, + webEndpointUrlTemplate: WEB_ENDPOINT_URL_TEMPLATE, + extensionsGallery: { + serviceUrl: 'https://open-vsx.org/vscode/gallery', + itemUrl: 'https://open-vsx.org/vscode/item', + resourceUrlTemplate: 'https://open-vsx.org/vscode/unpkg/{publisher}/{name}/{version}/{path}', + controlUrl: '', + nlsBaseUrl: '', + publisherUrl: '' } - return undefined } +thisWithVSCodeParams._VSCODE_PACKAGE_JSON = VSCODE_PACKAGE_JSON -async function parsePort (host: string, strPort: string | undefined) { - if (strPort != null) { - let range - if (strPort.match(/^\d+$/) != null) { - return parseInt(strPort, 10) - } else if ((range = parseRange(strPort)) != null) { - const port = await findFreePort(host, range.start, range.end) - if (port !== undefined) { - return port - } - // Remote-SSH extension relies on this exact port error message, treat as an API - console.warn(`--port: Could not find free port in range: ${range.start} - ${range.end} (inclusive).`) - process.exit(1) - } else { - console.warn(`--port "${strPort}" is not a valid number or range. Ranges must be in the form 'from-to' with 'from' an integer larger than 0 and not larger than 'end'.`) - process.exit(1) - } - } - return 8000 +const PRODUCT_JSON_PATH = process.env.PRODUCT_JSON_PATH +if (PRODUCT_JSON_PATH != null) { + const productJson = await fs.readFile(PRODUCT_JSON_PATH, { encoding: 'utf8' }) + Object.assign(thisWithVSCodeParams._VSCODE_PRODUCT_JSON, JSON.parse(productJson)) } -const parsedArgs = parseArgs(process.argv.slice(2), serverOptions) -if (parsedArgs.help) { - const serverOptionsWithoutExtensionManagement = Object.fromEntries(Object.entries(serverOptions).filter(([, def]) => def.cat !== 'e')) - // eslint-disable-next-line no-console - console.log(buildHelpMessage(product.nameLong, 'vscode-ext-host-server', product.version, serverOptionsWithoutExtensionManagement, { noInputFiles: true, noPipe: true })) -} else if (parsedArgs.version) { - // eslint-disable-next-line no-console - console.log(buildVersionMessage(product.version, product.commit)) -} else { - const host = parsedArgs.host ?? 'localhost' - - const nodeListenOptions = ( - parsedArgs['socket-path'] != null - ? { path: parsedArgs['socket-path'] } - : { host, port: await parsePort(host, parsedArgs.port) } - ) +// Create a directory for system extensions to be installed in, VSCode +// will try to read this folder to find system extensions, and will +// error if it does not exist. +const currentDirPath = path.dirname(fileURLToPath(import.meta.url)) +await fs.mkdir(path.join(currentDirPath, 'extensions'), { recursive: true }) - void start(nodeListenOptions) -} +import('./server-main') diff --git a/src/service-override/extensionGallery.ts b/src/service-override/extensionGallery.ts new file mode 100644 index 00000000..06e6ef8c --- /dev/null +++ b/src/service-override/extensionGallery.ts @@ -0,0 +1,81 @@ +import { IEditorOverrideServices } from 'vs/editor/standalone/browser/standaloneServices' +import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors' +import { IExtensionGalleryService, IExtensionManagementService, IExtensionTipsService, IGlobalExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement' +import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService' +import { GlobalExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionEnablementService' +import { IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/common/extensions' +import { ExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/browser/extensionsWorkbenchService' +import { IExtensionManagementServerService, IWebExtensionsScannerService, IWorkbenchExtensionEnablementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement' +import { ExtensionManagementServerService } from 'vs/workbench/services/extensionManagement/common/extensionManagementServerService' +import { IExtensionIgnoredRecommendationsService, IExtensionRecommendationsService } from 'vs/workbench/services/extensionRecommendations/common/extensionRecommendations' +import { ExtensionRecommendationsService } from 'vs/workbench/contrib/extensions/browser/extensionRecommendationsService' +import { WebExtensionsScannerService } from 'vs/workbench/services/extensionManagement/browser/webExtensionsScannerService' +import { IExtensionRecommendationNotificationService } from 'vs/platform/extensionRecommendations/common/extensionRecommendations' +import { IIgnoredExtensionsManagementService, IgnoredExtensionsManagementService } from 'vs/platform/userDataSync/common/ignoredExtensions' +import { ExtensionManifestPropertiesService, IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService' +import { IBuiltinExtensionsScannerService } from 'vs/platform/extensions/common/extensions' +import { BuiltinExtensionsScannerService } from 'vs/workbench/services/extensionManagement/browser/builtinExtensionsScannerService' +import { ExtensionIgnoredRecommendationsService } from 'vs/workbench/services/extensionRecommendations/common/extensionIgnoredRecommendationsService' +import { IWorkspaceExtensionsConfigService, WorkspaceExtensionsConfigService } from 'vs/workbench/services/extensionRecommendations/common/workspaceExtensionsConfig' +import { IRemoteExtensionsScannerService } from 'vs/platform/remote/common/remoteExtensionsScanner' +import { RemoteExtensionsScannerService } from 'vs/workbench/services/remote/common/remoteExtensionsScanner' +import { ExtensionRecommendationNotificationService } from 'vs/workbench/contrib/extensions/browser/extensionRecommendationNotificationService' +import { ExtensionTipsService } from 'vs/platform/extensionManagement/common/extensionTipsService' +import { ExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/extensionManagementService' +import { IRemoteUserDataProfilesService, RemoteUserDataProfilesService } from 'vs/workbench/services/userDataProfile/common/remoteUserDataProfiles' +import { ExtensionEnablementService } from 'vs/workbench/services/extensionManagement/browser/extensionEnablementService' +import { IInstantiationService, ILabelService, IRemoteAgentService } from '../services' +import 'vs/workbench/contrib/extensions/browser/extensions.contribution' +import 'vs/workbench/contrib/extensions/browser/extensions.web.contribution' + +class ExtensionManagementServerServiceOverride extends ExtensionManagementServerService { + constructor ( + private isWebOnly: boolean, + @IRemoteAgentService readonly remoteAgentService: IRemoteAgentService, + @ILabelService readonly labelService: ILabelService, + @IInstantiationService readonly instantiationService: IInstantiationService + ) { + super(remoteAgentService, labelService, instantiationService) + + if (this.isWebOnly) { + /** + * If `isWebOnly` is set to true, we explicitly set the remote extension management server to `null`, even if + * we're connected to a remote server. + */ + // Cannot override read-only property, but this is the only way we can override it to be null, + // overriding the field doesn't work and setting a getter is not allowed. + // @ts-ignore + this.remoteExtensionManagementServer = null + } + } +} + +export interface ExtensionGalleryOptions { + /** + * Whether we should only allow for web extensions to be installed, this is generally + * true if there is no server part. + */ + webOnly: boolean +} + +export default function getServiceOverride (options: ExtensionGalleryOptions = { webOnly: false }): IEditorOverrideServices { + return { + [IExtensionGalleryService.toString()]: new SyncDescriptor(ExtensionGalleryService, [], true), + [IGlobalExtensionEnablementService.toString()]: new SyncDescriptor(GlobalExtensionEnablementService, [], true), + [IExtensionsWorkbenchService.toString()]: new SyncDescriptor(ExtensionsWorkbenchService, [], true), + [IExtensionManagementServerService.toString()]: new SyncDescriptor(ExtensionManagementServerServiceOverride, [options.webOnly], true), + [IExtensionRecommendationsService.toString()]: new SyncDescriptor(ExtensionRecommendationsService, [], true), + [IExtensionRecommendationNotificationService.toString()]: new SyncDescriptor(ExtensionRecommendationNotificationService, [], true), + [IWebExtensionsScannerService.toString()]: new SyncDescriptor(WebExtensionsScannerService, [], true), + [IExtensionIgnoredRecommendationsService.toString()]: new SyncDescriptor(ExtensionIgnoredRecommendationsService, [], true), + [IIgnoredExtensionsManagementService.toString()]: new SyncDescriptor(IgnoredExtensionsManagementService, [], true), + [IExtensionManifestPropertiesService.toString()]: new SyncDescriptor(ExtensionManifestPropertiesService, [], true), + [IExtensionManagementService.toString()]: new SyncDescriptor(ExtensionManagementService, [], true), + [IBuiltinExtensionsScannerService.toString()]: new SyncDescriptor(BuiltinExtensionsScannerService, [], true), + [IWorkspaceExtensionsConfigService.toString()]: new SyncDescriptor(WorkspaceExtensionsConfigService, [], true), + [IRemoteExtensionsScannerService.toString()]: new SyncDescriptor(RemoteExtensionsScannerService, [], true), + [IExtensionTipsService.toString()]: new SyncDescriptor(ExtensionTipsService, [], true), + [IRemoteUserDataProfilesService.toString()]: new SyncDescriptor(RemoteUserDataProfilesService, [], true), + [IWorkbenchExtensionEnablementService.toString()]: new SyncDescriptor(ExtensionEnablementService, [], true) + } +} diff --git a/src/service-override/extensions.ts b/src/service-override/extensions.ts index 44f6087a..011e40dd 100644 --- a/src/service-override/extensions.ts +++ b/src/service-override/extensions.ts @@ -1,19 +1,19 @@ import { IFileService } from 'vs/platform/files/common/files' -import { ILifecycleService, LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle' +import { ILifecycleService } from 'vs/workbench/services/lifecycle/common/lifecycle' import { ExtensionHostExtensions, ExtensionHostStartup, IExtensionHost, IExtensionService, nullExtensionDescription, toExtensionDescription } from 'vs/workbench/services/extensions/common/extensions' import { ILogService, ILoggerService } from 'vs/platform/log/common/log' import { ExtensionIdentifier, ExtensionIdentifierMap, IExtension, IExtensionDescription, IRelaxedExtensionDescription } from 'vs/platform/extensions/common/extensions' import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace' import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation' import { INotificationService } from 'vs/platform/notification/common/notification' -import { AbstractExtensionService, DeltaExtensionsQueueItem, ResolvedExtensions } from 'vs/workbench/services/extensions/common/abstractExtensionService' +import { DeltaExtensionsQueueItem } from 'vs/workbench/services/extensions/common/abstractExtensionService' import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry' import { Event } from 'vs/base/common/event' import { IDialogService } from 'vs/platform/dialogs/common/dialogs' -import { IRemoteAuthorityResolverService, ResolverResult } from 'vs/platform/remote/common/remoteAuthorityResolver' +import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver' import { IRemoteExtensionsScannerService } from 'vs/platform/remote/common/remoteExtensionsScanner' import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService' -import { IWorkbenchExtensionEnablementService, IWorkbenchExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement' +import { IWebExtensionsScannerService, IWorkbenchExtensionEnablementService, IWorkbenchExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement' import { ExtensionManifestPropertiesService, IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService' import { IConfigurationService } from 'vs/platform/configuration/common/configuration' import { IProductService } from 'vs/platform/product/common/productService' @@ -22,9 +22,7 @@ import { IEditorOverrideServices } from 'vs/editor/standalone/browser/standalone import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors' import { IUserDataInitializationService } from 'vs/workbench/services/userData/browser/userDataInit' import { ExtensionsProposedApi } from 'vs/workbench/services/extensions/common/extensionsProposedApi' -import { BrowserExtensionHostFactory, BrowserExtensionHostKindPicker } from 'vs/workbench/services/extensions/browser/extensionService' -import { FetchFileSystemProvider } from 'vs/workbench/services/extensions/browser/webWorkerFileSystemProvider' -import { Schemas } from 'vs/base/common/network' +import { BrowserExtensionHostFactory, BrowserExtensionHostKindPicker, ExtensionService } from 'vs/workbench/services/extensions/browser/extensionService' import { ExtensionHostKind, ExtensionRunningPreference } from 'vs/workbench/services/extensions/common/extensionHostKind' import { ExtensionRunningLocation, LocalProcessRunningLocation, LocalWebWorkerRunningLocation } from 'vs/workbench/services/extensions/common/extensionRunningLocation' import { ExtensionRunningLocationTracker } from 'vs/workbench/services/extensions/common/extensionRunningLocationTracker' @@ -49,8 +47,12 @@ import { ILayoutService } from 'vs/platform/layout/browser/layoutService' import { IStorageService } from 'vs/platform/storage/common/storage' import { ILabelService } from 'vs/platform/label/common/label' import { ExtensionKind } from 'vs/platform/environment/common/environment' +import { IUserDataProfileService } from 'vs/workbench/services/userDataProfile/common/userDataProfile' +import { IWorkspaceTrustManagementService } from 'vs/platform/workspace/common/workspaceTrust' +import { IRemoteExplorerService } from 'vs/workbench/services/remote/common/remoteExplorerService' import { ExtensionDescriptionRegistrySnapshot } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry' import { changeUrlDomain } from './tools/url' +import { CustomSchemas } from './files' import { registerAssets } from '../assets' import { unsupported } from '../tools' import 'vs/workbench/api/browser/extensionHost.contribution' @@ -360,7 +362,7 @@ export interface IExtensionWithExtHostKind extends IExtension { extHostKind?: ExtensionHostKind } -export class SimpleExtensionService extends AbstractExtensionService implements IExtensionService { +export class ExtensionServiceOverride extends ExtensionService implements IExtensionService { constructor ( workerConfig: WorkerConfig | undefined, @IInstantiationService instantiationService: IInstantiationService, @@ -374,19 +376,23 @@ export class SimpleExtensionService extends AbstractExtensionService implements @IWorkspaceContextService contextService: IWorkspaceContextService, @IConfigurationService configurationService: IConfigurationService, @IExtensionManifestPropertiesService extensionManifestPropertiesService: IExtensionManifestPropertiesService, + @IWebExtensionsScannerService webExtensionsScannerService: IWebExtensionsScannerService, @ILogService logService: ILogService, @IRemoteAgentService remoteAgentService: IRemoteAgentService, @IRemoteExtensionsScannerService remoteExtensionsScannerService: IRemoteExtensionsScannerService, @ILifecycleService lifecycleService: ILifecycleService, @IRemoteAuthorityResolverService remoteAuthorityResolverService: IRemoteAuthorityResolverService, @IUserDataInitializationService userDataInitializationService: IUserDataInitializationService, + @IUserDataProfileService userDataProfileService: IUserDataProfileService, + @IWorkspaceTrustManagementService workspaceTrustManagementService: IWorkspaceTrustManagementService, + @IRemoteExplorerService remoteExplorerService: IRemoteExplorerService, @IDialogService dialogService: IDialogService ) { const extensionsProposedApi = instantiationService.createInstance(ExtensionsProposedApi) const extensionHostFactory = new LocalBrowserExtensionHostFactory( workerConfig, extensionsProposedApi, - async () => [], + async () => this._scanWebExtensions(), () => this._getExtensionRegistrySnapshotWhenReady(), instantiationService, remoteAgentService, @@ -409,27 +415,18 @@ export class SimpleExtensionService extends AbstractExtensionService implements contextService, configurationService, extensionManifestPropertiesService, + webExtensionsScannerService, logService, remoteAgentService, remoteExtensionsScannerService, lifecycleService, remoteAuthorityResolverService, + userDataInitializationService, + userDataProfileService, + workspaceTrustManagementService, + remoteExplorerService, dialogService ) - - // Initialize installed extensions first and do it only after workbench is ready - void lifecycleService.when(LifecyclePhase.Ready).then(async () => { - await userDataInitializationService.initializeInstalledExtensions(instantiationService) - return this._initialize() - }) - - this._initFetchFileSystem() - } - - private _initFetchFileSystem (): void { - const provider = new FetchFileSystemProvider() - this._register(this._fileService.registerProvider(Schemas.http, provider)) - this._register(this._fileService.registerProvider(Schemas.https, provider)) } public async deltaExtensions (toAdd: IExtensionWithExtHostKind[], toRemove: IExtension[]): Promise { @@ -446,21 +443,11 @@ export class SimpleExtensionService extends AbstractExtensionService implements await this._handleDeltaExtensions(new DeltaExtensionsQueueItem(toAdd, toRemove)) } - protected override async _resolveExtensions (): Promise { - return new ResolvedExtensions([], [], false, false) - } - protected override async _scanSingleExtension (extension: IExtension): Promise | null> { - return toExtensionDescription(extension) - } - - protected _onExtensionHostExit (): void { - // Dispose everything associated with the extension host - this._doStopExtensionHosts() - } - - protected _resolveAuthority (remoteAuthority: string): Promise { - return this._resolveAuthorityOnExtensionHosts(ExtensionHostKind.LocalWebWorker, remoteAuthority) + if (extension.location.scheme === CustomSchemas.extensionFile) { + return toExtensionDescription(extension) + } + return super._scanSingleExtension(extension) } } @@ -481,7 +468,7 @@ export default function getServiceOverride (workerConfig?: WorkerConfig, _iframe : undefined return { - [IExtensionService.toString()]: new SyncDescriptor(SimpleExtensionService, [_workerConfig], false), + [IExtensionService.toString()]: new SyncDescriptor(ExtensionServiceOverride, [_workerConfig], false), [IExtensionManifestPropertiesService.toString()]: new SyncDescriptor(ExtensionManifestPropertiesService, [], true) } } diff --git a/src/service-override/files.ts b/src/service-override/files.ts index 7c341f9b..02580dae 100644 --- a/src/service-override/files.ts +++ b/src/service-override/files.ts @@ -516,12 +516,20 @@ const userDataFileSystemProvider = new InMemoryFileSystemProvider() // The `mkdirp` logic is inside the service, and the provider will just fail if asked to write a file in a non-existent directory void userDataFileSystemProvider.mkdir(URI.from({ scheme: Schemas.vscodeUserData, path: '/User/' })) +export namespace CustomSchemas { + /** + * A schema that is used for models that exist in memory + * only and that have no correspondence on a server or such. + */ + export const extensionFile = 'extension-file' +} + const providers: Record = { - extension: extensionFileSystemProvider, + [CustomSchemas.extensionFile]: extensionFileSystemProvider, [logsPath.scheme]: new InMemoryFileSystemProvider(), [Schemas.vscodeUserData]: userDataFileSystemProvider, [Schemas.tmp]: new InMemoryFileSystemProvider(), - file: fileSystemProvider + [Schemas.file]: fileSystemProvider } class MemoryFileService extends FileService { diff --git a/src/services.ts b/src/services.ts index 7fc9a067..f17c55d4 100644 --- a/src/services.ts +++ b/src/services.ts @@ -11,6 +11,7 @@ import { IAction } from 'vs/base/common/actions' import { IProductService } from 'vs/platform/product/common/productService' import { DisposableStore, IDisposable } from 'vs/base/common/lifecycle' import { IWorkbenchConstructionOptions } from 'vs/workbench/browser/web.api' +import { IProductConfiguration } from 'vs/base/common/product' import getLayoutServiceOverride from './service-override/layout' import getEnvironmentServiceOverride from './service-override/environment' import getExtensionsServiceOverride from './service-override/extensions' @@ -25,8 +26,9 @@ export async function initialize (overrides: IEditorOverrideServices, container: initializeWorkbench(container, configuration) const instantiationService = StandaloneServices.initialize({ - [IProductService.toString()]: mixin({ + [IProductService.toString()]: mixin(>{ version: VSCODE_VERSION, + quality: 'oss', commit: VSCODE_REF, nameShort: 'Code - OSS Dev', nameLong: 'Code - OSS Dev',