mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-14 03:58:33 -05:00
Merge from vscode 31e03b8ffbb218a87e3941f2b63a249f061fe0e4 (#4986)
This commit is contained in:
@@ -1,59 +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 { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility';
|
||||
import { isWindows } from 'vs/base/common/platform';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { IWindowService } from 'vs/platform/windows/common/windows';
|
||||
|
||||
export class AccessibilityService implements IAccessibilityService {
|
||||
_serviceBrand: any;
|
||||
|
||||
private _accessibilitySupport = AccessibilitySupport.Unknown;
|
||||
private readonly _onDidChangeAccessibilitySupport = new Emitter<void>();
|
||||
readonly onDidChangeAccessibilitySupport: Event<void> = this._onDidChangeAccessibilitySupport.event;
|
||||
|
||||
constructor(
|
||||
@IWindowService private readonly windowService: IWindowService
|
||||
) { }
|
||||
|
||||
alwaysUnderlineAccessKeys(): Promise<boolean> {
|
||||
if (!isWindows) {
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
|
||||
return new Promise<boolean>(async (resolve) => {
|
||||
const Registry = await import('vscode-windows-registry');
|
||||
|
||||
let value;
|
||||
try {
|
||||
value = Registry.GetStringRegKey('HKEY_CURRENT_USER', 'Control Panel\\Accessibility\\Keyboard Preference', 'On');
|
||||
} catch {
|
||||
resolve(false);
|
||||
}
|
||||
|
||||
resolve(value === '1');
|
||||
});
|
||||
}
|
||||
|
||||
setAccessibilitySupport(accessibilitySupport: AccessibilitySupport): void {
|
||||
if (this._accessibilitySupport === accessibilitySupport) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._accessibilitySupport = accessibilitySupport;
|
||||
this._onDidChangeAccessibilitySupport.fire();
|
||||
}
|
||||
|
||||
getAccessibilitySupport(): AccessibilitySupport {
|
||||
if (this._accessibilitySupport === AccessibilitySupport.Unknown) {
|
||||
const config = this.windowService.getConfiguration();
|
||||
this._accessibilitySupport = (config && config.accessibilitySupport) ? AccessibilitySupport.Enabled : AccessibilitySupport.Disabled;
|
||||
|
||||
}
|
||||
|
||||
return this._accessibilitySupport;
|
||||
}
|
||||
}
|
||||
@@ -9,9 +9,10 @@ import * as arrays from 'vs/base/common/arrays';
|
||||
import * as types from 'vs/base/common/types';
|
||||
import * as objects from 'vs/base/common/objects';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { OVERRIDE_PROPERTY_PATTERN } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { OVERRIDE_PROPERTY_PATTERN, ConfigurationScope, IConfigurationRegistry, Extensions, IConfigurationPropertySchema } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { IOverrides, overrideIdentifierFromKey, addToValueTree, toValuesTree, IConfigurationModel, getConfigurationValue, IConfigurationOverrides, IConfigurationData, getDefaultValues, getConfigurationKeys, IConfigurationChangeEvent, ConfigurationTarget, removeFromValueTree, toOverrides } from 'vs/platform/configuration/common/configuration';
|
||||
import { Workspace } from 'vs/platform/workspace/common/workspace';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
|
||||
export class ConfigurationModel implements IConfigurationModel {
|
||||
|
||||
@@ -195,10 +196,11 @@ export class DefaultConfigurationModel extends ConfigurationModel {
|
||||
|
||||
export class ConfigurationModelParser {
|
||||
|
||||
private _raw: any = null;
|
||||
private _configurationModel: ConfigurationModel | null = null;
|
||||
private _parseErrors: any[] = [];
|
||||
|
||||
constructor(protected readonly _name: string) { }
|
||||
constructor(protected readonly _name: string, private _scopes?: ConfigurationScope[]) { }
|
||||
|
||||
get configurationModel(): ConfigurationModel {
|
||||
return this._configurationModel || new ConfigurationModel();
|
||||
@@ -208,15 +210,26 @@ export class ConfigurationModelParser {
|
||||
return this._parseErrors;
|
||||
}
|
||||
|
||||
public parse(content: string | null | undefined): void {
|
||||
public parseContent(content: string | null | undefined): void {
|
||||
if (content) {
|
||||
const raw = this.parseContent(content);
|
||||
const configurationModel = this.parseRaw(raw);
|
||||
this._configurationModel = new ConfigurationModel(configurationModel.contents, configurationModel.keys, configurationModel.overrides);
|
||||
const raw = this.doParseContent(content);
|
||||
this.parseRaw(raw);
|
||||
}
|
||||
}
|
||||
|
||||
protected parseContent(content: string): any {
|
||||
public parseRaw(raw: any): void {
|
||||
this._raw = raw;
|
||||
const configurationModel = this.doParseRaw(raw);
|
||||
this._configurationModel = new ConfigurationModel(configurationModel.contents, configurationModel.keys, configurationModel.overrides);
|
||||
}
|
||||
|
||||
public parse(): void {
|
||||
if (this._raw) {
|
||||
this.parseRaw(this._raw);
|
||||
}
|
||||
}
|
||||
|
||||
protected doParseContent(content: string): any {
|
||||
let raw: any = {};
|
||||
let currentProperty: string | null = null;
|
||||
let currentParent: any = [];
|
||||
@@ -273,12 +286,36 @@ export class ConfigurationModelParser {
|
||||
return raw;
|
||||
}
|
||||
|
||||
protected parseRaw(raw: any): IConfigurationModel {
|
||||
protected doParseRaw(raw: any): IConfigurationModel {
|
||||
if (this._scopes) {
|
||||
const configurationProperties = Registry.as<IConfigurationRegistry>(Extensions.Configuration).getConfigurationProperties();
|
||||
raw = this.filterByScope(raw, configurationProperties, true, this._scopes);
|
||||
}
|
||||
const contents = toValuesTree(raw, message => console.error(`Conflict in settings file ${this._name}: ${message}`));
|
||||
const keys = Object.keys(raw);
|
||||
const overrides: IOverrides[] = toOverrides(raw, message => console.error(`Conflict in settings file ${this._name}: ${message}`));
|
||||
return { contents, keys, overrides };
|
||||
}
|
||||
|
||||
private filterByScope(properties: {}, configurationProperties: { [qualifiedKey: string]: IConfigurationPropertySchema }, filterOverriddenProperties: boolean, scopes: ConfigurationScope[]): {} {
|
||||
const result = {};
|
||||
for (let key in properties) {
|
||||
if (OVERRIDE_PROPERTY_PATTERN.test(key) && filterOverriddenProperties) {
|
||||
result[key] = this.filterByScope(properties[key], configurationProperties, false, scopes);
|
||||
} else {
|
||||
const scope = this.getScope(key, configurationProperties);
|
||||
if (scopes.indexOf(scope) !== -1) {
|
||||
result[key] = properties[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private getScope(key: string, configurationProperties: { [qualifiedKey: string]: IConfigurationPropertySchema }): ConfigurationScope {
|
||||
const propertySchema = configurationProperties[key];
|
||||
return propertySchema && typeof propertySchema.scope !== 'undefined' ? propertySchema.scope : ConfigurationScope.WINDOW;
|
||||
}
|
||||
}
|
||||
|
||||
export class Configuration {
|
||||
|
||||
@@ -27,7 +27,7 @@ export class NodeBasedUserConfiguration extends Disposable {
|
||||
this.userConfigModelWatcher = new ConfigWatcher(this.settingsPath, {
|
||||
changeBufferDelay: 300, onError: error => onUnexpectedError(error), defaultConfig: new ConfigurationModelParser(this.settingsPath), parse: (content: string, parseErrors: any[]) => {
|
||||
const userConfigModelParser = new ConfigurationModelParser(this.settingsPath);
|
||||
userConfigModelParser.parse(content);
|
||||
userConfigModelParser.parseContent(content);
|
||||
parseErrors = [...userConfigModelParser.errors];
|
||||
return userConfigModelParser;
|
||||
}, initCallback: () => c(undefined)
|
||||
|
||||
@@ -9,7 +9,6 @@ import { IDisposable, Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IConfigurationService, IConfigurationChangeEvent, IConfigurationOverrides, ConfigurationTarget, compare, isConfigurationOverrides, IConfigurationData } from 'vs/platform/configuration/common/configuration';
|
||||
import { DefaultConfigurationModel, Configuration, ConfigurationChangeEvent, ConfigurationModel } from 'vs/platform/configuration/common/configurationModels';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
import { NodeBasedUserConfiguration } from 'vs/platform/configuration/node/configuration';
|
||||
|
||||
@@ -24,11 +23,11 @@ export class ConfigurationService extends Disposable implements IConfigurationSe
|
||||
readonly onDidChangeConfiguration: Event<IConfigurationChangeEvent> = this._onDidChangeConfiguration.event;
|
||||
|
||||
constructor(
|
||||
@IEnvironmentService environmentService: IEnvironmentService
|
||||
configurationPath: string
|
||||
) {
|
||||
super();
|
||||
|
||||
this.userConfiguration = this._register(new NodeBasedUserConfiguration(environmentService.appSettingsPath));
|
||||
this.userConfiguration = this._register(new NodeBasedUserConfiguration(configurationPath));
|
||||
|
||||
// Initialize
|
||||
const defaults = new DefaultConfigurationModel();
|
||||
|
||||
@@ -250,10 +250,10 @@ suite('CustomConfigurationModel', () => {
|
||||
|
||||
test('simple merge using models', () => {
|
||||
let base = new ConfigurationModelParser('base');
|
||||
base.parse(JSON.stringify({ 'a': 1, 'b': 2 }));
|
||||
base.parseContent(JSON.stringify({ 'a': 1, 'b': 2 }));
|
||||
|
||||
let add = new ConfigurationModelParser('add');
|
||||
add.parse(JSON.stringify({ 'a': 3, 'c': 4 }));
|
||||
add.parseContent(JSON.stringify({ 'a': 3, 'c': 4 }));
|
||||
|
||||
let result = base.configurationModel.merge(add.configurationModel);
|
||||
assert.deepEqual(result.contents, { 'a': 3, 'b': 2, 'c': 4 });
|
||||
@@ -261,14 +261,14 @@ suite('CustomConfigurationModel', () => {
|
||||
|
||||
test('simple merge with an undefined contents', () => {
|
||||
let base = new ConfigurationModelParser('base');
|
||||
base.parse(JSON.stringify({ 'a': 1, 'b': 2 }));
|
||||
base.parseContent(JSON.stringify({ 'a': 1, 'b': 2 }));
|
||||
let add = new ConfigurationModelParser('add');
|
||||
let result = base.configurationModel.merge(add.configurationModel);
|
||||
assert.deepEqual(result.contents, { 'a': 1, 'b': 2 });
|
||||
|
||||
base = new ConfigurationModelParser('base');
|
||||
add = new ConfigurationModelParser('add');
|
||||
add.parse(JSON.stringify({ 'a': 1, 'b': 2 }));
|
||||
add.parseContent(JSON.stringify({ 'a': 1, 'b': 2 }));
|
||||
result = base.configurationModel.merge(add.configurationModel);
|
||||
assert.deepEqual(result.contents, { 'a': 1, 'b': 2 });
|
||||
|
||||
@@ -280,25 +280,25 @@ suite('CustomConfigurationModel', () => {
|
||||
|
||||
test('Recursive merge using config models', () => {
|
||||
let base = new ConfigurationModelParser('base');
|
||||
base.parse(JSON.stringify({ 'a': { 'b': 1 } }));
|
||||
base.parseContent(JSON.stringify({ 'a': { 'b': 1 } }));
|
||||
let add = new ConfigurationModelParser('add');
|
||||
add.parse(JSON.stringify({ 'a': { 'b': 2 } }));
|
||||
add.parseContent(JSON.stringify({ 'a': { 'b': 2 } }));
|
||||
let result = base.configurationModel.merge(add.configurationModel);
|
||||
assert.deepEqual(result.contents, { 'a': { 'b': 2 } });
|
||||
});
|
||||
|
||||
test('Test contents while getting an existing property', () => {
|
||||
let testObject = new ConfigurationModelParser('test');
|
||||
testObject.parse(JSON.stringify({ 'a': 1 }));
|
||||
testObject.parseContent(JSON.stringify({ 'a': 1 }));
|
||||
assert.deepEqual(testObject.configurationModel.getValue('a'), 1);
|
||||
|
||||
testObject.parse(JSON.stringify({ 'a': { 'b': 1 } }));
|
||||
testObject.parseContent(JSON.stringify({ 'a': { 'b': 1 } }));
|
||||
assert.deepEqual(testObject.configurationModel.getValue('a'), { 'b': 1 });
|
||||
});
|
||||
|
||||
test('Test contents are undefined for non existing properties', () => {
|
||||
const testObject = new ConfigurationModelParser('test');
|
||||
testObject.parse(JSON.stringify({
|
||||
testObject.parseContent(JSON.stringify({
|
||||
awesome: true
|
||||
}));
|
||||
|
||||
@@ -313,7 +313,7 @@ suite('CustomConfigurationModel', () => {
|
||||
|
||||
test('Test configWithOverrides gives all content merged with overrides', () => {
|
||||
const testObject = new ConfigurationModelParser('test');
|
||||
testObject.parse(JSON.stringify({ 'a': 1, 'c': 1, '[b]': { 'a': 2 } }));
|
||||
testObject.parseContent(JSON.stringify({ 'a': 1, 'c': 1, '[b]': { 'a': 2 } }));
|
||||
|
||||
assert.deepEqual(testObject.configurationModel.override('b').contents, { 'a': 2, 'c': 1, '[b]': { 'a': 2 } });
|
||||
});
|
||||
@@ -326,17 +326,17 @@ suite('CustomConfigurationModel', () => {
|
||||
|
||||
test('Test update with empty data', () => {
|
||||
const testObject = new ConfigurationModelParser('test');
|
||||
testObject.parse('');
|
||||
testObject.parseContent('');
|
||||
|
||||
assert.deepEqual(testObject.configurationModel.contents, {});
|
||||
assert.deepEqual(testObject.configurationModel.keys, []);
|
||||
|
||||
testObject.parse(null!);
|
||||
testObject.parseContent(null!);
|
||||
|
||||
assert.deepEqual(testObject.configurationModel.contents, {});
|
||||
assert.deepEqual(testObject.configurationModel.keys, []);
|
||||
|
||||
testObject.parse(undefined!);
|
||||
testObject.parseContent(undefined!);
|
||||
|
||||
assert.deepEqual(testObject.configurationModel.contents, {});
|
||||
assert.deepEqual(testObject.configurationModel.keys, []);
|
||||
@@ -472,7 +472,7 @@ suite('Configuration', () => {
|
||||
|
||||
test('Test update value', () => {
|
||||
const parser = new ConfigurationModelParser('test');
|
||||
parser.parse(JSON.stringify({ 'a': 1 }));
|
||||
parser.parseContent(JSON.stringify({ 'a': 1 }));
|
||||
const testObject: Configuration = new Configuration(parser.configurationModel, new ConfigurationModel());
|
||||
|
||||
testObject.updateValue('a', 2);
|
||||
@@ -482,7 +482,7 @@ suite('Configuration', () => {
|
||||
|
||||
test('Test update value after inspect', () => {
|
||||
const parser = new ConfigurationModelParser('test');
|
||||
parser.parse(JSON.stringify({ 'a': 1 }));
|
||||
parser.parseContent(JSON.stringify({ 'a': 1 }));
|
||||
const testObject: Configuration = new Configuration(parser.configurationModel, new ConfigurationModel());
|
||||
|
||||
testObject.inspect('a', {}, undefined);
|
||||
|
||||
@@ -10,29 +10,17 @@ import * as fs from 'fs';
|
||||
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { ConfigurationService } from 'vs/platform/configuration/node/configurationService';
|
||||
import { ParsedArgs } from 'vs/platform/environment/common/environment';
|
||||
import { parseArgs } from 'vs/platform/environment/node/argv';
|
||||
import { EnvironmentService } from 'vs/platform/environment/node/environmentService';
|
||||
import * as uuid from 'vs/base/common/uuid';
|
||||
import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { testFile } from 'vs/base/test/node/utils';
|
||||
|
||||
class SettingsTestEnvironmentService extends EnvironmentService {
|
||||
|
||||
constructor(args: ParsedArgs, _execPath: string, private customAppSettingsHome: string) {
|
||||
super(args, _execPath);
|
||||
}
|
||||
|
||||
get appSettingsPath(): string { return this.customAppSettingsHome; }
|
||||
}
|
||||
|
||||
suite('ConfigurationService - Node', () => {
|
||||
|
||||
test('simple', async () => {
|
||||
const res = await testFile('config', 'config.json');
|
||||
fs.writeFileSync(res.testFile, '{ "foo": "bar" }');
|
||||
|
||||
const service = new ConfigurationService(new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, res.testFile));
|
||||
const service = new ConfigurationService(res.testFile);
|
||||
const config = service.getValue<{
|
||||
foo: string;
|
||||
}>();
|
||||
@@ -49,7 +37,7 @@ suite('ConfigurationService - Node', () => {
|
||||
|
||||
fs.writeFileSync(res.testFile, '{ "testworkbench.editor.tabs": true }');
|
||||
|
||||
const service = new ConfigurationService(new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, res.testFile));
|
||||
const service = new ConfigurationService(res.testFile);
|
||||
const config = service.getValue<{
|
||||
testworkbench: {
|
||||
editor: {
|
||||
@@ -71,7 +59,7 @@ suite('ConfigurationService - Node', () => {
|
||||
|
||||
fs.writeFileSync(res.testFile, ',,,,');
|
||||
|
||||
const service = new ConfigurationService(new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, res.testFile));
|
||||
const service = new ConfigurationService(res.testFile);
|
||||
const config = service.getValue<{
|
||||
foo: string;
|
||||
}>();
|
||||
@@ -87,7 +75,7 @@ suite('ConfigurationService - Node', () => {
|
||||
const newDir = path.join(parentDir, 'config', id);
|
||||
const testFile = path.join(newDir, 'config.json');
|
||||
|
||||
const service = new ConfigurationService(new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, testFile));
|
||||
const service = new ConfigurationService(testFile);
|
||||
|
||||
const config = service.getValue<{ foo: string }>();
|
||||
assert.ok(config);
|
||||
@@ -98,7 +86,7 @@ suite('ConfigurationService - Node', () => {
|
||||
test('trigger configuration change event', async () => {
|
||||
const res = await testFile('config', 'config.json');
|
||||
|
||||
const service = new ConfigurationService(new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, res.testFile));
|
||||
const service = new ConfigurationService(res.testFile);
|
||||
return new Promise((c, e) => {
|
||||
service.onDidChangeConfiguration(() => {
|
||||
assert.equal(service.getValue('foo'), 'bar');
|
||||
@@ -115,7 +103,7 @@ suite('ConfigurationService - Node', () => {
|
||||
|
||||
fs.writeFileSync(res.testFile, '{ "foo": "bar" }');
|
||||
|
||||
const service = new ConfigurationService(new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, res.testFile));
|
||||
const service = new ConfigurationService(res.testFile);
|
||||
let config = service.getValue<{
|
||||
foo: string;
|
||||
}>();
|
||||
@@ -163,7 +151,7 @@ suite('ConfigurationService - Node', () => {
|
||||
}
|
||||
});
|
||||
|
||||
let serviceWithoutFile = new ConfigurationService(new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, '__testFile'));
|
||||
let serviceWithoutFile = new ConfigurationService('__testFile');
|
||||
let setting = serviceWithoutFile.getValue<ITestSetting>();
|
||||
|
||||
assert.ok(setting);
|
||||
@@ -172,7 +160,7 @@ suite('ConfigurationService - Node', () => {
|
||||
return testFile('config', 'config.json').then(async res => {
|
||||
fs.writeFileSync(res.testFile, '{ "testworkbench.editor.tabs": true }');
|
||||
|
||||
const service = new ConfigurationService(new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, res.testFile));
|
||||
const service = new ConfigurationService(res.testFile);
|
||||
|
||||
let setting = service.getValue<ITestSetting>();
|
||||
|
||||
@@ -205,7 +193,7 @@ suite('ConfigurationService - Node', () => {
|
||||
});
|
||||
|
||||
const r = await testFile('config', 'config.json');
|
||||
const service = new ConfigurationService(new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, r.testFile));
|
||||
const service = new ConfigurationService(r.testFile);
|
||||
let res = service.inspect('something.missing');
|
||||
assert.strictEqual(res.value, undefined);
|
||||
assert.strictEqual(res.default, undefined);
|
||||
@@ -241,7 +229,7 @@ suite('ConfigurationService - Node', () => {
|
||||
});
|
||||
|
||||
const r = await testFile('config', 'config.json');
|
||||
const service = new ConfigurationService(new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, r.testFile));
|
||||
const service = new ConfigurationService(r.testFile);
|
||||
let res = service.inspect('lookup.service.testNullSetting');
|
||||
assert.strictEqual(res.default, null);
|
||||
assert.strictEqual(res.value, null);
|
||||
|
||||
@@ -17,6 +17,7 @@ import { IContextMenuDelegate } from 'vs/base/browser/contextmenu';
|
||||
import { EventType, $, removeNode } from 'vs/base/browser/dom';
|
||||
import { attachMenuStyler } from 'vs/platform/theme/common/styler';
|
||||
import { domEvent } from 'vs/base/browser/event';
|
||||
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
|
||||
|
||||
export interface IContextMenuHandlerOptions {
|
||||
blockMouse: boolean;
|
||||
@@ -83,6 +84,25 @@ export class ContextMenuHandler {
|
||||
menu.onDidCancel(() => this.contextViewService.hideContextView(true), null, menuDisposables);
|
||||
menu.onDidBlur(() => this.contextViewService.hideContextView(true), null, menuDisposables);
|
||||
domEvent(window, EventType.BLUR)(() => { this.contextViewService.hideContextView(true); }, null, menuDisposables);
|
||||
domEvent(window, EventType.MOUSE_DOWN)((e: MouseEvent) => {
|
||||
let event = new StandardMouseEvent(e);
|
||||
let element: HTMLElement | null = event.target;
|
||||
|
||||
// Don't do anything as we are likely creating a context menu
|
||||
if (event.rightButton) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (element) {
|
||||
if (element === container) {
|
||||
return;
|
||||
}
|
||||
|
||||
element = element.parentElement;
|
||||
}
|
||||
|
||||
this.contextViewService.hideContextView(true);
|
||||
}, null, menuDisposables);
|
||||
|
||||
return combinedDisposable([...menuDisposables, menu]);
|
||||
},
|
||||
|
||||
@@ -30,6 +30,11 @@ export interface IRemoteDiagnosticInfo extends IDiagnosticInfo {
|
||||
hostName: string;
|
||||
}
|
||||
|
||||
export interface IRemoteDiagnosticError {
|
||||
hostName: string;
|
||||
errorMessage: string;
|
||||
}
|
||||
|
||||
export interface IDiagnosticInfoOptions {
|
||||
includeProcesses?: boolean;
|
||||
folders?: UriComponents[];
|
||||
@@ -46,4 +51,8 @@ export interface WorkspaceStats {
|
||||
configFiles: WorkspaceStatItem[];
|
||||
fileCount: number;
|
||||
maxFilesReached: boolean;
|
||||
}
|
||||
|
||||
export function isRemoteDiagnosticError(x: any): x is IRemoteDiagnosticError {
|
||||
return !!x.hostName && !!x.errorMessage;
|
||||
}
|
||||
@@ -15,7 +15,7 @@ import { app } from 'electron';
|
||||
import { basename } from 'vs/base/common/path';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IMachineInfo, WorkspaceStats, SystemInfo } from 'vs/platform/diagnostics/common/diagnosticsService';
|
||||
import { IMachineInfo, WorkspaceStats, SystemInfo, IRemoteDiagnosticInfo, isRemoteDiagnosticError } from 'vs/platform/diagnostics/common/diagnosticsService';
|
||||
import { collectWorkspaceStats, getMachineInfo } from 'vs/platform/diagnostics/node/diagnosticsService';
|
||||
import { ProcessItem } from 'vs/base/common/processes';
|
||||
|
||||
@@ -92,23 +92,28 @@ export class DiagnosticsService implements IDiagnosticsService {
|
||||
try {
|
||||
const remoteData = await launchService.getRemoteDiagnostics({ includeProcesses: true, includeWorkspaceMetadata: true });
|
||||
remoteData.forEach(diagnostics => {
|
||||
processInfo += `\n\nRemote: ${diagnostics.hostName}`;
|
||||
if (diagnostics.processes) {
|
||||
processInfo += `\n${this.formatProcessList(info, diagnostics.processes)}`;
|
||||
}
|
||||
if (isRemoteDiagnosticError(diagnostics)) {
|
||||
processInfo += `\n${diagnostics.errorMessage}`;
|
||||
workspaceInfo += `\n${diagnostics.errorMessage}`;
|
||||
} else {
|
||||
processInfo += `\n\nRemote: ${diagnostics.hostName}`;
|
||||
if (diagnostics.processes) {
|
||||
processInfo += `\n${this.formatProcessList(info, diagnostics.processes)}`;
|
||||
}
|
||||
|
||||
if (diagnostics.workspaceMetadata) {
|
||||
workspaceInfo += `\n| Remote: ${diagnostics.hostName}`;
|
||||
for (const folder of Object.keys(diagnostics.workspaceMetadata)) {
|
||||
const metadata = diagnostics.workspaceMetadata[folder];
|
||||
if (diagnostics.workspaceMetadata) {
|
||||
workspaceInfo += `\n| Remote: ${diagnostics.hostName}`;
|
||||
for (const folder of Object.keys(diagnostics.workspaceMetadata)) {
|
||||
const metadata = diagnostics.workspaceMetadata[folder];
|
||||
|
||||
let countMessage = `${metadata.fileCount} files`;
|
||||
if (metadata.maxFilesReached) {
|
||||
countMessage = `more than ${countMessage}`;
|
||||
let countMessage = `${metadata.fileCount} files`;
|
||||
if (metadata.maxFilesReached) {
|
||||
countMessage = `more than ${countMessage}`;
|
||||
}
|
||||
|
||||
workspaceInfo += `| Folder (${folder}): ${countMessage}`;
|
||||
workspaceInfo += this.formatWorkspaceStats(metadata);
|
||||
}
|
||||
|
||||
workspaceInfo += `| Folder (${folder}): ${countMessage}`;
|
||||
workspaceInfo += this.formatWorkspaceStats(metadata);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -135,7 +140,7 @@ export class DiagnosticsService implements IDiagnosticsService {
|
||||
processArgs: `${info.mainArguments.join(' ')}`,
|
||||
gpuStatus: app.getGPUFeatureStatus(),
|
||||
screenReader: `${app.isAccessibilitySupportEnabled() ? 'yes' : 'no'}`,
|
||||
remoteData: await launchService.getRemoteDiagnostics({ includeProcesses: false, includeWorkspaceMetadata: false })
|
||||
remoteData: (await launchService.getRemoteDiagnostics({ includeProcesses: false, includeWorkspaceMetadata: false })).filter((x): x is IRemoteDiagnosticInfo => !(x instanceof Error))
|
||||
};
|
||||
|
||||
|
||||
@@ -169,25 +174,29 @@ export class DiagnosticsService implements IDiagnosticsService {
|
||||
try {
|
||||
const data = await launchService.getRemoteDiagnostics({ includeProcesses: true, includeWorkspaceMetadata: true });
|
||||
data.forEach(diagnostics => {
|
||||
output.push('\n\n');
|
||||
output.push(`Remote: ${diagnostics.hostName}`);
|
||||
output.push(this.formatMachineInfo(diagnostics.machineInfo));
|
||||
if (isRemoteDiagnosticError(diagnostics)) {
|
||||
output.push(`\n${diagnostics.errorMessage}`);
|
||||
} else {
|
||||
output.push('\n\n');
|
||||
output.push(`Remote: ${diagnostics.hostName}`);
|
||||
output.push(this.formatMachineInfo(diagnostics.machineInfo));
|
||||
|
||||
if (diagnostics.processes) {
|
||||
output.push(this.formatProcessList(info, diagnostics.processes));
|
||||
}
|
||||
if (diagnostics.processes) {
|
||||
output.push(this.formatProcessList(info, diagnostics.processes));
|
||||
}
|
||||
|
||||
if (diagnostics.workspaceMetadata) {
|
||||
for (const folder of Object.keys(diagnostics.workspaceMetadata)) {
|
||||
const metadata = diagnostics.workspaceMetadata[folder];
|
||||
if (diagnostics.workspaceMetadata) {
|
||||
for (const folder of Object.keys(diagnostics.workspaceMetadata)) {
|
||||
const metadata = diagnostics.workspaceMetadata[folder];
|
||||
|
||||
let countMessage = `${metadata.fileCount} files`;
|
||||
if (metadata.maxFilesReached) {
|
||||
countMessage = `more than ${countMessage}`;
|
||||
let countMessage = `${metadata.fileCount} files`;
|
||||
if (metadata.maxFilesReached) {
|
||||
countMessage = `more than ${countMessage}`;
|
||||
}
|
||||
|
||||
output.push(`Folder (${folder}): ${countMessage}`);
|
||||
output.push(this.formatWorkspaceStats(metadata));
|
||||
}
|
||||
|
||||
output.push(`Folder (${folder}): ${countMessage}`);
|
||||
output.push(this.formatWorkspaceStats(metadata));
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -306,13 +315,13 @@ export class DiagnosticsService implements IDiagnosticsService {
|
||||
output.push('CPU %\tMem MB\t PID\tProcess');
|
||||
|
||||
if (rootProcess) {
|
||||
this.formatProcessItem(mapPidToWindowTitle, output, rootProcess, 0);
|
||||
this.formatProcessItem(info.mainPID, mapPidToWindowTitle, output, rootProcess, 0);
|
||||
}
|
||||
|
||||
return output.join('\n');
|
||||
}
|
||||
|
||||
private formatProcessItem(mapPidToWindowTitle: Map<number, string>, output: string[], item: ProcessItem, indent: number): void {
|
||||
private formatProcessItem(mainPid: number, mapPidToWindowTitle: Map<number, string>, output: string[], item: ProcessItem, indent: number): void {
|
||||
const isRoot = (indent === 0);
|
||||
|
||||
const MB = 1024 * 1024;
|
||||
@@ -320,7 +329,7 @@ export class DiagnosticsService implements IDiagnosticsService {
|
||||
// Format name with indent
|
||||
let name: string;
|
||||
if (isRoot) {
|
||||
name = `${product.applicationName} main`;
|
||||
name = item.pid === mainPid ? `${product.applicationName} main` : 'remote agent';
|
||||
} else {
|
||||
name = `${repeat(' ', indent)} ${item.name}`;
|
||||
|
||||
@@ -333,7 +342,7 @@ export class DiagnosticsService implements IDiagnosticsService {
|
||||
|
||||
// Recurse into children if any
|
||||
if (Array.isArray(item.children)) {
|
||||
item.children.forEach(child => this.formatProcessItem(mapPidToWindowTitle, output, child, indent + 1));
|
||||
item.children.forEach(child => this.formatProcessItem(mainPid, mapPidToWindowTitle, output, child, indent + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,12 +226,12 @@ export async function registerWindowDriver(accessor: ServicesAccessor): Promise<
|
||||
const windowDriverRegistryChannel = mainProcessService.getChannel('windowDriverRegistry');
|
||||
const windowDriverRegistry = new WindowDriverRegistryChannelClient(windowDriverRegistryChannel);
|
||||
|
||||
await windowDriverRegistry.registerWindowDriver(windowService.getCurrentWindowId());
|
||||
await windowDriverRegistry.registerWindowDriver(windowService.windowId);
|
||||
// const options = await windowDriverRegistry.registerWindowDriver(windowId);
|
||||
|
||||
// if (options.verbose) {
|
||||
// windowDriver.openDevTools();
|
||||
// }
|
||||
|
||||
return toDisposable(() => windowDriverRegistry.reloadWindowDriver(windowService.getCurrentWindowId()));
|
||||
return toDisposable(() => windowDriverRegistry.reloadWindowDriver(windowService.windowId));
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ export interface ParsedArgs {
|
||||
'show-versions'?: boolean;
|
||||
'install-extension'?: string | string[];
|
||||
'uninstall-extension'?: string | string[];
|
||||
'locate-extension'?: string | string[];
|
||||
'enable-proposed-api'?: string | string[];
|
||||
'open-url'?: boolean;
|
||||
'skip-getting-started'?: boolean;
|
||||
@@ -109,6 +110,9 @@ export interface IEnvironmentService {
|
||||
appSettingsPath: string;
|
||||
appKeybindingsPath: string;
|
||||
|
||||
machineSettingsHome: string;
|
||||
machineSettingsPath: string;
|
||||
|
||||
settingsSearchBuildId?: number;
|
||||
settingsSearchUrl?: string;
|
||||
|
||||
@@ -124,7 +128,7 @@ export interface IEnvironmentService {
|
||||
disableExtensions: boolean | string[];
|
||||
builtinExtensionsPath: string;
|
||||
extensionsPath: string;
|
||||
extensionDevelopmentLocationURI?: URI | URI[];
|
||||
extensionDevelopmentLocationURI?: URI[];
|
||||
extensionTestsLocationURI?: URI;
|
||||
|
||||
debugExtensionHost: IExtensionHostDebugParams;
|
||||
|
||||
@@ -66,6 +66,7 @@ export const options: Option[] = [
|
||||
{ id: 'max-memory', type: 'string', cat: 't', description: localize('maxMemory', "Max memory size for a window (in Mbytes).") },
|
||||
|
||||
{ id: 'remote', type: 'string' },
|
||||
{ id: 'locate-extension', type: 'string' },
|
||||
{ id: 'extensionDevelopmentPath', type: 'string' },
|
||||
{ id: 'extensionTestsPath', type: 'string' },
|
||||
{ id: 'debugId', type: 'string' },
|
||||
|
||||
@@ -110,6 +110,12 @@ export class EnvironmentService implements IEnvironmentService {
|
||||
@memoize
|
||||
get appSettingsPath(): string { return path.join(this.appSettingsHome, 'settings.json'); }
|
||||
|
||||
@memoize
|
||||
get machineSettingsHome(): string { return path.join(this.userDataPath, 'Machine'); }
|
||||
|
||||
@memoize
|
||||
get machineSettingsPath(): string { return path.join(this.machineSettingsHome, 'settings.json'); }
|
||||
|
||||
@memoize
|
||||
get globalStorageHome(): string { return path.join(this.appSettingsHome, 'globalStorage'); }
|
||||
|
||||
@@ -172,7 +178,7 @@ export class EnvironmentService implements IEnvironmentService {
|
||||
}
|
||||
|
||||
@memoize
|
||||
get extensionDevelopmentLocationURI(): URI | URI[] | undefined {
|
||||
get extensionDevelopmentLocationURI(): URI[] | undefined {
|
||||
const s = this._args.extensionDevelopmentPath;
|
||||
if (Array.isArray(s)) {
|
||||
return s.map(p => {
|
||||
@@ -183,9 +189,9 @@ export class EnvironmentService implements IEnvironmentService {
|
||||
});
|
||||
} else if (s) {
|
||||
if (/^[^:/?#]+?:\/\//.test(s)) {
|
||||
return URI.parse(s);
|
||||
return [URI.parse(s)];
|
||||
}
|
||||
return URI.file(path.normalize(s));
|
||||
return [URI.file(path.normalize(s))];
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -753,7 +753,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
|
||||
}
|
||||
|
||||
loadAllDependencies(extensions: IExtensionIdentifier[], token: CancellationToken): Promise<IGalleryExtension[]> {
|
||||
return this.getDependenciesReccursively(extensions.map(e => e.id), [], token);
|
||||
return this.getDependenciesRecursively(extensions.map(e => e.id), [], token);
|
||||
}
|
||||
|
||||
getAllVersions(extension: IGalleryExtension, compatible: boolean): Promise<IGalleryExtensionVersion[]> {
|
||||
@@ -812,7 +812,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
|
||||
});
|
||||
}
|
||||
|
||||
private getDependenciesReccursively(toGet: string[], result: IGalleryExtension[], token: CancellationToken): Promise<IGalleryExtension[]> {
|
||||
private getDependenciesRecursively(toGet: string[], result: IGalleryExtension[], token: CancellationToken): Promise<IGalleryExtension[]> {
|
||||
if (!toGet || !toGet.length) {
|
||||
return Promise.resolve(result);
|
||||
}
|
||||
@@ -832,7 +832,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
|
||||
result = distinct(result.concat(loadedDependencies), d => d.identifier.uuid);
|
||||
const dependencies: string[] = [];
|
||||
dependenciesSet.forEach(d => !ExtensionGalleryService.hasExtensionByName(result, d) && dependencies.push(d));
|
||||
return this.getDependenciesReccursively(dependencies, result, token);
|
||||
return this.getDependenciesRecursively(dependencies, result, token);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -903,7 +903,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
|
||||
if (version) {
|
||||
return version;
|
||||
}
|
||||
return this.getLastValidExtensionVersionReccursively(extension, versions);
|
||||
return this.getLastValidExtensionVersionRecursively(extension, versions);
|
||||
}
|
||||
|
||||
private getLastValidExtensionVersionFromProperties(extension: IRawGalleryExtension, versions: IRawGalleryExtensionVersion[]): Promise<IRawGalleryExtensionVersion> | null {
|
||||
@@ -936,7 +936,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
|
||||
.then(manifest => manifest ? manifest.engines.vscode : Promise.reject<string>('Error while reading manifest'));
|
||||
}
|
||||
|
||||
private getLastValidExtensionVersionReccursively(extension: IRawGalleryExtension, versions: IRawGalleryExtensionVersion[]): Promise<IRawGalleryExtensionVersion | null> {
|
||||
private getLastValidExtensionVersionRecursively(extension: IRawGalleryExtension, versions: IRawGalleryExtensionVersion[]): Promise<IRawGalleryExtensionVersion | null> {
|
||||
if (!versions.length) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
@@ -945,7 +945,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
|
||||
return this.getEngine(version)
|
||||
.then(engine => {
|
||||
if (!isEngineValid(engine)) {
|
||||
return this.getLastValidExtensionVersionReccursively(extension, versions.slice(1));
|
||||
return this.getLastValidExtensionVersionRecursively(extension, versions.slice(1));
|
||||
}
|
||||
|
||||
version.properties = version.properties || [];
|
||||
|
||||
@@ -13,6 +13,7 @@ import { startsWithIgnoreCase } from 'vs/base/common/strings';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { isEqualOrParent, isEqual } from 'vs/base/common/resources';
|
||||
import { isUndefinedOrNull } from 'vs/base/common/types';
|
||||
import { VSBuffer, VSBufferReadable } from 'vs/base/common/buffer';
|
||||
|
||||
export const IFileService = createDecorator<IFileService>('fileService');
|
||||
|
||||
@@ -123,10 +124,15 @@ export interface IFileService {
|
||||
*/
|
||||
resolveStreamContent(resource: URI, options?: IResolveContentOptions): Promise<IStreamContent>;
|
||||
|
||||
/**
|
||||
* @deprecated use writeFile instead
|
||||
*/
|
||||
updateContent(resource: URI, value: string | ITextSnapshot, options?: IWriteTextFileOptions): Promise<IFileStatWithMetadata>;
|
||||
|
||||
/**
|
||||
* Updates the content replacing its previous value.
|
||||
*/
|
||||
updateContent(resource: URI, value: string | ITextSnapshot, options?: IUpdateContentOptions): Promise<IFileStatWithMetadata>;
|
||||
writeFile(resource: URI, bufferOrReadable: VSBuffer | VSBufferReadable, options?: IWriteFileOptions): Promise<IFileStatWithMetadata>;
|
||||
|
||||
/**
|
||||
* Moves the file/folder to a new path identified by the resource.
|
||||
@@ -143,12 +149,17 @@ export interface IFileService {
|
||||
copy(source: URI, target: URI, overwrite?: boolean): Promise<IFileStatWithMetadata>;
|
||||
|
||||
/**
|
||||
* Creates a new file with the given path. The returned promise
|
||||
* @deprecated use createFile2 instead
|
||||
*/
|
||||
createFile(resource: URI, content?: string, options?: ICreateFileOptions): Promise<IFileStatWithMetadata>;
|
||||
|
||||
/**
|
||||
* Creates a new file with the given path and optional contents. The returned promise
|
||||
* will have the stat model object as a result.
|
||||
*
|
||||
* The optional parameter content can be used as value to fill into the new file.
|
||||
*/
|
||||
createFile(resource: URI, content?: string, options?: ICreateFileOptions): Promise<IFileStatWithMetadata>;
|
||||
createFile2(resource: URI, bufferOrReadable?: VSBuffer | VSBufferReadable, options?: ICreateFileOptions): Promise<IFileStatWithMetadata>;
|
||||
|
||||
/**
|
||||
* Creates a new folder with the given path. The returned promise
|
||||
@@ -650,17 +661,6 @@ export interface ITextSnapshot {
|
||||
read(): string | null;
|
||||
}
|
||||
|
||||
export class StringSnapshot implements ITextSnapshot {
|
||||
private _value: string | null;
|
||||
constructor(value: string) {
|
||||
this._value = value;
|
||||
}
|
||||
read(): string | null {
|
||||
let ret = this._value;
|
||||
this._value = null;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Helper method to convert a snapshot into its full string form.
|
||||
*/
|
||||
@@ -674,6 +674,35 @@ export function snapshotToString(snapshot: ITextSnapshot): string {
|
||||
return chunks.join('');
|
||||
}
|
||||
|
||||
export class TextSnapshotReadable implements VSBufferReadable {
|
||||
private preambleHandled: boolean;
|
||||
|
||||
constructor(private snapshot: ITextSnapshot, private preamble?: string) { }
|
||||
|
||||
read(): VSBuffer | null {
|
||||
let value = this.snapshot.read();
|
||||
|
||||
// Handle preamble if provided
|
||||
if (!this.preambleHandled) {
|
||||
this.preambleHandled = true;
|
||||
|
||||
if (typeof this.preamble === 'string') {
|
||||
if (typeof value === 'string') {
|
||||
value = this.preamble + value;
|
||||
} else {
|
||||
value = this.preamble;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof value === 'string') {
|
||||
return VSBuffer.fromString(value);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Streamable content and meta information of a file.
|
||||
*/
|
||||
@@ -724,7 +753,20 @@ export interface IResolveContentOptions {
|
||||
position?: number;
|
||||
}
|
||||
|
||||
export interface IUpdateContentOptions {
|
||||
export interface IWriteFileOptions {
|
||||
|
||||
/**
|
||||
* The last known modification time of the file. This can be used to prevent dirty writes.
|
||||
*/
|
||||
mtime?: number;
|
||||
|
||||
/**
|
||||
* The etag of the file. This can be used to prevent dirty writes.
|
||||
*/
|
||||
etag?: string;
|
||||
}
|
||||
|
||||
export interface IWriteTextFileOptions extends IWriteFileOptions {
|
||||
|
||||
/**
|
||||
* The encoding to use when updating a file.
|
||||
@@ -746,21 +788,6 @@ export interface IUpdateContentOptions {
|
||||
* ask the user to authenticate as super user.
|
||||
*/
|
||||
writeElevated?: boolean;
|
||||
|
||||
/**
|
||||
* The last known modification time of the file. This can be used to prevent dirty writes.
|
||||
*/
|
||||
mtime?: number;
|
||||
|
||||
/**
|
||||
* The etag of the file. This can be used to prevent dirty writes.
|
||||
*/
|
||||
etag?: string;
|
||||
|
||||
/**
|
||||
* Run mkdirp before saving.
|
||||
*/
|
||||
mkdirp?: boolean;
|
||||
}
|
||||
|
||||
export interface IResolveFileOptions {
|
||||
@@ -797,7 +824,7 @@ export interface ICreateFileOptions {
|
||||
}
|
||||
|
||||
export class FileOperationError extends Error {
|
||||
constructor(message: string, public fileOperationResult: FileOperationResult, public options?: IResolveContentOptions & IUpdateContentOptions & ICreateFileOptions) {
|
||||
constructor(message: string, public fileOperationResult: FileOperationResult, public options?: IResolveContentOptions & IWriteTextFileOptions & ICreateFileOptions) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
@@ -1132,7 +1159,7 @@ export interface ILegacyFileService extends IDisposable {
|
||||
|
||||
resolveStreamContent(resource: URI, options?: IResolveContentOptions): Promise<IStreamContent>;
|
||||
|
||||
updateContent(resource: URI, value: string | ITextSnapshot, options?: IUpdateContentOptions): Promise<IFileStatWithMetadata>;
|
||||
updateContent(resource: URI, value: string | ITextSnapshot, options?: IWriteTextFileOptions): Promise<IFileStatWithMetadata>;
|
||||
|
||||
createFile(resource: URI, content?: string, options?: ICreateFileOptions): Promise<IFileStatWithMetadata>;
|
||||
}
|
||||
@@ -33,7 +33,7 @@ export class SharedProcessService implements ISharedProcessService {
|
||||
@IEnvironmentService environmentService: IEnvironmentService
|
||||
) {
|
||||
this.withSharedProcessConnection = windowsService.whenSharedProcessReady()
|
||||
.then(() => connect(environmentService.sharedIPCHandle, `window:${windowService.getCurrentWindowId()}`));
|
||||
.then(() => connect(environmentService.sharedIPCHandle, `window:${windowService.windowId}`));
|
||||
}
|
||||
|
||||
getChannel(channelName: string): IChannel {
|
||||
|
||||
@@ -15,6 +15,8 @@ import { isMacintosh, IProcessEnvironment } from 'vs/base/common/platform';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IWindowsService } from 'vs/platform/windows/common/windows';
|
||||
import { IWindowState } from 'vs/platform/windows/electron-main/windows';
|
||||
import { listProcesses } from 'vs/base/node/ps';
|
||||
import { isRemoteDiagnosticError } from 'vs/platform/diagnostics/common/diagnosticsService';
|
||||
|
||||
const DEFAULT_BACKGROUND_COLOR = '#1E1E1E';
|
||||
|
||||
@@ -44,6 +46,35 @@ export class IssueService implements IIssueService {
|
||||
});
|
||||
});
|
||||
|
||||
ipcMain.on('vscode:listProcesses', async (event: Event) => {
|
||||
const processes = [];
|
||||
|
||||
try {
|
||||
const mainPid = await this.launchService.getMainProcessId();
|
||||
processes.push({ name: localize('local', "Local"), rootProcess: await listProcesses(mainPid) });
|
||||
(await this.launchService.getRemoteDiagnostics({ includeProcesses: true }))
|
||||
.forEach(data => {
|
||||
if (isRemoteDiagnosticError(data)) {
|
||||
processes.push({
|
||||
name: data.hostName,
|
||||
rootProcess: data
|
||||
});
|
||||
} else {
|
||||
if (data.processes) {
|
||||
processes.push({
|
||||
name: data.hostName,
|
||||
rootProcess: data.processes
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
this.logService.error(`Listing processes failed: ${e}`);
|
||||
}
|
||||
|
||||
event.sender.send('vscode:listProcessesResponse', processes);
|
||||
});
|
||||
|
||||
ipcMain.on('vscode:issuePerformanceInfoRequest', (event: Event) => {
|
||||
this.getPerformanceInfo().then(msg => {
|
||||
event.sender.send('vscode:issuePerformanceInfoResponse', msg);
|
||||
|
||||
@@ -19,7 +19,7 @@ import { BrowserWindow, ipcMain, Event as IpcEvent } from 'electron';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { hasArgs } from 'vs/platform/environment/node/argv';
|
||||
import { coalesce } from 'vs/base/common/arrays';
|
||||
import { IDiagnosticInfoOptions, IDiagnosticInfo, IRemoteDiagnosticInfo } from 'vs/platform/diagnostics/common/diagnosticsService';
|
||||
import { IDiagnosticInfoOptions, IDiagnosticInfo, IRemoteDiagnosticInfo, IRemoteDiagnosticError } from 'vs/platform/diagnostics/common/diagnosticsService';
|
||||
|
||||
export const ID = 'launchService';
|
||||
export const ILaunchService = createDecorator<ILaunchService>(ID);
|
||||
@@ -71,7 +71,7 @@ export interface ILaunchService {
|
||||
getMainProcessId(): Promise<number>;
|
||||
getMainProcessInfo(): Promise<IMainProcessInfo>;
|
||||
getLogsPath(): Promise<string>;
|
||||
getRemoteDiagnostics(options: IRemoteDiagnosticOptions): Promise<IRemoteDiagnosticInfo[]>;
|
||||
getRemoteDiagnostics(options: IRemoteDiagnosticOptions): Promise<(IRemoteDiagnosticInfo | IRemoteDiagnosticError)[]>;
|
||||
}
|
||||
|
||||
export class LaunchChannel implements IServerChannel {
|
||||
@@ -299,9 +299,9 @@ export class LaunchService implements ILaunchService {
|
||||
return Promise.resolve(this.environmentService.logsPath);
|
||||
}
|
||||
|
||||
getRemoteDiagnostics(options: IRemoteDiagnosticOptions): Promise<IRemoteDiagnosticInfo[]> {
|
||||
getRemoteDiagnostics(options: IRemoteDiagnosticOptions): Promise<(IRemoteDiagnosticInfo | IRemoteDiagnosticError)[]> {
|
||||
const windows = this.windowsMainService.getWindows();
|
||||
const promises: Promise<IDiagnosticInfo | undefined>[] = windows.map(window => {
|
||||
const promises: Promise<IDiagnosticInfo | IRemoteDiagnosticError | undefined>[] = windows.map(window => {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (window.remoteAuthority) {
|
||||
const replyChannel = `vscode:getDiagnosticInfoResponse${window.id}`;
|
||||
@@ -315,18 +315,14 @@ export class LaunchService implements ILaunchService {
|
||||
ipcMain.once(replyChannel, (_: IpcEvent, data: IRemoteDiagnosticInfo) => {
|
||||
// No data is returned if getting the connection fails.
|
||||
if (!data) {
|
||||
resolve();
|
||||
}
|
||||
|
||||
if (typeof (data) === 'string') {
|
||||
reject(new Error(data));
|
||||
resolve({ hostName: window.remoteAuthority!, errorMessage: `Unable to resolve connection to '${window.remoteAuthority}'.` });
|
||||
}
|
||||
|
||||
resolve(data);
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
resolve();
|
||||
resolve({ hostName: window.remoteAuthority!, errorMessage: `Fetching remote diagnostics for '${window.remoteAuthority}' timed out.` });
|
||||
}, 5000);
|
||||
} else {
|
||||
resolve();
|
||||
@@ -334,7 +330,7 @@ export class LaunchService implements ILaunchService {
|
||||
});
|
||||
});
|
||||
|
||||
return Promise.all(promises).then(diagnostics => diagnostics.filter((x): x is IRemoteDiagnosticInfo => !!x));
|
||||
return Promise.all(promises).then(diagnostics => diagnostics.filter((x): x is IRemoteDiagnosticInfo | IRemoteDiagnosticError => !!x));
|
||||
}
|
||||
|
||||
private getFolderURIs(window: ICodeWindow): URI[] {
|
||||
|
||||
@@ -53,7 +53,7 @@ export class LifecycleService extends AbstractLifecycleService {
|
||||
}
|
||||
|
||||
private registerListeners(): void {
|
||||
const windowId = this.windowService.getCurrentWindowId();
|
||||
const windowId = this.windowService.windowId;
|
||||
|
||||
// Main side indicates that window is about to unload, check for vetos
|
||||
ipc.on('vscode:onBeforeUnload', (_event: unknown, reply: { okChannel: string, cancelChannel: string, reason: ShutdownReason }) => {
|
||||
|
||||
@@ -29,7 +29,7 @@ import { ObjectTree, IObjectTreeOptions } from 'vs/base/browser/ui/tree/objectTr
|
||||
import { ITreeEvent, ITreeRenderer, IAsyncDataSource, IDataSource, ITreeMouseEvent } from 'vs/base/browser/ui/tree/tree';
|
||||
import { AsyncDataTree, IAsyncDataTreeOptions } from 'vs/base/browser/ui/tree/asyncDataTree';
|
||||
import { DataTree, IDataTreeOptions } from 'vs/base/browser/ui/tree/dataTree';
|
||||
import { IKeyboardNavigationEventFilter } from 'vs/base/browser/ui/tree/abstractTree';
|
||||
import { IKeyboardNavigationEventFilter, IAbstractTreeOptions } from 'vs/base/browser/ui/tree/abstractTree';
|
||||
import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility';
|
||||
|
||||
export type ListWidget = List<any> | PagedList<any> | ITree | ObjectTree<any, any> | DataTree<any, any, any> | AsyncDataTree<any, any, any>;
|
||||
@@ -659,8 +659,9 @@ export interface IOpenEvent<T> {
|
||||
browserEvent?: UIEvent;
|
||||
}
|
||||
|
||||
export interface IResourceResultsNavigationOptions {
|
||||
openOnFocus: boolean;
|
||||
export interface IResourceResultsNavigationOptions2 {
|
||||
openOnFocus?: boolean;
|
||||
openOnSelection?: boolean;
|
||||
}
|
||||
|
||||
export interface SelectionKeyboardEvent extends KeyboardEvent {
|
||||
@@ -676,14 +677,24 @@ export function getSelectionKeyboardEvent(typeArg = 'keydown', preserveFocus?: b
|
||||
|
||||
export class TreeResourceNavigator2<T, TFilterData> extends Disposable {
|
||||
|
||||
private options: IResourceResultsNavigationOptions2;
|
||||
|
||||
private readonly _onDidOpenResource = new Emitter<IOpenEvent<T | null>>();
|
||||
readonly onDidOpenResource: Event<IOpenEvent<T | null>> = this._onDidOpenResource.event;
|
||||
|
||||
constructor(
|
||||
private tree: WorkbenchObjectTree<T, TFilterData> | WorkbenchDataTree<any, T, TFilterData> | WorkbenchAsyncDataTree<any, T, TFilterData>,
|
||||
private options?: IResourceResultsNavigationOptions
|
||||
options?: IResourceResultsNavigationOptions2
|
||||
) {
|
||||
super();
|
||||
|
||||
this.options = {
|
||||
...<IResourceResultsNavigationOptions2>{
|
||||
openOnSelection: true
|
||||
},
|
||||
...(options || {})
|
||||
};
|
||||
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
@@ -692,7 +703,10 @@ export class TreeResourceNavigator2<T, TFilterData> extends Disposable {
|
||||
this._register(this.tree.onDidChangeFocus(e => this.onFocus(e)));
|
||||
}
|
||||
|
||||
this._register(this.tree.onDidChangeSelection(e => this.onSelection(e)));
|
||||
if (this.options && this.options.openOnSelection) {
|
||||
this._register(this.tree.onDidChangeSelection(e => this.onSelection(e)));
|
||||
}
|
||||
|
||||
this._register(this.tree.onDidOpen(e => this.onSelection(e)));
|
||||
}
|
||||
|
||||
@@ -766,15 +780,9 @@ function createKeyboardNavigationEventFilter(container: HTMLElement, keybindingS
|
||||
|
||||
export class WorkbenchObjectTree<T extends NonNullable<any>, TFilterData = void> extends ObjectTree<T, TFilterData> {
|
||||
|
||||
readonly contextKeyService: IContextKeyService;
|
||||
|
||||
protected disposables: IDisposable[];
|
||||
|
||||
private hasSelectionOrFocus: IContextKey<boolean>;
|
||||
private hasDoubleSelection: IContextKey<boolean>;
|
||||
private hasMultiSelection: IContextKey<boolean>;
|
||||
|
||||
private _useAltAsMultipleSelectionModifier: boolean;
|
||||
private internals: WorkbenchTreeInternals<any, T, TFilterData>;
|
||||
get contextKeyService(): IContextKeyService { return this.internals.contextKeyService; }
|
||||
get useAltAsMultipleSelectionModifier(): boolean { return this.internals.useAltAsMultipleSelectionModifier; }
|
||||
|
||||
constructor(
|
||||
container: HTMLElement,
|
||||
@@ -788,132 +796,19 @@ export class WorkbenchObjectTree<T extends NonNullable<any>, TFilterData = void>
|
||||
@IKeybindingService keybindingService: IKeybindingService,
|
||||
@IAccessibilityService accessibilityService: IAccessibilityService
|
||||
) {
|
||||
WorkbenchListSupportsKeyboardNavigation.bindTo(contextKeyService);
|
||||
|
||||
if (!didBindWorkbenchListAutomaticKeyboardNavigation) {
|
||||
WorkbenchListAutomaticKeyboardNavigation.bindTo(contextKeyService);
|
||||
didBindWorkbenchListAutomaticKeyboardNavigation = true;
|
||||
}
|
||||
|
||||
const getAutomaticKeyboardNavigation = () => {
|
||||
// give priority to the context key value to disable this completely
|
||||
let automaticKeyboardNavigation = contextKeyService.getContextKeyValue<boolean>(WorkbenchListAutomaticKeyboardNavigationKey);
|
||||
|
||||
if (automaticKeyboardNavigation) {
|
||||
automaticKeyboardNavigation = configurationService.getValue<boolean>(automaticKeyboardNavigationSettingKey);
|
||||
}
|
||||
|
||||
return automaticKeyboardNavigation;
|
||||
};
|
||||
|
||||
const accessibilityOn = accessibilityService.getAccessibilitySupport() === AccessibilitySupport.Enabled;
|
||||
const keyboardNavigation = accessibilityOn ? 'simple' : configurationService.getValue<string>(keyboardNavigationSettingKey);
|
||||
const horizontalScrolling = typeof options.horizontalScrolling !== 'undefined' ? options.horizontalScrolling : getHorizontalScrollingSetting(configurationService);
|
||||
const openOnSingleClick = useSingleClickToOpen(configurationService);
|
||||
const [workbenchListOptions, workbenchListOptionsDisposable] = toWorkbenchListOptions(options, configurationService, keybindingService);
|
||||
|
||||
super(container, delegate, renderers, {
|
||||
keyboardSupport: false,
|
||||
styleController: new DefaultStyleController(getSharedListStyleSheet()),
|
||||
...computeStyles(themeService.getTheme(), defaultListStyles),
|
||||
...workbenchListOptions,
|
||||
indent: configurationService.getValue(treeIndentKey),
|
||||
automaticKeyboardNavigation: getAutomaticKeyboardNavigation(),
|
||||
simpleKeyboardNavigation: keyboardNavigation === 'simple',
|
||||
filterOnType: keyboardNavigation === 'filter',
|
||||
horizontalScrolling,
|
||||
openOnSingleClick,
|
||||
keyboardNavigationEventFilter: createKeyboardNavigationEventFilter(container, keybindingService)
|
||||
});
|
||||
|
||||
this.disposables.push(workbenchListOptionsDisposable);
|
||||
|
||||
this.contextKeyService = createScopedContextKeyService(contextKeyService, this);
|
||||
|
||||
const listSupportsMultiSelect = WorkbenchListSupportsMultiSelectContextKey.bindTo(this.contextKeyService);
|
||||
listSupportsMultiSelect.set(!(options.multipleSelectionSupport === false));
|
||||
|
||||
this.hasSelectionOrFocus = WorkbenchListHasSelectionOrFocus.bindTo(this.contextKeyService);
|
||||
this.hasDoubleSelection = WorkbenchListDoubleSelection.bindTo(this.contextKeyService);
|
||||
this.hasMultiSelection = WorkbenchListMultiSelection.bindTo(this.contextKeyService);
|
||||
|
||||
this._useAltAsMultipleSelectionModifier = useAltAsMultipleSelectionModifier(configurationService);
|
||||
|
||||
const interestingContextKeys = new Set();
|
||||
interestingContextKeys.add(WorkbenchListAutomaticKeyboardNavigationKey);
|
||||
const updateKeyboardNavigation = () => {
|
||||
const accessibilityOn = accessibilityService.getAccessibilitySupport() === AccessibilitySupport.Enabled;
|
||||
const keyboardNavigation = accessibilityOn ? 'simple' : configurationService.getValue<string>(keyboardNavigationSettingKey);
|
||||
this.updateOptions({
|
||||
simpleKeyboardNavigation: keyboardNavigation === 'simple',
|
||||
filterOnType: keyboardNavigation === 'filter'
|
||||
});
|
||||
};
|
||||
|
||||
this.disposables.push(
|
||||
this.contextKeyService,
|
||||
(listService as ListService).register(this),
|
||||
attachListStyler(this, themeService),
|
||||
this.onDidChangeSelection(() => {
|
||||
const selection = this.getSelection();
|
||||
const focus = this.getFocus();
|
||||
|
||||
this.hasSelectionOrFocus.set(selection.length > 0 || focus.length > 0);
|
||||
this.hasMultiSelection.set(selection.length > 1);
|
||||
this.hasDoubleSelection.set(selection.length === 2);
|
||||
}),
|
||||
this.onDidChangeFocus(() => {
|
||||
const selection = this.getSelection();
|
||||
const focus = this.getFocus();
|
||||
|
||||
this.hasSelectionOrFocus.set(selection.length > 0 || focus.length > 0);
|
||||
}),
|
||||
configurationService.onDidChangeConfiguration(e => {
|
||||
if (e.affectsConfiguration(openModeSettingKey)) {
|
||||
this.updateOptions({ openOnSingleClick: useSingleClickToOpen(configurationService) });
|
||||
}
|
||||
if (e.affectsConfiguration(multiSelectModifierSettingKey)) {
|
||||
this._useAltAsMultipleSelectionModifier = useAltAsMultipleSelectionModifier(configurationService);
|
||||
}
|
||||
if (e.affectsConfiguration(treeIndentKey)) {
|
||||
const indent = configurationService.getValue<number>(treeIndentKey);
|
||||
this.updateOptions({ indent });
|
||||
}
|
||||
if (e.affectsConfiguration(keyboardNavigationSettingKey)) {
|
||||
updateKeyboardNavigation();
|
||||
}
|
||||
if (e.affectsConfiguration(automaticKeyboardNavigationSettingKey)) {
|
||||
this.updateOptions({ automaticKeyboardNavigation: getAutomaticKeyboardNavigation() });
|
||||
}
|
||||
}),
|
||||
this.contextKeyService.onDidChangeContext(e => {
|
||||
if (e.affectsSome(interestingContextKeys)) {
|
||||
this.updateOptions({ automaticKeyboardNavigation: getAutomaticKeyboardNavigation() });
|
||||
}
|
||||
}),
|
||||
accessibilityService.onDidChangeAccessibilitySupport(() => updateKeyboardNavigation())
|
||||
);
|
||||
}
|
||||
|
||||
get useAltAsMultipleSelectionModifier(): boolean {
|
||||
return this._useAltAsMultipleSelectionModifier;
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
super.dispose();
|
||||
this.disposables = dispose(this.disposables);
|
||||
const { options: treeOptions, getAutomaticKeyboardNavigation, disposable } = workbenchTreeDataPreamble(container, options, contextKeyService, themeService, configurationService, keybindingService, accessibilityService);
|
||||
super(container, delegate, renderers, treeOptions);
|
||||
this.disposables.push(disposable);
|
||||
this.internals = new WorkbenchTreeInternals(this, treeOptions, getAutomaticKeyboardNavigation, contextKeyService, listService, themeService, configurationService, accessibilityService);
|
||||
this.disposables.push(this.internals);
|
||||
}
|
||||
}
|
||||
|
||||
export class WorkbenchDataTree<TInput, T, TFilterData = void> extends DataTree<TInput, T, TFilterData> {
|
||||
|
||||
readonly contextKeyService: IContextKeyService;
|
||||
|
||||
private hasSelectionOrFocus: IContextKey<boolean>;
|
||||
private hasDoubleSelection: IContextKey<boolean>;
|
||||
private hasMultiSelection: IContextKey<boolean>;
|
||||
|
||||
private _useAltAsMultipleSelectionModifier: boolean;
|
||||
private internals: WorkbenchTreeInternals<TInput, T, TFilterData>;
|
||||
get contextKeyService(): IContextKeyService { return this.internals.contextKeyService; }
|
||||
get useAltAsMultipleSelectionModifier(): boolean { return this.internals.useAltAsMultipleSelectionModifier; }
|
||||
|
||||
constructor(
|
||||
container: HTMLElement,
|
||||
@@ -928,127 +823,19 @@ export class WorkbenchDataTree<TInput, T, TFilterData = void> extends DataTree<T
|
||||
@IKeybindingService keybindingService: IKeybindingService,
|
||||
@IAccessibilityService accessibilityService: IAccessibilityService
|
||||
) {
|
||||
WorkbenchListSupportsKeyboardNavigation.bindTo(contextKeyService);
|
||||
|
||||
if (!didBindWorkbenchListAutomaticKeyboardNavigation) {
|
||||
WorkbenchListAutomaticKeyboardNavigation.bindTo(contextKeyService);
|
||||
didBindWorkbenchListAutomaticKeyboardNavigation = true;
|
||||
}
|
||||
|
||||
const getAutomaticKeyboardNavigation = () => {
|
||||
// give priority to the context key value to disable this completely
|
||||
let automaticKeyboardNavigation = contextKeyService.getContextKeyValue<boolean>(WorkbenchListAutomaticKeyboardNavigationKey);
|
||||
|
||||
if (automaticKeyboardNavigation) {
|
||||
automaticKeyboardNavigation = configurationService.getValue<boolean>(automaticKeyboardNavigationSettingKey);
|
||||
}
|
||||
|
||||
return automaticKeyboardNavigation;
|
||||
};
|
||||
|
||||
const accessibilityOn = accessibilityService.getAccessibilitySupport() === AccessibilitySupport.Enabled;
|
||||
const keyboardNavigation = accessibilityOn ? 'simple' : configurationService.getValue<string>(keyboardNavigationSettingKey);
|
||||
const horizontalScrolling = typeof options.horizontalScrolling !== 'undefined' ? options.horizontalScrolling : getHorizontalScrollingSetting(configurationService);
|
||||
const openOnSingleClick = useSingleClickToOpen(configurationService);
|
||||
const [workbenchListOptions, workbenchListOptionsDisposable] = toWorkbenchListOptions(options, configurationService, keybindingService);
|
||||
|
||||
super(container, delegate, renderers, dataSource, {
|
||||
keyboardSupport: false,
|
||||
styleController: new DefaultStyleController(getSharedListStyleSheet()),
|
||||
...computeStyles(themeService.getTheme(), defaultListStyles),
|
||||
...workbenchListOptions,
|
||||
indent: configurationService.getValue(treeIndentKey),
|
||||
automaticKeyboardNavigation: getAutomaticKeyboardNavigation(),
|
||||
simpleKeyboardNavigation: keyboardNavigation === 'simple',
|
||||
filterOnType: keyboardNavigation === 'filter',
|
||||
horizontalScrolling,
|
||||
openOnSingleClick,
|
||||
keyboardNavigationEventFilter: createKeyboardNavigationEventFilter(container, keybindingService)
|
||||
});
|
||||
|
||||
this.disposables.push(workbenchListOptionsDisposable);
|
||||
|
||||
this.contextKeyService = createScopedContextKeyService(contextKeyService, this);
|
||||
|
||||
const listSupportsMultiSelect = WorkbenchListSupportsMultiSelectContextKey.bindTo(this.contextKeyService);
|
||||
listSupportsMultiSelect.set(!(options.multipleSelectionSupport === false));
|
||||
|
||||
this.hasSelectionOrFocus = WorkbenchListHasSelectionOrFocus.bindTo(this.contextKeyService);
|
||||
this.hasDoubleSelection = WorkbenchListDoubleSelection.bindTo(this.contextKeyService);
|
||||
this.hasMultiSelection = WorkbenchListMultiSelection.bindTo(this.contextKeyService);
|
||||
|
||||
this._useAltAsMultipleSelectionModifier = useAltAsMultipleSelectionModifier(configurationService);
|
||||
|
||||
const interestingContextKeys = new Set();
|
||||
interestingContextKeys.add(WorkbenchListAutomaticKeyboardNavigationKey);
|
||||
const updateKeyboardNavigation = () => {
|
||||
const accessibilityOn = accessibilityService.getAccessibilitySupport() === AccessibilitySupport.Enabled;
|
||||
const keyboardNavigation = accessibilityOn ? 'simple' : configurationService.getValue<string>(keyboardNavigationSettingKey);
|
||||
this.updateOptions({
|
||||
simpleKeyboardNavigation: keyboardNavigation === 'simple',
|
||||
filterOnType: keyboardNavigation === 'filter'
|
||||
});
|
||||
};
|
||||
|
||||
this.disposables.push(
|
||||
this.contextKeyService,
|
||||
(listService as ListService).register(this),
|
||||
attachListStyler(this, themeService),
|
||||
this.onDidChangeSelection(() => {
|
||||
const selection = this.getSelection();
|
||||
const focus = this.getFocus();
|
||||
|
||||
this.hasSelectionOrFocus.set(selection.length > 0 || focus.length > 0);
|
||||
this.hasMultiSelection.set(selection.length > 1);
|
||||
this.hasDoubleSelection.set(selection.length === 2);
|
||||
}),
|
||||
this.onDidChangeFocus(() => {
|
||||
const selection = this.getSelection();
|
||||
const focus = this.getFocus();
|
||||
|
||||
this.hasSelectionOrFocus.set(selection.length > 0 || focus.length > 0);
|
||||
}),
|
||||
configurationService.onDidChangeConfiguration(e => {
|
||||
if (e.affectsConfiguration(openModeSettingKey)) {
|
||||
this.updateOptions({ openOnSingleClick: useSingleClickToOpen(configurationService) });
|
||||
}
|
||||
if (e.affectsConfiguration(multiSelectModifierSettingKey)) {
|
||||
this._useAltAsMultipleSelectionModifier = useAltAsMultipleSelectionModifier(configurationService);
|
||||
}
|
||||
if (e.affectsConfiguration(treeIndentKey)) {
|
||||
const indent = configurationService.getValue<number>(treeIndentKey);
|
||||
this.updateOptions({ indent });
|
||||
}
|
||||
if (e.affectsConfiguration(keyboardNavigationSettingKey)) {
|
||||
updateKeyboardNavigation();
|
||||
}
|
||||
if (e.affectsConfiguration(automaticKeyboardNavigationSettingKey)) {
|
||||
this.updateOptions({ automaticKeyboardNavigation: getAutomaticKeyboardNavigation() });
|
||||
}
|
||||
}),
|
||||
this.contextKeyService.onDidChangeContext(e => {
|
||||
if (e.affectsSome(interestingContextKeys)) {
|
||||
this.updateOptions({ automaticKeyboardNavigation: getAutomaticKeyboardNavigation() });
|
||||
}
|
||||
}),
|
||||
accessibilityService.onDidChangeAccessibilitySupport(() => updateKeyboardNavigation())
|
||||
);
|
||||
}
|
||||
|
||||
get useAltAsMultipleSelectionModifier(): boolean {
|
||||
return this._useAltAsMultipleSelectionModifier;
|
||||
const { options: treeOptions, getAutomaticKeyboardNavigation, disposable } = workbenchTreeDataPreamble(container, options, contextKeyService, themeService, configurationService, keybindingService, accessibilityService);
|
||||
super(container, delegate, renderers, dataSource, treeOptions);
|
||||
this.disposables.push(disposable);
|
||||
this.internals = new WorkbenchTreeInternals(this, treeOptions, getAutomaticKeyboardNavigation, contextKeyService, listService, themeService, configurationService, accessibilityService);
|
||||
this.disposables.push(this.internals);
|
||||
}
|
||||
}
|
||||
|
||||
export class WorkbenchAsyncDataTree<TInput, T, TFilterData = void> extends AsyncDataTree<TInput, T, TFilterData> {
|
||||
|
||||
readonly contextKeyService: IContextKeyService;
|
||||
|
||||
private hasSelectionOrFocus: IContextKey<boolean>;
|
||||
private hasDoubleSelection: IContextKey<boolean>;
|
||||
private hasMultiSelection: IContextKey<boolean>;
|
||||
|
||||
private _useAltAsMultipleSelectionModifier: boolean;
|
||||
private internals: WorkbenchTreeInternals<TInput, T, TFilterData>;
|
||||
get contextKeyService(): IContextKeyService { return this.internals.contextKeyService; }
|
||||
get useAltAsMultipleSelectionModifier(): boolean { return this.internals.useAltAsMultipleSelectionModifier; }
|
||||
|
||||
constructor(
|
||||
container: HTMLElement,
|
||||
@@ -1063,31 +850,51 @@ export class WorkbenchAsyncDataTree<TInput, T, TFilterData = void> extends Async
|
||||
@IKeybindingService keybindingService: IKeybindingService,
|
||||
@IAccessibilityService accessibilityService: IAccessibilityService
|
||||
) {
|
||||
WorkbenchListSupportsKeyboardNavigation.bindTo(contextKeyService);
|
||||
const { options: treeOptions, getAutomaticKeyboardNavigation, disposable } = workbenchTreeDataPreamble(container, options, contextKeyService, themeService, configurationService, keybindingService, accessibilityService);
|
||||
super(container, delegate, renderers, dataSource, treeOptions);
|
||||
this.disposables.push(disposable);
|
||||
this.internals = new WorkbenchTreeInternals(this, treeOptions, getAutomaticKeyboardNavigation, contextKeyService, listService, themeService, configurationService, accessibilityService);
|
||||
this.disposables.push(this.internals);
|
||||
}
|
||||
}
|
||||
|
||||
if (!didBindWorkbenchListAutomaticKeyboardNavigation) {
|
||||
WorkbenchListAutomaticKeyboardNavigation.bindTo(contextKeyService);
|
||||
didBindWorkbenchListAutomaticKeyboardNavigation = true;
|
||||
function workbenchTreeDataPreamble<T, TFilterData>(
|
||||
container: HTMLElement,
|
||||
options: IAbstractTreeOptions<T, TFilterData>,
|
||||
contextKeyService: IContextKeyService,
|
||||
themeService: IThemeService,
|
||||
configurationService: IConfigurationService,
|
||||
keybindingService: IKeybindingService,
|
||||
accessibilityService: IAccessibilityService,
|
||||
): { options: IAbstractTreeOptions<T, TFilterData>, getAutomaticKeyboardNavigation: () => boolean | undefined, disposable: IDisposable } {
|
||||
WorkbenchListSupportsKeyboardNavigation.bindTo(contextKeyService);
|
||||
|
||||
if (!didBindWorkbenchListAutomaticKeyboardNavigation) {
|
||||
WorkbenchListAutomaticKeyboardNavigation.bindTo(contextKeyService);
|
||||
didBindWorkbenchListAutomaticKeyboardNavigation = true;
|
||||
}
|
||||
|
||||
const getAutomaticKeyboardNavigation = () => {
|
||||
// give priority to the context key value to disable this completely
|
||||
let automaticKeyboardNavigation = contextKeyService.getContextKeyValue<boolean>(WorkbenchListAutomaticKeyboardNavigationKey);
|
||||
|
||||
if (automaticKeyboardNavigation) {
|
||||
automaticKeyboardNavigation = configurationService.getValue<boolean>(automaticKeyboardNavigationSettingKey);
|
||||
}
|
||||
|
||||
const getAutomaticKeyboardNavigation = () => {
|
||||
// give priority to the context key value to disable this completely
|
||||
let automaticKeyboardNavigation = contextKeyService.getContextKeyValue<boolean>(WorkbenchListAutomaticKeyboardNavigationKey);
|
||||
return automaticKeyboardNavigation;
|
||||
};
|
||||
|
||||
if (automaticKeyboardNavigation) {
|
||||
automaticKeyboardNavigation = configurationService.getValue<boolean>(automaticKeyboardNavigationSettingKey);
|
||||
}
|
||||
const accessibilityOn = accessibilityService.getAccessibilitySupport() === AccessibilitySupport.Enabled;
|
||||
const keyboardNavigation = accessibilityOn ? 'simple' : configurationService.getValue<string>(keyboardNavigationSettingKey);
|
||||
const horizontalScrolling = typeof options.horizontalScrolling !== 'undefined' ? options.horizontalScrolling : getHorizontalScrollingSetting(configurationService);
|
||||
const openOnSingleClick = useSingleClickToOpen(configurationService);
|
||||
const [workbenchListOptions, disposable] = toWorkbenchListOptions(options, configurationService, keybindingService);
|
||||
|
||||
return automaticKeyboardNavigation;
|
||||
};
|
||||
|
||||
const accessibilityOn = accessibilityService.getAccessibilitySupport() === AccessibilitySupport.Enabled;
|
||||
const keyboardNavigation = accessibilityOn ? 'simple' : configurationService.getValue<string>(keyboardNavigationSettingKey);
|
||||
const horizontalScrolling = typeof options.horizontalScrolling !== 'undefined' ? options.horizontalScrolling : getHorizontalScrollingSetting(configurationService);
|
||||
const openOnSingleClick = useSingleClickToOpen(configurationService);
|
||||
const [workbenchListOptions, workbenchListOptionsDisposable] = toWorkbenchListOptions(options, configurationService, keybindingService);
|
||||
|
||||
super(container, delegate, renderers, dataSource, {
|
||||
return {
|
||||
getAutomaticKeyboardNavigation,
|
||||
disposable,
|
||||
options: {
|
||||
keyboardSupport: false,
|
||||
styleController: new DefaultStyleController(getSharedListStyleSheet()),
|
||||
...computeStyles(themeService.getTheme(), defaultListStyles),
|
||||
@@ -1099,11 +906,30 @@ export class WorkbenchAsyncDataTree<TInput, T, TFilterData = void> extends Async
|
||||
horizontalScrolling,
|
||||
openOnSingleClick,
|
||||
keyboardNavigationEventFilter: createKeyboardNavigationEventFilter(container, keybindingService)
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
this.disposables.push(workbenchListOptionsDisposable);
|
||||
class WorkbenchTreeInternals<TInput, T, TFilterData> {
|
||||
|
||||
this.contextKeyService = createScopedContextKeyService(contextKeyService, this);
|
||||
readonly contextKeyService: IContextKeyService;
|
||||
private hasSelectionOrFocus: IContextKey<boolean>;
|
||||
private hasDoubleSelection: IContextKey<boolean>;
|
||||
private hasMultiSelection: IContextKey<boolean>;
|
||||
private _useAltAsMultipleSelectionModifier: boolean;
|
||||
private disposables: IDisposable[] = [];
|
||||
|
||||
constructor(
|
||||
tree: WorkbenchObjectTree<T, TFilterData> | WorkbenchDataTree<TInput, T, TFilterData> | WorkbenchAsyncDataTree<TInput, T, TFilterData>,
|
||||
options: IAbstractTreeOptions<T, TFilterData>,
|
||||
getAutomaticKeyboardNavigation: () => boolean | undefined,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IListService listService: IListService,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IConfigurationService configurationService: IConfigurationService,
|
||||
@IAccessibilityService accessibilityService: IAccessibilityService,
|
||||
) {
|
||||
this.contextKeyService = createScopedContextKeyService(contextKeyService, tree);
|
||||
|
||||
const listSupportsMultiSelect = WorkbenchListSupportsMultiSelectContextKey.bindTo(this.contextKeyService);
|
||||
listSupportsMultiSelect.set(!(options.multipleSelectionSupport === false));
|
||||
@@ -1119,7 +945,7 @@ export class WorkbenchAsyncDataTree<TInput, T, TFilterData = void> extends Async
|
||||
const updateKeyboardNavigation = () => {
|
||||
const accessibilityOn = accessibilityService.getAccessibilitySupport() === AccessibilitySupport.Enabled;
|
||||
const keyboardNavigation = accessibilityOn ? 'simple' : configurationService.getValue<string>(keyboardNavigationSettingKey);
|
||||
this.updateOptions({
|
||||
tree.updateOptions({
|
||||
simpleKeyboardNavigation: keyboardNavigation === 'simple',
|
||||
filterOnType: keyboardNavigation === 'filter'
|
||||
});
|
||||
@@ -1127,43 +953,43 @@ export class WorkbenchAsyncDataTree<TInput, T, TFilterData = void> extends Async
|
||||
|
||||
this.disposables.push(
|
||||
this.contextKeyService,
|
||||
(listService as ListService).register(this),
|
||||
attachListStyler(this, themeService),
|
||||
this.onDidChangeSelection(() => {
|
||||
const selection = this.getSelection();
|
||||
const focus = this.getFocus();
|
||||
(listService as ListService).register(tree),
|
||||
attachListStyler(tree, themeService),
|
||||
tree.onDidChangeSelection(() => {
|
||||
const selection = tree.getSelection();
|
||||
const focus = tree.getFocus();
|
||||
|
||||
this.hasSelectionOrFocus.set(selection.length > 0 || focus.length > 0);
|
||||
this.hasMultiSelection.set(selection.length > 1);
|
||||
this.hasDoubleSelection.set(selection.length === 2);
|
||||
}),
|
||||
this.onDidChangeFocus(() => {
|
||||
const selection = this.getSelection();
|
||||
const focus = this.getFocus();
|
||||
tree.onDidChangeFocus(() => {
|
||||
const selection = tree.getSelection();
|
||||
const focus = tree.getFocus();
|
||||
|
||||
this.hasSelectionOrFocus.set(selection.length > 0 || focus.length > 0);
|
||||
}),
|
||||
configurationService.onDidChangeConfiguration(e => {
|
||||
if (e.affectsConfiguration(openModeSettingKey)) {
|
||||
this.updateOptions({ openOnSingleClick: useSingleClickToOpen(configurationService) });
|
||||
tree.updateOptions({ openOnSingleClick: useSingleClickToOpen(configurationService) });
|
||||
}
|
||||
if (e.affectsConfiguration(multiSelectModifierSettingKey)) {
|
||||
this._useAltAsMultipleSelectionModifier = useAltAsMultipleSelectionModifier(configurationService);
|
||||
}
|
||||
if (e.affectsConfiguration(treeIndentKey)) {
|
||||
const indent = configurationService.getValue<number>(treeIndentKey);
|
||||
this.updateOptions({ indent });
|
||||
tree.updateOptions({ indent });
|
||||
}
|
||||
if (e.affectsConfiguration(keyboardNavigationSettingKey)) {
|
||||
updateKeyboardNavigation();
|
||||
}
|
||||
if (e.affectsConfiguration(automaticKeyboardNavigationSettingKey)) {
|
||||
this.updateOptions({ automaticKeyboardNavigation: getAutomaticKeyboardNavigation() });
|
||||
tree.updateOptions({ automaticKeyboardNavigation: getAutomaticKeyboardNavigation() });
|
||||
}
|
||||
}),
|
||||
this.contextKeyService.onDidChangeContext(e => {
|
||||
if (e.affectsSome(interestingContextKeys)) {
|
||||
this.updateOptions({ automaticKeyboardNavigation: getAutomaticKeyboardNavigation() });
|
||||
tree.updateOptions({ automaticKeyboardNavigation: getAutomaticKeyboardNavigation() });
|
||||
}
|
||||
}),
|
||||
accessibilityService.onDidChangeAccessibilitySupport(() => updateKeyboardNavigation())
|
||||
@@ -1173,6 +999,10 @@ export class WorkbenchAsyncDataTree<TInput, T, TFilterData = void> extends Async
|
||||
get useAltAsMultipleSelectionModifier(): boolean {
|
||||
return this._useAltAsMultipleSelectionModifier;
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.disposables = dispose(this.disposables);
|
||||
}
|
||||
}
|
||||
|
||||
const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);
|
||||
|
||||
@@ -11,7 +11,7 @@ export interface IRemoteAgentEnvironment {
|
||||
pid: number;
|
||||
appRoot: URI;
|
||||
appSettingsHome: URI;
|
||||
appSettingsPath: URI;
|
||||
settingsPath: URI;
|
||||
logsPath: URI;
|
||||
extensionsPath: URI;
|
||||
extensionHostLogsPath: URI;
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
|
||||
export const REMOTE_HOST_SCHEME = 'vscode-remote';
|
||||
export const REMOTE_HOST_SCHEME = Schemas.vscodeRemote;
|
||||
|
||||
export function getRemoteAuthority(uri: URI): string | undefined {
|
||||
return uri.scheme === REMOTE_HOST_SCHEME ? uri.authority : undefined;
|
||||
|
||||
21
src/vs/platform/remote/common/tunnel.ts
Normal file
21
src/vs/platform/remote/common/tunnel.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
|
||||
export const ITunnelService = createDecorator<ITunnelService>('tunnelService');
|
||||
|
||||
export interface RemoteTunnel {
|
||||
readonly tunnelRemotePort: number;
|
||||
readonly tunnelLocalPort: number;
|
||||
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export interface ITunnelService {
|
||||
_serviceBrand: any;
|
||||
|
||||
openTunnel(remotePort: number): Promise<RemoteTunnel> | undefined;
|
||||
}
|
||||
@@ -3,10 +3,42 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as net from 'net';
|
||||
import { NodeSocket } from 'vs/base/parts/ipc/node/ipc.net';
|
||||
import { IWebSocketFactory, IConnectCallback } from 'vs/platform/remote/common/remoteAgentConnection';
|
||||
|
||||
export const nodeWebSocketFactory = new class implements IWebSocketFactory {
|
||||
connect(host: string, port: number, query: string, callback: IConnectCallback): void {
|
||||
throw new Error(`Not implemented`);
|
||||
const errorListener = (err: any) => callback(err, undefined);
|
||||
|
||||
const socket = net.createConnection({ host: host, port: port }, () => {
|
||||
socket.removeListener('error', errorListener);
|
||||
|
||||
// https://tools.ietf.org/html/rfc6455#section-4
|
||||
const buffer = Buffer.alloc(16);
|
||||
for (let i = 0; i < 16; i++) {
|
||||
buffer[i] = Math.round(Math.random() * 256);
|
||||
}
|
||||
const nonce = buffer.toString('base64');
|
||||
|
||||
let headers = [
|
||||
`GET ws://${host}:${port}/?${query}&skipWebSocketFrames=true HTTP/1.1`,
|
||||
`Connection: Upgrade`,
|
||||
`Upgrade: websocket`,
|
||||
`Sec-WebSocket-Key: ${nonce}`
|
||||
];
|
||||
socket.write(headers.join('\r\n') + '\r\n\r\n');
|
||||
|
||||
const onData = (data: Buffer) => {
|
||||
const strData = data.toString();
|
||||
if (strData.indexOf('\r\n\r\n') >= 0) {
|
||||
// headers received OK
|
||||
socket.off('data', onData);
|
||||
callback(undefined, new NodeSocket(socket));
|
||||
}
|
||||
};
|
||||
socket.on('data', onData);
|
||||
});
|
||||
socket.once('error', errorListener);
|
||||
}
|
||||
};
|
||||
|
||||
21
src/vs/platform/remote/node/tunnelService.ts
Normal file
21
src/vs/platform/remote/node/tunnelService.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ITunnelService, RemoteTunnel } from 'vs/platform/remote/common/tunnel';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
|
||||
export class TunnelService implements ITunnelService {
|
||||
_serviceBrand: any;
|
||||
|
||||
public constructor(
|
||||
) {
|
||||
}
|
||||
|
||||
openTunnel(remotePort: number): Promise<RemoteTunnel> | undefined {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
registerSingleton(ITunnelService, TunnelService);
|
||||
@@ -67,13 +67,21 @@ export interface IStatusbarService {
|
||||
_serviceBrand: any;
|
||||
|
||||
/**
|
||||
* Adds an entry to the statusbar with the given alignment and priority. Use the returned IDisposable
|
||||
* to remove the statusbar entry.
|
||||
* Adds an entry to the statusbar with the given alignment and priority. Use the returned accessor
|
||||
* to update or remove the statusbar entry.
|
||||
*/
|
||||
addEntry(entry: IStatusbarEntry, alignment: StatusbarAlignment, priority?: number): IDisposable;
|
||||
addEntry(entry: IStatusbarEntry, alignment: StatusbarAlignment, priority?: number): IStatusbarEntryAccessor;
|
||||
|
||||
/**
|
||||
* Prints something to the status bar area with optional auto dispose and delay.
|
||||
*/
|
||||
setStatusMessage(message: string, autoDisposeAfter?: number, delayBy?: number): IDisposable;
|
||||
}
|
||||
|
||||
export interface IStatusbarEntryAccessor extends IDisposable {
|
||||
|
||||
/**
|
||||
* Allows to update an existing status bar entry.
|
||||
*/
|
||||
update(properties: IStatusbarEntry): void;
|
||||
}
|
||||
@@ -1,62 +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 { ITelemetryService, ITelemetryInfo, ITelemetryData } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { NullTelemetryService, combinedAppender, LogAppender } from 'vs/platform/telemetry/common/telemetryUtils';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { IProductService } from 'vs/platform/product/common/product';
|
||||
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';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { IWindowService } from 'vs/platform/windows/common/windows';
|
||||
import { resolveWorkbenchCommonProperties } from 'vs/platform/telemetry/node/workbenchCommonProperties';
|
||||
import { TelemetryService as BaseTelemetryService, ITelemetryServiceConfig } from 'vs/platform/telemetry/common/telemetryService';
|
||||
|
||||
export class TelemetryService extends Disposable implements ITelemetryService {
|
||||
|
||||
_serviceBrand: any;
|
||||
|
||||
private impl: ITelemetryService;
|
||||
|
||||
constructor(
|
||||
@IEnvironmentService environmentService: IEnvironmentService,
|
||||
@IProductService productService: IProductService,
|
||||
@ISharedProcessService sharedProcessService: ISharedProcessService,
|
||||
@ILogService logService: ILogService,
|
||||
@IStorageService storageService: IStorageService,
|
||||
@IConfigurationService configurationService: IConfigurationService,
|
||||
@IWindowService windowService: IWindowService
|
||||
) {
|
||||
super();
|
||||
|
||||
if (!environmentService.isExtensionDevelopment && !environmentService.args['disable-telemetry'] && !!productService.enableTelemetry) {
|
||||
const channel = sharedProcessService.getChannel('telemetryAppender');
|
||||
const config: ITelemetryServiceConfig = {
|
||||
appender: combinedAppender(new TelemetryAppenderClient(channel), new LogAppender(logService)),
|
||||
commonProperties: resolveWorkbenchCommonProperties(storageService, productService.commit, productService.version, windowService.getConfiguration().machineId, environmentService.installSourcePath),
|
||||
piiPaths: [environmentService.appRoot, environmentService.extensionsPath]
|
||||
};
|
||||
|
||||
this.impl = this._register(new BaseTelemetryService(config, configurationService));
|
||||
} else {
|
||||
this.impl = NullTelemetryService;
|
||||
}
|
||||
}
|
||||
|
||||
get isOptedIn(): boolean {
|
||||
return this.impl.isOptedIn;
|
||||
}
|
||||
|
||||
publicLog(eventName: string, data?: ITelemetryData, anonymizeFilePaths?: boolean): Promise<void> {
|
||||
return this.impl.publicLog(eventName, data, anonymizeFilePaths);
|
||||
}
|
||||
|
||||
getTelemetryInfo(): Promise<ITelemetryInfo> {
|
||||
return this.impl.getTelemetryInfo();
|
||||
}
|
||||
}
|
||||
@@ -226,8 +226,8 @@ export interface IWindowService {
|
||||
|
||||
readonly hasFocus: boolean;
|
||||
|
||||
getConfiguration(): IWindowConfiguration;
|
||||
getCurrentWindowId(): number;
|
||||
readonly windowId: number;
|
||||
|
||||
pickFileFolderAndOpen(options: INativeOpenDialogOptions): Promise<void>;
|
||||
pickFileAndOpen(options: INativeOpenDialogOptions): Promise<void>;
|
||||
pickFolderAndOpen(options: INativeOpenDialogOptions): Promise<void>;
|
||||
@@ -459,7 +459,7 @@ export class ActiveWindowManager implements IDisposable {
|
||||
|
||||
this.firstActiveWindowIdPromise = createCancelablePromise(_ => windowsService.getActiveWindowId());
|
||||
this.firstActiveWindowIdPromise
|
||||
.then(id => this.activeWindowId = id)
|
||||
.then(id => this.activeWindowId = typeof this.activeWindowId === 'number' ? this.activeWindowId : id)
|
||||
.finally(this.firstActiveWindowIdPromise = undefined);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,185 +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 { Event } from 'vs/base/common/event';
|
||||
import { IWindowService, IWindowsService, INativeOpenDialogOptions, IEnterWorkspaceResult, IMessageBoxResult, IWindowConfiguration, IDevToolsOptions, IOpenSettings, IURIToOpen, isFolderToOpen, isWorkspaceToOpen } from 'vs/platform/windows/common/windows';
|
||||
import { IRecentlyOpened } from 'vs/platform/history/common/history';
|
||||
import { ISerializableCommandAction } from 'vs/platform/actions/common/actions';
|
||||
import { ParsedArgs } from 'vs/platform/environment/common/environment';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
|
||||
export class WindowService extends Disposable implements IWindowService {
|
||||
|
||||
readonly onDidChangeFocus: Event<boolean>;
|
||||
readonly onDidChangeMaximize: Event<boolean>;
|
||||
|
||||
_serviceBrand: any;
|
||||
|
||||
private windowId: number;
|
||||
|
||||
private _hasFocus: boolean;
|
||||
get hasFocus(): boolean { return this._hasFocus; }
|
||||
|
||||
constructor(
|
||||
private configuration: IWindowConfiguration,
|
||||
@IWindowsService private readonly windowsService: IWindowsService,
|
||||
@ILabelService private readonly labelService: ILabelService
|
||||
) {
|
||||
super();
|
||||
|
||||
this.windowId = configuration.windowId;
|
||||
|
||||
const onThisWindowFocus = Event.map(Event.filter(windowsService.onWindowFocus, id => id === this.windowId), _ => true);
|
||||
const onThisWindowBlur = Event.map(Event.filter(windowsService.onWindowBlur, id => id === this.windowId), _ => false);
|
||||
const onThisWindowMaximize = Event.map(Event.filter(windowsService.onWindowMaximize, id => id === this.windowId), _ => true);
|
||||
const onThisWindowUnmaximize = Event.map(Event.filter(windowsService.onWindowUnmaximize, id => id === this.windowId), _ => false);
|
||||
this.onDidChangeFocus = Event.any(onThisWindowFocus, onThisWindowBlur);
|
||||
this.onDidChangeMaximize = Event.any(onThisWindowMaximize, onThisWindowUnmaximize);
|
||||
|
||||
this._hasFocus = document.hasFocus();
|
||||
this.isFocused().then(focused => this._hasFocus = focused);
|
||||
this._register(this.onDidChangeFocus(focus => this._hasFocus = focus));
|
||||
}
|
||||
|
||||
getCurrentWindowId(): number {
|
||||
return this.windowId;
|
||||
}
|
||||
|
||||
getConfiguration(): IWindowConfiguration {
|
||||
return this.configuration;
|
||||
}
|
||||
|
||||
pickFileFolderAndOpen(options: INativeOpenDialogOptions): Promise<void> {
|
||||
options.windowId = this.windowId;
|
||||
|
||||
return this.windowsService.pickFileFolderAndOpen(options);
|
||||
}
|
||||
|
||||
pickFileAndOpen(options: INativeOpenDialogOptions): Promise<void> {
|
||||
options.windowId = this.windowId;
|
||||
|
||||
return this.windowsService.pickFileAndOpen(options);
|
||||
}
|
||||
|
||||
pickFolderAndOpen(options: INativeOpenDialogOptions): Promise<void> {
|
||||
options.windowId = this.windowId;
|
||||
|
||||
return this.windowsService.pickFolderAndOpen(options);
|
||||
}
|
||||
|
||||
pickWorkspaceAndOpen(options: INativeOpenDialogOptions): Promise<void> {
|
||||
options.windowId = this.windowId;
|
||||
|
||||
return this.windowsService.pickWorkspaceAndOpen(options);
|
||||
}
|
||||
|
||||
reloadWindow(args?: ParsedArgs): Promise<void> {
|
||||
return this.windowsService.reloadWindow(this.windowId, args);
|
||||
}
|
||||
|
||||
openDevTools(options?: IDevToolsOptions): Promise<void> {
|
||||
return this.windowsService.openDevTools(this.windowId, options);
|
||||
}
|
||||
|
||||
toggleDevTools(): Promise<void> {
|
||||
return this.windowsService.toggleDevTools(this.windowId);
|
||||
}
|
||||
|
||||
closeWorkspace(): Promise<void> {
|
||||
return this.windowsService.closeWorkspace(this.windowId);
|
||||
}
|
||||
|
||||
enterWorkspace(path: URI): Promise<IEnterWorkspaceResult | undefined> {
|
||||
return this.windowsService.enterWorkspace(this.windowId, path);
|
||||
}
|
||||
|
||||
openWindow(uris: IURIToOpen[], options: IOpenSettings = {}): Promise<void> {
|
||||
if (!!this.configuration.remoteAuthority) {
|
||||
uris.forEach(u => u.label = u.label || this.getRecentLabel(u));
|
||||
}
|
||||
return this.windowsService.openWindow(this.windowId, uris, options);
|
||||
}
|
||||
|
||||
closeWindow(): Promise<void> {
|
||||
return this.windowsService.closeWindow(this.windowId);
|
||||
}
|
||||
|
||||
toggleFullScreen(): Promise<void> {
|
||||
return this.windowsService.toggleFullScreen(this.windowId);
|
||||
}
|
||||
|
||||
setRepresentedFilename(fileName: string): Promise<void> {
|
||||
return this.windowsService.setRepresentedFilename(this.windowId, fileName);
|
||||
}
|
||||
|
||||
getRecentlyOpened(): Promise<IRecentlyOpened> {
|
||||
return this.windowsService.getRecentlyOpened(this.windowId);
|
||||
}
|
||||
|
||||
focusWindow(): Promise<void> {
|
||||
return this.windowsService.focusWindow(this.windowId);
|
||||
}
|
||||
|
||||
isFocused(): Promise<boolean> {
|
||||
return this.windowsService.isFocused(this.windowId);
|
||||
}
|
||||
|
||||
isMaximized(): Promise<boolean> {
|
||||
return this.windowsService.isMaximized(this.windowId);
|
||||
}
|
||||
|
||||
maximizeWindow(): Promise<void> {
|
||||
return this.windowsService.maximizeWindow(this.windowId);
|
||||
}
|
||||
|
||||
unmaximizeWindow(): Promise<void> {
|
||||
return this.windowsService.unmaximizeWindow(this.windowId);
|
||||
}
|
||||
|
||||
minimizeWindow(): Promise<void> {
|
||||
return this.windowsService.minimizeWindow(this.windowId);
|
||||
}
|
||||
|
||||
onWindowTitleDoubleClick(): Promise<void> {
|
||||
return this.windowsService.onWindowTitleDoubleClick(this.windowId);
|
||||
}
|
||||
|
||||
setDocumentEdited(flag: boolean): Promise<void> {
|
||||
return this.windowsService.setDocumentEdited(this.windowId, flag);
|
||||
}
|
||||
|
||||
showMessageBox(options: Electron.MessageBoxOptions): Promise<IMessageBoxResult> {
|
||||
return this.windowsService.showMessageBox(this.windowId, options);
|
||||
}
|
||||
|
||||
showSaveDialog(options: Electron.SaveDialogOptions): Promise<string> {
|
||||
return this.windowsService.showSaveDialog(this.windowId, options);
|
||||
}
|
||||
|
||||
showOpenDialog(options: Electron.OpenDialogOptions): Promise<string[]> {
|
||||
return this.windowsService.showOpenDialog(this.windowId, options);
|
||||
}
|
||||
|
||||
updateTouchBar(items: ISerializableCommandAction[][]): Promise<void> {
|
||||
return this.windowsService.updateTouchBar(this.windowId, items);
|
||||
}
|
||||
|
||||
resolveProxy(url: string): Promise<string | undefined> {
|
||||
return this.windowsService.resolveProxy(this.windowId, url);
|
||||
}
|
||||
|
||||
private getRecentLabel(u: IURIToOpen): string {
|
||||
if (isFolderToOpen(u)) {
|
||||
return this.labelService.getWorkspaceLabel(u.folderUri, { verbose: true });
|
||||
} else if (isWorkspaceToOpen(u)) {
|
||||
return this.labelService.getWorkspaceLabel({ id: '', configPath: u.workspaceUri }, { verbose: true });
|
||||
} else {
|
||||
return this.labelService.getUriLabel(u.fileUri);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user