Merge from vscode 1eb87b0e9ce9886afeaecec22b31abd0d9b7939f (#7282)

* Merge from vscode 1eb87b0e9ce9886afeaecec22b31abd0d9b7939f

* fix various icon issues

* fix preview features
This commit is contained in:
Anthony Dresser
2019-09-19 21:50:52 -07:00
committed by GitHub
parent 9d3d64eef3
commit db498db0a8
459 changed files with 10195 additions and 7528 deletions

View File

@@ -337,7 +337,7 @@ export class WorkspaceConfiguration extends Disposable {
setFolders(folders: IStoredWorkspaceFolder[], jsonEditingService: JSONEditingService): Promise<void> {
if (this._workspaceIdentifier) {
return jsonEditingService.write(this._workspaceIdentifier.configPath, { key: 'folders', value: folders }, true)
return jsonEditingService.write(this._workspaceIdentifier.configPath, [{ key: 'folders', value: folders }], true)
.then(() => this.reload());
}
return Promise.resolve();

View File

@@ -36,5 +36,5 @@ export interface IJSONEditingService {
_serviceBrand: undefined;
write(resource: URI, value: IJSONValue, save: boolean): Promise<void>;
write(resource: URI, values: IJSONValue[], save: boolean): Promise<void>;
}

View File

@@ -35,20 +35,24 @@ export class JSONEditingService implements IJSONEditingService {
this.queue = new Queue<void>();
}
write(resource: URI, value: IJSONValue, save: boolean): Promise<void> {
return Promise.resolve(this.queue.queue(() => this.doWriteConfiguration(resource, value, save))); // queue up writes to prevent race conditions
write(resource: URI, values: IJSONValue[], save: boolean): Promise<void> {
return Promise.resolve(this.queue.queue(() => this.doWriteConfiguration(resource, values, save))); // queue up writes to prevent race conditions
}
private async doWriteConfiguration(resource: URI, value: IJSONValue, save: boolean): Promise<void> {
private async doWriteConfiguration(resource: URI, values: IJSONValue[], save: boolean): Promise<void> {
const reference = await this.resolveAndValidate(resource, save);
await this.writeToBuffer(reference.object.textEditorModel, value);
await this.writeToBuffer(reference.object.textEditorModel, values);
reference.dispose();
}
private async writeToBuffer(model: ITextModel, value: IJSONValue): Promise<any> {
const edit = this.getEdits(model, value)[0];
if (this.applyEditsToBuffer(edit, model)) {
private async writeToBuffer(model: ITextModel, values: IJSONValue[]): Promise<any> {
let hasEdits: boolean = false;
for (const value of values) {
const edit = this.getEdits(model, value)[0];
hasEdits = this.applyEditsToBuffer(edit, model);
}
if (hasEdits) {
return this.textFileService.save(model.uri);
}
}
@@ -133,4 +137,4 @@ export class JSONEditingService implements IJSONEditingService {
}
}
registerSingleton(IJSONEditingService, JSONEditingService, true);
registerSingleton(IJSONEditingService, JSONEditingService, true);

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { writeFile } from 'vs/base/node/pfs';
import product from 'vs/platform/product/node/product';
import product from 'vs/platform/product/common/product';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { Registry } from 'vs/platform/registry/common/platform';
import { IConfigurationNode, IConfigurationRegistry, Extensions, IConfigurationPropertySchema } from 'vs/platform/configuration/common/configurationRegistry';

View File

@@ -1161,21 +1161,21 @@ suite.skip('WorkspaceConfigurationService-Multiroot', () => { // {{SQL CARBON ED
test('application settings are not read from workspace', () => {
fs.writeFileSync(globalSettingsFile, '{ "configurationService.workspace.applicationSetting": "userValue" }');
return jsonEditingServce.write(workspaceContextService.getWorkspace().configuration!, { key: 'settings', value: { 'configurationService.workspace.applicationSetting': 'workspaceValue' } }, true)
return jsonEditingServce.write(workspaceContextService.getWorkspace().configuration!, [{ key: 'settings', value: { 'configurationService.workspace.applicationSetting': 'workspaceValue' } }], true)
.then(() => testObject.reloadConfiguration())
.then(() => assert.equal(testObject.getValue('configurationService.workspace.applicationSetting'), 'userValue'));
});
test('machine settings are not read from workspace', () => {
fs.writeFileSync(globalSettingsFile, '{ "configurationService.workspace.machineSetting": "userValue" }');
return jsonEditingServce.write(workspaceContextService.getWorkspace().configuration!, { key: 'settings', value: { 'configurationService.workspace.machineSetting': 'workspaceValue' } }, true)
return jsonEditingServce.write(workspaceContextService.getWorkspace().configuration!, [{ key: 'settings', value: { 'configurationService.workspace.machineSetting': 'workspaceValue' } }], true)
.then(() => testObject.reloadConfiguration())
.then(() => assert.equal(testObject.getValue('configurationService.workspace.machineSetting'), 'userValue'));
});
test('workspace settings override user settings after defaults are registered ', () => {
fs.writeFileSync(globalSettingsFile, '{ "configurationService.workspace.newSetting": "userValue" }');
return jsonEditingServce.write(workspaceContextService.getWorkspace().configuration!, { key: 'settings', value: { 'configurationService.workspace.newSetting': 'workspaceValue' } }, true)
return jsonEditingServce.write(workspaceContextService.getWorkspace().configuration!, [{ key: 'settings', value: { 'configurationService.workspace.newSetting': 'workspaceValue' } }], true)
.then(() => testObject.reloadConfiguration())
.then(() => {
configurationRegistry.registerConfiguration({
@@ -1194,7 +1194,7 @@ suite.skip('WorkspaceConfigurationService-Multiroot', () => { // {{SQL CARBON ED
test('workspace settings override user settings after defaults are registered for machine overridable settings ', () => {
fs.writeFileSync(globalSettingsFile, '{ "configurationService.workspace.newMachineOverridableSetting": "userValue" }');
return jsonEditingServce.write(workspaceContextService.getWorkspace().configuration!, { key: 'settings', value: { 'configurationService.workspace.newMachineOverridableSetting': 'workspaceValue' } }, true)
return jsonEditingServce.write(workspaceContextService.getWorkspace().configuration!, [{ key: 'settings', value: { 'configurationService.workspace.newMachineOverridableSetting': 'workspaceValue' } }], true)
.then(() => testObject.reloadConfiguration())
.then(() => {
configurationRegistry.registerConfiguration({
@@ -1268,7 +1268,7 @@ suite.skip('WorkspaceConfigurationService-Multiroot', () => { // {{SQL CARBON ED
test('resource setting in folder is read after it is registered later', () => {
fs.writeFileSync(workspaceContextService.getWorkspace().folders[0].toResource('.vscode/settings.json').fsPath, '{ "configurationService.workspace.testNewResourceSetting2": "workspaceFolderValue" }');
return jsonEditingServce.write(workspaceContextService.getWorkspace().configuration!, { key: 'settings', value: { 'configurationService.workspace.testNewResourceSetting2': 'workspaceValue' } }, true)
return jsonEditingServce.write(workspaceContextService.getWorkspace().configuration!, [{ key: 'settings', value: { 'configurationService.workspace.testNewResourceSetting2': 'workspaceValue' } }], true)
.then(() => testObject.reloadConfiguration())
.then(() => {
configurationRegistry.registerConfiguration({
@@ -1288,7 +1288,7 @@ suite.skip('WorkspaceConfigurationService-Multiroot', () => { // {{SQL CARBON ED
test('machine overridable setting in folder is read after it is registered later', () => {
fs.writeFileSync(workspaceContextService.getWorkspace().folders[0].toResource('.vscode/settings.json').fsPath, '{ "configurationService.workspace.testNewMachineOverridableSetting2": "workspaceFolderValue" }');
return jsonEditingServce.write(workspaceContextService.getWorkspace().configuration!, { key: 'settings', value: { 'configurationService.workspace.testNewMachineOverridableSetting2': 'workspaceValue' } }, true)
return jsonEditingServce.write(workspaceContextService.getWorkspace().configuration!, [{ key: 'settings', value: { 'configurationService.workspace.testNewMachineOverridableSetting2': 'workspaceValue' } }], true)
.then(() => testObject.reloadConfiguration())
.then(() => {
configurationRegistry.registerConfiguration({
@@ -1331,7 +1331,7 @@ suite.skip('WorkspaceConfigurationService-Multiroot', () => { // {{SQL CARBON ED
assert.equal(actual.workspaceFolder, undefined);
assert.equal(actual.value, 'userValue');
return jsonEditingServce.write(workspaceContextService.getWorkspace().configuration!, { key: 'settings', value: { 'configurationService.workspace.testResourceSetting': 'workspaceValue' } }, true)
return jsonEditingServce.write(workspaceContextService.getWorkspace().configuration!, [{ key: 'settings', value: { 'configurationService.workspace.testResourceSetting': 'workspaceValue' } }], true)
.then(() => testObject.reloadConfiguration())
.then(() => {
actual = testObject.inspect('configurationService.workspace.testResourceSetting');
@@ -1373,7 +1373,7 @@ suite.skip('WorkspaceConfigurationService-Multiroot', () => { // {{SQL CARBON ED
}
]
};
return jsonEditingServce.write(workspaceContextService.getWorkspace().configuration!, { key: 'launch', value: expectedLaunchConfiguration }, true)
return jsonEditingServce.write(workspaceContextService.getWorkspace().configuration!, [{ key: 'launch', value: expectedLaunchConfiguration }], true)
.then(() => testObject.reloadConfiguration())
.then(() => {
const actual = testObject.getValue('launch');
@@ -1398,7 +1398,7 @@ suite.skip('WorkspaceConfigurationService-Multiroot', () => { // {{SQL CARBON ED
}
]
};
return jsonEditingServce.write(workspaceContextService.getWorkspace().configuration!, { key: 'launch', value: expectedLaunchConfiguration }, true)
return jsonEditingServce.write(workspaceContextService.getWorkspace().configuration!, [{ key: 'launch', value: expectedLaunchConfiguration }], true)
.then(() => testObject.reloadConfiguration())
.then(() => {
const actual = testObject.inspect('launch').workspace;
@@ -1496,7 +1496,7 @@ suite.skip('WorkspaceConfigurationService-Multiroot', () => { // {{SQL CARBON ED
});
test('task configurations are not read from workspace', () => {
return jsonEditingServce.write(workspaceContextService.getWorkspace().configuration!, { key: 'tasks', value: { 'version': '1.0' } }, true)
return jsonEditingServce.write(workspaceContextService.getWorkspace().configuration!, [{ key: 'tasks', value: { 'version': '1.0' } }], true)
.then(() => testObject.reloadConfiguration())
.then(() => {
const actual = testObject.inspect('tasks.version');

View File

@@ -3,14 +3,16 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ICredentialsService } from 'vs/workbench/services/credentials/common/credentials';
import { ICredentialsService } from 'vs/platform/credentials/common/credentials';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
export interface ICredentialsProvider {
getPassword(service: string, account: string): Promise<string | null>;
setPassword(service: string, account: string, password: string): Promise<void>;
deletePassword(service: string, account: string): Promise<boolean>;
findPassword(service: string): Promise<string | null>;
findCredentials(service: string): Promise<Array<{ account: string, password: string }>>;
}

View File

@@ -1,19 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
export const ICredentialsService = createDecorator<ICredentialsService>('ICredentialsService');
export interface ICredentialsService {
_serviceBrand: undefined;
getPassword(service: string, account: string): Promise<string | null>;
setPassword(service: string, account: string, password: string): Promise<void>;
deletePassword(service: string, account: string): Promise<boolean>;
findPassword(service: string): Promise<string | null>;
findCredentials(service: string): Promise<Array<{ account: string, password: string }>>;
}

View File

@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ICredentialsService } from 'vs/workbench/services/credentials/common/credentials';
import { ICredentialsService } from 'vs/platform/credentials/common/credentials';
import { IdleValue } from 'vs/base/common/async';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';

View File

@@ -0,0 +1,140 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import { IDialogService, IDialogOptions, IConfirmation, IConfirmationResult, DialogType, IShowResult } 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 } 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';
export class DialogService implements IDialogService {
_serviceBrand: undefined;
private allowableCommands = ['copy', 'cut'];
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 dialogDisposables = new DisposableStore();
const dialog = new Dialog(
this.layoutService.container,
confirmation.message,
buttons,
{
detail: confirmation.detail,
cancelId: 1,
type: confirmation.type,
keyEventProcessor: (event: StandardKeyboardEvent) => {
const resolved = this.keybindingService.softDispatch(event, this.layoutService.container);
if (resolved && resolved.commandId) {
if (this.allowableCommands.indexOf(resolved.commandId) === -1) {
EventHelper.stop(event, true);
}
}
},
checkboxChecked: confirmation.checkbox ? confirmation.checkbox.checked : undefined,
checkboxLabel: confirmation.checkbox ? confirmation.checkbox.label : undefined
});
dialogDisposables.add(dialog);
dialogDisposables.add(attachDialogStyler(dialog, this.themeService));
const result = await dialog.show();
dialogDisposables.dispose();
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 dialogDisposables = new DisposableStore();
const dialog = new Dialog(
this.layoutService.container,
message,
buttons,
{
detail: options ? options.detail : undefined,
cancelId: options ? options.cancelId : undefined,
type: this.getDialogType(severity),
keyEventProcessor: (event: StandardKeyboardEvent) => {
const resolved = this.keybindingService.softDispatch(event, this.layoutService.container);
if (resolved && resolved.commandId) {
if (this.allowableCommands.indexOf(resolved.commandId) === -1) {
EventHelper.stop(event, true);
}
}
},
checkboxLabel: options && options.checkbox ? options.checkbox.label : undefined,
checkboxChecked: options && options.checkbox ? options.checkbox.checked : undefined
});
dialogDisposables.add(dialog);
dialogDisposables.add(attachDialogStyler(dialog, this.themeService));
const result = await dialog.show();
dialogDisposables.dispose();
return {
choice: result.button,
checkboxChecked: result.checkboxChecked
};
}
async about(): Promise<void> {
const detail = nls.localize('aboutDetail',
"Version: {0}\nCommit: {1}\nDate: {2}\nBrowser: {3}",
this.productService.version || 'Unknown',
this.productService.commit || 'Unknown',
this.productService.date || 'Unknown',
navigator.userAgent
);
const { choice } = await this.show(Severity.Info, this.productService.nameLong, [nls.localize('copy', "Copy"), nls.localize('ok', "OK")], { detail });
if (choice === 0) {
this.clipboardService.writeText(detail);
}
}
}
registerSingleton(IDialogService, DialogService, true);

View File

@@ -23,7 +23,6 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
import { equalsIgnoreCase, format, startsWithIgnoreCase } from 'vs/base/common/strings';
import { OpenLocalFileCommand, OpenLocalFileFolderCommand, OpenLocalFolderCommand, SaveLocalFileCommand } from 'vs/workbench/browser/actions/workspaceActions';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEnvironment';
import { isValidBasename } from 'vs/base/common/extpath';
@@ -32,6 +31,60 @@ import { Emitter } from 'vs/base/common/event';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { createCancelablePromise, CancelablePromise } from 'vs/base/common/async';
import { CancellationToken } from 'vs/base/common/cancellation';
import { ICommandHandler } from 'vs/platform/commands/common/commands';
import { ITextFileService, ISaveOptions } from 'vs/workbench/services/textfile/common/textfiles';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { toResource } from 'vs/workbench/common/editor';
export namespace OpenLocalFileCommand {
export const ID = 'workbench.action.files.openLocalFile';
export const LABEL = nls.localize('openLocalFile', "Open Local File...");
export function handler(): ICommandHandler {
return accessor => {
const dialogService = accessor.get(IFileDialogService);
return dialogService.pickFileAndOpen({ forceNewWindow: false, availableFileSystems: [Schemas.file] });
};
}
}
export namespace SaveLocalFileCommand {
export const ID = 'workbench.action.files.saveLocalFile';
export const LABEL = nls.localize('saveLocalFile', "Save Local File...");
export function handler(): ICommandHandler {
return accessor => {
const textFileService = accessor.get(ITextFileService);
const editorService = accessor.get(IEditorService);
let resource: URI | undefined = toResource(editorService.activeEditor);
const options: ISaveOptions = { force: true, availableFileSystems: [Schemas.file] };
if (resource) {
return textFileService.saveAs(resource, undefined, options);
}
return Promise.resolve(undefined);
};
}
}
export namespace OpenLocalFolderCommand {
export const ID = 'workbench.action.files.openLocalFolder';
export const LABEL = nls.localize('openLocalFolder', "Open Local Folder...");
export function handler(): ICommandHandler {
return accessor => {
const dialogService = accessor.get(IFileDialogService);
return dialogService.pickFolderAndOpen({ forceNewWindow: false, availableFileSystems: [Schemas.file] });
};
}
}
export namespace OpenLocalFileFolderCommand {
export const ID = 'workbench.action.files.openLocalFileFolder';
export const LABEL = nls.localize('openLocalFileFolder', "Open Local...");
export function handler(): ICommandHandler {
return accessor => {
const dialogService = accessor.get(IFileDialogService);
return dialogService.pickFileFolderAndOpen({ forceNewWindow: false, availableFileSystems: [Schemas.file] });
};
}
}
interface FileQuickPickItem extends IQuickPickItem {
uri: URI;

View File

@@ -4,21 +4,25 @@
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import product from 'vs/platform/product/node/product';
import * as os from 'os';
import product from 'vs/platform/product/common/product';
import Severity from 'vs/base/common/severity';
import { isLinux, isWindows } from 'vs/base/common/platform';
import { IWindowService } from 'vs/platform/windows/common/windows';
import { mnemonicButtonLabel } from 'vs/base/common/labels';
import { IDialogService, IConfirmation, IConfirmationResult, IDialogOptions, IShowResult } from 'vs/platform/dialogs/common/dialogs';
import { DialogService as HTMLDialogService } from 'vs/platform/dialogs/browser/dialogService';
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 { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService';
import { DialogChannel } from 'vs/platform/dialogs/node/dialogIpc';
import { DialogChannel } from 'vs/platform/dialogs/electron-browser/dialogIpc';
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 { IElectronService } from 'vs/platform/electron/node/electron';
interface IMassagedMessageBoxOptions {
@@ -36,6 +40,7 @@ interface IMassagedMessageBoxOptions {
}
export class DialogService implements IDialogService {
_serviceBrand: undefined;
private impl: IDialogService;
@@ -47,25 +52,33 @@ export class DialogService implements IDialogService {
@IThemeService themeService: IThemeService,
@IWindowService windowService: IWindowService,
@ISharedProcessService sharedProcessService: ISharedProcessService,
@IKeybindingService keybindingService: IKeybindingService
@IKeybindingService keybindingService: IKeybindingService,
@IProductService productService: IProductService,
@IClipboardService clipboardService: IClipboardService,
@IElectronService electronService: IElectronService
) {
// Use HTML based dialogs
if (configurationService.getValue('workbench.dialogs.customEnabled') === true) {
this.impl = new HTMLDialogService(logService, layoutService, themeService, keybindingService);
this.impl = new HTMLDialogService(logService, layoutService, themeService, keybindingService, productService, clipboardService);
}
// Electron dialog service
else {
this.impl = new NativeDialogService(windowService, logService, sharedProcessService);
this.impl = new NativeDialogService(windowService, logService, sharedProcessService, electronService, clipboardService);
}
}
confirm(confirmation: IConfirmation): Promise<IConfirmationResult> {
return this.impl.confirm(confirmation);
}
show(severity: Severity, message: string, buttons: string[], options?: IDialogOptions | undefined): Promise<IShowResult> {
return this.impl.show(severity, message, buttons, options);
}
about(): Promise<void> {
return this.impl.about();
}
}
class NativeDialogService implements IDialogService {
@@ -75,7 +88,9 @@ class NativeDialogService implements IDialogService {
constructor(
@IWindowService private readonly windowService: IWindowService,
@ILogService private readonly logService: ILogService,
@ISharedProcessService sharedProcessService: ISharedProcessService
@ISharedProcessService sharedProcessService: ISharedProcessService,
@IElectronService private readonly electronService: IElectronService,
@IClipboardService private readonly clipboardService: IClipboardService
) {
sharedProcessService.registerChannel('dialog', new DialogChannel(this));
}
@@ -189,6 +204,51 @@ class NativeDialogService implements IDialogService {
return { options, buttonIndexMap };
}
async about(): Promise<void> {
let version = product.version;
if (product.target) {
version = `${version} (${product.target} setup)`;
}
const isSnap = process.platform === 'linux' && process.env.SNAP && process.env.SNAP_REVISION;
const detail = nls.localize('aboutDetail', // {{SQL CARBON EDIT}} update about dialog
"Version: {0}\nCommit: {1}\nDate: {2}\nVS Code: {8}\nElectron: {3}\nChrome: {4}\nNode.js: {5}\nV8: {6}\nOS: {7}",
version,
product.commit || 'Unknown',
product.date || 'Unknown',
process.versions['electron'],
process.versions['chrome'],
process.versions['node'],
process.versions['v8'],
`${os.type()} ${os.arch()} ${os.release()}${isSnap ? ' snap' : ''}`,
product.vscodeVersion
);
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.electronService.showMessageBox({
title: product.nameLong,
type: 'info',
message: product.nameLong,
detail: `\n${detail}`,
buttons,
noLink: true,
defaultId: buttons.indexOf(ok),
cancelId: buttons.indexOf(ok)
});
if (buttons[result.response] === copy) {
this.clipboardService.writeText(detail);
}
}
}
registerSingleton(IDialogService, DialogService, true);

View File

@@ -3,18 +3,19 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IWindowConfiguration, IPath, IPathsToWaitFor } from 'vs/platform/windows/common/windows';
import { IExtensionHostDebugParams, IDebugParams, BACKUPS } from 'vs/platform/environment/common/environment';
import { URI } from 'vs/base/common/uri';
import { IProcessEnvironment } from 'vs/base/common/platform';
import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
import { ExportData } from 'vs/base/common/performance';
import { LogLevel } from 'vs/platform/log/common/log';
import { joinPath } from 'vs/base/common/resources';
import { Schemas } from 'vs/base/common/network';
import { ExportData } from 'vs/base/common/performance';
import { IProcessEnvironment } from 'vs/base/common/platform';
import { joinPath } from 'vs/base/common/resources';
import { URI } from 'vs/base/common/uri';
import { generateUuid } from 'vs/base/common/uuid';
import { BACKUPS, IDebugParams, IExtensionHostDebugParams } from 'vs/platform/environment/common/environment';
import { LogLevel } from 'vs/platform/log/common/log';
import { IPath, IPathsToWaitFor, IWindowConfiguration } from 'vs/platform/windows/common/windows';
import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { IWorkbenchConstructionOptions } from 'vs/workbench/workbench.web.api';
import { generateUuid } from 'vs/base/common/uuid';
import product from 'vs/platform/product/common/product';
export class BrowserWindowConfiguration implements IWindowConfiguration {
@@ -83,6 +84,7 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment
this.configuration.machineId = generateUuid();
this.userRoamingDataHome = URI.file('/User').with({ scheme: Schemas.userData });
this.settingsResource = joinPath(this.userRoamingDataHome, 'settings.json');
this.settingsSyncPreviewResource = joinPath(this.userRoamingDataHome, '.settings.json');
this.keybindingsResource = joinPath(this.userRoamingDataHome, 'keybindings.json');
this.keyboardLayoutResource = joinPath(this.userRoamingDataHome, 'keyboardLayout.json');
this.localeResource = joinPath(this.userRoamingDataHome, 'locale.json');
@@ -140,6 +142,7 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment
appSettingsHome: URI;
userRoamingDataHome: URI;
settingsResource: URI;
settingsSyncPreviewResource: URI;
keybindingsResource: URI;
keyboardLayoutResource: URI;
localeResource: URI;
@@ -178,12 +181,19 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment
galleryMachineIdResource?: URI;
readonly logFile: URI;
get webviewExternalEndpoint(): string {
// TODO: get fallback from product.json
return (this.options.webviewEndpoint || 'https://{{uuid}}.vscode-webview-test.com/{{commit}}')
.replace('{{commit}}', product.commit || '211fa02efe8c041fd7baa8ec3dce199d5185aa44');
}
get webviewResourceRoot(): string {
return this.options.webviewEndpoint ? `${this.options.webviewEndpoint}/vscode-resource{{resource}}` : 'vscode-resource:{{resource}}';
return `${this.webviewExternalEndpoint}/vscode-resource{{resource}}`;
}
get webviewCspSource(): string {
return this.options.webviewEndpoint ? this.options.webviewEndpoint : 'vscode-resource:';
return this.webviewExternalEndpoint
.replace('{{uuid}}', '*');
}
}

View File

@@ -24,6 +24,7 @@ export interface IWorkbenchEnvironmentService extends IEnvironmentService {
readonly debugSearch: IDebugParams;
readonly webviewExternalEndpoint: string;
readonly webviewResourceRoot: string;
readonly webviewCspSource: string;

View File

@@ -12,11 +12,17 @@ import { Schemas } from 'vs/base/common/network';
import { toBackupWorkspaceResource } from 'vs/workbench/services/backup/common/backup';
import { join } from 'vs/base/common/path';
import { IDebugParams } from 'vs/platform/environment/common/environment';
import product from 'vs/platform/product/common/product';
export class WorkbenchEnvironmentService extends EnvironmentService implements IWorkbenchEnvironmentService {
_serviceBrand: undefined;
get webviewExternalEndpoint(): string {
const baseEndpoint = 'https://{{uuid}}.vscode-webview-test.com/{{commit}}';
return baseEndpoint.replace('{{commit}}', product.commit || '211fa02efe8c041fd7baa8ec3dce199d5185aa44');
}
readonly webviewResourceRoot = 'vscode-resource:{{resource}}';
readonly webviewCspSource = 'vscode-resource:';

View File

@@ -17,7 +17,7 @@ import { ExtensionType, IExtension } from 'vs/platform/extensions/common/extensi
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { isUIExtension } from 'vs/workbench/services/extensions/common/extensionsUtil';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IProductService } from 'vs/platform/product/common/product';
import { IProductService } from 'vs/platform/product/common/productService';
const DISABLED_EXTENSIONS_STORAGE_PATH = 'extensionsIdentifiers/disabled';
const ENABLED_EXTENSIONS_STORAGE_PATH = 'extensionsIdentifiers/enabled';
@@ -377,4 +377,4 @@ class StorageManager extends Disposable {
}
}
registerSingleton(IExtensionEnablementService, ExtensionEnablementService, true);
registerSingleton(IExtensionEnablementService, ExtensionEnablementService, true);

View File

@@ -16,7 +16,7 @@ import { CancellationToken } from 'vs/base/common/cancellation';
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { localize } from 'vs/nls';
import { isUIExtension } from 'vs/workbench/services/extensions/common/extensionsUtil';
import { IProductService } from 'vs/platform/product/common/product';
import { IProductService } from 'vs/platform/product/common/productService';
import { Schemas } from 'vs/base/common/network';
import { IDownloadService } from 'vs/platform/download/common/download';

View File

@@ -17,7 +17,7 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { ILogService } from 'vs/platform/log/common/log';
import { RemoteExtensionManagementChannelClient } from 'vs/workbench/services/extensions/electron-browser/remoteExtensionManagementIpc';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IProductService } from 'vs/platform/product/common/product';
import { IProductService } from 'vs/platform/product/common/productService';
import { ILabelService } from 'vs/platform/label/common/label';
const localExtensionManagementServerAuthority: string = 'vscode-local';
@@ -63,4 +63,4 @@ export class ExtensionManagementServerService implements IExtensionManagementSer
}
}
registerSingleton(IExtensionManagementServerService, ExtensionManagementServerService);
registerSingleton(IExtensionManagementServerService, ExtensionManagementServerService);

View File

@@ -12,7 +12,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IFileService } from 'vs/platform/files/common/files';
import { IProductService } from 'vs/platform/product/common/product';
import { IProductService } from 'vs/platform/product/common/productService';
import { AbstractExtensionService } from 'vs/workbench/services/extensions/common/abstractExtensionService';
import { ExtensionHostProcessManager } from 'vs/workbench/services/extensions/common/extensionHostProcessManager';
import { RemoteExtensionHostClient, IInitDataProvider } from 'vs/workbench/services/extensions/common/remoteExtensionHostClient';

View File

@@ -9,7 +9,7 @@ import { DisposableStore, toDisposable } from 'vs/base/common/lifecycle';
import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc';
import { VSBuffer } from 'vs/base/common/buffer';
import { createMessageOfType, MessageType, isMessageOfType } from 'vs/workbench/services/extensions/common/extensionHostProtocol';
import { IInitData } from 'vs/workbench/api/common/extHost.protocol';
import { IInitData, UIKind } from 'vs/workbench/api/common/extHost.protocol';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { ILabelService } from 'vs/platform/label/common/label';
@@ -18,7 +18,7 @@ import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'
import * as platform from 'vs/base/common/platform';
import { URI } from 'vs/base/common/uri';
import { IExtensionHostStarter } from 'vs/workbench/services/extensions/common/extensions';
import { IProductService } from 'vs/platform/product/common/product';
import { IProductService } from 'vs/platform/product/common/productService';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
export class WebWorkerExtensionHostStarter implements IExtensionHostStarter {
@@ -151,6 +151,7 @@ export class WebWorkerExtensionHostStarter implements IExtensionHostStarter {
authority: this._environmentService.configuration.remoteAuthority,
isRemote: false
},
uiKind: platform.isWeb ? UIKind.Web : UIKind.Desktop
};
}
}

View File

@@ -23,7 +23,7 @@ import { ExtensionHostProcessManager } from 'vs/workbench/services/extensions/co
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { IFileService } from 'vs/platform/files/common/files';
import { parseExtensionDevOptions } from 'vs/workbench/services/extensions/common/extensionDevOptions';
import { IProductService } from 'vs/platform/product/common/product';
import { IProductService } from 'vs/platform/product/common/productService';
const hasOwnProperty = Object.hasOwnProperty;
const NO_OP_VOID_PROMISE = Promise.resolve<void>(undefined);

View File

@@ -267,6 +267,11 @@ export const schema = {
body: 'onView:${5:viewId}',
description: nls.localize('vscode.extension.activationEvents.onView', 'An activation event emitted whenever the specified view is expanded.'),
},
{
label: 'onIdentity',
body: 'onIdentity:${8:identity}',
description: nls.localize('vscode.extension.activationEvents.onIdentity', 'An activation event emitted whenever the specified user identity.'),
},
{
label: 'onUri',
body: 'onUri',

View File

@@ -8,7 +8,7 @@ import { IExtensionManifest } from 'vs/platform/extensions/common/extensions';
import { ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry';
import { getGalleryExtensionId, areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { isNonEmptyArray } from 'vs/base/common/arrays';
import { IProductService } from 'vs/platform/product/common/product';
import { IProductService } from 'vs/platform/product/common/productService';
export function isWebExtension(manifest: IExtensionManifest, configurationService: IConfigurationService): boolean {
const extensionKind = getExtensionKind(manifest, configurationService);

View File

@@ -0,0 +1,32 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IRemoteConsoleLog, parse } from 'vs/base/common/console';
import { ILogService } from 'vs/platform/log/common/log';
export function logRemoteEntry(logService: ILogService, entry: IRemoteConsoleLog): void {
const args = parse(entry).args;
const firstArg = args.shift();
if (typeof firstArg !== 'string') {
return;
}
if (!entry.severity) {
entry.severity = 'info';
}
switch (entry.severity) {
case 'log':
case 'info':
logService.info(firstArg, ...args);
break;
case 'warn':
logService.warn(firstArg, ...args);
break;
case 'error':
logService.error(firstArg, ...args);
break;
}
}

View File

@@ -11,7 +11,7 @@ import { ILogService } from 'vs/platform/log/common/log';
import { connectRemoteAgentExtensionHost, IRemoteExtensionHostStartParams, IConnectionOptions, ISocketFactory } from 'vs/platform/remote/common/remoteAgentConnection';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { IInitData } from 'vs/workbench/api/common/extHost.protocol';
import { IInitData, UIKind } from 'vs/workbench/api/common/extHost.protocol';
import { MessageType, createMessageOfType, isMessageOfType } from 'vs/workbench/services/extensions/common/extensionHostProtocol';
import { IExtensionHostStarter } from 'vs/workbench/services/extensions/common/extensions';
import { parseExtensionDevOptions } from 'vs/workbench/services/extensions/common/extensionDevOptions';
@@ -25,7 +25,7 @@ import { PersistentProtocol } from 'vs/base/parts/ipc/common/ipc.net';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { VSBuffer } from 'vs/base/common/buffer';
import { IExtensionHostDebugService } from 'vs/platform/debug/common/extensionHostDebug';
import { IProductService } from 'vs/platform/product/common/product';
import { IProductService } from 'vs/platform/product/common/productService';
import { ISignService } from 'vs/platform/sign/common/sign';
export interface IInitDataProvider {
@@ -216,6 +216,7 @@ export class RemoteExtensionHostClient extends Disposable implements IExtensionH
logLevel: this._logService.getLevel(),
logsLocation: remoteExtensionHostData.extensionHostLogsPath,
autoStart: true,
uiKind: platform.isWeb ? UIKind.Web : UIKind.Desktop
};
return r;
});

View File

@@ -5,7 +5,6 @@
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IExtensionDescription, ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { URI } from 'vs/base/common/uri';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
@@ -27,7 +26,7 @@ export class StaticExtensionsService implements IStaticExtensionsService {
this._descriptions = staticExtensions.map(data => <IExtensionDescription>{
identifier: new ExtensionIdentifier(`${data.packageJSON.publisher}.${data.packageJSON.name}`),
extensionLocation: URI.revive(data.extensionLocation),
extensionLocation: data.extensionLocation,
...data.packageJSON,
});
}

View File

@@ -17,8 +17,7 @@ import * as pfs from 'vs/base/node/pfs';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IExtensionEnablementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
import { BUILTIN_MANIFEST_CACHE_FILE, MANIFEST_CACHE_FOLDER, USER_MANIFEST_CACHE_FILE, ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import pkg from 'vs/platform/product/node/package';
import product from 'vs/platform/product/node/product';
import product from 'vs/platform/product/common/product';
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
import { IWindowService } from 'vs/platform/windows/common/windows';
import { ExtensionScanner, ExtensionScannerInput, IExtensionReference, IExtensionResolver, IRelaxedExtensionDescription } from 'vs/workbench/services/extensions/node/extensionPoints';
@@ -68,7 +67,7 @@ export class CachedExtensionScanner {
public async scanSingleExtension(path: string, isBuiltin: boolean, log: ILog): Promise<IExtensionDescription | null> {
const translations = await this.translationConfig;
const version = pkg.version;
const version = product.version;
const commit = product.commit;
const devMode = !!process.env['VSCODE_DEV'];
const locale = platform.language;
@@ -243,7 +242,7 @@ export class CachedExtensionScanner {
translations: Translations
): Promise<{ system: IExtensionDescription[], user: IExtensionDescription[], development: IExtensionDescription[] }> {
const version = pkg.version;
const version = product.version;
const commit = product.commit;
const devMode = !!process.env['VSCODE_DEV'];
const locale = platform.language;

View File

@@ -13,9 +13,9 @@ import { Emitter, Event } from 'vs/base/common/event';
import { toDisposable, DisposableStore } from 'vs/base/common/lifecycle';
import * as objects from 'vs/base/common/objects';
import * as platform from 'vs/base/common/platform';
import pkg from 'vs/platform/product/node/package';
import { URI } from 'vs/base/common/uri';
import { IRemoteConsoleLog, log, parse } from 'vs/base/common/console';
import { IRemoteConsoleLog, log } from 'vs/base/common/console';
import { logRemoteEntry } from 'vs/workbench/services/extensions/common/remoteConsoleUtil';
import { findFreePort, randomPort } from 'vs/base/node/ports';
import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc';
import { PersistentProtocol } from 'vs/base/parts/ipc/common/ipc.net';
@@ -24,12 +24,12 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/
import { ILabelService } from 'vs/platform/label/common/label';
import { ILifecycleService, WillShutdownEvent } from 'vs/platform/lifecycle/common/lifecycle';
import { ILogService } from 'vs/platform/log/common/log';
import product from 'vs/platform/product/node/product';
import product from 'vs/platform/product/common/product';
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows';
import { IWindowService } from 'vs/platform/windows/common/windows';
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { IInitData } from 'vs/workbench/api/common/extHost.protocol';
import { IInitData, UIKind } from 'vs/workbench/api/common/extHost.protocol';
import { MessageType, createMessageOfType, isMessageOfType } from 'vs/workbench/services/extensions/common/extensionHostProtocol';
import { withNullAsUndefined } from 'vs/base/common/types';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
@@ -68,7 +68,6 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter {
private readonly _extensionHostLogsLocation: URI,
@IWorkspaceContextService private readonly _contextService: IWorkspaceContextService,
@INotificationService private readonly _notificationService: INotificationService,
@IWindowsService private readonly _windowsService: IWindowsService,
@IWindowService private readonly _windowService: IWindowService,
@ILifecycleService private readonly _lifecycleService: ILifecycleService,
@IWorkbenchEnvironmentService private readonly _environmentService: IWorkbenchEnvironmentService,
@@ -388,7 +387,7 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter {
const workspace = this._contextService.getWorkspace();
const r: IInitData = {
commit: product.commit,
version: pkg.version,
version: product.version,
vscodeVersion: product.vscodeVersion, // {{SQL CARBON EDIT}} add vscode version
parentPid: process.pid,
environment: {
@@ -421,7 +420,8 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter {
telemetryInfo,
logLevel: this._logService.getLevel(),
logsLocation: this._extensionHostLogsLocation,
autoStart: this._autoStart
autoStart: this._autoStart,
uiKind: UIKind.Desktop
};
return r;
});
@@ -436,7 +436,7 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter {
// Log on main side if running tests from cli
if (this._isExtensionDevTestFromCli) {
this._windowsService.log(entry.severity, parse(entry).args);
logRemoteEntry(this._logService, entry);
}
// Broadcast to other windows if we are in development mode

View File

@@ -32,7 +32,7 @@ import { ExtensionIdentifier, IExtension, ExtensionType, IExtensionDescription }
import { Schemas } from 'vs/base/common/network';
import { IFileService } from 'vs/platform/files/common/files';
import { PersistentConnectionEventType } from 'vs/platform/remote/common/remoteAgentConnection';
import { IProductService } from 'vs/platform/product/common/product';
import { IProductService } from 'vs/platform/product/common/productService';
import { Logger } from 'vs/workbench/services/extensions/common/extensionPoints';
import { flatten } from 'vs/base/common/arrays';
import { IStaticExtensionsService } from 'vs/workbench/services/extensions/common/staticExtensions';

View File

@@ -16,7 +16,7 @@ import { isNonEmptyArray } from 'vs/base/common/arrays';
import { values } from 'vs/base/common/map';
import { CancellationToken } from 'vs/base/common/cancellation';
import { localize } from 'vs/nls';
import { IProductService } from 'vs/platform/product/common/product';
import { IProductService } from 'vs/platform/product/common/productService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ExtensionManagementChannelClient } from 'vs/platform/extensionManagement/common/extensionManagementIpc';

View File

@@ -11,7 +11,7 @@ import { Event } from 'vs/base/common/event';
import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc';
import { PersistentProtocol, ProtocolConstants, BufferedEmitter } from 'vs/base/parts/ipc/common/ipc.net';
import { NodeSocket, WebSocketNodeSocket } from 'vs/base/parts/ipc/node/ipc.net';
import product from 'vs/platform/product/node/product';
import product from 'vs/platform/product/common/product';
import { IInitData } from 'vs/workbench/api/common/extHost.protocol';
import { MessageType, createMessageOfType, isMessageOfType, IExtHostSocketMessage, IExtHostReadyMessage } from 'vs/workbench/services/extensions/common/extensionHostProtocol';
import { ExtensionHostMain, IExitFn } from 'vs/workbench/services/extensions/common/extensionHostMain';

View File

@@ -11,7 +11,7 @@ import { IExtHostConfiguration, ExtHostConfiguration } from 'vs/workbench/api/co
import { IExtHostCommands, ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
import { IExtHostDocumentsAndEditors, ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
import { IExtHostTerminalService, WorkerExtHostTerminalService } from 'vs/workbench/api/common/extHostTerminalService';
import { IExtHostTask } from 'vs/workbench/api/common/extHostTask';
import { IExtHostTask, WorkerExtHostTask } from 'vs/workbench/api/common/extHostTask';
import { IExtHostDebugService } from 'vs/workbench/api/common/extHostDebugService';
import { IExtHostSearch } from 'vs/workbench/api/common/extHostSearch';
import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths';
@@ -49,7 +49,7 @@ function NotImplementedProxy<T>(name: ServiceIdentifier<T>): { new(): T } {
};
}
registerSingleton(IExtHostTerminalService, WorkerExtHostTerminalService);
registerSingleton(IExtHostTask, class extends NotImplementedProxy(IExtHostTask) { });
registerSingleton(IExtHostTask, WorkerExtHostTask);
registerSingleton(IExtHostDebugService, class extends NotImplementedProxy(IExtHostDebugService) { });
registerSingleton(IExtHostSearch, class extends NotImplementedProxy(IExtHostSearch) { });
registerSingleton(IExtensionStoragePaths, class extends NotImplementedProxy(IExtensionStoragePaths) {

View File

@@ -0,0 +1,20 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IHostService } from 'vs/workbench/services/host/browser/host';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
export class BrowserHostService implements IHostService {
_serviceBrand: undefined;
//#region Window
readonly windowCount = Promise.resolve(1);
//#endregion
}
registerSingleton(IHostService, BrowserHostService, true);

View File

@@ -0,0 +1,22 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
export const IHostService = createDecorator<IHostService>('hostService');
export interface IHostService {
_serviceBrand: undefined;
//#region Window
/**
* The number of windows that belong to the current client session.
*/
readonly windowCount: Promise<number>;
//#endregion
}

View File

@@ -0,0 +1,23 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IHostService } from 'vs/workbench/services/host/browser/host';
import { IElectronService } from 'vs/platform/electron/node/electron';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
export class DesktopHostService implements IHostService {
_serviceBrand: undefined;
constructor(@IElectronService private readonly electronService: IElectronService) { }
//#region Window
get windowCount() { return this.electronService.windowCount(); }
//#endregion
}
registerSingleton(IHostService, DesktopHostService, true);

View File

@@ -10,7 +10,7 @@ import Severity from 'vs/base/common/severity';
import { URI } from 'vs/base/common/uri';
import { ChecksumPair, IIntegrityService, IntegrityTestResult } from 'vs/workbench/services/integrity/common/integrity';
import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import product from 'vs/platform/product/node/product';
import product from 'vs/platform/product/common/product';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';

View File

@@ -557,7 +557,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic
return this.textFileService.read(workspaceConfig)
.then(content => {
if (Object.keys(parse(content.value)).indexOf('settings') === -1) {
return this.jsonEditingService.write(resource, { key: 'settings', value: {} }, true).then(undefined, () => { });
return this.jsonEditingService.write(resource, [{ key: 'settings', value: {} }], true).then(undefined, () => { });
}
return undefined;
});

View File

@@ -7,7 +7,7 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/
import { IRemoteAgentConnection, IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver';
import { AbstractRemoteAgentService, RemoteAgentConnection } from 'vs/workbench/services/remote/common/abstractRemoteAgentService';
import { IProductService } from 'vs/platform/product/common/product';
import { IProductService } from 'vs/platform/product/common/productService';
import { IWebSocketFactory, BrowserSocketFactory } from 'vs/platform/remote/browser/browserSocketFactory';
import { ISignService } from 'vs/platform/sign/common/sign';
import { ISocketFactory } from 'vs/platform/remote/common/remoteAgentConnection';

View File

@@ -7,7 +7,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment'
import { IWindowConfiguration } from 'vs/platform/windows/common/windows';
import { IRemoteAgentConnection, IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver';
import product from 'vs/platform/product/node/product';
import product from 'vs/platform/product/common/product';
import { nodeSocketFactory } from 'vs/platform/remote/node/nodeSocketFactory';
import { AbstractRemoteAgentService, RemoteAgentConnection } from 'vs/workbench/services/remote/common/abstractRemoteAgentService';
import { ISignService } from 'vs/platform/sign/common/sign';

View File

@@ -8,7 +8,7 @@ import { Barrier } from 'vs/base/common/async';
import { Disposable } from 'vs/base/common/lifecycle';
import { NodeSocket } from 'vs/base/parts/ipc/node/ipc.net';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import product from 'vs/platform/product/node/product';
import product from 'vs/platform/product/common/product';
import { connectRemoteAgentTunnel, IConnectionOptions } from 'vs/platform/remote/common/remoteAgentConnection';
import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver';
import { ITunnelService, RemoteTunnel } from 'vs/platform/remote/common/tunnel';

View File

@@ -252,7 +252,10 @@ export class TextSearchMatch implements ITextSearchMatch {
constructor(text: string, range: ISearchRange | ISearchRange[], previewOptions?: ITextSearchPreviewOptions) {
this.ranges = range;
if (previewOptions && previewOptions.matchLines === 1 && (!Array.isArray(range) || range.length === 1)) {
// Trim preview if this is one match and a single-line match with a preview requested.
// Otherwise send the full text, like for replace or for showing multiple previews.
// TODO this is fishy.
if (previewOptions && previewOptions.matchLines === 1 && (!Array.isArray(range) || range.length === 1) && isSingleLineRange(range)) {
const oneRange = Array.isArray(range) ? range[0] : range;
// 1 line preview requested
@@ -273,7 +276,6 @@ export class TextSearchMatch implements ITextSearchMatch {
} else {
const firstMatchLine = Array.isArray(range) ? range[0].startLineNumber : range.startLineNumber;
// n line, no preview requested, or multiple matches in the preview
this.preview = {
text,
matches: mapArrayOrNot(range, r => new SearchRange(r.startLineNumber - firstMatchLine, r.startColumn, r.endLineNumber - firstMatchLine, r.endColumn))
@@ -282,6 +284,12 @@ export class TextSearchMatch implements ITextSearchMatch {
}
}
function isSingleLineRange(range: ISearchRange | ISearchRange[]): boolean {
return Array.isArray(range) ?
range[0].startLineNumber === range[0].endLineNumber :
range.startLineNumber === range.endLineNumber;
}
export class SearchRange implements ISearchRange {
startLineNumber: number;
startColumn: number;

View File

@@ -125,7 +125,7 @@ export function rgErrorMsgForDisplay(msg: string): Maybe<SearchError> {
const firstLine = lines[0].trim();
if (lines.some(l => startsWith(l, 'regex parse error'))) {
return new SearchError('Regex parse error', SearchErrorCode.regexParseError);
return new SearchError(buildRegexParseError(lines), SearchErrorCode.regexParseError);
}
const match = firstLine.match(/grep config error: unknown encoding: (.*)/);
@@ -150,6 +150,21 @@ export function rgErrorMsgForDisplay(msg: string): Maybe<SearchError> {
return undefined;
}
export function buildRegexParseError(lines: string[]): string {
let errorMessage: string[] = ['Regex parse error'];
let pcre2ErrorLine = lines.filter(l => (startsWith(l, 'PCRE2:')));
if (pcre2ErrorLine.length >= 1) {
let pcre2ErrorMessage = pcre2ErrorLine[0].replace('PCRE2:', '');
if (pcre2ErrorMessage.indexOf(':') !== -1 && pcre2ErrorMessage.split(':').length >= 2) {
let pcre2ActualErrorMessage = pcre2ErrorMessage.split(':')[1];
errorMessage.push(':' + pcre2ActualErrorMessage);
}
}
return errorMessage.join('');
}
export class RipgrepParser extends EventEmitter {
private remainder = '';
private isDone = false;

View File

@@ -12,7 +12,7 @@ suite('TextSearchResult', () => {
charsPerLine: 100
};
function assertPreviewRangeText(text: string, result: TextSearchMatch): void {
function assertOneLinePreviewRangeText(text: string, result: TextSearchMatch): void {
assert.equal(
result.preview.text.substring((<SearchRange>result.preview.matches).startColumn, (<SearchRange>result.preview.matches).endColumn),
text);
@@ -22,49 +22,49 @@ suite('TextSearchResult', () => {
const range = new OneLineRange(5, 0, 0);
const result = new TextSearchMatch('', range);
assert.deepEqual(result.ranges, range);
assertPreviewRangeText('', result);
assertOneLinePreviewRangeText('', result);
});
test('empty with preview options', () => {
const range = new OneLineRange(5, 0, 0);
const result = new TextSearchMatch('', range, previewOptions1);
assert.deepEqual(result.ranges, range);
assertPreviewRangeText('', result);
assertOneLinePreviewRangeText('', result);
});
test('short without preview options', () => {
const range = new OneLineRange(5, 4, 7);
const result = new TextSearchMatch('foo bar', range);
assert.deepEqual(result.ranges, range);
assertPreviewRangeText('bar', result);
assertOneLinePreviewRangeText('bar', result);
});
test('short with preview options', () => {
const range = new OneLineRange(5, 4, 7);
const result = new TextSearchMatch('foo bar', range, previewOptions1);
assert.deepEqual(result.ranges, range);
assertPreviewRangeText('bar', result);
assertOneLinePreviewRangeText('bar', result);
});
test('leading', () => {
const range = new OneLineRange(5, 25, 28);
const result = new TextSearchMatch('long text very long text foo', range, previewOptions1);
assert.deepEqual(result.ranges, range);
assertPreviewRangeText('foo', result);
assertOneLinePreviewRangeText('foo', result);
});
test('trailing', () => {
const range = new OneLineRange(5, 0, 3);
const result = new TextSearchMatch('foo long text very long text long text very long text long text very long text long text very long text long text very long text', range, previewOptions1);
assert.deepEqual(result.ranges, range);
assertPreviewRangeText('foo', result);
assertOneLinePreviewRangeText('foo', result);
});
test('middle', () => {
const range = new OneLineRange(5, 30, 33);
const result = new TextSearchMatch('long text very long text long foo text very long text long text very long text long text very long text long text very long text', range, previewOptions1);
assert.deepEqual(result.ranges, range);
assertPreviewRangeText('foo', result);
assertOneLinePreviewRangeText('foo', result);
});
test('truncating match', () => {
@@ -76,7 +76,7 @@ suite('TextSearchResult', () => {
const range = new OneLineRange(0, 4, 7);
const result = new TextSearchMatch('foo bar', range, previewOptions);
assert.deepEqual(result.ranges, range);
assertPreviewRangeText('b', result);
assertOneLinePreviewRangeText('b', result);
});
test('one line of multiline match', () => {
@@ -88,7 +88,11 @@ suite('TextSearchResult', () => {
const range = new SearchRange(5, 4, 6, 3);
const result = new TextSearchMatch('foo bar\nfoo bar', range, previewOptions);
assert.deepEqual(result.ranges, range);
assertPreviewRangeText('bar', result);
assert.equal(result.preview.text, 'foo bar\nfoo bar');
assert.equal((<SearchRange>result.preview.matches).startLineNumber, 0);
assert.equal((<SearchRange>result.preview.matches).startColumn, 4);
assert.equal((<SearchRange>result.preview.matches).endLineNumber, 1);
assert.equal((<SearchRange>result.preview.matches).endColumn, 3);
});
// test('all lines of multiline match', () => {
@@ -102,4 +106,4 @@ suite('TextSearchResult', () => {
// assert.deepEqual(result.range, range);
// assertPreviewRangeText('bar\nfoo', result);
// });
});
});

View File

@@ -376,7 +376,7 @@ suite('Search-integration', function () {
});
});
test('invalid regex', () => {
test('invalid regex case 1', () => {
const config: ITextQuery = {
type: QueryType.Text,
folderQueries: ROOT_FOLDER_QUERY,
@@ -387,11 +387,30 @@ suite('Search-integration', function () {
throw new Error('expected fail');
}, err => {
const searchError = deserializeSearchError(err.message);
assert.equal(searchError.message, 'Regex parse error');
let regexParseErrorForUnclosedParenthesis = 'Regex parse error: unmatched closing parenthesis';
assert.equal(searchError.message, regexParseErrorForUnclosedParenthesis);
assert.equal(searchError.code, SearchErrorCode.regexParseError);
});
});
test('invalid regex case 2', () => {
const config: ITextQuery = {
type: QueryType.Text,
folderQueries: ROOT_FOLDER_QUERY,
contentPattern: { pattern: '(?<!a.*)', isRegExp: true },
};
return doSearchTest(config, 0).then(() => {
throw new Error('expected fail');
}, err => {
const searchError = deserializeSearchError(err.message);
let regexParseErrorForLookAround = 'Regex parse error: lookbehind assertion is not fixed length';
assert.equal(searchError.message, regexParseErrorForLookAround);
assert.equal(searchError.code, SearchErrorCode.regexParseError);
});
});
test('invalid glob', () => {
const config: ITextQuery = {
type: QueryType.Text,

View File

@@ -14,7 +14,7 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { ClassifiedEvent, StrictPropertyCheck, GDPRClassification } from 'vs/platform/telemetry/common/gdprTypings';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { resolveWorkbenchCommonProperties } from 'vs/platform/telemetry/browser/workbenchCommonProperties';
import { IProductService } from 'vs/platform/product/common/product';
import { IProductService } from 'vs/platform/product/common/productService';
import { ApplicationInsights } from '@microsoft/applicationinsights-web';
export class WebTelemetryAppender implements ITelemetryAppender {

View File

@@ -8,7 +8,7 @@ import { NullTelemetryService, combinedAppender, LogAppender } from 'vs/platform
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { Disposable } from 'vs/base/common/lifecycle';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { IProductService } from 'vs/platform/product/common/product';
import { IProductService } from 'vs/platform/product/common/productService';
import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService';
import { TelemetryAppenderClient } from 'vs/platform/telemetry/node/telemetryIpc';
import { ILogService } from 'vs/platform/log/common/log';

View File

@@ -0,0 +1,62 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { AbstractTextFileService } from 'vs/workbench/services/textfile/browser/textFileService';
import { ITextFileService, IResourceEncodings, IResourceEncoding, ModelState } from 'vs/workbench/services/textfile/common/textfiles';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { ShutdownReason } from 'vs/platform/lifecycle/common/lifecycle';
import { Schemas } from 'vs/base/common/network';
export class BrowserTextFileService extends AbstractTextFileService {
readonly encoding: IResourceEncodings = {
getPreferredWriteEncoding(): IResourceEncoding {
return { encoding: 'utf8', hasBOM: false };
}
};
protected onBeforeShutdown(reason: ShutdownReason): boolean {
// Web: we cannot perform long running in the shutdown phase
// As such we need to check sync if there are any dirty files
// that have not been backed up yet and then prevent the shutdown
// if that is the case.
return this.doBeforeShutdownSync();
}
private doBeforeShutdownSync(): boolean {
if (this.models.getAll().some(model => model.hasState(ModelState.PENDING_SAVE) || model.hasState(ModelState.PENDING_AUTO_SAVE))) {
return true; // files are pending to be saved: veto
}
const dirtyResources = this.getDirty();
if (!dirtyResources.length) {
return false; // no dirty: no veto
}
if (!this.isHotExitEnabled) {
return true; // dirty without backup: veto
}
for (const dirtyResource of dirtyResources) {
let hasBackup = false;
if (this.fileService.canHandleResource(dirtyResource)) {
const model = this.models.get(dirtyResource);
hasBackup = !!(model && model.hasBackup());
} else if (dirtyResource.scheme === Schemas.untitled) {
hasBackup = this.untitledEditorService.hasBackup(dirtyResource);
}
if (!hasBackup) {
console.warn('Unload prevented: pending backups');
return true; // dirty without backup: veto
}
}
return false; // dirty with backups: no veto
}
}
registerSingleton(ITextFileService, BrowserTextFileService);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -29,7 +29,7 @@ export class TextResourcePropertiesService implements ITextResourcePropertiesSer
remoteAgentService.getEnvironment().then(remoteEnv => this.remoteEnvironment = remoteEnv);
}
getEOL(resource: URI, language?: string): string {
getEOL(resource?: URI, language?: string): string {
const filesConfiguration = this.configurationService.getValue<{ eol: string }>('files', { overrideIdentifier: language, resource });
if (filesConfiguration && filesConfiguration.eol && filesConfiguration.eol !== 'auto') {
return filesConfiguration.eol;
@@ -38,12 +38,12 @@ export class TextResourcePropertiesService implements ITextResourcePropertiesSer
return os === OperatingSystem.Linux || os === OperatingSystem.Macintosh ? '\n' : '\r\n';
}
private getOS(resource: URI): OperatingSystem {
private getOS(resource?: URI): OperatingSystem {
let os = OS;
const remoteAuthority = this.environmentService.configuration.remoteAuthority;
if (remoteAuthority) {
if (resource.scheme !== Schemas.file) {
if (resource && resource.scheme !== Schemas.file) {
const osCacheKey = `resource.authority.os.${remoteAuthority}`;
os = this.remoteEnvironment ? this.remoteEnvironment.os : /* Get it from cache */ this.storageService.getNumber(osCacheKey, StorageScope.WORKSPACE, OS);
this.storageService.store(osCacheKey, os, StorageScope.WORKSPACE);

View File

@@ -5,7 +5,7 @@
import { tmpdir } from 'os';
import { localize } from 'vs/nls';
import { TextFileService } from 'vs/workbench/services/textfile/common/textFileService';
import { AbstractTextFileService } from 'vs/workbench/services/textfile/browser/textFileService';
import { ITextFileService, ITextFileStreamContent, ITextFileContent, IResourceEncodings, IResourceEncoding, IReadTextFileOptions, IWriteTextFileOptions, stringToSnapshot, TextFileOperationResult, TextFileOperationError } from 'vs/workbench/services/textfile/common/textfiles';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { URI } from 'vs/base/common/uri';
@@ -14,7 +14,7 @@ import { Schemas } from 'vs/base/common/network';
import { exists, stat, chmod, rimraf, MAX_FILE_SIZE, MAX_HEAP_SIZE } from 'vs/base/node/pfs';
import { join, dirname } from 'vs/base/common/path';
import { isMacintosh } from 'vs/base/common/platform';
import product from 'vs/platform/product/node/product';
import product from 'vs/platform/product/common/product';
import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { UTF8, UTF8_with_bom, UTF16be, UTF16le, encodingExists, encodeStream, UTF8_BOM, toDecodeStream, IDecodeStreamResult, detectEncodingByBOMFromBuffer, isUTFEncoding } from 'vs/base/node/encoding';
@@ -28,7 +28,7 @@ import { createTextBufferFactoryFromStream } from 'vs/editor/common/model/textMo
import { ITextSnapshot } from 'vs/editor/common/model';
import { nodeReadableToString, streamToNodeReadable, nodeStreamToVSBufferReadable } from 'vs/base/node/stream';
export class NodeTextFileService extends TextFileService {
export class NativeTextFileService extends AbstractTextFileService {
private _encoding!: EncodingOracle;
get encoding(): EncodingOracle {
@@ -404,4 +404,4 @@ export class EncodingOracle extends Disposable implements IResourceEncodings {
}
}
registerSingleton(ITextFileService, NodeTextFileService);
registerSingleton(ITextFileService, NativeTextFileService);

View File

@@ -22,7 +22,7 @@ import { generateUuid } from 'vs/base/common/uuid';
import { join, basename } from 'vs/base/common/path';
import { getPathFromAmdModule } from 'vs/base/common/amd';
import { UTF16be, UTF16le, UTF8_with_bom, UTF8 } from 'vs/base/node/encoding';
import { NodeTextFileService, EncodingOracle, IEncodingOverride } from 'vs/workbench/services/textfile/node/textFileService';
import { NativeTextFileService, EncodingOracle, IEncodingOverride } from 'vs/workbench/services/textfile/electron-browser/nativeTextFileService';
import { DefaultEndOfLine, ITextSnapshot } from 'vs/editor/common/model';
import { TextModel } from 'vs/editor/common/model/textModel';
import { isWindows } from 'vs/base/common/platform';
@@ -37,7 +37,7 @@ class ServiceAccessor {
}
}
class TestNodeTextFileService extends NodeTextFileService {
class TestNativeTextFileService extends NativeTextFileService {
private _testEncoding: TestEncodingOracle | undefined;
get encoding(): TestEncodingOracle {
@@ -84,7 +84,7 @@ suite('Files - TextFileService i/o', () => {
const collection = new ServiceCollection();
collection.set(IFileService, fileService);
service = instantiationService.createChild(collection).createInstance(TestNodeTextFileService);
service = instantiationService.createChild(collection).createInstance(TestNativeTextFileService);
const id = generateUuid();
testDir = join(parentDir, id);

View File

@@ -7,7 +7,7 @@ import * as sinon from 'sinon';
import * as platform from 'vs/base/common/platform';
import { URI } from 'vs/base/common/uri';
import { ILifecycleService, BeforeShutdownEvent, ShutdownReason } from 'vs/platform/lifecycle/common/lifecycle';
import { workbenchInstantiationService, TestLifecycleService, TestTextFileService, TestWindowsService, TestContextService, TestFileService } from 'vs/workbench/test/workbenchTestServices';
import { workbenchInstantiationService, TestLifecycleService, TestTextFileService, TestWindowsService, TestContextService, TestFileService, TestHostService } from 'vs/workbench/test/workbenchTestServices';
import { toResource } from 'vs/base/test/common/utils';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IWindowsService } from 'vs/platform/windows/common/windows';
@@ -21,6 +21,7 @@ import { IWorkspaceContextService, Workspace } from 'vs/platform/workspace/commo
import { IModelService } from 'vs/editor/common/services/modelService';
import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl';
import { Schemas } from 'vs/base/common/network';
import { IHostService } from 'vs/workbench/services/host/browser/host';
class ServiceAccessor {
constructor(
@@ -30,7 +31,8 @@ class ServiceAccessor {
@IWindowsService public windowsService: TestWindowsService,
@IWorkspaceContextService public contextService: TestContextService,
@IModelService public modelService: ModelServiceImpl,
@IFileService public fileService: TestFileService
@IFileService public fileService: TestFileService,
@IHostService public hostService: TestHostService
) {
}
}
@@ -424,7 +426,7 @@ suite('Files - TextFileService', () => {
}
// Set multiple windows if required
if (multipleWindows) {
accessor.windowsService.windowCount = 2;
accessor.hostService.windowCount = Promise.resolve(2);
}
// Set cancel to force a veto if hot exit does not trigger
service.setConfirmResult(ConfirmResult.CANCEL);

View File

@@ -7,7 +7,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'
import { virtualMachineHint } from 'vs/base/node/id';
import * as perf from 'vs/base/common/performance';
import * as os from 'os';
import { IWindowsService } from 'vs/platform/windows/common/windows';
import { IHostService } from 'vs/workbench/services/host/browser/host';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
@@ -308,7 +308,7 @@ class TimerService implements ITimerService {
private _startupMetrics?: Promise<IStartupMetrics>;
constructor(
@IWindowsService private readonly _windowsService: IWindowsService,
@IHostService private readonly _hostService: IHostService,
@IWorkbenchEnvironmentService private readonly _environmentService: IWorkbenchEnvironmentService,
@ILifecycleService private readonly _lifecycleService: ILifecycleService,
@IWorkspaceContextService private readonly _contextService: IWorkspaceContextService,
@@ -380,7 +380,7 @@ class TimerService implements ITimerService {
isLatestVersion: Boolean(await this._updateService.isLatestVersion()),
didUseCachedData: didUseCachedData(),
windowKind: this._lifecycleService.startupKind,
windowCount: await this._windowsService.getWindowCount(),
windowCount: await this._hostService.windowCount,
viewletId: activeViewlet ? activeViewlet.getId() : undefined,
editorIds: this._editorService.visibleEditors.map(input => input.getTypeId()),
panelId: activePanel ? activePanel.getId() : undefined,

View File

@@ -14,6 +14,7 @@ export interface ITitleProperties {
}
export interface ITitleService {
_serviceBrand: undefined;
/**
@@ -25,4 +26,4 @@ export interface ITitleService {
* Update some environmental title properties.
*/
updateProperties(properties: ITitleProperties): void;
}
}

View File

@@ -9,7 +9,7 @@ import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProces
import { URLServiceChannelClient, URLHandlerChannel } from 'vs/platform/url/common/urlIpc';
import { URLService } from 'vs/platform/url/node/urlService';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import product from 'vs/platform/product/node/product';
import product from 'vs/platform/product/common/product';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IWindowService } from 'vs/platform/windows/common/windows';

View File

@@ -50,7 +50,7 @@ class Directory implements IStat {
export type Entry = File | Directory;
export class InMemoryUserDataProvider extends Disposable implements IFileSystemProvider {
export class InMemoryFileSystemProvider extends Disposable implements IFileSystemProvider {
readonly capabilities: FileSystemProviderCapabilities = FileSystemProviderCapabilities.FileReadWrite;
readonly onDidChangeCapabilities: Event<void> = Event.None;

View File

@@ -0,0 +1,192 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as objects from 'vs/base/common/objects';
import { parse, findNodeAtLocation, parseTree } from 'vs/base/common/json';
import { EditOperation } from 'vs/editor/common/core/editOperation';
import { IModeService } from 'vs/editor/common/services/modeService';
import { ITextModel } from 'vs/editor/common/model';
import { setProperty } from 'vs/base/common/jsonEdit';
import { Range } from 'vs/editor/common/core/range';
import { Selection } from 'vs/editor/common/core/selection';
import { IModelService } from 'vs/editor/common/services/modelService';
import { Position } from 'vs/editor/common/core/position';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { ISettingsMergeService } from 'vs/platform/userDataSync/common/userDataSync';
class SettingsMergeService implements ISettingsMergeService {
_serviceBrand: undefined;
constructor(
@IModelService private readonly modelService: IModelService,
@IModeService private readonly modeService: IModeService
) { }
async merge(localContent: string, remoteContent: string, baseContent: string | null): Promise<{ mergeContent: string, hasChanges: boolean, hasConflicts: boolean }> {
const local = parse(localContent);
const remote = parse(remoteContent);
const base = baseContent ? parse(baseContent) : null;
const localToRemote = this.compare(local, remote);
if (localToRemote.added.size === 0 && localToRemote.removed.size === 0 && localToRemote.updated.size === 0) {
// No changes found between local and remote.
return { mergeContent: localContent, hasChanges: false, hasConflicts: false };
}
const conflicts: Set<string> = new Set<string>();
const baseToLocal = base ? this.compare(base, local) : { added: Object.keys(local).reduce((r, k) => { r.add(k); return r; }, new Set<string>()), removed: new Set<string>(), updated: new Set<string>() };
const baseToRemote = base ? this.compare(base, remote) : { added: Object.keys(remote).reduce((r, k) => { r.add(k); return r; }, new Set<string>()), removed: new Set<string>(), updated: new Set<string>() };
const settingsPreviewModel = this.modelService.createModel(localContent, this.modeService.create('jsonc'));
// Removed settings in Local
for (const key of baseToLocal.removed.keys()) {
// Got updated in remote
if (baseToRemote.updated.has(key)) {
conflicts.add(key);
}
}
// Removed settings in Remote
for (const key of baseToRemote.removed.keys()) {
if (conflicts.has(key)) {
continue;
}
// Got updated in local
if (baseToLocal.updated.has(key)) {
conflicts.add(key);
} else {
this.editSetting(settingsPreviewModel, key, undefined);
}
}
// Added settings in Local
for (const key of baseToLocal.added.keys()) {
if (conflicts.has(key)) {
continue;
}
// Got added in remote
if (baseToRemote.added.has(key)) {
// Has different value
if (localToRemote.updated.has(key)) {
conflicts.add(key);
}
}
}
// Added settings in remote
for (const key of baseToRemote.added.keys()) {
if (conflicts.has(key)) {
continue;
}
// Got added in local
if (baseToLocal.added.has(key)) {
// Has different value
if (localToRemote.updated.has(key)) {
conflicts.add(key);
}
} else {
this.editSetting(settingsPreviewModel, key, remote[key]);
}
}
// Updated settings in Local
for (const key of baseToLocal.updated.keys()) {
if (conflicts.has(key)) {
continue;
}
// Got updated in remote
if (baseToRemote.updated.has(key)) {
// Has different value
if (localToRemote.updated.has(key)) {
conflicts.add(key);
}
}
}
// Updated settings in Remote
for (const key of baseToRemote.updated.keys()) {
if (conflicts.has(key)) {
continue;
}
// Got updated in local
if (baseToLocal.updated.has(key)) {
// Has different value
if (localToRemote.updated.has(key)) {
conflicts.add(key);
}
} else {
this.editSetting(settingsPreviewModel, key, remote[key]);
}
}
for (const key of conflicts.keys()) {
const tree = parseTree(settingsPreviewModel.getValue());
const valueNode = findNodeAtLocation(tree, [key]);
const eol = settingsPreviewModel.getEOL();
const remoteEdit = setProperty(`{${eol}\t${eol}}`, [key], remote[key], { tabSize: 4, insertSpaces: false, eol: eol })[0];
const remoteContent = remoteEdit ? `${remoteEdit.content.substring(remoteEdit.offset + remoteEdit.length + 1)},${eol}` : '';
if (valueNode) {
// Updated in Local and Remote with different value
const keyPosition = settingsPreviewModel.getPositionAt(valueNode.parent!.offset);
const valuePosition = settingsPreviewModel.getPositionAt(valueNode.offset + valueNode.length);
const editOperations = [
EditOperation.insert(new Position(keyPosition.lineNumber - 1, settingsPreviewModel.getLineMaxColumn(keyPosition.lineNumber - 1)), `${eol}<<<<<<< local`),
EditOperation.insert(new Position(valuePosition.lineNumber, settingsPreviewModel.getLineMaxColumn(valuePosition.lineNumber)), `${eol}=======${eol}${remoteContent}>>>>>>> remote`)
];
settingsPreviewModel.pushEditOperations([new Selection(keyPosition.lineNumber, keyPosition.column, keyPosition.lineNumber, keyPosition.column)], editOperations, () => []);
} else {
// Removed in Local, but updated in Remote
const position = new Position(settingsPreviewModel.getLineCount() - 1, settingsPreviewModel.getLineMaxColumn(settingsPreviewModel.getLineCount() - 1));
const editOperations = [
EditOperation.insert(position, `${eol}<<<<<<< local${eol}=======${eol}${remoteContent}>>>>>>> remote`)
];
settingsPreviewModel.pushEditOperations([new Selection(position.lineNumber, position.column, position.lineNumber, position.column)], editOperations, () => []);
}
}
return { mergeContent: settingsPreviewModel.getValue(), hasChanges: true, hasConflicts: conflicts.size > 0 };
}
private editSetting(model: ITextModel, key: string, value: any | undefined): void {
const insertSpaces = false;
const tabSize = 4;
const eol = model.getEOL();
const edit = setProperty(model.getValue(), [key], value, { tabSize, insertSpaces, eol })[0];
if (edit) {
const startPosition = model.getPositionAt(edit.offset);
const endPosition = model.getPositionAt(edit.offset + edit.length);
const range = new Range(startPosition.lineNumber, startPosition.column, endPosition.lineNumber, endPosition.column);
let currentText = model.getValueInRange(range);
if (edit.content !== currentText) {
const editOperation = currentText ? EditOperation.replace(range, edit.content) : EditOperation.insert(startPosition, edit.content);
model.pushEditOperations([new Selection(startPosition.lineNumber, startPosition.column, startPosition.lineNumber, startPosition.column)], [editOperation], () => []);
}
}
}
private compare(from: { [key: string]: any }, to: { [key: string]: any }): { added: Set<string>, removed: Set<string>, updated: Set<string> } {
const fromKeys = Object.keys(from);
const toKeys = Object.keys(to);
const added = toKeys.filter(key => fromKeys.indexOf(key) === -1).reduce((r, key) => { r.add(key); return r; }, new Set<string>());
const removed = fromKeys.filter(key => toKeys.indexOf(key) === -1).reduce((r, key) => { r.add(key); return r; }, new Set<string>());
const updated: Set<string> = new Set<string>();
for (const key of fromKeys) {
if (removed.has(key)) {
continue;
}
const value1 = from[key];
const value2 = to[key];
if (!objects.equals(value1, value2)) {
updated.add(key);
}
}
return { added, removed, updated };
}
}
registerSingleton(ISettingsMergeService, SettingsMergeService);

View File

@@ -0,0 +1,49 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { SyncStatus, SyncSource, IUserDataSyncService } from 'vs/platform/userDataSync/common/userDataSync';
import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService';
import { Disposable } from 'vs/base/common/lifecycle';
import { Emitter, Event } from 'vs/base/common/event';
import { IChannel } from 'vs/base/parts/ipc/common/ipc';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
export class UserDataSyncService extends Disposable implements IUserDataSyncService {
_serviceBrand: undefined;
private readonly channel: IChannel;
private _status: SyncStatus = SyncStatus.Uninitialized;
get status(): SyncStatus { return this._status; }
private _onDidChangeStatus: Emitter<SyncStatus> = this._register(new Emitter<SyncStatus>());
readonly onDidChangeStatus: Event<SyncStatus> = this._onDidChangeStatus.event;
get onDidChangeLocal(): Event<void> { return this.channel.listen('onDidChangeLocal'); }
private _conflictsSource: SyncSource | null = null;
get conflictsSource(): SyncSource | null { return this._conflictsSource; }
constructor(
@ISharedProcessService sharedProcessService: ISharedProcessService
) {
super();
this.channel = sharedProcessService.getChannel('userDataSync');
this._register(this.channel.listen<SyncStatus>('onDidChangeStatus')(status => this.updateStatus(status)));
}
sync(_continue?: boolean): Promise<boolean> {
return this.channel.call('sync', [_continue]);
}
private async updateStatus(status: SyncStatus): Promise<void> {
this._conflictsSource = await this.channel.call<SyncSource>('getConflictsSource');
this._status = status;
this._onDidChangeStatus.fire(status);
}
}
registerSingleton(IUserDataSyncService, UserDataSyncService);

View File

@@ -31,6 +31,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { ILabelService } from 'vs/platform/label/common/label';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { IHostService } from 'vs/workbench/services/host/browser/host';
export class WorkspaceEditingService implements IWorkspaceEditingService {
@@ -54,7 +55,8 @@ export class WorkspaceEditingService implements IWorkspaceEditingService {
@IFileDialogService private readonly fileDialogService: IFileDialogService,
@IDialogService private readonly dialogService: IDialogService,
@ILifecycleService readonly lifecycleService: ILifecycleService,
@ILabelService readonly labelService: ILabelService
@ILabelService readonly labelService: ILabelService,
@IHostService private readonly hostService: IHostService
) {
this.registerListeners();
}
@@ -82,7 +84,7 @@ export class WorkspaceEditingService implements IWorkspaceEditingService {
return false; // only care about untitled workspaces to ask for saving
}
const windowCount = await this.windowsService.getWindowCount();
const windowCount = await this.hostService.windowCount;
if (reason === ShutdownReason.CLOSE && !isMacintosh && windowCount === 1) {
return false; // Windows/Linux: quits when last window is closed, so do not ask then
@@ -448,7 +450,7 @@ export class WorkspaceEditingService implements IWorkspaceEditingService {
}
}
return this.jsonEditingService.write(toWorkspace.configPath, { key: 'settings', value: targetWorkspaceConfiguration }, true);
return this.jsonEditingService.write(toWorkspace.configPath, [{ key: 'settings', value: targetWorkspaceConfiguration }], true);
}
private getCurrentWorkspaceIdentifier(): IWorkspaceIdentifier | undefined {

View File

@@ -0,0 +1,27 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IWorkspacesService, IWorkspaceFolderCreationData, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
import { URI } from 'vs/base/common/uri';
export class WorkspacesService implements IWorkspacesService {
_serviceBrand: undefined;
async createUntitledWorkspace(folders?: IWorkspaceFolderCreationData[], remoteAuthority?: string): Promise<IWorkspaceIdentifier> {
throw new Error('Untitled workspaces are currently unsupported in Web');
}
async deleteUntitledWorkspace(workspace: IWorkspaceIdentifier): Promise<void> {
throw new Error('Untitled workspaces are currently unsupported in Web');
}
async getWorkspaceIdentifier(workspacePath: URI): Promise<IWorkspaceIdentifier> {
throw new Error('Untitled workspaces are currently unsupported in Web');
}
}
registerSingleton(IWorkspacesService, WorkspacesService, true);

View File

@@ -0,0 +1,35 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IChannel } from 'vs/base/parts/ipc/common/ipc';
import { IWorkspacesService, IWorkspaceIdentifier, IWorkspaceFolderCreationData, reviveWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService';
import { URI } from 'vs/base/common/uri';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
export class WorkspacesService implements IWorkspacesService {
_serviceBrand: undefined;
private channel: IChannel;
constructor(@IMainProcessService mainProcessService: IMainProcessService) {
this.channel = mainProcessService.getChannel('workspaces');
}
createUntitledWorkspace(folders?: IWorkspaceFolderCreationData[], remoteAuthority?: string): Promise<IWorkspaceIdentifier> {
return this.channel.call('createUntitledWorkspace', [folders, remoteAuthority]).then(reviveWorkspaceIdentifier);
}
deleteUntitledWorkspace(workspaceIdentifier: IWorkspaceIdentifier): Promise<void> {
return this.channel.call('deleteUntitledWorkspace', workspaceIdentifier);
}
getWorkspaceIdentifier(configPath: URI): Promise<IWorkspaceIdentifier> {
return this.channel.call('getWorkspaceIdentifier', configPath).then(reviveWorkspaceIdentifier);
}
}
registerSingleton(IWorkspacesService, WorkspacesService, true);