mirror of
https://github.com/coder/code-server.git
synced 2026-05-08 21:37:27 +02:00
Update to VS Code 1.52.1
This commit is contained in:
@@ -24,6 +24,7 @@ import { trim } from 'vs/base/common/strings';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { IPathService } from 'vs/workbench/services/path/common/pathService';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
|
||||
export abstract class AbstractFileDialogService implements IFileDialogService {
|
||||
|
||||
@@ -45,7 +46,7 @@ export abstract class AbstractFileDialogService implements IFileDialogService {
|
||||
@IPathService private readonly pathService: IPathService
|
||||
) { }
|
||||
|
||||
defaultFilePath(schemeFilter = this.getSchemeFilterForWindow()): URI | undefined {
|
||||
async defaultFilePath(schemeFilter = this.getSchemeFilterForWindow()): Promise<URI> {
|
||||
|
||||
// Check for last active file first...
|
||||
let candidate = this.historyService.getLastActiveFile(schemeFilter);
|
||||
@@ -57,10 +58,14 @@ export abstract class AbstractFileDialogService implements IFileDialogService {
|
||||
candidate = candidate && resources.dirname(candidate);
|
||||
}
|
||||
|
||||
return candidate || undefined;
|
||||
if (!candidate) {
|
||||
candidate = await this.pathService.userHome({ preferLocal: schemeFilter === Schemas.file });
|
||||
}
|
||||
|
||||
return candidate;
|
||||
}
|
||||
|
||||
defaultFolderPath(schemeFilter = this.getSchemeFilterForWindow()): URI | undefined {
|
||||
async defaultFolderPath(schemeFilter = this.getSchemeFilterForWindow()): Promise<URI> {
|
||||
|
||||
// Check for last active file root first...
|
||||
let candidate = this.historyService.getLastActiveWorkspaceRoot(schemeFilter);
|
||||
@@ -70,10 +75,14 @@ export abstract class AbstractFileDialogService implements IFileDialogService {
|
||||
candidate = this.historyService.getLastActiveFile(schemeFilter);
|
||||
}
|
||||
|
||||
return candidate && resources.dirname(candidate) || undefined;
|
||||
if (!candidate) {
|
||||
return this.pathService.userHome({ preferLocal: schemeFilter === Schemas.file });
|
||||
} else {
|
||||
return resources.dirname(candidate);
|
||||
}
|
||||
}
|
||||
|
||||
defaultWorkspacePath(schemeFilter = this.getSchemeFilterForWindow(), filename?: string): URI | undefined {
|
||||
async defaultWorkspacePath(schemeFilter = this.getSchemeFilterForWindow(), filename?: string): Promise<URI> {
|
||||
let defaultWorkspacePath: URI | undefined;
|
||||
// Check for current workspace config file first...
|
||||
if (this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE) {
|
||||
@@ -85,7 +94,7 @@ export abstract class AbstractFileDialogService implements IFileDialogService {
|
||||
|
||||
// ...then fallback to default file path
|
||||
if (!defaultWorkspacePath) {
|
||||
defaultWorkspacePath = this.defaultFilePath(schemeFilter);
|
||||
defaultWorkspacePath = await this.defaultFilePath(schemeFilter);
|
||||
}
|
||||
|
||||
if (defaultWorkspacePath && filename) {
|
||||
@@ -155,7 +164,7 @@ export abstract class AbstractFileDialogService implements IFileDialogService {
|
||||
if (stat.isDirectory || options.forceNewWindow || preferNewWindow) {
|
||||
return this.hostService.openWindow([toOpen], { forceNewWindow: options.forceNewWindow });
|
||||
} else {
|
||||
return this.openerService.open(uri, { fromUserGesture: true });
|
||||
return this.openerService.open(uri, { fromUserGesture: true, editorOptions: { pinned: true } });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -172,7 +181,7 @@ export abstract class AbstractFileDialogService implements IFileDialogService {
|
||||
if (options.forceNewWindow || preferNewWindow) {
|
||||
return this.hostService.openWindow([{ fileUri: uri }], { forceNewWindow: options.forceNewWindow });
|
||||
} else {
|
||||
return this.openerService.open(uri, { fromUserGesture: true });
|
||||
return this.openerService.open(uri, { fromUserGesture: true, editorOptions: { pinned: true } });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,149 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import { IDialogService, IDialogOptions, IConfirmation, IConfirmationResult, DialogType, IShowResult, IInputResult, ICheckbox, IInput } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { ILayoutService } from 'vs/platform/layout/browser/layoutService';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import Severity from 'vs/base/common/severity';
|
||||
import { Dialog, IDialogResult } from 'vs/base/browser/ui/dialog/dialog';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { attachDialogStyler } from 'vs/platform/theme/common/styler';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { EventHelper } from 'vs/base/browser/dom';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { fromNow } from 'vs/base/common/date';
|
||||
|
||||
export class DialogService implements IDialogService {
|
||||
|
||||
declare readonly _serviceBrand: undefined;
|
||||
|
||||
private static readonly ALLOWABLE_COMMANDS = [
|
||||
'copy',
|
||||
'cut',
|
||||
'editor.action.selectAll',
|
||||
'editor.action.clipboardCopyAction',
|
||||
'editor.action.clipboardCutAction',
|
||||
'editor.action.clipboardPasteAction'
|
||||
];
|
||||
|
||||
constructor(
|
||||
@ILogService private readonly logService: ILogService,
|
||||
@ILayoutService private readonly layoutService: ILayoutService,
|
||||
@IThemeService private readonly themeService: IThemeService,
|
||||
@IKeybindingService private readonly keybindingService: IKeybindingService,
|
||||
@IProductService private readonly productService: IProductService,
|
||||
@IClipboardService private readonly clipboardService: IClipboardService
|
||||
) { }
|
||||
|
||||
async confirm(confirmation: IConfirmation): Promise<IConfirmationResult> {
|
||||
this.logService.trace('DialogService#confirm', confirmation.message);
|
||||
|
||||
const buttons: string[] = [];
|
||||
if (confirmation.primaryButton) {
|
||||
buttons.push(confirmation.primaryButton);
|
||||
} else {
|
||||
buttons.push(nls.localize({ key: 'yesButton', comment: ['&& denotes a mnemonic'] }, "&&Yes"));
|
||||
}
|
||||
|
||||
if (confirmation.secondaryButton) {
|
||||
buttons.push(confirmation.secondaryButton);
|
||||
} else if (typeof confirmation.secondaryButton === 'undefined') {
|
||||
buttons.push(nls.localize('cancelButton', "Cancel"));
|
||||
}
|
||||
|
||||
const result = await this.doShow(confirmation.type, confirmation.message, buttons, confirmation.detail, 1, confirmation.checkbox);
|
||||
|
||||
return { confirmed: result.button === 0, checkboxChecked: result.checkboxChecked };
|
||||
}
|
||||
|
||||
private getDialogType(severity: Severity): DialogType {
|
||||
return (severity === Severity.Info) ? 'question' : (severity === Severity.Error) ? 'error' : (severity === Severity.Warning) ? 'warning' : 'none';
|
||||
}
|
||||
|
||||
async show(severity: Severity, message: string, buttons: string[], options?: IDialogOptions): Promise<IShowResult> {
|
||||
this.logService.trace('DialogService#show', message);
|
||||
|
||||
const result = await this.doShow(this.getDialogType(severity), message, buttons, options?.detail, options?.cancelId, options?.checkbox);
|
||||
|
||||
return {
|
||||
choice: result.button,
|
||||
checkboxChecked: result.checkboxChecked
|
||||
};
|
||||
}
|
||||
|
||||
private async doShow(type: 'none' | 'info' | 'error' | 'question' | 'warning' | 'pending' | undefined, message: string, buttons: string[], detail?: string, cancelId?: number, checkbox?: ICheckbox, inputs?: IInput[]): Promise<IDialogResult> {
|
||||
const dialogDisposables = new DisposableStore();
|
||||
const dialog = new Dialog(
|
||||
this.layoutService.container,
|
||||
message,
|
||||
buttons,
|
||||
{
|
||||
detail,
|
||||
cancelId,
|
||||
type,
|
||||
keyEventProcessor: (event: StandardKeyboardEvent) => {
|
||||
const resolved = this.keybindingService.softDispatch(event, this.layoutService.container);
|
||||
if (resolved && resolved.commandId) {
|
||||
if (DialogService.ALLOWABLE_COMMANDS.indexOf(resolved.commandId) === -1) {
|
||||
EventHelper.stop(event, true);
|
||||
}
|
||||
}
|
||||
},
|
||||
checkboxLabel: checkbox?.label,
|
||||
checkboxChecked: checkbox?.checked,
|
||||
inputs
|
||||
});
|
||||
|
||||
dialogDisposables.add(dialog);
|
||||
dialogDisposables.add(attachDialogStyler(dialog, this.themeService));
|
||||
|
||||
const result = await dialog.show();
|
||||
dialogDisposables.dispose();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
async input(severity: Severity, message: string, buttons: string[], inputs: IInput[], options?: IDialogOptions): Promise<IInputResult> {
|
||||
this.logService.trace('DialogService#input', message);
|
||||
|
||||
const result = await this.doShow(this.getDialogType(severity), message, buttons, options?.detail, options?.cancelId, options?.checkbox, inputs);
|
||||
|
||||
return {
|
||||
choice: result.button,
|
||||
checkboxChecked: result.checkboxChecked,
|
||||
values: result.values
|
||||
};
|
||||
}
|
||||
|
||||
async about(): Promise<void> {
|
||||
const detailString = (useAgo: boolean): string => {
|
||||
return nls.localize('aboutDetail',
|
||||
"code-server: v{4}\n VS Code: v{0}\nCommit: {1}\nDate: {2}\nBrowser: {3}",
|
||||
this.productService.version || 'Unknown',
|
||||
this.productService.commit || 'Unknown',
|
||||
this.productService.date ? `${this.productService.date}${useAgo ? ' (' + fromNow(new Date(this.productService.date), true) + ')' : ''}` : 'Unknown',
|
||||
navigator.userAgent,
|
||||
this.productService.codeServerVersion || 'Unknown',
|
||||
);
|
||||
};
|
||||
|
||||
const detail = detailString(true);
|
||||
const detailToCopy = detailString(false);
|
||||
|
||||
|
||||
const { choice } = await this.show(Severity.Info, this.productService.nameLong, [nls.localize('copy', "Copy"), nls.localize('ok', "OK")], { detail, cancelId: 1 });
|
||||
|
||||
if (choice === 0) {
|
||||
this.clipboardService.writeText(detailToCopy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
registerSingleton(IDialogService, DialogService, true);
|
||||
@@ -15,7 +15,7 @@ export class FileDialogService extends AbstractFileDialogService implements IFil
|
||||
const schema = this.getFileSystemSchema(options);
|
||||
|
||||
if (!options.defaultUri) {
|
||||
options.defaultUri = this.defaultFilePath(schema);
|
||||
options.defaultUri = await this.defaultFilePath(schema);
|
||||
}
|
||||
|
||||
return this.pickFileFolderAndOpenSimplified(schema, options, false);
|
||||
@@ -25,7 +25,7 @@ export class FileDialogService extends AbstractFileDialogService implements IFil
|
||||
const schema = this.getFileSystemSchema(options);
|
||||
|
||||
if (!options.defaultUri) {
|
||||
options.defaultUri = this.defaultFilePath(schema);
|
||||
options.defaultUri = await this.defaultFilePath(schema);
|
||||
}
|
||||
|
||||
return this.pickFileAndOpenSimplified(schema, options, false);
|
||||
@@ -35,7 +35,7 @@ export class FileDialogService extends AbstractFileDialogService implements IFil
|
||||
const schema = this.getFileSystemSchema(options);
|
||||
|
||||
if (!options.defaultUri) {
|
||||
options.defaultUri = this.defaultFolderPath(schema);
|
||||
options.defaultUri = await this.defaultFolderPath(schema);
|
||||
}
|
||||
|
||||
return this.pickFolderAndOpenSimplified(schema, options);
|
||||
@@ -45,7 +45,7 @@ export class FileDialogService extends AbstractFileDialogService implements IFil
|
||||
const schema = this.getFileSystemSchema(options);
|
||||
|
||||
if (!options.defaultUri) {
|
||||
options.defaultUri = this.defaultWorkspacePath(schema);
|
||||
options.defaultUri = await this.defaultWorkspacePath(schema);
|
||||
}
|
||||
|
||||
return this.pickWorkspaceAndOpenSimplified(schema, options);
|
||||
|
||||
@@ -212,11 +212,16 @@ export class SimpleFileDialog {
|
||||
path = path.replace(/\\/g, '/');
|
||||
}
|
||||
const uri: URI = this.scheme === Schemas.file ? URI.file(path) : URI.from({ scheme: this.scheme, path });
|
||||
return resources.toLocalResource(uri, uri.scheme === Schemas.file ? undefined : this.remoteAuthority, this.pathService.defaultUriScheme);
|
||||
return resources.toLocalResource(uri,
|
||||
// If the default scheme is file, then we don't care about the remote authority
|
||||
uri.scheme === Schemas.file ? undefined : this.remoteAuthority,
|
||||
// If there is a remote authority, then we should use the system's default URI as the local scheme.
|
||||
// If there is *no* remote authority, then we should use the default scheme for this dialog as that is already local.
|
||||
this.remoteAuthority ? this.pathService.defaultUriScheme : uri.scheme);
|
||||
}
|
||||
|
||||
private getScheme(available: readonly string[] | undefined, defaultUri: URI | undefined): string {
|
||||
if (available) {
|
||||
if (available && available.length > 0) {
|
||||
if (defaultUri && (available.indexOf(defaultUri.scheme) >= 0)) {
|
||||
return defaultUri.scheme;
|
||||
}
|
||||
@@ -919,7 +924,8 @@ export class SimpleFileDialog {
|
||||
const ext = resources.extname(file);
|
||||
for (let i = 0; i < this.options.filters.length; i++) {
|
||||
for (let j = 0; j < this.options.filters[i].extensions.length; j++) {
|
||||
if (ext === ('.' + this.options.filters[i].extensions[j])) {
|
||||
const testExt = this.options.filters[i].extensions[j];
|
||||
if ((testExt === '*') || (ext === ('.' + testExt))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import Severity from 'vs/base/common/severity';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IConfirmation, IConfirmationResult, IDialogOptions, IDialogService, IInput, IInputResult, IShowResult } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { DialogsModel, IDialogsModel } from 'vs/workbench/common/dialogs';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
|
||||
export class DialogService extends Disposable implements IDialogService {
|
||||
_serviceBrand: undefined;
|
||||
|
||||
readonly model: IDialogsModel = this._register(new DialogsModel());
|
||||
|
||||
async confirm(confirmation: IConfirmation): Promise<IConfirmationResult> {
|
||||
const handle = this.model.show({ confirmArgs: { confirmation } });
|
||||
return await handle.result as IConfirmationResult;
|
||||
}
|
||||
|
||||
async show(severity: Severity, message: string, buttons: string[], options?: IDialogOptions): Promise<IShowResult> {
|
||||
const handle = this.model.show({ showArgs: { severity, message, buttons, options } });
|
||||
return await handle.result as IShowResult;
|
||||
}
|
||||
|
||||
async input(severity: Severity, message: string, buttons: string[], inputs: IInput[], options?: IDialogOptions): Promise<IInputResult> {
|
||||
const handle = this.model.show({ inputArgs: { severity, message, buttons, inputs, options } });
|
||||
return await handle.result as IInputResult;
|
||||
}
|
||||
|
||||
async about(): Promise<void> {
|
||||
const handle = this.model.show({});
|
||||
await handle.result;
|
||||
}
|
||||
}
|
||||
|
||||
registerSingleton(IDialogService, DialogService, true);
|
||||
@@ -1,268 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import Severity from 'vs/base/common/severity';
|
||||
import { isLinux, isWindows } from 'vs/base/common/platform';
|
||||
import { mnemonicButtonLabel } from 'vs/base/common/labels';
|
||||
import { IDialogService, IConfirmation, IConfirmationResult, IDialogOptions, IShowResult, IInputResult, IInput } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { DialogService as HTMLDialogService } from 'vs/workbench/services/dialogs/browser/dialogService';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { ILayoutService } from 'vs/platform/layout/browser/layoutService';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
import { INativeHostService } from 'vs/platform/native/electron-sandbox/native';
|
||||
import { MessageBoxOptions } from 'vs/base/parts/sandbox/common/electronTypes';
|
||||
import { fromNow } from 'vs/base/common/date';
|
||||
import { process } from 'vs/base/parts/sandbox/electron-sandbox/globals';
|
||||
|
||||
interface IMassagedMessageBoxOptions {
|
||||
|
||||
/**
|
||||
* OS massaged message box options.
|
||||
*/
|
||||
options: MessageBoxOptions;
|
||||
|
||||
/**
|
||||
* Since the massaged result of the message box options potentially
|
||||
* changes the order of buttons, we have to keep a map of these
|
||||
* changes so that we can still return the correct index to the caller.
|
||||
*/
|
||||
buttonIndexMap: number[];
|
||||
}
|
||||
|
||||
export class DialogService implements IDialogService {
|
||||
|
||||
declare readonly _serviceBrand: undefined;
|
||||
|
||||
private nativeImpl: IDialogService;
|
||||
private customImpl: IDialogService;
|
||||
|
||||
constructor(
|
||||
@IConfigurationService private configurationService: IConfigurationService,
|
||||
@ILogService logService: ILogService,
|
||||
@ILayoutService layoutService: ILayoutService,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IKeybindingService keybindingService: IKeybindingService,
|
||||
@IProductService productService: IProductService,
|
||||
@IClipboardService clipboardService: IClipboardService,
|
||||
@INativeHostService nativeHostService: INativeHostService
|
||||
) {
|
||||
this.customImpl = new HTMLDialogService(logService, layoutService, themeService, keybindingService, productService, clipboardService);
|
||||
this.nativeImpl = new NativeDialogService(logService, nativeHostService, productService, clipboardService);
|
||||
}
|
||||
|
||||
private get useCustomDialog(): boolean {
|
||||
return this.configurationService.getValue('window.dialogStyle') === 'custom';
|
||||
}
|
||||
|
||||
confirm(confirmation: IConfirmation): Promise<IConfirmationResult> {
|
||||
if (this.useCustomDialog) {
|
||||
return this.customImpl.confirm(confirmation);
|
||||
}
|
||||
|
||||
return this.nativeImpl.confirm(confirmation);
|
||||
}
|
||||
|
||||
show(severity: Severity, message: string, buttons: string[], options?: IDialogOptions): Promise<IShowResult> {
|
||||
if (this.useCustomDialog) {
|
||||
return this.customImpl.show(severity, message, buttons, options);
|
||||
}
|
||||
|
||||
return this.nativeImpl.show(severity, message, buttons, options);
|
||||
}
|
||||
|
||||
input(severity: Severity, message: string, buttons: string[], inputs: IInput[], options?: IDialogOptions): Promise<IInputResult> {
|
||||
return this.customImpl.input(severity, message, buttons, inputs, options);
|
||||
}
|
||||
|
||||
about(): Promise<void> {
|
||||
return this.nativeImpl.about();
|
||||
}
|
||||
}
|
||||
|
||||
class NativeDialogService implements IDialogService {
|
||||
|
||||
declare readonly _serviceBrand: undefined;
|
||||
|
||||
constructor(
|
||||
@ILogService private readonly logService: ILogService,
|
||||
@INativeHostService private readonly nativeHostService: INativeHostService,
|
||||
@IProductService private readonly productService: IProductService,
|
||||
@IClipboardService private readonly clipboardService: IClipboardService
|
||||
) {
|
||||
}
|
||||
|
||||
async confirm(confirmation: IConfirmation): Promise<IConfirmationResult> {
|
||||
this.logService.trace('DialogService#confirm', confirmation.message);
|
||||
|
||||
const { options, buttonIndexMap } = this.massageMessageBoxOptions(this.getConfirmOptions(confirmation));
|
||||
|
||||
const result = await this.nativeHostService.showMessageBox(options);
|
||||
return {
|
||||
confirmed: buttonIndexMap[result.response] === 0 ? true : false,
|
||||
checkboxChecked: result.checkboxChecked
|
||||
};
|
||||
}
|
||||
|
||||
private getConfirmOptions(confirmation: IConfirmation): MessageBoxOptions {
|
||||
const buttons: string[] = [];
|
||||
if (confirmation.primaryButton) {
|
||||
buttons.push(confirmation.primaryButton);
|
||||
} else {
|
||||
buttons.push(nls.localize({ key: 'yesButton', comment: ['&& denotes a mnemonic'] }, "&&Yes"));
|
||||
}
|
||||
|
||||
if (confirmation.secondaryButton) {
|
||||
buttons.push(confirmation.secondaryButton);
|
||||
} else if (typeof confirmation.secondaryButton === 'undefined') {
|
||||
buttons.push(nls.localize('cancelButton', "Cancel"));
|
||||
}
|
||||
|
||||
const opts: MessageBoxOptions = {
|
||||
title: confirmation.title,
|
||||
message: confirmation.message,
|
||||
buttons,
|
||||
cancelId: 1
|
||||
};
|
||||
|
||||
if (confirmation.detail) {
|
||||
opts.detail = confirmation.detail;
|
||||
}
|
||||
|
||||
if (confirmation.type) {
|
||||
opts.type = confirmation.type;
|
||||
}
|
||||
|
||||
if (confirmation.checkbox) {
|
||||
opts.checkboxLabel = confirmation.checkbox.label;
|
||||
opts.checkboxChecked = confirmation.checkbox.checked;
|
||||
}
|
||||
|
||||
return opts;
|
||||
}
|
||||
|
||||
async show(severity: Severity, message: string, buttons: string[], dialogOptions?: IDialogOptions): Promise<IShowResult> {
|
||||
this.logService.trace('DialogService#show', message);
|
||||
|
||||
const { options, buttonIndexMap } = this.massageMessageBoxOptions({
|
||||
message,
|
||||
buttons,
|
||||
type: (severity === Severity.Info) ? 'question' : (severity === Severity.Error) ? 'error' : (severity === Severity.Warning) ? 'warning' : 'none',
|
||||
cancelId: dialogOptions ? dialogOptions.cancelId : undefined,
|
||||
detail: dialogOptions ? dialogOptions.detail : undefined,
|
||||
checkboxLabel: dialogOptions && dialogOptions.checkbox ? dialogOptions.checkbox.label : undefined,
|
||||
checkboxChecked: dialogOptions && dialogOptions.checkbox ? dialogOptions.checkbox.checked : undefined
|
||||
});
|
||||
|
||||
const result = await this.nativeHostService.showMessageBox(options);
|
||||
return { choice: buttonIndexMap[result.response], checkboxChecked: result.checkboxChecked };
|
||||
}
|
||||
|
||||
private massageMessageBoxOptions(options: MessageBoxOptions): IMassagedMessageBoxOptions {
|
||||
let buttonIndexMap = (options.buttons || []).map((button, index) => index);
|
||||
let buttons = (options.buttons || []).map(button => mnemonicButtonLabel(button));
|
||||
let cancelId = options.cancelId;
|
||||
|
||||
// Linux: order of buttons is reverse
|
||||
// macOS: also reverse, but the OS handles this for us!
|
||||
if (isLinux) {
|
||||
buttons = buttons.reverse();
|
||||
buttonIndexMap = buttonIndexMap.reverse();
|
||||
}
|
||||
|
||||
// Default Button (always first one)
|
||||
options.defaultId = buttonIndexMap[0];
|
||||
|
||||
// Cancel Button
|
||||
if (typeof cancelId === 'number') {
|
||||
|
||||
// Ensure the cancelId is the correct one from our mapping
|
||||
cancelId = buttonIndexMap[cancelId];
|
||||
|
||||
// macOS/Linux: the cancel button should always be to the left of the primary action
|
||||
// if we see more than 2 buttons, move the cancel one to the left of the primary
|
||||
if (!isWindows && buttons.length > 2 && cancelId !== 1) {
|
||||
const cancelButton = buttons[cancelId];
|
||||
buttons.splice(cancelId, 1);
|
||||
buttons.splice(1, 0, cancelButton);
|
||||
|
||||
const cancelButtonIndex = buttonIndexMap[cancelId];
|
||||
buttonIndexMap.splice(cancelId, 1);
|
||||
buttonIndexMap.splice(1, 0, cancelButtonIndex);
|
||||
|
||||
cancelId = 1;
|
||||
}
|
||||
}
|
||||
|
||||
options.buttons = buttons;
|
||||
options.cancelId = cancelId;
|
||||
options.noLink = true;
|
||||
options.title = options.title || this.productService.nameLong;
|
||||
|
||||
return { options, buttonIndexMap };
|
||||
}
|
||||
|
||||
input(): never {
|
||||
throw new Error('Unsupported'); // we have no native API for password dialogs in Electron
|
||||
}
|
||||
|
||||
async about(): Promise<void> {
|
||||
let version = this.productService.version;
|
||||
if (this.productService.target) {
|
||||
version = `${version} (${this.productService.target} setup)`;
|
||||
}
|
||||
|
||||
const isSnap = process.platform === 'linux' && process.env.SNAP && process.env.SNAP_REVISION;
|
||||
const osProps = await this.nativeHostService.getOSProperties();
|
||||
|
||||
const detailString = (useAgo: boolean): string => {
|
||||
return nls.localize({ key: 'aboutDetail', comment: ['Electron, Chrome, Node.js and V8 are product names that need no translation'] },
|
||||
"Version: {0}\nCommit: {1}\nDate: {2}\nElectron: {3}\nChrome: {4}\nNode.js: {5}\nV8: {6}\nOS: {7}",
|
||||
version,
|
||||
this.productService.commit || 'Unknown',
|
||||
this.productService.date ? `${this.productService.date}${useAgo ? ' (' + fromNow(new Date(this.productService.date), true) + ')' : ''}` : 'Unknown',
|
||||
process.versions['electron'],
|
||||
process.versions['chrome'],
|
||||
process.versions['node'],
|
||||
process.versions['v8'],
|
||||
`${osProps.type} ${osProps.arch} ${osProps.release}${isSnap ? ' snap' : ''}`
|
||||
);
|
||||
};
|
||||
|
||||
const detail = detailString(true);
|
||||
const detailToCopy = detailString(false);
|
||||
|
||||
const ok = nls.localize('okButton', "OK");
|
||||
const copy = mnemonicButtonLabel(nls.localize({ key: 'copy', comment: ['&& denotes a mnemonic'] }, "&&Copy"));
|
||||
let buttons: string[];
|
||||
if (isLinux) {
|
||||
buttons = [copy, ok];
|
||||
} else {
|
||||
buttons = [ok, copy];
|
||||
}
|
||||
|
||||
const result = await this.nativeHostService.showMessageBox({
|
||||
title: this.productService.nameLong,
|
||||
type: 'info',
|
||||
message: this.productService.nameLong,
|
||||
detail: `\n${detail}`,
|
||||
buttons,
|
||||
noLink: true,
|
||||
defaultId: buttons.indexOf(ok),
|
||||
cancelId: buttons.indexOf(ok)
|
||||
});
|
||||
|
||||
if (buttons[result.response] === copy) {
|
||||
this.clipboardService.writeText(detailToCopy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
registerSingleton(IDialogService, DialogService, true);
|
||||
@@ -68,7 +68,7 @@ export class FileDialogService extends AbstractFileDialogService implements IFil
|
||||
const schema = this.getFileSystemSchema(options);
|
||||
|
||||
if (!options.defaultUri) {
|
||||
options.defaultUri = this.defaultFilePath(schema);
|
||||
options.defaultUri = await this.defaultFilePath(schema);
|
||||
}
|
||||
|
||||
const shouldUseSimplified = this.shouldUseSimplified(schema);
|
||||
@@ -82,7 +82,7 @@ export class FileDialogService extends AbstractFileDialogService implements IFil
|
||||
const schema = this.getFileSystemSchema(options);
|
||||
|
||||
if (!options.defaultUri) {
|
||||
options.defaultUri = this.defaultFilePath(schema);
|
||||
options.defaultUri = await this.defaultFilePath(schema);
|
||||
}
|
||||
|
||||
const shouldUseSimplified = this.shouldUseSimplified(schema);
|
||||
@@ -96,7 +96,7 @@ export class FileDialogService extends AbstractFileDialogService implements IFil
|
||||
const schema = this.getFileSystemSchema(options);
|
||||
|
||||
if (!options.defaultUri) {
|
||||
options.defaultUri = this.defaultFolderPath(schema);
|
||||
options.defaultUri = await this.defaultFolderPath(schema);
|
||||
}
|
||||
|
||||
if (this.shouldUseSimplified(schema).useSimplified) {
|
||||
@@ -109,7 +109,7 @@ export class FileDialogService extends AbstractFileDialogService implements IFil
|
||||
const schema = this.getFileSystemSchema(options);
|
||||
|
||||
if (!options.defaultUri) {
|
||||
options.defaultUri = this.defaultWorkspacePath(schema);
|
||||
options.defaultUri = await this.defaultWorkspacePath(schema);
|
||||
}
|
||||
|
||||
if (this.shouldUseSimplified(schema).useSimplified) {
|
||||
|
||||
Reference in New Issue
Block a user