Merge from vscode 5e80bf449c995aa32a59254c0ff845d37da11b70 (#9317)

This commit is contained in:
Anthony Dresser
2020-02-24 21:15:52 -08:00
committed by GitHub
parent 628fd8d74d
commit 4a9c47d3d6
93 changed files with 3109 additions and 813 deletions

View File

@@ -24,7 +24,7 @@ import { ILogService } from 'vs/platform/log/common/log';
import { IStateService } from 'vs/platform/state/node/state';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IURLService, IOpenURLOptions } from 'vs/platform/url/common/url';
import { IURLService } from 'vs/platform/url/common/url';
import { URLHandlerChannelClient, URLHandlerRouter } from 'vs/platform/url/common/urlIpc';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { NullTelemetryService, combinedAppender, LogAppender } from 'vs/platform/telemetry/common/telemetryUtils';
@@ -73,10 +73,10 @@ import { IDiagnosticsService } from 'vs/platform/diagnostics/node/diagnosticsSer
import { ExtensionHostDebugBroadcastChannel } from 'vs/platform/debug/common/extensionHostDebugIpc';
import { IElectronMainService, ElectronMainService } from 'vs/platform/electron/electron-main/electronMainService';
import { ISharedProcessMainService, SharedProcessMainService } from 'vs/platform/ipc/electron-main/sharedProcessMainService';
import { assign } from 'vs/base/common/objects';
import { IDialogMainService, DialogMainService } from 'vs/platform/dialogs/electron-main/dialogs';
import { withNullAsUndefined } from 'vs/base/common/types';
import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv';
import { coalesce } from 'vs/base/common/arrays';
export class CodeApplication extends Disposable {
@@ -395,7 +395,7 @@ export class CodeApplication extends Disposable {
const windows = appInstantiationService.invokeFunction(accessor => this.openFirstWindow(accessor, electronIpcServer, sharedProcessClient));
// Post Open Windows Tasks
appInstantiationService.invokeFunction(this.afterWindowOpen.bind(this));
appInstantiationService.invokeFunction(accessor => this.afterWindowOpen(accessor));
// Tracing: Stop tracing after windows are ready if enabled
if (this.environmentService.args.trace) {
@@ -575,9 +575,8 @@ export class CodeApplication extends Disposable {
electronIpcServer.registerChannel('logger', loggerChannel);
sharedProcessClient.then(client => client.registerChannel('logger', loggerChannel));
const windowsMainService = this.windowsMainService = accessor.get(IWindowsMainService);
// ExtensionHost Debug broadcast service
const windowsMainService = this.windowsMainService = accessor.get(IWindowsMainService);
electronIpcServer.registerChannel(ExtensionHostDebugBroadcastChannel.ChannelName, new ElectronExtensionHostDebugBroadcastChannel(windowsMainService));
// Signal phase: ready (services set)
@@ -586,47 +585,67 @@ export class CodeApplication extends Disposable {
// Propagate to clients
this.dialogMainService = accessor.get(IDialogMainService);
// Create a URL handler to open file URIs in the active window
// Check for initial URLs to handle from protocol link invocations
const environmentService = accessor.get(IEnvironmentService);
const pendingWindowOpenablesFromProtocolLinks: IWindowOpenable[] = [];
const pendingProtocolLinksToHandle = coalesce([
// Windows/Linux: protocol handler invokes CLI with --open-url
...environmentService.args['open-url'] ? environmentService.args._urls || [] : [],
// macOS: open-url events
...((<any>global).getOpenUrls() || []) as string[]
].map(pendingUrlToHandle => {
try {
return URI.parse(pendingUrlToHandle);
} catch (error) {
return undefined;
}
})).filter(pendingUriToHandle => {
// filter out any protocol link that wants to open as window so that
// we open the right set of windows on startup and not restore the
// previous workspace too.
const windowOpenable = this.getWindowOpenableFromProtocolLink(pendingUriToHandle);
if (windowOpenable) {
pendingWindowOpenablesFromProtocolLinks.push(windowOpenable);
return false;
}
return true;
});
// Create a URL handler to open file URIs in the active window
const app = this;
urlService.registerHandler({
async handleURL(uri: URI, options?: IOpenURLOptions): Promise<boolean> {
async handleURL(uri: URI): Promise<boolean> {
// Catch file/remote URLs
if ((uri.authority === Schemas.file || uri.authority === Schemas.vscodeRemote) && !!uri.path) {
const cli = assign(Object.create(null), environmentService.args);
const urisToOpen: IWindowOpenable[] = [];
// Check for URIs to open in window
const windowOpenableFromProtocolLink = app.getWindowOpenableFromProtocolLink(uri);
if (windowOpenableFromProtocolLink) {
windowsMainService.open({
context: OpenContext.API,
cli: { ...environmentService.args },
urisToOpen: [windowOpenableFromProtocolLink],
gotoLineMode: true
});
// File path
if (uri.authority === Schemas.file) {
// we configure as fileUri, but later validation will
// make sure to open as folder or workspace if possible
urisToOpen.push({ fileUri: URI.file(uri.fsPath) });
}
return true;
}
// Remote path
else {
// Example conversion:
// From: vscode://vscode-remote/wsl+ubuntu/mnt/c/GitDevelopment/monaco
// To: vscode-remote://wsl+ubuntu/mnt/c/GitDevelopment/monaco
const secondSlash = uri.path.indexOf(posix.sep, 1 /* skip over the leading slash */);
if (secondSlash !== -1) {
const authority = uri.path.substring(1, secondSlash);
const path = uri.path.substring(secondSlash);
const remoteUri = URI.from({ scheme: Schemas.vscodeRemote, authority, path, query: uri.query, fragment: uri.fragment });
// If we have not yet handled the URI and we have no window opened (macOS only)
// we first open a window and then try to open that URI within that window
if (isMacintosh && windowsMainService.getWindowCount() === 0) {
const [window] = windowsMainService.open({
context: OpenContext.API,
cli: { ...environmentService.args },
forceEmpty: true,
gotoLineMode: true
});
if (hasWorkspaceFileExtension(path)) {
urisToOpen.push({ workspaceUri: remoteUri });
} else {
urisToOpen.push({ folderUri: remoteUri });
}
}
}
await window.ready();
if (urisToOpen.length > 0) {
windowsMainService.open({ context: OpenContext.API, cli, urisToOpen, gotoLineMode: true });
return true;
}
return urlService.open(uri);
}
return false;
@@ -638,37 +657,13 @@ export class CodeApplication extends Disposable {
const activeWindowRouter = new StaticRouter(ctx => activeWindowManager.getActiveClientId().then(id => ctx === id));
const urlHandlerRouter = new URLHandlerRouter(activeWindowRouter);
const urlHandlerChannel = electronIpcServer.getChannel('urlHandler', urlHandlerRouter);
const multiplexURLHandler = new URLHandlerChannelClient(urlHandlerChannel);
// On Mac, Code can be running without any open windows, so we must create a window to handle urls,
// if there is none
if (isMacintosh) {
urlService.registerHandler({
async handleURL(uri: URI, options?: IOpenURLOptions): Promise<boolean> {
if (windowsMainService.getWindowCount() === 0) {
const cli = { ...environmentService.args };
const [window] = windowsMainService.open({ context: OpenContext.API, cli, forceEmpty: true, gotoLineMode: true });
await window.ready();
return urlService.open(uri);
}
return false;
}
});
}
// Register the multiple URL handler
urlService.registerHandler(multiplexURLHandler);
urlService.registerHandler(new URLHandlerChannelClient(urlHandlerChannel));
// Watch Electron URLs and forward them to the UrlService
const args = this.environmentService.args;
const urls = args['open-url'] ? args._urls : [];
const urlListener = new ElectronURLListener(urls || [], urlService, windowsMainService, this.environmentService);
this._register(urlListener);
this._register(new ElectronURLListener(pendingProtocolLinksToHandle, urlService, windowsMainService, this.environmentService));
// Open our first window
const args = this.environmentService.args;
const macOpenFiles: string[] = (<any>global).macOpenFiles;
const context = !!process.env['VSCODE_CLI'] ? OpenContext.CLI : OpenContext.DESKTOP;
const hasCliArgs = args._.length;
@@ -677,6 +672,19 @@ export class CodeApplication extends Disposable {
const noRecentEntry = args['skip-add-to-recently-opened'] === true;
const waitMarkerFileURI = args.wait && args.waitMarkerFilePath ? URI.file(args.waitMarkerFilePath) : undefined;
// check for a pending window to open from URI
// e.g. when running code with --open-uri from
// a protocol handler
if (pendingWindowOpenablesFromProtocolLinks.length > 0) {
return windowsMainService.open({
context,
cli: args,
urisToOpen: pendingWindowOpenablesFromProtocolLinks,
gotoLineMode: true,
initialStartup: true
});
}
// new window if "-n" or "--remote" was used without paths
if ((args['new-window'] || args.remote) && !hasCliArgs && !hasFolderURIs && !hasFileURIs) {
return windowsMainService.open({
@@ -698,7 +706,6 @@ export class CodeApplication extends Disposable {
urisToOpen: macOpenFiles.map(file => this.getWindowOpenableFromPathSync(file)),
noRecentEntry,
waitMarkerFileURI,
gotoLineMode: false,
initialStartup: true
});
}
@@ -716,6 +723,40 @@ export class CodeApplication extends Disposable {
});
}
private getWindowOpenableFromProtocolLink(uri: URI): IWindowOpenable | undefined {
if (!uri.path) {
return undefined;
}
// File path
if (uri.authority === Schemas.file) {
// we configure as fileUri, but later validation will
// make sure to open as folder or workspace if possible
return { fileUri: URI.file(uri.fsPath) };
}
// Remote path
else if (uri.authority === Schemas.vscodeRemote) {
// Example conversion:
// From: vscode://vscode-remote/wsl+ubuntu/mnt/c/GitDevelopment/monaco
// To: vscode-remote://wsl+ubuntu/mnt/c/GitDevelopment/monaco
const secondSlash = uri.path.indexOf(posix.sep, 1 /* skip over the leading slash */);
if (secondSlash !== -1) {
const authority = uri.path.substring(1, secondSlash);
const path = uri.path.substring(secondSlash);
const remoteUri = URI.from({ scheme: Schemas.vscodeRemote, authority, path, query: uri.query, fragment: uri.fragment });
if (hasWorkspaceFileExtension(path)) {
return { workspaceUri: remoteUri };
} else {
return { folderUri: remoteUri };
}
}
}
return undefined;
}
private getWindowOpenableFromPathSync(path: string): IWindowOpenable {
try {
const fileStat = statSync(path);
@@ -734,6 +775,7 @@ export class CodeApplication extends Disposable {
}
private afterWindowOpen(accessor: ServicesAccessor): void {
// Signal phase: after window open
this.lifecycleMainService.phase = LifecycleMainPhase.AfterWindowOpen;
@@ -763,7 +805,7 @@ class ElectronExtensionHostDebugBroadcastChannel<TContext> extends ExtensionHost
super();
}
call(ctx: TContext, command: string, arg?: any): Promise<any> {
async call(ctx: TContext, command: string, arg?: any): Promise<any> {
if (command === 'openExtensionDevelopmentHostWindow') {
const env = arg[1];
const pargs = parseArgs(arg[0], OPTIONS);
@@ -775,7 +817,6 @@ class ElectronExtensionHostDebugBroadcastChannel<TContext> extends ExtensionHost
userEnv: Object.keys(env).length > 0 ? env : undefined
});
}
return Promise.resolve();
} else {
return super.call(ctx, command, arg);
}

View File

@@ -19,8 +19,8 @@ export function validatePaths(args: ParsedArgs): ParsedArgs {
args._ = [];
}
// Normalize paths and watch out for goto line mode
if (!args['remote']) {
// Normalize paths and watch out for goto line mode
const paths = doValidatePaths(args._, args.goto);
args._ = paths;
}