mirror of
https://github.com/coder/code-server.git
synced 2026-06-11 20:47:10 +02:00
chore(vscode): update to 1.55.2
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { isMacintosh, isLinux, isWeb, IProcessEnvironment } from 'vs/base/common/platform';
|
||||
import { isMacintosh, isLinux, isWeb, IProcessEnvironment, isNative } from 'vs/base/common/platform';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
|
||||
@@ -19,6 +19,14 @@ export const WindowMinimumSize = {
|
||||
|
||||
export interface IBaseOpenWindowsOptions {
|
||||
readonly forceReuseWindow?: boolean;
|
||||
/**
|
||||
* The remote authority to use when windows are opened with either
|
||||
* - no workspace (empty window)
|
||||
* - a workspace that is neither `file://` nor `vscode-remote://`
|
||||
* Use 'null' for a local window.
|
||||
* If not set, defaults to the remote authority of the current window.
|
||||
*/
|
||||
readonly remoteAuthority?: string | null;
|
||||
}
|
||||
|
||||
export interface IOpenWindowOptions extends IBaseOpenWindowsOptions {
|
||||
@@ -48,7 +56,6 @@ export interface IOpenedWindow {
|
||||
}
|
||||
|
||||
export interface IOpenEmptyWindowOptions extends IBaseOpenWindowsOptions {
|
||||
readonly remoteAuthority?: string;
|
||||
}
|
||||
|
||||
export type IWindowOpenable = IWorkspaceToOpen | IFolderToOpen | IFileToOpen;
|
||||
@@ -87,7 +94,7 @@ export function getMenuBarVisibility(configurationService: IConfigurationService
|
||||
const titleBarStyle = getTitleBarStyle(configurationService);
|
||||
const menuBarVisibility = configurationService.getValue<MenuBarVisibility | 'default'>('window.menuBarVisibility');
|
||||
|
||||
if (menuBarVisibility === 'default' || (titleBarStyle === 'native' && menuBarVisibility === 'compact')) {
|
||||
if (menuBarVisibility === 'default' || (titleBarStyle === 'native' && menuBarVisibility === 'compact') || (isMacintosh && isNative)) {
|
||||
return 'classic';
|
||||
} else {
|
||||
return menuBarVisibility;
|
||||
@@ -114,7 +121,6 @@ export interface IWindowSettings {
|
||||
readonly enableMenuBarMnemonics: boolean;
|
||||
readonly closeWhenEmpty: boolean;
|
||||
readonly clickThroughInactive: boolean;
|
||||
readonly enableExperimentalMainProcessWorkspaceStorage: boolean;
|
||||
}
|
||||
|
||||
export function getTitleBarStyle(configurationService: IConfigurationService): 'native' | 'custom' {
|
||||
@@ -254,8 +260,6 @@ export interface INativeWindowConfiguration extends IWindowConfiguration, Native
|
||||
filesToWait?: IPathsToWaitFor;
|
||||
|
||||
os: IOSConfiguration;
|
||||
|
||||
enableExperimentalMainProcessWorkspaceStorage: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,9 +15,9 @@ import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv';
|
||||
import { NativeParsedArgs } from 'vs/platform/environment/common/argv';
|
||||
import product from 'vs/platform/product/common/product';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { WindowMinimumSize, IWindowSettings, MenuBarVisibility, getTitleBarStyle, getMenuBarVisibility, zoomLevelToZoomFactor, INativeWindowConfiguration } from 'vs/platform/windows/common/windows';
|
||||
import { Disposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { browserCodeLoadingCacheStrategy, isLinux, isMacintosh, isWindows } from 'vs/base/common/platform';
|
||||
import { defaultWindowState, ICodeWindow, ILoadEvent, IWindowState, WindowError, WindowMode } from 'vs/platform/windows/electron-main/windows';
|
||||
import { ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
|
||||
@@ -26,7 +26,6 @@ import { IBackupMainService } from 'vs/platform/backup/electron-main/backup';
|
||||
import { ISerializableCommandAction } from 'vs/platform/actions/common/actions';
|
||||
import { resolveMarketplaceHeaders } from 'vs/platform/extensionManagement/common/extensionGalleryService';
|
||||
import { IThemeMainService } from 'vs/platform/theme/electron-main/themeMainService';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IDialogMainService } from 'vs/platform/dialogs/electron-main/dialogMainService';
|
||||
import { mnemonicButtonLabel } from 'vs/base/common/labels';
|
||||
@@ -37,6 +36,7 @@ import { ByteSize, IFileService } from 'vs/platform/files/common/files';
|
||||
import { FileAccess, Schemas } from 'vs/base/common/network';
|
||||
import { isLaunchedFromCli } from 'vs/platform/environment/node/argvHelper';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { INativeHostMainService } from 'vs/platform/native/electron-main/nativeHostMainService';
|
||||
|
||||
export interface IWindowCreationOptions {
|
||||
state: IWindowState;
|
||||
@@ -89,8 +89,6 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
|
||||
private hiddenTitleBarStyle: boolean | undefined;
|
||||
private showTimeoutHandle: NodeJS.Timeout | undefined;
|
||||
private _lastFocusTime = -1;
|
||||
private _readyState = ReadyState.NONE;
|
||||
private windowState: IWindowState;
|
||||
private currentMenuBarVisibility: MenuBarVisibility | undefined;
|
||||
|
||||
@@ -118,7 +116,9 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
@IBackupMainService private readonly backupMainService: IBackupMainService,
|
||||
@ITelemetryService private readonly telemetryService: ITelemetryService,
|
||||
@IDialogMainService private readonly dialogMainService: IDialogMainService,
|
||||
@ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService
|
||||
@ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService,
|
||||
@INativeHostMainService private readonly nativeHostMainService: INativeHostMainService,
|
||||
@IProductService private readonly productService: IProductService
|
||||
) {
|
||||
super();
|
||||
|
||||
@@ -143,7 +143,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
minWidth: WindowMinimumSize.WIDTH,
|
||||
minHeight: WindowMinimumSize.HEIGHT,
|
||||
show: !isFullscreenOrMaximized,
|
||||
title: product.nameLong,
|
||||
title: this.productService.nameLong,
|
||||
webPreferences: {
|
||||
preload: FileAccess.asFileUri('vs/base/parts/sandbox/electron-browser/preload.js', require).fsPath,
|
||||
v8CacheOptions: browserCodeLoadingCacheStrategy,
|
||||
@@ -195,7 +195,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
|
||||
const useNativeTabs = isMacintosh && windowConfig?.nativeTabs === true;
|
||||
if (useNativeTabs) {
|
||||
options.tabbingIdentifier = product.nameShort; // this opts in to sierra tabs
|
||||
options.tabbingIdentifier = this.productService.nameShort; // this opts in to sierra tabs
|
||||
}
|
||||
|
||||
const useCustomTitleStyle = getTitleBarStyle(this.configurationService) === 'custom';
|
||||
@@ -262,7 +262,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
this.createTouchBar();
|
||||
|
||||
// Request handling
|
||||
this.marketplaceHeadersPromise = resolveMarketplaceHeaders(product.version, this.environmentMainService, this.fileService, {
|
||||
this.marketplaceHeadersPromise = resolveMarketplaceHeaders(this.productService.version, this.environmentMainService, this.fileService, {
|
||||
get: key => storageMainService.globalStorage.get(key),
|
||||
store: (key, value) => storageMainService.globalStorage.set(key, value)
|
||||
});
|
||||
@@ -345,6 +345,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
this._win.focus();
|
||||
}
|
||||
|
||||
private _lastFocusTime = -1;
|
||||
get lastFocusTime(): number { return this._lastFocusTime; }
|
||||
|
||||
get backupPath(): string | undefined { return this.currentConfig?.backupPath; }
|
||||
@@ -353,8 +354,10 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
|
||||
get remoteAuthority(): string | undefined { return this.currentConfig?.remoteAuthority; }
|
||||
|
||||
private readyState = ReadyState.NONE;
|
||||
|
||||
setReady(): void {
|
||||
this._readyState = ReadyState.READY;
|
||||
this.readyState = ReadyState.READY;
|
||||
|
||||
// inform all waiting promises that we are ready now
|
||||
while (this.whenReadyCallbacks.length) {
|
||||
@@ -377,7 +380,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
}
|
||||
|
||||
get isReady(): boolean {
|
||||
return this._readyState === ReadyState.READY;
|
||||
return this.readyState === ReadyState.READY;
|
||||
}
|
||||
|
||||
get whenClosedOrLoaded(): Promise<void> {
|
||||
@@ -409,13 +412,14 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
this.dispose();
|
||||
});
|
||||
|
||||
// Block all SVG requests from unsupported origins
|
||||
const svgFileSchemes = new Set([Schemas.file, Schemas.vscodeFileResource, Schemas.vscodeRemoteResource, 'devtools']);
|
||||
this._win.webContents.session.webRequest.onBeforeRequest((details, callback) => {
|
||||
const uri = URI.parse(details.url);
|
||||
|
||||
// Prevent loading of remote svgs
|
||||
if (uri && uri.path.endsWith('.svg')) {
|
||||
const safeScheme = svgFileSchemes.has(uri.scheme) ||
|
||||
uri.path.includes(Schemas.vscodeRemoteResource);
|
||||
if (uri.path.endsWith('.svg')) {
|
||||
const safeScheme = svgFileSchemes.has(uri.scheme) || uri.path.includes(Schemas.vscodeRemoteResource);
|
||||
if (!safeScheme) {
|
||||
return callback({ cancel: true });
|
||||
}
|
||||
@@ -424,25 +428,27 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
return callback({ cancel: false });
|
||||
});
|
||||
|
||||
// Configure SVG header content type properly
|
||||
this._win.webContents.session.webRequest.onHeadersReceived((details, callback) => {
|
||||
const responseHeaders = details.responseHeaders as Record<string, (string) | (string[])>;
|
||||
const contentType = (responseHeaders['content-type'] || responseHeaders['Content-Type']);
|
||||
const contentTypes = (responseHeaders['content-type'] || responseHeaders['Content-Type']);
|
||||
|
||||
if (contentType && Array.isArray(contentType)) {
|
||||
if (contentTypes && Array.isArray(contentTypes)) {
|
||||
const uri = URI.parse(details.url);
|
||||
|
||||
// https://github.com/microsoft/vscode/issues/97564
|
||||
// ensure local svg files have Content-Type image/svg+xml
|
||||
if (uri && uri.path.endsWith('.svg')) {
|
||||
if (uri.path.endsWith('.svg')) {
|
||||
if (svgFileSchemes.has(uri.scheme)) {
|
||||
responseHeaders['Content-Type'] = ['image/svg+xml'];
|
||||
|
||||
return callback({ cancel: false, responseHeaders });
|
||||
}
|
||||
}
|
||||
|
||||
// remote extension schemes have the following format
|
||||
// http://127.0.0.1:<port>/vscode-remote-resource?path=
|
||||
if (!uri.path.includes(Schemas.vscodeRemoteResource) &&
|
||||
contentType.some(x => x.toLowerCase().includes('image/svg'))) {
|
||||
if (!uri.path.includes(Schemas.vscodeRemoteResource) && contentTypes.some(contentType => contentType.toLowerCase().includes('image/svg'))) {
|
||||
return callback({ cancel: true });
|
||||
}
|
||||
}
|
||||
@@ -452,7 +458,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
|
||||
// Remember that we loaded
|
||||
this._win.webContents.on('did-finish-load', () => {
|
||||
this._readyState = ReadyState.LOADING;
|
||||
this.readyState = ReadyState.LOADING;
|
||||
|
||||
// Associate properties from the load request if provided
|
||||
if (this.pendingLoadConfig) {
|
||||
@@ -468,7 +474,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
});
|
||||
|
||||
if (isMacintosh) {
|
||||
const displayChangedScheduler = this._register(new RunOnceScheduler(() => {
|
||||
this._register(this.nativeHostMainService.onDidChangeDisplay(() => {
|
||||
if (!this._win) {
|
||||
return; // disposed
|
||||
}
|
||||
@@ -480,27 +486,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
this.setFullScreen(false);
|
||||
this.setFullScreen(true);
|
||||
}
|
||||
}, 100));
|
||||
|
||||
const displayChangedListener = (event: Event, display: Display, changedMetrics?: string[]) => {
|
||||
if (Array.isArray(changedMetrics) && changedMetrics.length === 1 && changedMetrics[0] === 'workArea') {
|
||||
// Electron will emit 'display-metrics-changed' events even when actually
|
||||
// going fullscreen, because the dock hides. However, we do not want to
|
||||
// react on this event as there is no change in display bounds.
|
||||
return;
|
||||
}
|
||||
|
||||
displayChangedScheduler.schedule();
|
||||
};
|
||||
|
||||
screen.on('display-metrics-changed', displayChangedListener);
|
||||
this._register(toDisposable(() => screen.removeListener('display-metrics-changed', displayChangedListener)));
|
||||
|
||||
screen.on('display-added', displayChangedListener);
|
||||
this._register(toDisposable(() => screen.removeListener('display-added', displayChangedListener)));
|
||||
|
||||
screen.on('display-removed', displayChangedListener);
|
||||
this._register(toDisposable(() => screen.removeListener('display-removed', displayChangedListener)));
|
||||
}));
|
||||
}
|
||||
|
||||
// Window (Un)Maximize
|
||||
@@ -578,7 +564,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
type: WindowError;
|
||||
reason: string | undefined;
|
||||
};
|
||||
this.telemetryService.publicLog2<WindowErrorEvent, WindowErrorClassification>('windowerror', { type, reason: (details && typeof details !== 'string') ? details.reason : undefined });
|
||||
this.telemetryService.publicLog2<WindowErrorEvent, WindowErrorClassification>('windowerror', { type, reason: typeof details !== 'string' ? details?.reason : undefined });
|
||||
|
||||
// Unresponsive
|
||||
if (type === WindowError.UNRESPONSIVE) {
|
||||
@@ -594,7 +580,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
|
||||
// Show Dialog
|
||||
const result = await this.dialogMainService.showMessageBox({
|
||||
title: product.nameLong,
|
||||
title: this.productService.nameLong,
|
||||
type: 'warning',
|
||||
buttons: [mnemonicButtonLabel(localize({ key: 'reopen', comment: ['&& denotes a mnemonic'] }, "&&Reopen")), mnemonicButtonLabel(localize({ key: 'wait', comment: ['&& denotes a mnemonic'] }, "&&Keep Waiting")), mnemonicButtonLabel(localize({ key: 'close', comment: ['&& denotes a mnemonic'] }, "&&Close"))],
|
||||
message: localize('appStalled', "The window is no longer responding"),
|
||||
@@ -624,7 +610,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
}
|
||||
|
||||
const result = await this.dialogMainService.showMessageBox({
|
||||
title: product.nameLong,
|
||||
title: this.productService.nameLong,
|
||||
type: 'warning',
|
||||
buttons: [mnemonicButtonLabel(localize({ key: 'reopen', comment: ['&& denotes a mnemonic'] }, "&&Reopen")), mnemonicButtonLabel(localize({ key: 'close', comment: ['&& denotes a mnemonic'] }, "&&Close"))],
|
||||
message,
|
||||
@@ -717,7 +703,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
|
||||
// If this is the first time the window is loaded, we associate the paths
|
||||
// directly with the window because we assume the loading will just work
|
||||
if (this._readyState === ReadyState.NONE) {
|
||||
if (this.readyState === ReadyState.NONE) {
|
||||
this.currentConfig = config;
|
||||
}
|
||||
|
||||
@@ -727,7 +713,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
// the window load event has fired.
|
||||
else {
|
||||
this.pendingLoadConfig = config;
|
||||
this._readyState = ReadyState.NAVIGATING;
|
||||
this.readyState = ReadyState.NAVIGATING;
|
||||
}
|
||||
|
||||
// Add disable-extensions to the config, but do not preserve it on currentConfig or
|
||||
@@ -750,7 +736,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
this.setRepresentedFilename('');
|
||||
}
|
||||
|
||||
this._win.setTitle(product.nameLong);
|
||||
this._win.setTitle(this.productService.nameLong);
|
||||
}
|
||||
|
||||
// Load URL
|
||||
@@ -870,8 +856,6 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
release: release()
|
||||
};
|
||||
|
||||
windowConfiguration.enableExperimentalMainProcessWorkspaceStorage = !!(windowConfig?.enableExperimentalMainProcessWorkspaceStorage);
|
||||
|
||||
// Config (combination of process.argv and window configuration)
|
||||
const environment = parseArgs(process.argv, OPTIONS);
|
||||
const config = Object.assign(environment, windowConfiguration) as unknown as { [key: string]: unknown };
|
||||
|
||||
@@ -197,6 +197,12 @@ export interface IOpenConfiguration extends IBaseOpenConfiguration {
|
||||
readonly gotoLineMode?: boolean;
|
||||
readonly initialStartup?: boolean;
|
||||
readonly noRecentEntry?: boolean;
|
||||
/**
|
||||
* The remote authority to use when windows are opened with either
|
||||
* - no workspace (empty window)
|
||||
* - a workspace that is neither `file://` nor `vscode-remote://`
|
||||
*/
|
||||
readonly remoteAuthority?: string;
|
||||
}
|
||||
|
||||
export interface IOpenEmptyConfiguration extends IBaseOpenConfiguration { }
|
||||
|
||||
@@ -20,7 +20,7 @@ import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IWindowSettings, IPath, isFileToOpen, isWorkspaceToOpen, isFolderToOpen, IWindowOpenable, IOpenEmptyWindowOptions, IAddFoldersRequest, IPathsToWaitFor, INativeWindowConfiguration, INativeOpenFileRequest } from 'vs/platform/windows/common/windows';
|
||||
import { findWindowOnFile, findWindowOnWorkspaceOrFolder, findWindowOnExtensionDevelopmentPath } from 'vs/platform/windows/electron-main/windowsFinder';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import product from 'vs/platform/product/common/product';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { IWindowsMainService, IOpenConfiguration, IWindowsCountChangedEvent, ICodeWindow, IOpenEmptyConfiguration, OpenContext } from 'vs/platform/windows/electron-main/windows';
|
||||
import { IWorkspacesHistoryMainService } from 'vs/platform/workspaces/electron-main/workspacesHistoryMainService';
|
||||
import { IProcessEnvironment, isMacintosh } from 'vs/base/common/platform';
|
||||
@@ -41,6 +41,7 @@ import { CharCode } from 'vs/base/common/charCode';
|
||||
import { getPathLabel } from 'vs/base/common/labels';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { cwd } from 'vs/base/common/process';
|
||||
|
||||
//#region Helper Interfaces
|
||||
|
||||
@@ -68,6 +69,10 @@ interface IOpenBrowserWindowOptions {
|
||||
interface IPathResolveOptions {
|
||||
readonly ignoreFileNotFound?: boolean;
|
||||
readonly gotoLineMode?: boolean;
|
||||
readonly forceOpenWorkspaceAsFile?: boolean;
|
||||
/**
|
||||
* The remoteAuthority to use if the URL to open is neither file nor vscode-remote
|
||||
*/
|
||||
readonly remoteAuthority?: string;
|
||||
}
|
||||
|
||||
@@ -145,7 +150,8 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic
|
||||
@IWorkspacesManagementMainService private readonly workspacesManagementMainService: IWorkspacesManagementMainService,
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
@IDialogMainService private readonly dialogMainService: IDialogMainService,
|
||||
@IFileService private readonly fileService: IFileService
|
||||
@IFileService private readonly fileService: IFileService,
|
||||
@IProductService private readonly productService: IProductService
|
||||
) {
|
||||
super();
|
||||
|
||||
@@ -160,16 +166,12 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic
|
||||
|
||||
openEmptyWindow(openConfig: IOpenEmptyConfiguration, options?: IOpenEmptyWindowOptions): ICodeWindow[] {
|
||||
let cli = this.environmentMainService.args;
|
||||
const remote = options?.remoteAuthority;
|
||||
if (cli && (cli.remote !== remote)) {
|
||||
cli = { ...cli, remote };
|
||||
}
|
||||
|
||||
const remoteAuthority = options?.remoteAuthority || undefined;
|
||||
const forceEmpty = true;
|
||||
const forceReuseWindow = options?.forceReuseWindow;
|
||||
const forceNewWindow = !forceReuseWindow;
|
||||
|
||||
return this.open({ ...openConfig, cli, forceEmpty, forceNewWindow, forceReuseWindow });
|
||||
return this.open({ ...openConfig, cli, forceEmpty, forceNewWindow, forceReuseWindow, remoteAuthority });
|
||||
}
|
||||
|
||||
open(openConfig: IOpenConfiguration): ICodeWindow[] {
|
||||
@@ -298,11 +300,11 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic
|
||||
const recents: IRecent[] = [];
|
||||
for (const pathToOpen of pathsToOpen) {
|
||||
if (isWorkspacePathToOpen(pathToOpen)) {
|
||||
recents.push({ label: pathToOpen.label, workspace: pathToOpen.workspace });
|
||||
recents.push({ label: pathToOpen.label, workspace: pathToOpen.workspace, remoteAuthority: pathToOpen.remoteAuthority });
|
||||
} else if (isSingleFolderWorkspacePathToOpen(pathToOpen)) {
|
||||
recents.push({ label: pathToOpen.label, folderUri: pathToOpen.workspace.uri });
|
||||
recents.push({ label: pathToOpen.label, folderUri: pathToOpen.workspace.uri, remoteAuthority: pathToOpen.remoteAuthority });
|
||||
} else if (pathToOpen.fileUri) {
|
||||
recents.push({ label: pathToOpen.label, fileUri: pathToOpen.fileUri });
|
||||
recents.push({ label: pathToOpen.label, fileUri: pathToOpen.fileUri, remoteAuthority: pathToOpen.remoteAuthority });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -507,7 +509,7 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic
|
||||
emptyToOpen++;
|
||||
}
|
||||
|
||||
const remoteAuthority = filesToOpen ? filesToOpen.remoteAuthority : (openConfig.cli && openConfig.cli.remote || undefined);
|
||||
const remoteAuthority = filesToOpen ? filesToOpen.remoteAuthority : openConfig.remoteAuthority;
|
||||
|
||||
for (let i = 0; i < emptyToOpen; i++) {
|
||||
addUsedWindow(this.doOpenEmpty(openConfig, openFolderInNewWindow, remoteAuthority, filesToOpen), !!filesToOpen);
|
||||
@@ -650,7 +652,7 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic
|
||||
|
||||
private doExtractPathsFromAPI(openConfig: IOpenConfiguration): IPathToOpen[] {
|
||||
const pathsToOpen: IPathToOpen[] = [];
|
||||
const pathResolveOptions: IPathResolveOptions = { gotoLineMode: openConfig.gotoLineMode };
|
||||
const pathResolveOptions: IPathResolveOptions = { gotoLineMode: openConfig.gotoLineMode, remoteAuthority: openConfig.remoteAuthority };
|
||||
for (const pathToOpen of coalesce(openConfig.urisToOpen || [])) {
|
||||
const path = this.resolveOpenable(pathToOpen, pathResolveOptions);
|
||||
|
||||
@@ -665,7 +667,7 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic
|
||||
const uri = this.resourceFromOpenable(pathToOpen);
|
||||
|
||||
const options: MessageBoxOptions = {
|
||||
title: product.nameLong,
|
||||
title: this.productService.nameLong,
|
||||
type: 'info',
|
||||
buttons: [localize('ok', "OK")],
|
||||
message: uri.scheme === Schemas.file ? localize('pathNotExistTitle', "Path does not exist") : localize('uriInvalidTitle', "URI can not be opened"),
|
||||
@@ -684,7 +686,7 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic
|
||||
|
||||
private doExtractPathsFromCLI(cli: NativeParsedArgs): IPath[] {
|
||||
const pathsToOpen: IPathToOpen[] = [];
|
||||
const pathResolveOptions: IPathResolveOptions = { ignoreFileNotFound: true, gotoLineMode: cli.goto, remoteAuthority: cli.remote || undefined };
|
||||
const pathResolveOptions: IPathResolveOptions = { ignoreFileNotFound: true, gotoLineMode: cli.goto, remoteAuthority: cli.remote || undefined, forceOpenWorkspaceAsFile: false };
|
||||
|
||||
// folder uris
|
||||
const folderUris = cli['folder-uri'];
|
||||
@@ -717,12 +719,11 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic
|
||||
// folder or file paths
|
||||
const cliPaths = cli._;
|
||||
for (const cliPath of cliPaths) {
|
||||
const path = this.doResolveFileOpenable(cliPath, pathResolveOptions);
|
||||
const path = cli.remote ? this.doResolvePathRemote(cliPath, cli.remote) : this.doResolveFilePath(cliPath, pathResolveOptions);
|
||||
if (path) {
|
||||
pathsToOpen.push(path);
|
||||
}
|
||||
}
|
||||
|
||||
return pathsToOpen;
|
||||
}
|
||||
|
||||
@@ -819,7 +820,10 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic
|
||||
// handle file:// openables with some extra validation
|
||||
let uri = this.resourceFromOpenable(openable);
|
||||
if (uri.scheme === Schemas.file) {
|
||||
return this.doResolveFileOpenable(openable, options);
|
||||
if (isFileToOpen(openable)) {
|
||||
options = { ...options, forceOpenWorkspaceAsFile: true };
|
||||
}
|
||||
return this.doResolveFilePath(uri.fsPath, options);
|
||||
}
|
||||
|
||||
// handle non file:// openables
|
||||
@@ -829,8 +833,8 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic
|
||||
private doResolveRemoteOpenable(openable: IWindowOpenable, options: IPathResolveOptions): IPathToOpen | undefined {
|
||||
let uri = this.resourceFromOpenable(openable);
|
||||
|
||||
// open remote if either specified in the cli or if it's a remotehost URI
|
||||
const remoteAuthority = options.remoteAuthority || getRemoteAuthority(uri);
|
||||
// use remote authority from vscode
|
||||
const remoteAuthority = getRemoteAuthority(uri) || options.remoteAuthority;
|
||||
|
||||
// normalize URI
|
||||
uri = removeTrailingPathSeparator(normalizePath(uri));
|
||||
@@ -867,17 +871,7 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic
|
||||
return openable.fileUri;
|
||||
}
|
||||
|
||||
private doResolveFileOpenable(path: string, options: IPathResolveOptions): IPathToOpen | undefined;
|
||||
private doResolveFileOpenable(openable: IWindowOpenable, options: IPathResolveOptions): IPathToOpen | undefined;
|
||||
private doResolveFileOpenable(pathOrOpenable: string | IWindowOpenable, options: IPathResolveOptions): IPathToOpen | undefined {
|
||||
let path: string;
|
||||
let forceOpenWorkspaceAsFile = false;
|
||||
if (typeof pathOrOpenable === 'string') {
|
||||
path = pathOrOpenable;
|
||||
} else {
|
||||
path = this.resourceFromOpenable(pathOrOpenable).fsPath;
|
||||
forceOpenWorkspaceAsFile = isFileToOpen(pathOrOpenable);
|
||||
}
|
||||
private doResolveFilePath(path: string, options: IPathResolveOptions): IPathToOpen | undefined {
|
||||
|
||||
// Extract line/col information from path
|
||||
let lineNumber: number | undefined;
|
||||
@@ -891,14 +885,44 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic
|
||||
path = parsedPath.path;
|
||||
}
|
||||
|
||||
// With remote: resolve path as remote URI
|
||||
const remoteAuthority = options.remoteAuthority;
|
||||
if (remoteAuthority) {
|
||||
return this.doResolvePathRemote(path, remoteAuthority, forceOpenWorkspaceAsFile);
|
||||
// Ensure the path is normalized and absolute
|
||||
path = sanitizeFilePath(normalize(path), cwd());
|
||||
|
||||
try {
|
||||
const pathStat = statSync(path);
|
||||
if (pathStat.isFile()) {
|
||||
|
||||
// Workspace (unless disabled via flag)
|
||||
if (!options.forceOpenWorkspaceAsFile) {
|
||||
const workspace = this.workspacesManagementMainService.resolveLocalWorkspaceSync(URI.file(path));
|
||||
if (workspace) {
|
||||
return { workspace: { id: workspace.id, configPath: workspace.configPath }, remoteAuthority: workspace.remoteAuthority, exists: true };
|
||||
}
|
||||
}
|
||||
|
||||
// File
|
||||
return { fileUri: URI.file(path), lineNumber, columnNumber, exists: true };
|
||||
}
|
||||
|
||||
// Folder (we check for isDirectory() because e.g. paths like /dev/null
|
||||
// are neither file nor folder but some external tools might pass them
|
||||
// over to us)
|
||||
else if (pathStat.isDirectory()) {
|
||||
return { workspace: getSingleFolderWorkspaceIdentifier(URI.file(path), pathStat), exists: true };
|
||||
}
|
||||
} catch (error) {
|
||||
const fileUri = URI.file(path);
|
||||
|
||||
// since file does not seem to exist anymore, remove from recent
|
||||
this.workspacesHistoryMainService.removeRecentlyOpened([fileUri]);
|
||||
|
||||
// assume this is a file that does not yet exist
|
||||
if (options.ignoreFileNotFound) {
|
||||
return { fileUri, exists: false };
|
||||
}
|
||||
}
|
||||
|
||||
// Without remote: resolve path as local URI
|
||||
return this.doResolvePathLocal(path, options, lineNumber, columnNumber, forceOpenWorkspaceAsFile);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private doResolvePathRemote(path: string, remoteAuthority: string, forceOpenWorkspaceAsFile?: boolean): IPathToOpen | undefined {
|
||||
@@ -938,48 +962,6 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic
|
||||
return { workspace: getSingleFolderWorkspaceIdentifier(uri), remoteAuthority };
|
||||
}
|
||||
|
||||
private doResolvePathLocal(path: string, options: IPathResolveOptions, lineNumber: number | undefined, columnNumber: number | undefined, forceOpenWorkspaceAsFile?: boolean): IPathToOpen | undefined {
|
||||
|
||||
// Ensure the path is normalized and absolute
|
||||
path = sanitizeFilePath(normalize(path), process.env['VSCODE_CWD'] || process.cwd());
|
||||
|
||||
try {
|
||||
const pathStat = statSync(path);
|
||||
if (pathStat.isFile()) {
|
||||
|
||||
// Workspace (unless disabled via flag)
|
||||
if (!forceOpenWorkspaceAsFile) {
|
||||
const workspace = this.workspacesManagementMainService.resolveLocalWorkspaceSync(URI.file(path));
|
||||
if (workspace) {
|
||||
return { workspace: { id: workspace.id, configPath: workspace.configPath }, remoteAuthority: workspace.remoteAuthority, exists: true };
|
||||
}
|
||||
}
|
||||
|
||||
// File
|
||||
return { fileUri: URI.file(path), lineNumber, columnNumber, exists: true };
|
||||
}
|
||||
|
||||
// Folder (we check for isDirectory() because e.g. paths like /dev/null
|
||||
// are neither file nor folder but some external tools might pass them
|
||||
// over to us)
|
||||
else if (pathStat.isDirectory()) {
|
||||
return { workspace: getSingleFolderWorkspaceIdentifier(URI.file(path), pathStat), exists: true };
|
||||
}
|
||||
} catch (error) {
|
||||
const fileUri = URI.file(path);
|
||||
|
||||
// since file does not seem to exist anymore, remove from recent
|
||||
this.workspacesHistoryMainService.removeRecentlyOpened([fileUri]);
|
||||
|
||||
// assume this is a file that does not yet exist
|
||||
if (options?.ignoreFileNotFound) {
|
||||
return { fileUri, exists: false };
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private shouldOpenNewWindow(openConfig: IOpenConfiguration): { openFolderInNewWindow: boolean; openFilesInNewWindow: boolean; } {
|
||||
|
||||
// let the user settings override how folders are open in a new window or same window unless we are forced
|
||||
@@ -1060,17 +1042,18 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic
|
||||
}
|
||||
}
|
||||
|
||||
let authority = '';
|
||||
let remoteAuthority = openConfig.remoteAuthority;
|
||||
for (const extensionDevelopmentPath of extensionDevelopmentPaths) {
|
||||
if (extensionDevelopmentPath.match(/^[a-zA-Z][a-zA-Z0-9\+\-\.]+:/)) {
|
||||
const url = URI.parse(extensionDevelopmentPath);
|
||||
if (url.scheme === Schemas.vscodeRemote) {
|
||||
if (authority) {
|
||||
if (url.authority !== authority) {
|
||||
const extensionDevelopmentPathRemoteAuthority = getRemoteAuthority(url);
|
||||
if (extensionDevelopmentPathRemoteAuthority) {
|
||||
if (remoteAuthority) {
|
||||
if (extensionDevelopmentPathRemoteAuthority !== remoteAuthority) {
|
||||
this.logService.error('more than one extension development path authority');
|
||||
}
|
||||
} else {
|
||||
authority = url.authority;
|
||||
remoteAuthority = extensionDevelopmentPathRemoteAuthority;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1086,7 +1069,7 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic
|
||||
return false;
|
||||
}
|
||||
|
||||
return uri.authority === authority;
|
||||
return getRemoteAuthority(uri) === remoteAuthority;
|
||||
});
|
||||
|
||||
folderUris = folderUris.filter(folderUriStr => {
|
||||
@@ -1095,7 +1078,7 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic
|
||||
return false;
|
||||
}
|
||||
|
||||
return folderUri ? folderUri.authority === authority : false;
|
||||
return folderUri ? getRemoteAuthority(folderUri) === remoteAuthority : false;
|
||||
});
|
||||
|
||||
fileUris = fileUris.filter(fileUriStr => {
|
||||
@@ -1104,18 +1087,14 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic
|
||||
return false;
|
||||
}
|
||||
|
||||
return fileUri ? fileUri.authority === authority : false;
|
||||
return fileUri ? getRemoteAuthority(fileUri) === remoteAuthority : false;
|
||||
});
|
||||
|
||||
openConfig.cli._ = cliArgs;
|
||||
openConfig.cli['folder-uri'] = folderUris;
|
||||
openConfig.cli['file-uri'] = fileUris;
|
||||
|
||||
// if there are no files or folders cli args left, use the "remote" cli argument
|
||||
const noFilesOrFolders = !cliArgs.length && !folderUris.length && !fileUris.length;
|
||||
if (noFilesOrFolders && authority) {
|
||||
openConfig.cli.remote = authority;
|
||||
}
|
||||
|
||||
// Open it
|
||||
const openArgs: IOpenConfiguration = {
|
||||
@@ -1125,7 +1104,8 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic
|
||||
forceEmpty: noFilesOrFolders,
|
||||
userEnv: openConfig.userEnv,
|
||||
noRecentEntry: true,
|
||||
waitMarkerFileURI: openConfig.waitMarkerFileURI
|
||||
waitMarkerFileURI: openConfig.waitMarkerFileURI,
|
||||
remoteAuthority
|
||||
};
|
||||
|
||||
return this.open(openArgs);
|
||||
|
||||
@@ -9,7 +9,7 @@ import { findWindowOnFile } from 'vs/platform/windows/electron-main/windowsFinde
|
||||
import { ICodeWindow, ILoadEvent, IWindowState } from 'vs/platform/windows/electron-main/windows';
|
||||
import { IWorkspaceIdentifier, toWorkspaceFolders } from 'vs/platform/workspaces/common/workspaces';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { getPathFromAmdModule } from 'vs/base/common/amd';
|
||||
import { getPathFromAmdModule } from 'vs/base/test/node/testUtils';
|
||||
import { extUriBiasedIgnorePathCase } from 'vs/base/common/resources';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
|
||||
Reference in New Issue
Block a user