Merge from vscode 2b0b9136329c181a9e381463a1f7dc3a2d105a34 (#4880)

This commit is contained in:
Karl Burtram
2019-04-05 10:09:18 -07:00
committed by GitHub
parent 9bd7e30d18
commit cb5bcf2248
433 changed files with 8915 additions and 8361 deletions

View File

@@ -7,7 +7,7 @@ import { Emitter, Event } from 'vs/base/common/event';
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
import { IMenu, IMenuActionOptions, IMenuItem, IMenuService, isIMenuItem, ISubmenuItem, MenuId, MenuItemAction, MenuRegistry, SubmenuItemAction } from 'vs/platform/actions/common/actions';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { ContextKeyExpr, IContextKeyService, IContextKeyChangeEvent } from 'vs/platform/contextkey/common/contextkey';
export class MenuService implements IMenuService {
@@ -52,7 +52,7 @@ class Menu implements IMenu {
// when context keys change we need to check if the menu also
// has changed
Event.debounce(
Event.debounce<IContextKeyChangeEvent, boolean>(
this._contextKeyService.onDidChangeContext,
(last, event) => last || event.affectsSome(this._contextKeys),
50

View File

@@ -7,7 +7,7 @@ import * as fs from 'fs';
import * as crypto from 'crypto';
import * as path from 'vs/base/common/path';
import * as platform from 'vs/base/common/platform';
import { writeFileAndFlushSync } from 'vs/base/node/extfs';
import { writeFileSync, writeFile, readFile, readdir, exists, rimraf, rename, RimRafMode } from 'vs/base/node/pfs';
import * as arrays from 'vs/base/common/arrays';
import { IBackupMainService, IBackupWorkspacesFormat, IEmptyWindowBackupInfo, IWorkspaceBackupInfo } from 'vs/platform/backup/common/backup';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
@@ -19,7 +19,6 @@ import { URI } from 'vs/base/common/uri';
import { isEqual as areResourcesEquals, getComparisonKey, hasToIgnoreCase } from 'vs/base/common/resources';
import { isEqual } from 'vs/base/common/extpath';
import { Schemas } from 'vs/base/common/network';
import { writeFile, readFile, readdir, exists, del, rename } from 'vs/base/node/pfs';
export class BackupMainService implements IBackupMainService {
@@ -343,7 +342,7 @@ export class BackupMainService implements IBackupMainService {
private async deleteStaleBackup(backupPath: string): Promise<void> {
try {
if (await exists(backupPath)) {
await del(backupPath);
await rimraf(backupPath, RimRafMode.MOVE);
}
} catch (ex) {
this.logService.error(`Backup: Could not delete stale backup: ${ex.toString()}`);
@@ -415,7 +414,7 @@ export class BackupMainService implements IBackupMainService {
private saveSync(): void {
try {
writeFileAndFlushSync(this.workspacesJsonPath, JSON.stringify(this.serializeBackups()));
writeFileSync(this.workspacesJsonPath, JSON.stringify(this.serializeBackups()));
} catch (ex) {
this.logService.error(`Backup: Could not save workspaces.json: ${ex.toString()}`);
}
@@ -435,7 +434,7 @@ export class BackupMainService implements IBackupMainService {
folderURIWorkspaces: this.folderWorkspaces.map(f => f.toString()),
emptyWorkspaceInfos: this.emptyWorkspaces,
emptyWorkspaces: this.emptyWorkspaces.map(info => info.backupFolder)
} as IBackupWorkspacesFormat;
};
}
private getRandomEmptyWindowId(): string {

View File

@@ -121,7 +121,7 @@ suite('BackupMainService', () => {
setup(() => {
// Delete any existing backups completely and then re-create it.
return pfs.del(backupHome, os.tmpdir()).then(() => {
return pfs.rimraf(backupHome, pfs.RimRafMode.MOVE).then(() => {
return pfs.mkdirp(backupHome);
}).then(() => {
configService = new TestConfigurationService();
@@ -132,7 +132,7 @@ suite('BackupMainService', () => {
});
teardown(() => {
return pfs.del(backupHome, os.tmpdir());
return pfs.rimraf(backupHome, pfs.RimRafMode.MOVE);
});
test('service validates backup workspaces on startup and cleans up (folder workspaces)', async function () {

View File

@@ -3,15 +3,11 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Disposable, toDisposable } from 'vs/base/common/lifecycle';
import { Disposable } from 'vs/base/common/lifecycle';
import { onUnexpectedError } from 'vs/base/common/errors';
import { ConfigurationModelParser, ConfigurationModel } from 'vs/platform/configuration/common/configurationModels';
import { ConfigWatcher } from 'vs/base/node/config';
import { Event, Emitter } from 'vs/base/common/event';
import { RunOnceScheduler } from 'vs/base/common/async';
import { URI } from 'vs/base/common/uri';
import { IFileService, FileChangesEvent } from 'vs/platform/files/common/files';
import * as resources from 'vs/base/common/resources';
export class NodeBasedUserConfiguration extends Disposable {
@@ -54,53 +50,7 @@ export class NodeBasedUserConfiguration extends Disposable {
return this.initialize().then(() => new Promise<ConfigurationModel>(c => this.userConfigModelWatcher.reload(userConfigModelParser => c(userConfigModelParser.configurationModel))));
}
}
export class FileServiceBasedUserConfiguration extends Disposable {
private readonly reloadConfigurationScheduler: RunOnceScheduler;
protected readonly _onDidChangeConfiguration: Emitter<ConfigurationModel> = this._register(new Emitter<ConfigurationModel>());
readonly onDidChangeConfiguration: Event<ConfigurationModel> = this._onDidChangeConfiguration.event;
constructor(
private readonly configurationResource: URI,
private readonly fileService: IFileService
) {
super();
this._register(fileService.onFileChanges(e => this.handleFileEvents(e)));
this.reloadConfigurationScheduler = this._register(new RunOnceScheduler(() => this.reload().then(configurationModel => this._onDidChangeConfiguration.fire(configurationModel)), 50));
this.fileService.watch(this.configurationResource);
this._register(toDisposable(() => this.fileService.unwatch(this.configurationResource)));
}
initialize(): Promise<ConfigurationModel> {
return this.reload();
}
reload(): Promise<ConfigurationModel> {
return this.fileService.resolveContent(this.configurationResource)
.then(content => content.value, () => {
// File not found
return '';
}).then(content => {
const parser = new ConfigurationModelParser(this.configurationResource.toString());
parser.parse(content);
return parser.configurationModel;
});
}
private handleFileEvents(event: FileChangesEvent): void {
const events = event.changes;
let affectedByChanges = false;
// Find changes that affect workspace file
for (let i = 0, len = events.length; i < len && !affectedByChanges; i++) {
affectedByChanges = resources.isEqual(this.configurationResource, events[i].resource);
}
if (affectedByChanges) {
this.reloadConfigurationScheduler.schedule();
}
getConfigurationModel(): ConfigurationModel {
return this.userConfigModelWatcher.getConfig().configurationModel;
}
}

View File

@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Emitter, Event } from 'vs/base/common/event';
import { Emitter, Event, PauseableEmitter } from 'vs/base/common/event';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { keys } from 'vs/base/common/map';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
@@ -95,7 +95,7 @@ class ConfigAwareContextValuesContainer extends Context {
constructor(
id: number,
private readonly _configurationService: IConfigurationService,
emitter: Emitter<string | string[]>
emitter: Emitter<IContextKeyChangeEvent>
) {
super(id, null);
@@ -104,7 +104,7 @@ class ConfigAwareContextValuesContainer extends Context {
// new setting, reset everything
const allKeys = keys(this._values);
this._values.clear();
emitter.fire(allKeys);
emitter.fire(new ArrayContextKeyChangeEvent(allKeys));
} else {
const changedKeys: string[] = [];
for (const configKey of event.affectedKeys) {
@@ -114,7 +114,7 @@ class ConfigAwareContextValuesContainer extends Context {
changedKeys.push(contextKey);
}
}
emitter.fire(changedKeys);
emitter.fire(new ArrayContextKeyChangeEvent(changedKeys));
}
});
}
@@ -165,44 +165,45 @@ class ConfigAwareContextValuesContainer extends Context {
class ContextKey<T> implements IContextKey<T> {
private _parent: AbstractContextKeyService;
private _service: AbstractContextKeyService;
private _key: string;
private _defaultValue: T | undefined;
constructor(parent: AbstractContextKeyService, key: string, defaultValue: T | undefined) {
this._parent = parent;
constructor(service: AbstractContextKeyService, key: string, defaultValue: T | undefined) {
this._service = service;
this._key = key;
this._defaultValue = defaultValue;
this.reset();
}
public set(value: T): void {
this._parent.setContext(this._key, value);
this._service.setContext(this._key, value);
}
public reset(): void {
if (typeof this._defaultValue === 'undefined') {
this._parent.removeContext(this._key);
this._service.removeContext(this._key);
} else {
this._parent.setContext(this._key, this._defaultValue);
this._service.setContext(this._key, this._defaultValue);
}
}
public get(): T | undefined {
return this._parent.getContextKeyValue<T>(this._key);
return this._service.getContextKeyValue<T>(this._key);
}
}
class SimpleContextKeyChangeEvent implements IContextKeyChangeEvent {
constructor(private readonly _key: string) { }
constructor(readonly key: string) { }
affectsSome(keys: IReadableSet<string>): boolean {
return keys.has(this._key);
return keys.has(this.key);
}
}
class ArrayContextKeyChangeEvent implements IContextKeyChangeEvent {
constructor(private readonly _keys: string[]) { }
constructor(readonly keys: string[]) { }
affectsSome(keys: IReadableSet<string>): boolean {
for (const key of this._keys) {
for (const key of this.keys) {
if (keys.has(key)) {
return true;
}
@@ -211,18 +212,28 @@ class ArrayContextKeyChangeEvent implements IContextKeyChangeEvent {
}
}
class CompositeContextKeyChangeEvent implements IContextKeyChangeEvent {
constructor(readonly events: IContextKeyChangeEvent[]) { }
affectsSome(keys: IReadableSet<string>): boolean {
for (const e of this.events) {
if (e.affectsSome(keys)) {
return true;
}
}
return false;
}
}
export abstract class AbstractContextKeyService implements IContextKeyService {
public _serviceBrand: any;
protected _isDisposed: boolean;
protected _onDidChangeContext: Event<IContextKeyChangeEvent>;
protected _onDidChangeContextKey: Emitter<string | string[]>;
protected _onDidChangeContext = new PauseableEmitter<IContextKeyChangeEvent>({ merge: input => new CompositeContextKeyChangeEvent(input) });
protected _myContextId: number;
constructor(myContextId: number) {
this._isDisposed = false;
this._myContextId = myContextId;
this._onDidChangeContextKey = new Emitter<string>();
}
abstract dispose(): void;
@@ -235,21 +246,23 @@ export abstract class AbstractContextKeyService implements IContextKeyService {
}
public get onDidChangeContext(): Event<IContextKeyChangeEvent> {
if (!this._onDidChangeContext) {
this._onDidChangeContext = Event.map(this._onDidChangeContextKey.event, ((changedKeyOrKeys): IContextKeyChangeEvent => {
return typeof changedKeyOrKeys === 'string'
? new SimpleContextKeyChangeEvent(changedKeyOrKeys)
: new ArrayContextKeyChangeEvent(changedKeyOrKeys);
}));
return this._onDidChangeContext.event;
}
bufferChangeEvents(callback: Function): void {
this._onDidChangeContext.pause();
try {
callback();
} finally {
this._onDidChangeContext.resume();
}
return this._onDidChangeContext;
}
public createScoped(domNode: IContextKeyServiceTarget): IContextKeyService {
if (this._isDisposed) {
throw new Error(`AbstractContextKeyService has been disposed`);
}
return new ScopedContextKeyService(this, this._onDidChangeContextKey, domNode);
return new ScopedContextKeyService(this, domNode);
}
public contextMatchesRules(rules: ContextKeyExpr | undefined): boolean {
@@ -280,7 +293,7 @@ export abstract class AbstractContextKeyService implements IContextKeyService {
return;
}
if (myContext.setValue(key, value)) {
this._onDidChangeContextKey.fire(key);
this._onDidChangeContext.fire(new SimpleContextKeyChangeEvent(key));
}
}
@@ -289,7 +302,7 @@ export abstract class AbstractContextKeyService implements IContextKeyService {
return;
}
if (this.getContextValuesContainer(this._myContextId).removeValue(key)) {
this._onDidChangeContextKey.fire(key);
this._onDidChangeContext.fire(new SimpleContextKeyChangeEvent(key));
}
}
@@ -308,19 +321,17 @@ export abstract class AbstractContextKeyService implements IContextKeyService {
export class ContextKeyService extends AbstractContextKeyService implements IContextKeyService {
private _lastContextId: number;
private _contexts: {
[contextId: string]: Context;
};
private readonly _contexts = new Map<number, Context>();
private _toDispose: IDisposable[] = [];
constructor(@IConfigurationService configurationService: IConfigurationService) {
super(0);
this._lastContextId = 0;
this._contexts = Object.create(null);
const myContext = new ConfigAwareContextValuesContainer(this._myContextId, configurationService, this._onDidChangeContextKey);
this._contexts[String(this._myContextId)] = myContext;
const myContext = new ConfigAwareContextValuesContainer(this._myContextId, configurationService, this._onDidChangeContext);
this._contexts.set(this._myContextId, myContext);
this._toDispose.push(myContext);
// Uncomment this to see the contexts continuously logged
@@ -344,7 +355,7 @@ export class ContextKeyService extends AbstractContextKeyService implements ICon
if (this._isDisposed) {
return NullContext.INSTANCE;
}
return this._contexts[String(contextId)];
return this._contexts.get(contextId) || NullContext.INSTANCE;
}
public createChildContext(parentContextId: number = this._myContextId): number {
@@ -352,15 +363,14 @@ export class ContextKeyService extends AbstractContextKeyService implements ICon
throw new Error(`ContextKeyService has been disposed`);
}
let id = (++this._lastContextId);
this._contexts[String(id)] = new Context(id, this.getContextValuesContainer(parentContextId));
this._contexts.set(id, new Context(id, this.getContextValuesContainer(parentContextId)));
return id;
}
public disposeContext(contextId: number): void {
if (this._isDisposed) {
return;
if (!this._isDisposed) {
this._contexts.delete(contextId);
}
delete this._contexts[String(contextId)];
}
}
@@ -369,10 +379,9 @@ class ScopedContextKeyService extends AbstractContextKeyService {
private _parent: AbstractContextKeyService;
private _domNode: IContextKeyServiceTarget | undefined;
constructor(parent: AbstractContextKeyService, emitter: Emitter<string | string[]>, domNode?: IContextKeyServiceTarget) {
constructor(parent: AbstractContextKeyService, domNode?: IContextKeyServiceTarget) {
super(parent.createChildContext());
this._parent = parent;
this._onDidChangeContextKey = emitter;
if (domNode) {
this._domNode = domNode;
@@ -390,7 +399,7 @@ class ScopedContextKeyService extends AbstractContextKeyService {
}
public get onDidChangeContext(): Event<IContextKeyChangeEvent> {
return this._parent.onDidChangeContext;
return Event.any(this._parent.onDidChangeContext, this._onDidChangeContext.event);
}
public getContextValuesContainer(contextId: number): Context {

View File

@@ -762,6 +762,9 @@ export interface IContextKeyService {
dispose(): void;
onDidChangeContext: Event<IContextKeyChangeEvent>;
bufferChangeEvents(callback: Function): void;
createKey<T>(key: string, defaultValue: T | undefined): IContextKey<T>;
contextMatchesRules(rules: ContextKeyExpr | undefined): boolean;
getContextKeyValue<T>(key: string): T | undefined;

View File

@@ -0,0 +1,44 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { UriComponents } from 'vs/base/common/uri';
import { ProcessItem } from 'vs/base/common/processes';
export interface IMachineInfo {
os: string;
cpus?: string;
memory: string;
vmHint: string;
}
export interface IDiagnosticInfo {
machineInfo: IMachineInfo;
workspaceMetadata?: { [key: string]: WorkspaceStats };
processes?: ProcessItem;
}
export interface SystemInfo extends IMachineInfo {
processArgs: string;
gpuStatus: any;
screenReader: string;
load?: string;
}
export interface IDiagnosticInfoOptions {
includeProcesses?: boolean;
folders?: UriComponents[];
includeExtensions?: boolean;
}
export interface WorkspaceStatItem {
name: string;
count: number;
}
export interface WorkspaceStats {
fileTypes: WorkspaceStatItem[];
configFiles: WorkspaceStatItem[];
fileCount: number;
maxFilesReached: boolean;
}

View File

@@ -3,19 +3,21 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IMainProcessInfo } from 'vs/platform/launch/electron-main/launchService';
import { ProcessItem, listProcesses } from 'vs/base/node/ps';
import { IMainProcessInfo, ILaunchService } from 'vs/platform/launch/electron-main/launchService';
import { listProcesses } from 'vs/base/node/ps';
import product from 'vs/platform/product/node/product';
import pkg from 'vs/platform/product/node/package';
import * as os from 'os';
import * as osLib from 'os';
import { virtualMachineHint } from 'vs/base/node/id';
import { repeat, pad } from 'vs/base/common/strings';
import { isWindows } from 'vs/base/common/platform';
import { app } from 'electron';
import { basename, join } from 'vs/base/common/path';
import { basename } from 'vs/base/common/path';
import { URI } from 'vs/base/common/uri';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { readdir, stat } from 'fs';
import { WorkspaceStats, SystemInfo } from 'vs/platform/diagnostics/common/diagnosticsService';
import { collectWorkspaceStats, getMachineInfo } from 'vs/platform/diagnostics/node/diagnosticsService';
import { ProcessItem } from 'vs/base/common/processes';
export const ID = 'diagnosticsService';
export const IDiagnosticsService = createDecorator<IDiagnosticsService>(ID);
@@ -23,10 +25,9 @@ export const IDiagnosticsService = createDecorator<IDiagnosticsService>(ID);
export interface IDiagnosticsService {
_serviceBrand: any;
formatEnvironment(info: IMainProcessInfo): string;
getPerformanceInfo(info: IMainProcessInfo): Promise<PerformanceInfo>;
getSystemInfo(info: IMainProcessInfo): SystemInfo;
getDiagnostics(info: IMainProcessInfo): Promise<string>;
getPerformanceInfo(launchService: ILaunchService): Promise<PerformanceInfo>;
getSystemInfo(launchService: ILaunchService): Promise<SystemInfo>;
getDiagnostics(launchService: ILaunchService): Promise<string>;
}
export interface VersionInfo {
@@ -34,16 +35,6 @@ export interface VersionInfo {
os: string;
}
export interface SystemInfo {
CPUs?: string;
'Memory (System)': string;
'Load (avg)'?: string;
VM: string;
'Screen Reader': string;
'Process Argv': string;
'GPU Status': Electron.GPUFeatureStatus;
}
export interface ProcessInfo {
cpu: number;
memory: number;
@@ -66,14 +57,14 @@ export class DiagnosticsService implements IDiagnosticsService {
const output: string[] = [];
output.push(`Version: ${pkg.name} ${pkg.version} (${product.commit || 'Commit unknown'}, ${product.date || 'Date unknown'})`);
output.push(`OS Version: ${os.type()} ${os.arch()} ${os.release()}`);
const cpus = os.cpus();
output.push(`OS Version: ${osLib.type()} ${osLib.arch()} ${osLib.release()}`);
const cpus = osLib.cpus();
if (cpus && cpus.length > 0) {
output.push(`CPUs: ${cpus[0].model} (${cpus.length} x ${cpus[0].speed})`);
}
output.push(`Memory (System): ${(os.totalmem() / GB).toFixed(2)}GB (${(os.freemem() / GB).toFixed(2)}GB free)`);
output.push(`Memory (System): ${(osLib.totalmem() / GB).toFixed(2)}GB (${(osLib.freemem() / GB).toFixed(2)}GB free)`);
if (!isWindows) {
output.push(`Load (avg): ${os.loadavg().map(l => Math.round(l)).join(', ')}`); // only provided on Linux/macOS
output.push(`Load (avg): ${osLib.loadavg().map(l => Math.round(l)).join(', ')}`); // only provided on Linux/macOS
}
output.push(`VM: ${Math.round((virtualMachineHint.value() * 100))}%`);
output.push(`Screen Reader: ${app.isAccessibilitySupportEnabled() ? 'yes' : 'no'}`);
@@ -83,82 +74,42 @@ export class DiagnosticsService implements IDiagnosticsService {
return output.join('\n');
}
getPerformanceInfo(info: IMainProcessInfo): Promise<PerformanceInfo> {
return listProcesses(info.mainPID).then(rootProcess => {
const workspaceInfoMessages: string[] = [];
// Workspace Stats
const workspaceStatPromises: Promise<void>[] = [];
if (info.windows.some(window => window.folderURIs && window.folderURIs.length > 0)) {
info.windows.forEach(window => {
if (window.folderURIs.length === 0) {
return;
}
workspaceInfoMessages.push(`| Window (${window.title})`);
window.folderURIs.forEach(uriComponents => {
const folderUri = URI.revive(uriComponents);
if (folderUri.scheme === 'file') {
const folder = folderUri.fsPath;
workspaceStatPromises.push(collectWorkspaceStats(folder, ['node_modules', '.git']).then(async stats => {
let countMessage = `${stats.fileCount} files`;
if (stats.maxFilesReached) {
countMessage = `more than ${countMessage}`;
}
workspaceInfoMessages.push(`| Folder (${basename(folder)}): ${countMessage}`);
workspaceInfoMessages.push(this.formatWorkspaceStats(stats));
}));
} else {
workspaceInfoMessages.push(`| Folder (${folderUri.toString()}): RPerformance stats not available.`);
}
});
});
}
return Promise.all(workspaceStatPromises).then(() => {
return {
processInfo: this.formatProcessList(info, rootProcess),
workspaceInfo: workspaceInfoMessages.join('\n')
};
}).catch(error => {
return {
processInfo: this.formatProcessList(info, rootProcess),
workspaceInfo: `Unable to calculate workspace stats: ${error}`
};
});
async getPerformanceInfo(launchService: ILaunchService): Promise<PerformanceInfo> {
const info = await launchService.getMainProcessInfo();
return Promise.all<ProcessItem, string>([listProcesses(info.mainPID), this.formatWorkspaceMetadata(info)]).then(result => {
const [rootProcess, workspaceInfo] = result;
return {
processInfo: this.formatProcessList(info, rootProcess),
workspaceInfo
};
});
}
getSystemInfo(info: IMainProcessInfo): SystemInfo {
const MB = 1024 * 1024;
const GB = 1024 * MB;
async getSystemInfo(launchService: ILaunchService): Promise<SystemInfo> {
const info = await launchService.getMainProcessInfo();
const { memory, vmHint, os, cpus } = getMachineInfo();
const systemInfo: SystemInfo = {
'Memory (System)': `${(os.totalmem() / GB).toFixed(2)}GB (${(os.freemem() / GB).toFixed(2)}GB free)`,
VM: `${Math.round((virtualMachineHint.value() * 100))}%`,
'Screen Reader': `${app.isAccessibilitySupportEnabled() ? 'yes' : 'no'}`,
'Process Argv': `${info.mainArguments.join(' ')}`,
'GPU Status': app.getGPUFeatureStatus()
os,
memory,
cpus,
vmHint,
processArgs: `${info.mainArguments.join(' ')}`,
gpuStatus: app.getGPUFeatureStatus(),
screenReader: `${app.isAccessibilitySupportEnabled() ? 'yes' : 'no'}`
};
const cpus = os.cpus();
if (cpus && cpus.length > 0) {
systemInfo.CPUs = `${cpus[0].model} (${cpus.length} x ${cpus[0].speed})`;
}
if (!isWindows) {
systemInfo['Load (avg)'] = `${os.loadavg().map(l => Math.round(l)).join(', ')}`;
systemInfo.load = `${osLib.loadavg().map(l => Math.round(l)).join(', ')}`;
}
return systemInfo;
return Promise.resolve(systemInfo);
}
getDiagnostics(info: IMainProcessInfo): Promise<string> {
async getDiagnostics(launchService: ILaunchService): Promise<string> {
const output: string[] = [];
return listProcesses(info.mainPID).then(rootProcess => {
const info = await launchService.getMainProcessInfo();
return listProcesses(info.mainPID).then(async rootProcess => {
// Environment Info
output.push('');
@@ -169,45 +120,16 @@ export class DiagnosticsService implements IDiagnosticsService {
output.push(this.formatProcessList(info, rootProcess));
// Workspace Stats
const workspaceStatPromises: Promise<void>[] = [];
if (info.windows.some(window => window.folderURIs && window.folderURIs.length > 0)) {
output.push('');
output.push('Workspace Stats: ');
info.windows.forEach(window => {
if (window.folderURIs.length === 0) {
return;
}
output.push(`| Window (${window.title})`);
window.folderURIs.forEach(uriComponents => {
const folderUri = URI.revive(uriComponents);
if (folderUri.scheme === 'file') {
const folder = folderUri.fsPath;
workspaceStatPromises.push(collectWorkspaceStats(folder, ['node_modules', '.git']).then(async stats => {
let countMessage = `${stats.fileCount} files`;
if (stats.maxFilesReached) {
countMessage = `more than ${countMessage}`;
}
output.push(`| Folder (${basename(folder)}): ${countMessage}`);
output.push(this.formatWorkspaceStats(stats));
}).catch(error => {
output.push(`| Error: Unable to collect workspace stats for folder ${folder} (${error.toString()})`);
}));
} else {
output.push(`| Folder (${folderUri.toString()}): Workspace stats not available.`);
}
});
});
output.push(await this.formatWorkspaceMetadata(info));
}
return Promise.all(workspaceStatPromises).then(() => {
output.push('');
output.push('');
output.push('');
output.push('');
return output.join('\n');
});
return output.join('\n');
});
}
@@ -268,6 +190,43 @@ export class DiagnosticsService implements IDiagnosticsService {
return Object.keys(gpuFeatures).map(feature => `${feature}: ${repeat(' ', longestFeatureName - feature.length)} ${gpuFeatures[feature]}`).join('\n ');
}
private formatWorkspaceMetadata(info: IMainProcessInfo): Promise<string> {
const output: string[] = [];
const workspaceStatPromises: Promise<void>[] = [];
info.windows.forEach(window => {
if (window.folderURIs.length === 0) {
return;
}
output.push(`| Window (${window.title})`);
window.folderURIs.forEach(uriComponents => {
const folderUri = URI.revive(uriComponents);
if (folderUri.scheme === 'file') {
const folder = folderUri.fsPath;
workspaceStatPromises.push(collectWorkspaceStats(folder, ['node_modules', '.git']).then(stats => {
let countMessage = `${stats.fileCount} files`;
if (stats.maxFilesReached) {
countMessage = `more than ${countMessage}`;
}
output.push(`| Folder (${basename(folder)}): ${countMessage}`);
output.push(this.formatWorkspaceStats(stats));
}).catch(error => {
output.push(`| Error: Unable to collect workspace stats for folder ${folder} (${error.toString()})`);
}));
} else {
output.push(`| Folder (${folderUri.toString()}): Workspace stats not available.`);
}
});
});
return Promise.all(workspaceStatPromises)
.then(_ => output.join('\n'))
.catch(e => `Unable to collect workspace stats: ${e}`);
}
private formatProcessList(info: IMainProcessInfo, rootProcess: ProcessItem): string {
const mapPidToWindowTitle = new Map<number, string>();
info.windows.forEach(window => mapPidToWindowTitle.set(window.pid, window.title));
@@ -299,7 +258,7 @@ export class DiagnosticsService implements IDiagnosticsService {
name = `${name} (${mapPidToWindowTitle.get(item.pid)})`;
}
}
const memory = process.platform === 'win32' ? item.mem : (os.totalmem() * (item.mem / 100));
const memory = process.platform === 'win32' ? item.mem : (osLib.totalmem() * (item.mem / 100));
output.push(`${pad(Number(item.load.toFixed(0)), 5, ' ')}\t${pad(Number((memory / MB).toFixed(0)), 6, ' ')}\t${pad(Number((item.pid).toFixed(0)), 6, ' ')}\t${name}`);
// Recurse into children if any
@@ -309,25 +268,6 @@ export class DiagnosticsService implements IDiagnosticsService {
}
}
interface WorkspaceStatItem {
name: string;
count: number;
}
interface WorkspaceStats {
fileTypes: WorkspaceStatItem[];
configFiles: WorkspaceStatItem[];
fileCount: number;
maxFilesReached: boolean;
// launchConfigFiles: WorkspaceStatItem[];
}
function asSortedItems(map: Map<string, number>): WorkspaceStatItem[] {
const a: WorkspaceStatItem[] = [];
map.forEach((value, index) => a.push({ name: index, count: value }));
return a.sort((a, b) => b.count - a.count);
}
// function collectLaunchConfigs(folder: string): Promise<WorkspaceStatItem[]> {
// const launchConfigs = new Map<string, number>();
@@ -368,137 +308,3 @@ function asSortedItems(map: Map<string, number>): WorkspaceStatItem[] {
// });
// });
// }
function collectWorkspaceStats(folder: string, filter: string[]): Promise<WorkspaceStats> {
const configFilePatterns = [
{ 'tag': 'grunt.js', 'pattern': /^gruntfile\.js$/i },
{ 'tag': 'gulp.js', 'pattern': /^gulpfile\.js$/i },
{ 'tag': 'tsconfig.json', 'pattern': /^tsconfig\.json$/i },
{ 'tag': 'package.json', 'pattern': /^package\.json$/i },
{ 'tag': 'jsconfig.json', 'pattern': /^jsconfig\.json$/i },
{ 'tag': 'tslint.json', 'pattern': /^tslint\.json$/i },
{ 'tag': 'eslint.json', 'pattern': /^eslint\.json$/i },
{ 'tag': 'tasks.json', 'pattern': /^tasks\.json$/i },
{ 'tag': 'launch.json', 'pattern': /^launch\.json$/i },
{ 'tag': 'settings.json', 'pattern': /^settings\.json$/i },
{ 'tag': 'webpack.config.js', 'pattern': /^webpack\.config\.js$/i },
{ 'tag': 'project.json', 'pattern': /^project\.json$/i },
{ 'tag': 'makefile', 'pattern': /^makefile$/i },
{ 'tag': 'sln', 'pattern': /^.+\.sln$/i },
{ 'tag': 'csproj', 'pattern': /^.+\.csproj$/i },
{ 'tag': 'cmake', 'pattern': /^.+\.cmake$/i }
];
const fileTypes = new Map<string, number>();
const configFiles = new Map<string, number>();
const MAX_FILES = 20000;
function walk(dir: string, filter: string[], token: { count: any; maxReached: any; }, done: (allFiles: string[]) => void): void {
let results: string[] = [];
readdir(dir, async (err, files) => {
// Ignore folders that can't be read
if (err) {
return done(results);
}
let pending = files.length;
if (pending === 0) {
return done(results);
}
for (const file of files) {
if (token.maxReached) {
return done(results);
}
stat(join(dir, file), (err, stats) => {
// Ignore files that can't be read
if (err) {
if (--pending === 0) {
return done(results);
}
} else {
if (stats.isDirectory()) {
if (filter.indexOf(file) === -1) {
walk(join(dir, file), filter, token, (res: string[]) => {
results = results.concat(res);
if (--pending === 0) {
return done(results);
}
});
} else {
if (--pending === 0) {
done(results);
}
}
} else {
if (token.count >= MAX_FILES) {
token.maxReached = true;
}
token.count++;
results.push(file);
if (--pending === 0) {
done(results);
}
}
}
});
}
});
}
const addFileType = (fileType: string) => {
if (fileTypes.has(fileType)) {
fileTypes.set(fileType, fileTypes.get(fileType)! + 1);
}
else {
fileTypes.set(fileType, 1);
}
};
const addConfigFiles = (fileName: string) => {
for (const each of configFilePatterns) {
if (each.pattern.test(fileName)) {
if (configFiles.has(each.tag)) {
configFiles.set(each.tag, configFiles.get(each.tag)! + 1);
} else {
configFiles.set(each.tag, 1);
}
}
}
};
const acceptFile = (name: string) => {
if (name.lastIndexOf('.') >= 0) {
const suffix: string | undefined = name.split('.').pop();
if (suffix) {
addFileType(suffix);
}
}
addConfigFiles(name);
};
const token: { count: number, maxReached: boolean } = { count: 0, maxReached: false };
return new Promise((resolve, reject) => {
walk(folder, filter, token, async (files) => {
files.forEach(acceptFile);
// TODO@rachel commented out due to severe performance issues
// see https://github.com/Microsoft/vscode/issues/70563
// const launchConfigs = await collectLaunchConfigs(folder);
resolve({
configFiles: asSortedItems(configFiles),
fileTypes: asSortedItems(fileTypes),
fileCount: token.count,
maxFilesReached: token.maxReached,
// launchConfigFiles: launchConfigs
});
});
});
}

View File

@@ -0,0 +1,167 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as os from 'os';
import { virtualMachineHint } from 'vs/base/node/id';
import { IMachineInfo, WorkspaceStats, WorkspaceStatItem } from 'vs/platform/diagnostics/common/diagnosticsService';
import { readdir, stat } from 'fs';
import { join } from 'vs/base/common/path';
export function getMachineInfo(): IMachineInfo {
const MB = 1024 * 1024;
const GB = 1024 * MB;
const machineInfo: IMachineInfo = {
os: `${os.type()} ${os.arch()} ${os.release()}`,
memory: `${(os.totalmem() / GB).toFixed(2)}GB (${(os.freemem() / GB).toFixed(2)}GB free)`,
vmHint: `${Math.round((virtualMachineHint.value() * 100))}%`,
};
const cpus = os.cpus();
if (cpus && cpus.length > 0) {
machineInfo.cpus = `${cpus[0].model} (${cpus.length} x ${cpus[0].speed})`;
}
return machineInfo;
}
export function collectWorkspaceStats(folder: string, filter: string[]): Promise<WorkspaceStats> {
const configFilePatterns = [
{ 'tag': 'grunt.js', 'pattern': /^gruntfile\.js$/i },
{ 'tag': 'gulp.js', 'pattern': /^gulpfile\.js$/i },
{ 'tag': 'tsconfig.json', 'pattern': /^tsconfig\.json$/i },
{ 'tag': 'package.json', 'pattern': /^package\.json$/i },
{ 'tag': 'jsconfig.json', 'pattern': /^jsconfig\.json$/i },
{ 'tag': 'tslint.json', 'pattern': /^tslint\.json$/i },
{ 'tag': 'eslint.json', 'pattern': /^eslint\.json$/i },
{ 'tag': 'tasks.json', 'pattern': /^tasks\.json$/i },
{ 'tag': 'launch.json', 'pattern': /^launch\.json$/i },
{ 'tag': 'settings.json', 'pattern': /^settings\.json$/i },
{ 'tag': 'webpack.config.js', 'pattern': /^webpack\.config\.js$/i },
{ 'tag': 'project.json', 'pattern': /^project\.json$/i },
{ 'tag': 'makefile', 'pattern': /^makefile$/i },
{ 'tag': 'sln', 'pattern': /^.+\.sln$/i },
{ 'tag': 'csproj', 'pattern': /^.+\.csproj$/i },
{ 'tag': 'cmake', 'pattern': /^.+\.cmake$/i }
];
const fileTypes = new Map<string, number>();
const configFiles = new Map<string, number>();
const MAX_FILES = 20000;
function walk(dir: string, filter: string[], token: { count: number, maxReached: boolean }, done: (allFiles: string[]) => void): void {
let results: string[] = [];
readdir(dir, async (err, files) => {
// Ignore folders that can't be read
if (err) {
return done(results);
}
let pending = files.length;
if (pending === 0) {
return done(results);
}
for (const file of files) {
if (token.maxReached) {
return done(results);
}
stat(join(dir, file), (err, stats) => {
// Ignore files that can't be read
if (err) {
if (--pending === 0) {
return done(results);
}
} else {
if (stats.isDirectory()) {
if (filter.indexOf(file) === -1) {
walk(join(dir, file), filter, token, (res: string[]) => {
results = results.concat(res);
if (--pending === 0) {
return done(results);
}
});
} else {
if (--pending === 0) {
done(results);
}
}
} else {
if (token.count >= MAX_FILES) {
token.maxReached = true;
}
token.count++;
results.push(file);
if (--pending === 0) {
done(results);
}
}
}
});
}
});
}
const addFileType = (fileType: string) => {
if (fileTypes.has(fileType)) {
fileTypes.set(fileType, fileTypes.get(fileType)! + 1);
}
else {
fileTypes.set(fileType, 1);
}
};
const addConfigFiles = (fileName: string) => {
for (const each of configFilePatterns) {
if (each.pattern.test(fileName)) {
if (configFiles.has(each.tag)) {
configFiles.set(each.tag, configFiles.get(each.tag)! + 1);
} else {
configFiles.set(each.tag, 1);
}
}
}
};
const acceptFile = (name: string) => {
if (name.lastIndexOf('.') >= 0) {
const suffix: string | undefined = name.split('.').pop();
if (suffix) {
addFileType(suffix);
}
}
addConfigFiles(name);
};
const token: { count: number, maxReached: boolean } = { count: 0, maxReached: false };
return new Promise((resolve, reject) => {
walk(folder, filter, token, async (files) => {
files.forEach(acceptFile);
// TODO@rachel commented out due to severe performance issues
// see https://github.com/Microsoft/vscode/issues/70563
// const launchConfigs = await collectLaunchConfigs(folder);
resolve({
configFiles: asSortedItems(configFiles),
fileTypes: asSortedItems(fileTypes),
fileCount: token.count,
maxFilesReached: token.maxReached,
// launchConfigFiles: launchConfigs
});
});
});
}
function asSortedItems(map: Map<string, number>): WorkspaceStatItem[] {
const a: WorkspaceStatItem[] = [];
map.forEach((value, index) => a.push({ name: index, count: value }));
return a.sort((a, b) => b.count - a.count);
}

View File

@@ -184,22 +184,22 @@ export interface IFileDialogService {
/**
* Shows a file-folder selection dialog and opens the selected entry.
*/
pickFileFolderAndOpen(options: IPickAndOpenOptions): Promise<any>;
pickFileFolderAndOpen(options: IPickAndOpenOptions): Promise<void>;
/**
* Shows a file selection dialog and opens the selected entry.
*/
pickFileAndOpen(options: IPickAndOpenOptions): Promise<any>;
pickFileAndOpen(options: IPickAndOpenOptions): Promise<void>;
/**
* Shows a folder selection dialog and opens the selected entry.
*/
pickFolderAndOpen(options: IPickAndOpenOptions): Promise<any>;
pickFolderAndOpen(options: IPickAndOpenOptions): Promise<void>;
/**
* Shows a workspace selection dialog and opens the selected entry.
*/
pickWorkspaceAndOpen(options: IPickAndOpenOptions): Promise<any>;
pickWorkspaceAndOpen(options: IPickAndOpenOptions): Promise<void>;
/**
* Shows a save file dialog and returns the chosen file URI.

View File

@@ -7,7 +7,6 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'
import { URI } from 'vs/base/common/uri';
export interface ParsedArgs {
[arg: string]: any;
_: string[];
'folder-uri'?: string | string[];
'file-uri'?: string | string[];
@@ -19,6 +18,7 @@ export interface ParsedArgs {
waitMarkerFilePath?: string;
diff?: boolean;
add?: boolean;
gitCredential?: string;
goto?: boolean;
'new-window'?: boolean;
'unity-launch'?: boolean; // Always open a new window, except if opening the first window or opening a file or folder as part of the launch.

View File

@@ -7,7 +7,7 @@ import * as minimist from 'minimist';
import * as os from 'os';
import { localize } from 'vs/nls';
import { ParsedArgs } from 'vs/platform/environment/common/environment';
import { join } from 'path';
import { join } from 'vs/base/common/path';
import { writeFileSync } from 'fs';
/**
@@ -102,8 +102,9 @@ export const options: Option[] = [
{ id: 'user', type: 'string', alias: 'U' },
{ id: 'command', type: 'string', alias: 'c' },
{ id: 'aad', type: 'boolean' },
{ id: 'integrated', type: 'boolean', alias: 'E' }
{ id: 'integrated', type: 'boolean', alias: 'E' },
// {{SQL CARBON EDIT}} - End
{ id: '_', type: 'string' }
];
export function parseArgs(args: string[], isOptionSupported = (_: Option) => true): ParsedArgs {

View File

@@ -18,8 +18,7 @@ import pkg from 'vs/platform/product/node/package';
import product from 'vs/platform/product/node/product';
import { isEngineValid } from 'vs/platform/extensions/node/extensionValidator';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { readFile } from 'vs/base/node/pfs';
import { writeFileAndFlushSync } from 'vs/base/node/extfs';
import { writeFileSync, readFile } from 'vs/base/node/pfs';
import { generateUuid, isUUID } from 'vs/base/common/uuid';
import { values } from 'vs/base/common/map';
// {{SQL CARBON EDIT}}
@@ -1004,7 +1003,7 @@ export function resolveMarketplaceHeaders(environmentService: IEnvironmentServic
if (!uuid) {
uuid = generateUuid();
try {
writeFileAndFlushSync(marketplaceMachineIdFile, uuid);
writeFileSync(marketplaceMachineIdFile, uuid);
} catch (error) {
//noop
}

View File

@@ -36,6 +36,6 @@ export class ExtensionsManifestCache extends Disposable {
}
invalidate(): void {
pfs.del(this.extensionsManifestCache).then(() => { }, () => { });
pfs.rimraf(this.extensionsManifestCache, pfs.RimRafMode.MOVE).then(() => { }, () => { });
}
}

View File

@@ -5,12 +5,11 @@
import * as assert from 'assert';
import * as os from 'os';
import * as extfs from 'vs/base/node/extfs';
import { EnvironmentService } from 'vs/platform/environment/node/environmentService';
import { parseArgs } from 'vs/platform/environment/node/argv';
import { getRandomTestPath } from 'vs/base/test/node/testUtils';
import { join } from 'vs/base/common/path';
import { mkdirp } from 'vs/base/node/pfs';
import { mkdirp, RimRafMode, rimraf } from 'vs/base/node/pfs';
// {{SQL CARBON EDIT}}
import { resolveMarketplaceHeaders, ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService';
import { isUUID } from 'vs/base/common/uuid';
@@ -22,15 +21,15 @@ suite('Extension Gallery Service', () => {
setup(done => {
// Delete any existing backups completely and then re-create it.
extfs.del(marketplaceHome, os.tmpdir(), () => {
rimraf(marketplaceHome, RimRafMode.MOVE).then(() => {
mkdirp(marketplaceHome).then(() => {
done();
}, error => done(error));
});
}, error => done(error));
});
teardown(done => {
extfs.del(marketplaceHome, os.tmpdir(), done);
rimraf(marketplaceHome, RimRafMode.MOVE).then(done, done);
});
test('marketplace machine id', () => {
@@ -147,4 +146,4 @@ suite('Extension Gallery Service', () => {
extension.publisher.publisherName = matchingText;
assert(ExtensionGalleryService.isMatchingExtension(extension, searchText), 'publisher publisherName field should be used for matching');
});
});
});

View File

@@ -1,12 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
// Broadcast communication constants
export const EXTENSION_LOG_BROADCAST_CHANNEL = 'vscode:extensionLog';
export const EXTENSION_ATTACH_BROADCAST_CHANNEL = 'vscode:extensionAttach';
export const EXTENSION_TERMINATE_BROADCAST_CHANNEL = 'vscode:extensionTerminate';
export const EXTENSION_RELOAD_BROADCAST_CHANNEL = 'vscode:extensionReload';
export const EXTENSION_CLOSE_EXTHOST_BROADCAST_CHANNEL = 'vscode:extensionCloseExtensionHost';

View File

@@ -7,7 +7,7 @@ import { sep } from 'vs/base/common/path';
import { URI } from 'vs/base/common/uri';
import * as glob from 'vs/base/common/glob';
import { isLinux } from 'vs/base/common/platform';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
import { Event } from 'vs/base/common/event';
import { startsWithIgnoreCase } from 'vs/base/common/strings';
import { IDisposable } from 'vs/base/common/lifecycle';
@@ -26,7 +26,8 @@ export interface IResourceEncoding {
}
export interface IFileService {
_serviceBrand: any;
_serviceBrand: ServiceIdentifier<any>;
//#region File System Provider
@@ -59,7 +60,7 @@ export interface IFileService {
/**
* Checks if the provider for the provided resource has the provided file system capability.
*/
hasCapability(resource: URI, capability: FileSystemProviderCapabilities): Promise<boolean>;
hasCapability(resource: URI, capability: FileSystemProviderCapabilities): boolean;
//#endregion
@@ -163,14 +164,11 @@ export interface IFileService {
del(resource: URI, options?: { useTrash?: boolean, recursive?: boolean }): Promise<void>;
/**
* Allows to start a watcher that reports file change events on the provided resource.
* Allows to start a watcher that reports file/folder change events on the provided resource.
*
* Note: watching a folder does not report events recursively for child folders yet.
*/
watch(resource: URI): void;
/**
* Allows to stop a watcher on the provided resource or absolute fs path.
*/
unwatch(resource: URI): void;
watch(resource: URI): IDisposable;
/**
* Frees up any resources occupied by this service.
@@ -231,6 +229,8 @@ export interface IFileSystemProvider {
readonly capabilities: FileSystemProviderCapabilities;
onDidChangeCapabilities: Event<void>;
onDidErrorOccur?: Event<Error>; // TODO@ben remove once file watchers are solid
onDidChangeFile: Event<IFileChange[]>;
watch(resource: URI, opts: IWatchOptions): IDisposable;
@@ -801,7 +801,7 @@ export class FileOperationError extends Error {
super(message);
}
static isFileOperationError(obj: any): obj is FileOperationError {
static isFileOperationError(obj: unknown): obj is FileOperationError {
return obj instanceof Error && !isUndefinedOrNull((obj as FileOperationError).fileOperationResult);
}
}
@@ -851,8 +851,8 @@ export interface IFilesConfiguration {
autoSave: string;
autoSaveDelay: number;
eol: string;
enableTrash: boolean;
hotExit: string;
useExperimentalFileWatcher: boolean;
};
}
@@ -1119,23 +1119,20 @@ export function etag(mtime: number | undefined, size: number | undefined): strin
// TODO@ben remove traces of legacy file service
export const ILegacyFileService = createDecorator<ILegacyFileService>('legacyFileService');
export interface ILegacyFileService {
export interface ILegacyFileService extends IDisposable {
_serviceBrand: any;
encoding: IResourceEncodings;
onFileChanges: Event<FileChangesEvent>;
onAfterOperation: Event<FileOperationEvent>;
registerProvider(scheme: string, provider: IFileSystemProvider): IDisposable;
resolveContent(resource: URI, options?: IResolveContentOptions): Promise<IContent>;
resolveStreamContent(resource: URI, options?: IResolveContentOptions): Promise<IStreamContent>;
updateContent(resource: URI, value: string | ITextSnapshot, options?: IUpdateContentOptions): Promise<IFileStat>;
updateContent(resource: URI, value: string | ITextSnapshot, options?: IUpdateContentOptions): Promise<IFileStatWithMetadata>;
createFile(resource: URI, content?: string, options?: ICreateFileOptions): Promise<IFileStat>;
watch(resource: URI): void;
unwatch(resource: URI): void;
createFile(resource: URI, content?: string, options?: ICreateFileOptions): Promise<IFileStatWithMetadata>;
}

View File

@@ -95,7 +95,7 @@ export interface IInstantiationService {
/**
*
*/
invokeFunction<R, TS extends any[]=[]>(fn: (accessor: ServicesAccessor, ...args: TS) => R, ...args: TS): R;
invokeFunction<R, TS extends any[] = []>(fn: (accessor: ServicesAccessor, ...args: TS) => R, ...args: TS): R;
/**
* Creates a child of this service which inherts all current services

View File

@@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/
import { illegalState } from 'vs/base/common/errors';
import { create } from 'vs/base/common/types';
import { Graph } from 'vs/platform/instantiation/common/graph';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { ServiceIdentifier, IInstantiationService, ServicesAccessor, _util, optional } from 'vs/platform/instantiation/common/instantiation';
@@ -40,7 +39,7 @@ export class InstantiationService implements IInstantiationService {
return new InstantiationService(services, this._strict, this);
}
invokeFunction<R, TS extends any[]=[]>(fn: (accessor: ServicesAccessor, ...args: TS) => R, ...args: TS): R {
invokeFunction<R, TS extends any[] = []>(fn: (accessor: ServicesAccessor, ...args: TS) => R, ...args: TS): R {
let _trace = Trace.traceInvocation(fn);
let _done = false;
try {
@@ -108,7 +107,7 @@ export class InstantiationService implements IInstantiationService {
}
// now create the instance
return <T>create.apply(null, [ctor].concat(args, serviceArgs));
return <T>new ctor(...[...args, ...serviceArgs]);
}
private _setServiceInstance<T>(id: ServiceIdentifier<T>, instance: T): void {

View File

@@ -9,7 +9,7 @@ import { parseArgs } from 'vs/platform/environment/node/argv';
import { IIssueService, IssueReporterData, IssueReporterFeatures, ProcessExplorerData } from 'vs/platform/issue/common/issue';
import { BrowserWindow, ipcMain, screen, Event, dialog } from 'electron';
import { ILaunchService } from 'vs/platform/launch/electron-main/launchService';
import { PerformanceInfo, SystemInfo, IDiagnosticsService } from 'vs/platform/diagnostics/electron-main/diagnosticsService';
import { PerformanceInfo, IDiagnosticsService } from 'vs/platform/diagnostics/electron-main/diagnosticsService';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { isMacintosh, IProcessEnvironment } from 'vs/base/common/platform';
import { ILogService } from 'vs/platform/log/common/log';
@@ -39,7 +39,7 @@ export class IssueService implements IIssueService {
private registerListeners(): void {
ipcMain.on('vscode:issueSystemInfoRequest', (event: Event) => {
this.getSystemInformation().then(msg => {
this.diagnosticsService.getSystemInfo(this.launchService).then(msg => {
event.sender.send('vscode:issueSystemInfoResponse', msg);
});
});
@@ -215,9 +215,7 @@ export class IssueService implements IIssueService {
}
public getSystemStatus(): Promise<string> {
return this.launchService.getMainProcessInfo().then(info => {
return this.diagnosticsService.getDiagnostics(info);
});
return this.diagnosticsService.getDiagnostics(this.launchService);
}
private getWindowPosition(parentWindow: BrowserWindow, defaultWidth: number, defaultHeight: number): IWindowState {
@@ -288,26 +286,16 @@ export class IssueService implements IIssueService {
return state;
}
private getSystemInformation(): Promise<SystemInfo> {
return new Promise((resolve, reject) => {
this.launchService.getMainProcessInfo().then(info => {
resolve(this.diagnosticsService.getSystemInfo(info));
});
});
}
private getPerformanceInfo(): Promise<PerformanceInfo> {
return new Promise((resolve, reject) => {
this.launchService.getMainProcessInfo().then(info => {
this.diagnosticsService.getPerformanceInfo(info)
.then(diagnosticInfo => {
resolve(diagnosticInfo);
})
.catch(err => {
this.logService.warn('issueService#getPerformanceInfo ', err.message);
reject(err);
});
});
this.diagnosticsService.getPerformanceInfo(this.launchService)
.then(diagnosticInfo => {
resolve(diagnosticInfo);
})
.catch(err => {
this.logService.warn('issueService#getPerformanceInfo ', err.message);
reject(err);
});
});
}

View File

@@ -106,6 +106,7 @@ suite('AbstractKeybindingService', () => {
_serviceBrand: undefined,
dispose: undefined!,
onDidChangeContext: undefined!,
bufferChangeEvents() { },
createKey: undefined!,
contextMatchesRules: undefined!,
getContextKeyValue: undefined!,

View File

@@ -53,6 +53,7 @@ export class MockContextKeyService implements IContextKeyService {
public get onDidChangeContext(): Event<IContextKeyChangeEvent> {
return Event.None;
}
public bufferChangeEvents() { }
public getContextKeyValue(key: string) {
const value = this._keys.get(key);
if (value) {

View File

@@ -11,6 +11,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'
import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, WORKSPACE_EXTENSION } from 'vs/platform/workspaces/common/workspaces';
import { localize } from 'vs/nls';
import { isEqualOrParent, basename } from 'vs/base/common/resources';
import { endsWith } from 'vs/base/common/strings';
export interface ILabelService {
_serviceBrand: any;
@@ -54,9 +55,11 @@ export function getSimpleWorkspaceLabel(workspace: IWorkspaceIdentifier | URI, w
return localize('untitledWorkspace', "Untitled (Workspace)");
}
const filename = basename(workspace.configPath);
const workspaceName = filename.substr(0, filename.length - WORKSPACE_EXTENSION.length - 1);
return localize('workspaceName', "{0} (Workspace)", workspaceName);
let filename = basename(workspace.configPath);
if (endsWith(filename, WORKSPACE_EXTENSION)) {
filename = filename.substr(0, filename.length - WORKSPACE_EXTENSION.length - 1);
}
return localize('workspaceName', "{0} (Workspace)", filename);
}

View File

@@ -311,6 +311,6 @@ export class LaunchService implements ILaunchService {
pid: win.webContents.getOSProcessId(),
title: win.getTitle(),
folderURIs
} as IWindowInfo;
};
}
}

View File

@@ -58,7 +58,7 @@ export abstract class AbstractLifecycleService extends Disposable implements ILi
}
}
when(phase: LifecyclePhase): Promise<any> {
when(phase: LifecyclePhase): Promise<void> {
if (phase <= this._phase) {
return Promise.resolve();
}
@@ -69,6 +69,6 @@ export abstract class AbstractLifecycleService extends Disposable implements ILi
this.phaseWhen.set(phase, barrier);
}
return barrier.wait();
return barrier.wait().then(undefined);
}
}

View File

@@ -7,7 +7,7 @@ import * as nls from 'vs/nls';
import { isMacintosh, language } from 'vs/base/common/platform';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { app, shell, Menu, MenuItem, BrowserWindow } from 'electron';
import { OpenContext, IRunActionInWindowRequest, getTitleBarStyle, IRunKeybindingInWindowRequest } from 'vs/platform/windows/common/windows';
import { OpenContext, IRunActionInWindowRequest, getTitleBarStyle, IRunKeybindingInWindowRequest, IURIToOpen } from 'vs/platform/windows/common/windows';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IUpdateService, StateType } from 'vs/platform/update/common/update';
@@ -473,7 +473,9 @@ export class Menubar {
private createOpenRecentMenuItem(uri: URI, label: string, commandId: string): Electron.MenuItem {
const revivedUri = URI.revive(uri);
const typeHint = commandId === 'openRecentFile' || commandId === 'openRecentWorkspace' ? 'file' : 'folder';
const uriToOpen: IURIToOpen =
(commandId === 'openRecentFile') ? { fileUri: revivedUri } :
(commandId === 'openRecentWorkspace') ? { workspaceUri: revivedUri } : { folderUri: revivedUri };
return new MenuItem(this.likeAction(commandId, {
label,
@@ -482,9 +484,8 @@ export class Menubar {
const success = this.windowsMainService.open({
context: OpenContext.MENU,
cli: this.environmentService.args,
urisToOpen: [{ uri: revivedUri, typeHint }],
forceNewWindow: openInNewWindow,
forceOpenWorkspaceAsFile: commandId === 'openRecentFile'
urisToOpen: [uriToOpen],
forceNewWindow: openInNewWindow
}).length > 0;
if (!success) {

View File

@@ -52,7 +52,7 @@ export interface IProgressService2 {
_serviceBrand: any;
withProgress<R=any>(options: IProgressOptions, task: (progress: IProgress<IProgressStep>) => Promise<R>, onDidCancel?: () => void): Promise<R>;
withProgress<R = any>(options: IProgressOptions, task: (progress: IProgress<IProgressStep>) => Promise<R>, onDidCancel?: () => void): Promise<R>;
}
export interface IProgressRunner {

View File

@@ -20,6 +20,10 @@ export class RemoteAuthorityResolverService implements IRemoteAuthorityResolverS
return Promise.resolve({ authority, host: authority, port: 80 });
}
clearResolvedAuthority(authority: string): void {
throw new Error(`Not implemented`);
}
setResolvedAuthority(resolvedAuthority: ResolvedAuthority) {
throw new Error(`Not implemented`);
}

View File

@@ -21,6 +21,7 @@ export interface IRemoteAuthorityResolverService {
resolveAuthority(authority: string): Promise<ResolvedAuthority>;
clearResolvedAuthority(authority: string): void;
setResolvedAuthority(resolvedAuthority: ResolvedAuthority): void;
setResolvedAuthorityError(authority: string, err: any): void;
}

View File

@@ -5,6 +5,7 @@
import { ResolvedAuthority, IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver';
import { ipcRenderer as ipc } from 'electron';
import * as errors from 'vs/base/common/errors';
class PendingResolveAuthorityRequest {
constructor(
@@ -38,6 +39,11 @@ export class RemoteAuthorityResolverService implements IRemoteAuthorityResolverS
return this._resolveAuthorityRequests[authority].promise;
}
clearResolvedAuthority(authority: string): void {
this._resolveAuthorityRequests[authority].reject(errors.canceled());
delete this._resolveAuthorityRequests[authority];
}
setResolvedAuthority(resolvedAuthority: ResolvedAuthority) {
if (this._resolveAuthorityRequests[resolvedAuthority.authority]) {
let request = this._resolveAuthorityRequests[resolvedAuthority.authority];

View File

@@ -12,6 +12,6 @@ export interface IStateService {
getItem<T>(key: string, defaultValue: T): T;
getItem<T>(key: string, defaultValue?: T): T | undefined;
setItem(key: string, data: any): void;
setItem(key: string, data?: object | string | number | boolean | undefined | null): void;
removeItem(key: string): void;
}

View File

@@ -6,11 +6,10 @@
import * as path from 'vs/base/common/path';
import * as fs from 'fs';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { writeFileAndFlushSync } from 'vs/base/node/extfs';
import { writeFileSync, readFile } from 'vs/base/node/pfs';
import { isUndefined, isUndefinedOrNull } from 'vs/base/common/types';
import { IStateService } from 'vs/platform/state/common/state';
import { ILogService } from 'vs/platform/log/common/log';
import { readFile } from 'vs/base/node/pfs';
export class FileStorage {
@@ -69,7 +68,7 @@ export class FileStorage {
return res;
}
setItem(key: string, data: any): void {
setItem(key: string, data?: object | string | number | boolean | undefined | null): void {
// Remove an item when it is undefined or null
if (isUndefinedOrNull(data)) {
@@ -103,7 +102,7 @@ export class FileStorage {
}
try {
writeFileAndFlushSync(this.dbPath, serializedDatabase); // permission issue can happen here
writeFileSync(this.dbPath, serializedDatabase); // permission issue can happen here
this.lastFlushedSerializedDatabase = serializedDatabase;
} catch (error) {
this.onError(error);
@@ -136,7 +135,7 @@ export class StateService implements IStateService {
return this.fileStorage.getItem(key, defaultValue);
}
setItem(key: string, data: any): void {
setItem(key: string, data?: object | string | number | boolean | undefined | null): void {
this.fileStorage.setItem(key, data);
}

View File

@@ -6,21 +6,21 @@
import * as assert from 'assert';
import * as os from 'os';
import * as path from 'vs/base/common/path';
import * as extfs from 'vs/base/node/extfs';
import { getRandomTestPath } from 'vs/base/test/node/testUtils';
import { FileStorage } from 'vs/platform/state/node/stateService';
import { mkdirp, rimraf, RimRafMode, writeFileSync } from 'vs/base/node/pfs';
suite('StateService', () => {
const parentDir = getRandomTestPath(os.tmpdir(), 'vsctests', 'stateservice');
const storageFile = path.join(parentDir, 'storage.json');
teardown(done => {
extfs.del(parentDir, os.tmpdir(), done);
rimraf(parentDir, RimRafMode.MOVE).then(done, done);
});
test('Basics', () => {
return extfs.mkdirp(parentDir).then(() => {
extfs.writeFileAndFlushSync(storageFile, '');
return mkdirp(parentDir).then(() => {
writeFileSync(storageFile, '');
let service = new FileStorage(storageFile, () => null);

View File

@@ -72,11 +72,12 @@ export interface IStorageService {
/**
* Store a value under the given key to storage. The value will be converted to a string.
* Storing either undefined or null will remove the entry under the key.
*
* The scope argument allows to define the scope of the storage
* operation to either the current workspace only or all workspaces.
*/
store(key: string, value: string | boolean | number, scope: StorageScope): void;
store(key: string, value: string | boolean | number | undefined | null, scope: StorageScope): void;
/**
* Delete an element stored under the provided key from storage.
@@ -153,7 +154,7 @@ export class InMemoryStorageService extends Disposable implements IStorageServic
return parseInt(value, 10);
}
store(key: string, value: string | boolean | number, scope: StorageScope): Promise<void> {
store(key: string, value: string | boolean | number | undefined | null, scope: StorageScope): Promise<void> {
// We remove the key for undefined/null values
if (isUndefinedOrNull(value)) {

View File

@@ -101,7 +101,7 @@ export class GlobalStorageDatabaseChannel extends Disposable implements IServerC
const items = new Map<Key, Value>();
events.forEach(event => items.set(event.key, this.storageMainService.get(event.key)));
return { items: mapToSerializable(items) } as ISerializableItemsChangeEvent;
return { items: mapToSerializable(items) };
}
listen(_: unknown, event: string): Event<any> {
@@ -120,7 +120,7 @@ export class GlobalStorageDatabaseChannel extends Disposable implements IServerC
case 'updateItems': {
return this.whenReady.then(() => {
const items = arg as ISerializableUpdateRequest;
const items: ISerializableUpdateRequest = arg;
if (items.insert) {
for (const [key, value] of items.insert) {
this.storageMainService.store(key, value);
@@ -199,7 +199,7 @@ export class GlobalStorageDatabaseChannelClient extends Disposable implements IS
close(): Promise<void> {
// when we are about to close, we start to ignore main-side changes since we close anyway
this.onDidChangeItemsOnMainListener = dispose(this.onDidChangeItemsOnMainListener);
dispose(this.onDidChangeItemsOnMainListener);
return Promise.resolve(); // global storage is closed on the main side
}
@@ -207,6 +207,6 @@ export class GlobalStorageDatabaseChannelClient extends Disposable implements IS
dispose(): void {
super.dispose();
this.onDidChangeItemsOnMainListener = dispose(this.onDidChangeItemsOnMainListener);
dispose(this.onDidChangeItemsOnMainListener);
}
}

View File

@@ -57,7 +57,7 @@ export interface IStorageMainService {
* Store a string value under the given key to storage. The value will
* be converted to a string.
*/
store(key: string, value: any): void;
store(key: string, value: string | boolean | number | undefined | null): void;
/**
* Delete an element stored under the provided key from storage.
@@ -109,7 +109,7 @@ export class StorageMainService extends Disposable implements IStorageMainServic
return {
logTrace: (this.logService.getLevel() === LogLevel.Trace) ? msg => this.logService.trace(msg) : undefined,
logError: error => this.logService.error(error)
} as ISQLiteStorageDatabaseLoggingOptions;
};
}
initialize(): Promise<void> {
@@ -160,7 +160,7 @@ export class StorageMainService extends Disposable implements IStorageMainServic
return this.storage.getNumber(key, fallbackValue);
}
store(key: string, value: any): Promise<void> {
store(key: string, value: string | boolean | number | undefined | null): Promise<void> {
return this.storage.set(key, value);
}

View File

@@ -105,8 +105,8 @@ export class StorageService extends Disposable implements IStorageService {
};
// Dispose old (if any)
this.workspaceStorage = dispose(this.workspaceStorage);
this.workspaceStorageListener = dispose(this.workspaceStorageListener);
dispose(this.workspaceStorage);
dispose(this.workspaceStorageListener);
// Create new
this.workspaceStoragePath = workspaceStoragePath;
@@ -176,7 +176,7 @@ export class StorageService extends Disposable implements IStorageService {
return this.getStorage(scope).getNumber(key, fallbackValue);
}
store(key: string, value: string | boolean | number, scope: StorageScope): void {
store(key: string, value: string | boolean | number | undefined | null, scope: StorageScope): void {
this.getStorage(scope).set(key, value);
}

View File

@@ -9,7 +9,7 @@ import { StorageService } from 'vs/platform/storage/node/storageService';
import { generateUuid } from 'vs/base/common/uuid';
import { join } from 'vs/base/common/path';
import { tmpdir } from 'os';
import { mkdirp, del } from 'vs/base/node/pfs';
import { mkdirp, rimraf, RimRafMode } from 'vs/base/node/pfs';
import { NullLogService } from 'vs/platform/log/common/log';
import { EnvironmentService } from 'vs/platform/environment/node/environmentService';
import { parseArgs } from 'vs/platform/environment/node/argv';
@@ -115,6 +115,6 @@ suite('StorageService', () => {
equal(storage.getBoolean('barBoolean', StorageScope.GLOBAL), true);
await storage.close();
await del(storageDir, tmpdir());
await rimraf(storageDir, RimRafMode.MOVE);
});
});

View File

@@ -59,6 +59,11 @@ export function resolveCommonProperties(commit: string | undefined, version: str
}
});
if (process.platform === 'linux' && process.env.SNAP && process.env.SNAP_REVISION) {
// __GDPR__COMMON__ "common.snap" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
result['common.snap'] = 'true';
}
return readFile(installSourcePath, 'utf8').then(contents => {
// __GDPR__COMMON__ "common.source" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }

View File

@@ -9,8 +9,7 @@ import * as fs from 'fs';
import { resolveWorkbenchCommonProperties } from 'vs/platform/telemetry/node/workbenchCommonProperties';
import { getRandomTestPath } from 'vs/base/test/node/testUtils';
import { IStorageService, StorageScope, InMemoryStorageService } from 'vs/platform/storage/common/storage';
import { del } from 'vs/base/node/extfs';
import { mkdirp } from 'vs/base/node/pfs';
import { mkdirp, rimraf, RimRafMode } from 'vs/base/node/pfs';
import { timeout } from 'vs/base/common/async';
suite('Telemetry - common properties', function () {
@@ -26,7 +25,7 @@ suite('Telemetry - common properties', function () {
});
teardown(done => {
del(parentDir, os.tmpdir(), done);
rimraf(parentDir, RimRafMode.MOVE).then(done, done);
});
// {{SQL CARBON EDIT}}

View File

@@ -16,6 +16,7 @@ import { LogLevel } from 'vs/platform/log/common/log';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { URI, UriComponents } from 'vs/base/common/uri';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { CancelablePromise, createCancelablePromise } from 'vs/base/common/async';
export const IWindowsService = createDecorator<IWindowsService>('windowsService');
@@ -23,7 +24,7 @@ export interface INativeOpenDialogOptions {
windowId?: number;
forceNewWindow?: boolean;
dialogOptions?: OpenDialogOptions;
defaultPath?: string;
telemetryEventName?: string;
telemetryExtraData?: ITelemetryData;
@@ -179,7 +180,6 @@ export interface IMessageBoxResult {
export interface IOpenSettings {
forceNewWindow?: boolean;
forceReuseWindow?: boolean;
forceOpenWorkspaceAsFile?: boolean;
diffMode?: boolean;
addMode?: boolean;
noRecentEntry?: boolean;
@@ -187,14 +187,36 @@ export interface IOpenSettings {
args?: ParsedArgs;
}
export type URIType = 'file' | 'folder';
export type IURIToOpen = IWorkspaceToOpen | IFolderToOpen | IFileToOpen;
export interface IURIToOpen {
uri: URI;
typeHint?: URIType;
export interface IWorkspaceToOpen {
workspaceUri: URI;
label?: string;
}
export interface IFolderToOpen {
folderUri: URI;
label?: string;
}
export interface IFileToOpen {
fileUri: URI;
label?: string;
}
export function isWorkspaceToOpen(uriToOpen: IURIToOpen): uriToOpen is IWorkspaceToOpen {
return !!uriToOpen['workspaceUri'];
}
export function isFolderToOpen(uriToOpen: IURIToOpen): uriToOpen is IFolderToOpen {
return !!uriToOpen['folderUri'];
}
export function isFileToOpen(uriToOpen: IURIToOpen): uriToOpen is IFileToOpen {
return !!uriToOpen['fileUri'];
}
export interface IWindowService {
_serviceBrand: any;
@@ -428,31 +450,31 @@ export interface IRunKeybindingInWindowRequest {
export class ActiveWindowManager implements IDisposable {
private disposables: IDisposable[] = [];
private firstActiveWindowIdPromise: Promise<any> | null;
private _activeWindowId: number | undefined;
private firstActiveWindowIdPromise: CancelablePromise<number | undefined> | undefined;
private activeWindowId: number | undefined;
constructor(@IWindowsService windowsService: IWindowsService) {
const onActiveWindowChange = Event.latch(Event.any(windowsService.onWindowOpen, windowsService.onWindowFocus));
onActiveWindowChange(this.setActiveWindow, this, this.disposables);
this.firstActiveWindowIdPromise = windowsService.getActiveWindowId()
.then(id => (typeof this._activeWindowId === 'undefined') && this.setActiveWindow(id));
this.firstActiveWindowIdPromise = createCancelablePromise(_ => windowsService.getActiveWindowId());
this.firstActiveWindowIdPromise
.then(id => this.activeWindowId = id)
.finally(this.firstActiveWindowIdPromise = undefined);
}
private setActiveWindow(windowId: number | undefined) {
if (this.firstActiveWindowIdPromise) {
this.firstActiveWindowIdPromise = null;
this.firstActiveWindowIdPromise.cancel();
this.firstActiveWindowIdPromise = undefined;
}
this._activeWindowId = windowId;
this.activeWindowId = windowId;
}
getActiveClientId(): Promise<string> {
if (this.firstActiveWindowIdPromise) {
return this.firstActiveWindowIdPromise;
}
return Promise.resolve(`window:${this._activeWindowId}`);
async getActiveClientId(): Promise<string | undefined> {
const id = this.firstActiveWindowIdPromise ? (await this.firstActiveWindowIdPromise) : this.activeWindowId;
return `window:${id}`;
}
dispose() {

View File

@@ -4,13 +4,12 @@
*--------------------------------------------------------------------------------------------*/
import { Event } from 'vs/base/common/event';
import { IWindowService, IWindowsService, INativeOpenDialogOptions, IEnterWorkspaceResult, IMessageBoxResult, IWindowConfiguration, IDevToolsOptions, IOpenSettings, IURIToOpen } from 'vs/platform/windows/common/windows';
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 { hasWorkspaceFileExtension } from 'vs/platform/workspaces/common/workspaces';
import { ILabelService } from 'vs/platform/label/common/label';
export class WindowService extends Disposable implements IWindowService {
@@ -100,7 +99,7 @@ export class WindowService extends Disposable implements IWindowService {
openWindow(uris: IURIToOpen[], options: IOpenSettings = {}): Promise<void> {
if (!!this.configuration.remoteAuthority) {
uris.forEach(u => u.label = u.label || this.getRecentLabel(u, !!(options && options.forceOpenWorkspaceAsFile)));
uris.forEach(u => u.label = u.label || this.getRecentLabel(u));
}
return this.windowsService.openWindow(this.windowId, uris, options);
}
@@ -173,13 +172,13 @@ export class WindowService extends Disposable implements IWindowService {
return this.windowsService.resolveProxy(this.windowId, url);
}
private getRecentLabel(u: IURIToOpen, forceOpenWorkspaceAsFile: boolean): string {
if (u.typeHint === 'folder') {
return this.labelService.getWorkspaceLabel(u.uri, { verbose: true });
} else if (!forceOpenWorkspaceAsFile && hasWorkspaceFileExtension(u.uri.path)) {
return this.labelService.getWorkspaceLabel({ id: '', configPath: u.uri }, { verbose: true });
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.uri);
return this.labelService.getUriLabel(u.fileUri);
}
}
}

View File

@@ -98,10 +98,10 @@ export interface IWindowsMainService {
closeWorkspace(win: ICodeWindow): void;
open(openConfig: IOpenConfiguration): ICodeWindow[];
openExtensionDevelopmentHostWindow(extensionDevelopmentPath: string, openConfig: IOpenConfiguration): void;
pickFileFolderAndOpen(options: INativeOpenDialogOptions): void;
pickFolderAndOpen(options: INativeOpenDialogOptions): void;
pickFileAndOpen(options: INativeOpenDialogOptions): void;
pickWorkspaceAndOpen(options: INativeOpenDialogOptions): void;
pickFileFolderAndOpen(options: INativeOpenDialogOptions): Promise<void>;
pickFolderAndOpen(options: INativeOpenDialogOptions): Promise<void>;
pickFileAndOpen(options: INativeOpenDialogOptions): Promise<void>;
pickWorkspaceAndOpen(options: INativeOpenDialogOptions): Promise<void>;
showMessageBox(options: Electron.MessageBoxOptions, win?: ICodeWindow): Promise<IMessageBoxResult>;
showSaveDialog(options: Electron.SaveDialogOptions, win?: ICodeWindow): Promise<string>;
showOpenDialog(options: Electron.OpenDialogOptions, win?: ICodeWindow): Promise<string[]>;
@@ -133,7 +133,6 @@ export interface IOpenConfiguration {
readonly forceEmpty?: boolean;
readonly diffMode?: boolean;
addMode?: boolean;
readonly forceOpenWorkspaceAsFile?: boolean;
readonly initialStartup?: boolean;
readonly noRecentEntry?: boolean;
}

View File

@@ -290,7 +290,6 @@ export class WindowsService implements IWindowsService, IURLHandler, IDisposable
cli: options.args ? { ...this.environmentService.args, ...options.args } : this.environmentService.args,
forceNewWindow: options.forceNewWindow,
forceReuseWindow: options.forceReuseWindow,
forceOpenWorkspaceAsFile: options.forceOpenWorkspaceAsFile,
diffMode: options.diffMode,
addMode: options.addMode,
noRecentEntry: options.noRecentEntry,
@@ -380,6 +379,7 @@ export class WindowsService implements IWindowsService, IURLHandler, IDisposable
version = `${version} (${product.target} setup)`;
}
const isSnap = process.platform === 'linux' && process.env.SNAP && process.env.SNAP_REVISION;
// {{SQL CARBON EDIT}}
const detail = nls.localize('aboutDetail',
"Version: {0}\nCommit: {1}\nDate: {2}\nVS Code {8}\nElectron: {3}\nChrome: {4}\nNode.js: {5}\nV8: {6}\nOS: {7}",
@@ -390,7 +390,7 @@ export class WindowsService implements IWindowsService, IURLHandler, IDisposable
process.versions['chrome'],
process.versions['node'],
process.versions['v8'],
`${os.type()} ${os.arch()} ${os.release()}`,
`${os.type()} ${os.arch()} ${os.release()}${isSnap ? ' snap' : ''}`,
product.vscodeVersion
);
@@ -422,7 +422,7 @@ export class WindowsService implements IWindowsService, IURLHandler, IDisposable
// Catch file URLs
if (uri.authority === Schemas.file && !!uri.path) {
this.openFileForURI({ uri: URI.file(uri.fsPath) }); // using fsPath on a non-file URI...
this.openFileForURI({ fileUri: URI.file(uri.fsPath) }); // using fsPath on a non-file URI...
return true;
}

View File

@@ -5,7 +5,7 @@
import { Event } from 'vs/base/common/event';
import { IServerChannel } from 'vs/base/parts/ipc/common/ipc';
import { IWindowsService, IURIToOpen, IOpenSettings } from 'vs/platform/windows/common/windows';
import { IWindowsService, IURIToOpen, IOpenSettings, isWorkspaceToOpen, isFolderToOpen } from 'vs/platform/windows/common/windows';
import { reviveWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
import { URI } from 'vs/base/common/uri';
import { IRecent, isRecentFile, isRecentFolder } from 'vs/platform/history/common/history';
@@ -89,7 +89,15 @@ export class WindowsChannel implements IServerChannel {
case 'openWindow': {
const urisToOpen: IURIToOpen[] = arg[1];
const options: IOpenSettings = arg[2];
urisToOpen.forEach(r => { r.uri = URI.revive(r.uri); return r; });
urisToOpen.forEach(r => {
if (isWorkspaceToOpen(r)) {
r.workspaceUri = URI.revive(r.workspaceUri);
} else if (isFolderToOpen(r)) {
r.folderUri = URI.revive(r.folderUri);
} else {
r.fileUri = URI.revive(r.fileUri);
}
});
options.waitMarkerFileURI = options.waitMarkerFileURI && URI.revive(options.waitMarkerFileURI);
return this.service.openWindow(arg[0], urisToOpen, options);
}

View File

@@ -6,10 +6,9 @@
import { IWorkspacesMainService, IWorkspaceIdentifier, hasWorkspaceFileExtension, UNTITLED_WORKSPACE_NAME, IResolvedWorkspace, IStoredWorkspaceFolder, isStoredWorkspaceFolder, IWorkspaceFolderCreationData, IUntitledWorkspaceInfo, getStoredWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { join, dirname } from 'vs/base/common/path';
import { mkdirp, writeFile } from 'vs/base/node/pfs';
import { readFileSync, existsSync, mkdirSync, writeFileSync } from 'fs';
import { mkdirp, writeFile, rimrafSync, readdirSync, writeFileSync } from 'vs/base/node/pfs';
import { readFileSync, existsSync, mkdirSync } from 'fs';
import { isLinux } from 'vs/base/common/platform';
import { delSync, readdirSync, writeFileAndFlushSync } from 'vs/base/node/extfs';
import { Event, Emitter } from 'vs/base/common/event';
import { ILogService } from 'vs/platform/log/common/log';
import { createHash } from 'crypto';
@@ -126,7 +125,7 @@ export class WorkspacesMainService extends Disposable implements IWorkspacesMain
mkdirSync(configPathDir);
}
writeFileAndFlushSync(configPath, JSON.stringify(storedWorkspace, null, '\t'));
writeFileSync(configPath, JSON.stringify(storedWorkspace, null, '\t'));
return workspace;
}
@@ -176,8 +175,9 @@ export class WorkspacesMainService extends Disposable implements IWorkspacesMain
private doDeleteUntitledWorkspaceSync(workspace: IWorkspaceIdentifier): void {
const configPath = originalFSPath(workspace.configPath);
try {
// Delete Workspace
delSync(dirname(configPath));
rimrafSync(dirname(configPath));
// Mark Workspace Storage to be deleted
const workspaceStoragePath = join(this.environmentService.workspaceStorageHome, workspace.id);

View File

@@ -27,7 +27,7 @@ export class WorkspacesChannel implements IServerChannel {
return {
uri: URI.revive(rawFolder.uri), // convert raw URI back to real URI
name: rawFolder.name
} as IWorkspaceFolderCreationData;
};
});
}

View File

@@ -55,13 +55,13 @@ suite('WorkspacesMainService', () => {
service = new TestWorkspacesMainService(environmentService, logService);
// Delete any existing backups completely and then re-create it.
return pfs.del(untitledWorkspacesHomePath, os.tmpdir()).then(() => {
return pfs.rimraf(untitledWorkspacesHomePath, pfs.RimRafMode.MOVE).then(() => {
return pfs.mkdirp(untitledWorkspacesHomePath);
});
});
teardown(() => {
return pfs.del(untitledWorkspacesHomePath, os.tmpdir());
return pfs.rimraf(untitledWorkspacesHomePath, pfs.RimRafMode.MOVE);
});
function assertPathEquals(p1: string, p2: string): void {