mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-05 17:23:51 -05:00
Merge from vscode 1eb87b0e9ce9886afeaecec22b31abd0d9b7939f (#7282)
* Merge from vscode 1eb87b0e9ce9886afeaecec22b31abd0d9b7939f * fix various icon issues * fix preview features
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -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>;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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 }>>;
|
||||
}
|
||||
|
||||
@@ -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 }>>;
|
||||
}
|
||||
@@ -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';
|
||||
|
||||
|
||||
140
src/vs/workbench/services/dialogs/browser/dialogService.ts
Normal file
140
src/vs/workbench/services/dialogs/browser/dialogService.ts
Normal 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);
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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}}', '*');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ export interface IWorkbenchEnvironmentService extends IEnvironmentService {
|
||||
|
||||
readonly debugSearch: IDebugParams;
|
||||
|
||||
readonly webviewExternalEndpoint: string;
|
||||
readonly webviewResourceRoot: string;
|
||||
readonly webviewCspSource: string;
|
||||
|
||||
|
||||
@@ -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:';
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
});
|
||||
|
||||
@@ -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,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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) {
|
||||
|
||||
20
src/vs/workbench/services/host/browser/browserHostService.ts
Normal file
20
src/vs/workbench/services/host/browser/browserHostService.ts
Normal 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);
|
||||
22
src/vs/workbench/services/host/browser/host.ts
Normal file
22
src/vs/workbench/services/host/browser/host.ts
Normal 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
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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';
|
||||
|
||||
@@ -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;
|
||||
});
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
// });
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
Reference in New Issue
Block a user