diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index cf63cbaf3e2..7faad37bebc 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -56,7 +56,6 @@ import { serve as serveDriver } from 'vs/platform/driver/electron-main/driver'; import { IMenubarService } from 'vs/platform/menubar/node/menubar'; import { MenubarService } from 'vs/platform/menubar/electron-main/menubarService'; import { MenubarChannel } from 'vs/platform/menubar/node/menubarIpc'; -import { hasArgs } from 'vs/platform/environment/node/argv'; import { RunOnceScheduler } from 'vs/base/common/async'; import { registerContextMenuListener } from 'vs/base/parts/contextmenu/electron-main/contextmenu'; import { homedir } from 'os'; @@ -616,9 +615,9 @@ export class CodeApplication extends Disposable { // Open our first window const macOpenFiles: string[] = (global).macOpenFiles; const context = !!process.env['VSCODE_CLI'] ? OpenContext.CLI : OpenContext.DESKTOP; - const hasCliArgs = hasArgs(args._); - const hasFolderURIs = hasArgs(args['folder-uri']); - const hasFileURIs = hasArgs(args['file-uri']); + const hasCliArgs = args._.length; + const hasFolderURIs = !!args['folder-uri']; + const hasFileURIs = !!args['file-uri']; const noRecentEntry = args['skip-add-to-recently-opened'] === true; const waitMarkerFileURI = args.wait && args.waitMarkerFilePath ? URI.file(args.waitMarkerFilePath) : undefined; diff --git a/src/vs/code/electron-main/windows.ts b/src/vs/code/electron-main/windows.ts index c7cdbd794e0..8541606e61a 100644 --- a/src/vs/code/electron-main/windows.ts +++ b/src/vs/code/electron-main/windows.ts @@ -12,7 +12,6 @@ import { IBackupMainService, IEmptyWindowBackupInfo } from 'vs/platform/backup/c import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment'; import { IStateService } from 'vs/platform/state/common/state'; import { CodeWindow, defaultWindowState } from 'vs/code/electron-main/window'; -import { hasArgs, asArray } from 'vs/platform/environment/node/argv'; import { ipcMain as ipc, screen, BrowserWindow, dialog, systemPreferences, FileFilter } from 'electron'; import { parseLineAndColumnAware } from 'vs/code/node/paths'; import { ILifecycleService, UnloadReason, LifecycleService, LifecycleMainPhase } from 'vs/platform/lifecycle/electron-main/lifecycleMain'; @@ -450,7 +449,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { // Make sure to pass focus to the most relevant of the windows if we open multiple if (usedWindows.length > 1) { - const focusLastActive = this.windowsState.lastActiveWindow && !openConfig.forceEmpty && !hasArgs(openConfig.cli._) && !hasArgs(openConfig.cli['file-uri']) && !hasArgs(openConfig.cli['folder-uri']) && !(openConfig.urisToOpen && openConfig.urisToOpen.length); + const focusLastActive = this.windowsState.lastActiveWindow && !openConfig.forceEmpty && openConfig.cli._.length && !openConfig.cli['file-uri'] && !openConfig.cli['folder-uri'] && !(openConfig.urisToOpen && openConfig.urisToOpen.length); let focusLastOpened = true; let focusLastWindow = true; @@ -811,7 +810,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { } // Extract paths: from CLI - else if (hasArgs(openConfig.cli._) || hasArgs(openConfig.cli['folder-uri']) || hasArgs(openConfig.cli['file-uri'])) { + else if (openConfig.cli._.length || openConfig.cli['folder-uri'] || openConfig.cli['file-uri']) { windowsToOpen = this.doExtractPathsFromCLI(openConfig.cli); isCommandLineOrAPICall = true; } @@ -885,31 +884,36 @@ export class WindowsManager extends Disposable implements IWindowsMainService { const parseOptions: IPathParseOptions = { ignoreFileNotFound: true, gotoLineMode: cli.goto, remoteAuthority: cli.remote || undefined }; // folder uris - const folderUris = asArray(cli['folder-uri']); - for (let f of folderUris) { - const folderUri = this.argToUri(f); - if (folderUri) { - const path = this.parseUri({ folderUri }, parseOptions); - if (path) { - pathsToOpen.push(path); + const folderUris = cli['folder-uri']; + if (folderUris) { + for (let f of folderUris) { + const folderUri = this.argToUri(f); + if (folderUri) { + const path = this.parseUri({ folderUri }, parseOptions); + if (path) { + pathsToOpen.push(path); + } } } } + // file uris - const fileUris = asArray(cli['file-uri']); - for (let f of fileUris) { - const fileUri = this.argToUri(f); - if (fileUri) { - const path = this.parseUri(hasWorkspaceFileExtension(f) ? { workspaceUri: fileUri } : { fileUri }, parseOptions); - if (path) { - pathsToOpen.push(path); + const fileUris = cli['file-uri']; + if (fileUris) { + for (let f of fileUris) { + const fileUri = this.argToUri(f); + if (fileUri) { + const path = this.parseUri(hasWorkspaceFileExtension(f) ? { workspaceUri: fileUri } : { fileUri }, parseOptions); + if (path) { + pathsToOpen.push(path); + } } } } // folder or file paths - const cliArgs = asArray(cli._); + const cliArgs = cli._; for (let cliArg of cliArgs) { const path = this.parsePath(cliArg, parseOptions); if (path) { @@ -1178,8 +1182,8 @@ export class WindowsManager extends Disposable implements IWindowsMainService { return; } - let folderUris = asArray(openConfig.cli['folder-uri']); - let fileUris = asArray(openConfig.cli['file-uri']); + let folderUris = openConfig.cli['folder-uri'] || []; + let fileUris = openConfig.cli['file-uri'] || []; let cliArgs = openConfig.cli._; // Fill in previously opened workspace unless an explicit path is provided and we are not unit testing diff --git a/src/vs/platform/environment/common/environment.ts b/src/vs/platform/environment/common/environment.ts index cfb931c013e..338a392f360 100644 --- a/src/vs/platform/environment/common/environment.ts +++ b/src/vs/platform/environment/common/environment.ts @@ -8,8 +8,8 @@ import { URI } from 'vs/base/common/uri'; export interface ParsedArgs { _: string[]; - 'folder-uri'?: string | string[]; - 'file-uri'?: string | string[]; + 'folder-uri'?: string[]; + 'file-uri'?: string[]; _urls?: string[]; help?: boolean; version?: boolean; @@ -36,7 +36,7 @@ export interface ParsedArgs { logExtensionHostCommunication?: boolean; 'extensions-dir'?: string; 'builtin-extensions-dir'?: string; - extensionDevelopmentPath?: string | string[]; // one or more local paths or URIs + extensionDevelopmentPath?: string[]; // one or more local paths or URIs extensionTestsPath?: string; // either a local path or a URI 'extension-development-confirm-save'?: boolean; 'inspect-extensions'?: string; @@ -45,14 +45,14 @@ export interface ParsedArgs { 'inspect-search'?: string; 'inspect-brk-search'?: string; 'disable-extensions'?: boolean; - 'disable-extension'?: string | string[]; + 'disable-extension'?: string[]; 'list-extensions'?: boolean; 'show-versions'?: boolean; 'category'?: string; - 'install-extension'?: string | string[]; - 'uninstall-extension'?: string | string[]; - 'locate-extension'?: string | string[]; - 'enable-proposed-api'?: string | string[]; + 'install-extension'?: string[]; + 'uninstall-extension'?: string[]; + 'locate-extension'?: string[]; + 'enable-proposed-api'?: string[]; 'open-url'?: boolean; 'skip-getting-started'?: boolean; 'skip-release-notes'?: boolean; diff --git a/src/vs/platform/environment/node/argv.ts b/src/vs/platform/environment/node/argv.ts index 5e22e54d396..3d6d64e3910 100644 --- a/src/vs/platform/environment/node/argv.ts +++ b/src/vs/platform/environment/node/argv.ts @@ -22,7 +22,7 @@ const helpCategories = { export interface Option { id: keyof ParsedArgs; - type: 'boolean' | 'string'; + type: 'boolean' | 'string' | 'string[]'; alias?: string; deprecates?: string; // old deprecated id args?: string | string[]; @@ -42,23 +42,23 @@ export const options: Option[] = [ { id: 'version', type: 'boolean', cat: 'o', alias: 'v', description: localize('version', "Print version.") }, { id: 'help', type: 'boolean', cat: 'o', alias: 'h', description: localize('help', "Print usage.") }, { id: 'telemetry', type: 'boolean', cat: 'o', description: localize('telemetry', "Shows all telemetry events which VS code collects.") }, - { id: 'folder-uri', type: 'string', cat: 'o', args: 'uri', description: localize('folderUri', "Opens a window with given folder uri(s)") }, - { id: 'file-uri', type: 'string', cat: 'o', args: 'uri', description: localize('fileUri', "Opens a window with given file uri(s)") }, + { id: 'folder-uri', type: 'string[]', cat: 'o', args: 'uri', description: localize('folderUri', "Opens a window with given folder uri(s)") }, + { id: 'file-uri', type: 'string[]', cat: 'o', args: 'uri', description: localize('fileUri', "Opens a window with given file uri(s)") }, { id: 'extensions-dir', type: 'string', deprecates: 'extensionHomePath', cat: 'e', args: 'dir', description: localize('extensionHomePath', "Set the root path for extensions.") }, { id: 'list-extensions', type: 'boolean', cat: 'e', description: localize('listExtensions', "List the installed extensions.") }, { id: 'show-versions', type: 'boolean', cat: 'e', description: localize('showVersions', "Show versions of installed extensions, when using --list-extension.") }, { id: 'category', type: 'string', cat: 'e', description: localize('category', "Filters installed extensions by provided category, when using --list-extension.") }, - { id: 'install-extension', type: 'string', cat: 'e', args: 'extension-id | path-to-vsix', description: localize('installExtension', "Installs or updates the extension. Use `--force` argument to avoid prompts.") }, - { id: 'uninstall-extension', type: 'string', cat: 'e', args: 'extension-id', description: localize('uninstallExtension', "Uninstalls an extension.") }, - { id: 'enable-proposed-api', type: 'string', cat: 'e', args: 'extension-id', description: localize('experimentalApis', "Enables proposed API features for extensions. Can receive one or more extension IDs to enable individually.") }, + { id: 'install-extension', type: 'string[]', cat: 'e', args: 'extension-id | path-to-vsix', description: localize('installExtension', "Installs or updates the extension. Use `--force` argument to avoid prompts.") }, + { id: 'uninstall-extension', type: 'string[]', cat: 'e', args: 'extension-id', description: localize('uninstallExtension', "Uninstalls an extension.") }, + { id: 'enable-proposed-api', type: 'string[]', cat: 'e', args: 'extension-id', description: localize('experimentalApis', "Enables proposed API features for extensions. Can receive one or more extension IDs to enable individually.") }, { id: 'verbose', type: 'boolean', cat: 't', description: localize('verbose', "Print verbose output (implies --wait).") }, { id: 'log', type: 'string', cat: 't', args: 'level', description: localize('log', "Log level to use. Default is 'info'. Allowed values are 'critical', 'error', 'warn', 'info', 'debug', 'trace', 'off'.") }, { id: 'status', type: 'boolean', alias: 's', cat: 't', description: localize('status', "Print process usage and diagnostics information.") }, { id: 'prof-startup', type: 'boolean', cat: 't', description: localize('prof-startup', "Run CPU profiler during startup") }, { id: 'disable-extensions', type: 'boolean', deprecates: 'disableExtensions', cat: 't', description: localize('disableExtensions', "Disable all installed extensions.") }, - { id: 'disable-extension', type: 'string', cat: 't', args: 'extension-id', description: localize('disableExtension', "Disable an extension.") }, + { id: 'disable-extension', type: 'string[]', cat: 't', args: 'extension-id', description: localize('disableExtension', "Disable an extension.") }, { id: 'inspect-extensions', type: 'string', deprecates: 'debugPluginHost', args: 'port', cat: 't', description: localize('inspect-extensions', "Allow debugging and profiling of extensions. Check the developer tools for the connection URI.") }, { id: 'inspect-brk-extensions', type: 'string', deprecates: 'debugBrkPluginHost', args: 'port', cat: 't', description: localize('inspect-brk-extensions', "Allow debugging and profiling of extensions with the extension host being paused after start. Check the developer tools for the connection URI.") }, @@ -66,8 +66,8 @@ export const options: Option[] = [ { id: 'max-memory', type: 'string', cat: 't', description: localize('maxMemory', "Max memory size for a window (in Mbytes).") }, { id: 'remote', type: 'string' }, - { id: 'locate-extension', type: 'string' }, - { id: 'extensionDevelopmentPath', type: 'string' }, + { id: 'locate-extension', type: 'string[]' }, + { id: 'extensionDevelopmentPath', type: 'string[]' }, { id: 'extensionTestsPath', type: 'string' }, { id: 'extension-development-confirm-save', type: 'boolean' }, { id: 'debugId', type: 'string' }, @@ -110,7 +110,7 @@ export function parseArgs(args: string[], isOptionSupported = (_: Option) => tru } } - if (o.type === 'string') { + if (o.type === 'string' || o.type === 'string[]') { string.push(o.id); if (o.deprecates) { string.push(o.deprecates); @@ -132,6 +132,12 @@ export function parseArgs(args: string[], isOptionSupported = (_: Option) => tru parsedArgs[o.id] = parsedArgs[o.deprecates]; delete parsedArgs[o.deprecates]; } + if (o.type === 'string[]') { + const val = parsedArgs[o.id]; + if (val && !Array.isArray(val)) { + parsedArgs[o.id] = [val]; + } + } } // https://github.com/microsoft/vscode/issues/58177 @@ -224,32 +230,6 @@ export function buildVersionMessage(version: string | undefined, commit: string return `${version || localize('unknownVersion', "Unknown version")}\n${commit || localize('unknownCommit', "Unknown commit")}\n${process.arch}`; } -/** - * Converts an argument into an array - * @param arg a argument value. Can be undefined, an entry or an array - */ -export function asArray(arg: string | string[] | undefined): string[] { - if (arg) { - if (Array.isArray(arg)) { - return arg; - } - return [arg]; - } - return []; -} - -/** - * Returns whether an argument is present. - */ -export function hasArgs(arg: string | string[] | undefined): boolean { - if (arg) { - if (Array.isArray(arg)) { - return !!arg.length; - } - return true; - } - return false; -} export function addArg(argv: string[], ...args: string[]): string[] { const endOfArgsMarkerIndex = argv.indexOf('--'); diff --git a/src/vs/platform/launch/electron-main/launchService.ts b/src/vs/platform/launch/electron-main/launchService.ts index 19e396d6052..876d2198d1f 100644 --- a/src/vs/platform/launch/electron-main/launchService.ts +++ b/src/vs/platform/launch/electron-main/launchService.ts @@ -17,7 +17,6 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { URI } from 'vs/base/common/uri'; import { BrowserWindow, ipcMain, Event as IpcEvent, app } from 'electron'; import { Event } from 'vs/base/common/event'; -import { hasArgs } from 'vs/platform/environment/node/argv'; import { coalesce } from 'vs/base/common/arrays'; import { IDiagnosticInfoOptions, IDiagnosticInfo, IRemoteDiagnosticInfo, IRemoteDiagnosticError } from 'vs/platform/diagnostics/common/diagnostics'; import { IMainProcessInfo, IWindowInfo } from 'vs/platform/launch/common/launchService'; @@ -173,7 +172,7 @@ export class LaunchService implements ILaunchService { } // Start without file/folder arguments - else if (!hasArgs(args._) && !hasArgs(args['folder-uri']) && !hasArgs(args['file-uri'])) { + else if (!args._.length && !args['folder-uri'] && !args['file-uri']) { let openNewWindow = false; // Force new window diff --git a/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts b/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts index d8ad2212ace..d8037ae2470 100644 --- a/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts +++ b/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts @@ -583,13 +583,9 @@ export class RawDebugSession { const v = args[key]; if (v) { - if (Array.isArray(v)) { - v.push(value); - } else { - args[key] = [v, value]; - } + v.push(value); } else { - args[key] = value; + args[key] = [value]; } } else {