mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-13 03:28:33 -05:00
Merge from vscode 2b0b9136329c181a9e381463a1f7dc3a2d105a34 (#4880)
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 () {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
44
src/vs/platform/diagnostics/common/diagnosticsService.ts
Normal file
44
src/vs/platform/diagnostics/common/diagnosticsService.ts
Normal 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;
|
||||
}
|
||||
@@ -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
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
167
src/vs/platform/diagnostics/node/diagnosticsService.ts
Normal file
167
src/vs/platform/diagnostics/node/diagnosticsService.ts
Normal 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);
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -36,6 +36,6 @@ export class ExtensionsManifestCache extends Disposable {
|
||||
}
|
||||
|
||||
invalidate(): void {
|
||||
pfs.del(this.extensionsManifestCache).then(() => { }, () => { });
|
||||
pfs.rimraf(this.extensionsManifestCache, pfs.RimRafMode.MOVE).then(() => { }, () => { });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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';
|
||||
@@ -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>;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -106,6 +106,7 @@ suite('AbstractKeybindingService', () => {
|
||||
_serviceBrand: undefined,
|
||||
dispose: undefined!,
|
||||
onDidChangeContext: undefined!,
|
||||
bufferChangeEvents() { },
|
||||
createKey: undefined!,
|
||||
contextMatchesRules: undefined!,
|
||||
getContextKeyValue: undefined!,
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -311,6 +311,6 @@ export class LaunchService implements ILaunchService {
|
||||
pid: win.webContents.getOSProcessId(),
|
||||
title: win.getTitle(),
|
||||
folderURIs
|
||||
} as IWindowInfo;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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`);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
@@ -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" }
|
||||
|
||||
@@ -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}}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user