Merge from vscode 6e530127a1bb8ffbd1bfb77dc680c321dc0d71f5 (#6844)

This commit is contained in:
Anthony Dresser
2019-08-20 21:07:47 -07:00
committed by GitHub
parent 1f00249646
commit ecb80f14f0
221 changed files with 3140 additions and 1552 deletions

View File

@@ -99,6 +99,10 @@ export const enum ConfigurationScope {
* Resource specific configuration, which can be configured in the user, workspace or folder settings.
*/
RESOURCE,
/**
* Machine specific configuration that can also be configured in workspace or folder settings.
*/
MACHINE_OVERRIDABLE,
}
export interface IConfigurationPropertySchema extends IJSONSchema {

View File

@@ -20,7 +20,7 @@ export class DownloadService implements IDownloadService {
) { }
async download(resource: URI, target: URI, cancellationToken: CancellationToken = CancellationToken.None): Promise<void> {
if (resource.scheme === Schemas.file) {
if (resource.scheme === Schemas.file || resource.scheme === Schemas.vscodeRemote) {
await this.fileService.copy(resource, target);
return;
}

View File

@@ -199,6 +199,7 @@ export interface IExtensionManagementService {
zip(extension: ILocalExtension): Promise<URI>;
unzip(zipLocation: URI, type: ExtensionType): Promise<IExtensionIdentifier>;
getManifest(vsix: URI): Promise<IExtensionManifest>;
install(vsix: URI): Promise<ILocalExtension>;
installFromGallery(extension: IGalleryExtension): Promise<ILocalExtension>;
uninstall(extension: ILocalExtension, force?: boolean): Promise<void>;

View File

@@ -9,7 +9,7 @@ import { Event } from 'vs/base/common/event';
import { URI, UriComponents } from 'vs/base/common/uri';
import { IURITransformer, DefaultURITransformer, transformAndReviveIncomingURIs } from 'vs/base/common/uriIpc';
import { cloneAndChange } from 'vs/base/common/objects';
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
import { ExtensionType, IExtensionManifest } from 'vs/platform/extensions/common/extensions';
function transformIncomingURI(uri: UriComponents, transformer: IURITransformer | null): URI {
return URI.revive(transformer ? transformer.transformIncoming(uri) : uri);
@@ -62,6 +62,7 @@ export class ExtensionManagementChannel implements IServerChannel {
case 'zip': return this.service.zip(transformIncomingExtension(args[0], uriTransformer)).then(uri => transformOutgoingURI(uri, uriTransformer));
case 'unzip': return this.service.unzip(transformIncomingURI(args[0], uriTransformer), args[1]);
case 'install': return this.service.install(transformIncomingURI(args[0], uriTransformer));
case 'getManifest': return this.service.getManifest(transformIncomingURI(args[0], uriTransformer));
case 'installFromGallery': return this.service.installFromGallery(args[0]);
case 'uninstall': return this.service.uninstall(transformIncomingExtension(args[0], uriTransformer), args[1]);
case 'reinstallFromGallery': return this.service.reinstallFromGallery(transformIncomingExtension(args[0], uriTransformer));
@@ -99,6 +100,10 @@ export class ExtensionManagementChannelClient implements IExtensionManagementSer
return Promise.resolve(this.channel.call<ILocalExtension>('install', [vsix])).then(local => transformIncomingExtension(local, null));
}
getManifest(vsix: URI): Promise<IExtensionManifest> {
return Promise.resolve(this.channel.call<IExtensionManifest>('getManifest', [vsix]));
}
installFromGallery(extension: IGalleryExtension): Promise<ILocalExtension> {
return Promise.resolve(this.channel.call<ILocalExtension>('installFromGallery', [extension])).then(local => transformIncomingExtension(local, null));
}

View File

@@ -164,6 +164,12 @@ export class ExtensionManagementService extends Disposable implements IExtension
return this.install(zipLocation, type).then(local => local.identifier);
}
async getManifest(vsix: URI): Promise<IExtensionManifest> {
const downloadLocation = await this.downloadVsix(vsix);
const zipPath = path.resolve(downloadLocation.fsPath);
return getManifest(zipPath);
}
private collectFiles(extension: ILocalExtension): Promise<IFile[]> {
const collectFilesFromDirectory = async (dir: string): Promise<string[]> => {

View File

@@ -71,7 +71,7 @@ export function restoreRecentlyOpened(data: RecentlyOpenedStorageData | undefine
result.workspaces.push({ folderUri: URI.file(workspace) });
} else if (isLegacySerializedWorkspace(workspace)) {
result.workspaces.push({ workspace: { id: workspace.id, configPath: URI.file(workspace.configPath) } });
} else if (isUriComponents(window)) {
} else if (isUriComponents(workspace)) {
// added by 1.26-insiders
result.workspaces.push({ folderUri: URI.revive(<UriComponents>workspace) });
}

View File

@@ -8,6 +8,7 @@ import { ILogService } from 'vs/platform/log/common/log';
import { AbstractLifecycleService } from 'vs/platform/lifecycle/common/lifecycleService';
import { localize } from 'vs/nls';
import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
import { addDisposableListener, EventType } from 'vs/base/browser/dom';
export class BrowserLifecycleService extends AbstractLifecycleService {
@@ -22,10 +23,10 @@ export class BrowserLifecycleService extends AbstractLifecycleService {
}
private registerListeners(): void {
window.onbeforeunload = () => this.beforeUnload();
addDisposableListener(window, EventType.BEFORE_UNLOAD, () => this.onBeforeUnload());
}
private beforeUnload(): string | null {
private onBeforeUnload(): string | null {
let veto = false;
// Before Shutdown
@@ -34,7 +35,7 @@ export class BrowserLifecycleService extends AbstractLifecycleService {
if (value === true) {
veto = true;
} else if (value instanceof Promise && !veto) {
console.warn(new Error('Long running onBeforeShutdown currently not supported'));
console.warn(new Error('Long running onBeforeShutdown currently not supported in the web'));
veto = true;
}
},
@@ -49,11 +50,14 @@ export class BrowserLifecycleService extends AbstractLifecycleService {
// No Veto: continue with Will Shutdown
this._onWillShutdown.fire({
join() {
console.warn(new Error('Long running onWillShutdown currently not supported'));
console.warn(new Error('Long running onWillShutdown currently not supported in the web'));
},
reason: ShutdownReason.QUIT
});
// Finally end with Shutdown event
this._onShutdown.fire();
return null;
}
}

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { IChannel } from 'vs/base/parts/ipc/common/ipc';
import { IMenubarService, IMenubarData } from 'vs/platform/menubar/common/menubar';
import { IMenubarService, IMenubarData } from 'vs/platform/menubar/node/menubar';
import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService';
import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';

View File

@@ -17,7 +17,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
import { mnemonicMenuLabel as baseMnemonicLabel } from 'vs/base/common/labels';
import { IWindowsMainService, IWindowsCountChangedEvent } from 'vs/platform/windows/electron-main/windows';
import { IHistoryMainService } from 'vs/platform/history/common/history';
import { IMenubarData, IMenubarKeybinding, MenubarMenuItem, isMenubarMenuItemSeparator, isMenubarMenuItemSubmenu, isMenubarMenuItemAction, IMenubarMenu, isMenubarMenuItemUriAction } from 'vs/platform/menubar/common/menubar';
import { IMenubarData, IMenubarKeybinding, MenubarMenuItem, isMenubarMenuItemSeparator, isMenubarMenuItemSubmenu, isMenubarMenuItemAction, IMenubarMenu, isMenubarMenuItemUriAction } from 'vs/platform/menubar/node/menubar';
import { URI } from 'vs/base/common/uri';
import { IStateService } from 'vs/platform/state/common/state';
import { ILifecycleService } from 'vs/platform/lifecycle/electron-main/lifecycleMain';

View File

@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IMenubarService, IMenubarData } from 'vs/platform/menubar/common/menubar';
import { IMenubarService, IMenubarData } from 'vs/platform/menubar/node/menubar';
import { Menubar } from 'vs/platform/menubar/electron-main/menubar';
import { ILogService } from 'vs/platform/log/common/log';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { IServerChannel } from 'vs/base/parts/ipc/common/ipc';
import { IMenubarService } from 'vs/platform/menubar/common/menubar';
import { IMenubarService } from 'vs/platform/menubar/node/menubar';
import { Event } from 'vs/base/common/event';
export class MenubarChannel implements IServerChannel {

View File

@@ -11,6 +11,7 @@ export const IOpenerService = createDecorator<IOpenerService>('openerService');
export interface IOpener {
open(resource: URI, options?: { openToSide?: boolean }): Promise<boolean>;
open(resource: URI, options?: { openExternal?: boolean }): Promise<boolean>;
}
export interface IOpenerService {
@@ -29,18 +30,11 @@ export interface IOpenerService {
* @return A promise that resolves when the opening is done.
*/
open(resource: URI, options?: { openToSide?: boolean }): Promise<boolean>;
/**
* Opens a URL externally.
*
* @param url A resource to open externally.
*/
openExternal(resource: URI): Promise<boolean>;
open(resource: URI, options?: { openExternal?: boolean }): Promise<boolean>;
}
export const NullOpenerService: IOpenerService = Object.freeze({
_serviceBrand: undefined,
registerOpener() { return { dispose() { } }; },
open() { return Promise.resolve(false); },
openExternal() { return Promise.resolve(false); }
});

View File

@@ -37,7 +37,7 @@ export class BrowserStorageService extends Disposable implements IStorageService
private workspaceStorageFile: URI;
private initializePromise: Promise<void>;
private periodicSaveScheduler = this._register(new RunOnceScheduler(() => this.saveState(), 5000));
private periodicSaveScheduler = this._register(new RunOnceScheduler(() => this.collectState(), 5000));
get hasPendingUpdate(): boolean {
return this.globalStorageDatabase.hasPendingUpdate || this.workspaceStorageDatabase.hasPendingUpdate;
@@ -57,14 +57,19 @@ export class BrowserStorageService extends Disposable implements IStorageService
this.periodicSaveScheduler.schedule();
}
private saveState(): void {
private collectState(): void {
runWhenIdle(() => {
// this event will potentially cause new state to be stored
// since new state will only be created while the document
// has focus, one optimization is to not run this when the
// document has no focus, assuming that state has not changed
if (document.hasFocus()) {
//
// another optimization is to not collect more state if we
// have a pending update already running which indicates
// that the connection is either slow or disconnected and
// thus unhealthy.
if (document.hasFocus() && !this.hasPendingUpdate) {
this._onWillSaveState.fire({ reason: WillSaveStateReason.NONE });
}
@@ -197,7 +202,7 @@ export class FileStorageDatabase extends Disposable implements IStorageDatabase
this._register(this.fileService.watch(this.file));
this._register(this.fileService.onFileChanges(e => {
if (document.hasFocus()) {
return; // ignore changes from ourselves by checking for focus
return; // optimization: ignore changes from ourselves by checking for focus
}
if (!e.contains(this.file, FileChangeType.UPDATED)) {
@@ -251,15 +256,17 @@ export class FileStorageDatabase extends Disposable implements IStorageDatabase
await this.pendingUpdate;
this._hasPendingUpdate = true;
this.pendingUpdate = (async () => {
try {
this._hasPendingUpdate = true;
await this.fileService.writeFile(this.file, VSBuffer.fromString(JSON.stringify(mapToSerializable(items))));
this.pendingUpdate = this.fileService.writeFile(this.file, VSBuffer.fromString(JSON.stringify(mapToSerializable(items))))
.then(() => {
this.ensureWatching(); // now that the file must exist, ensure we watch it for changes
})
.finally(() => {
} finally {
this._hasPendingUpdate = false;
});
}
})();
return this.pendingUpdate;
}

View File

@@ -5,7 +5,7 @@
import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc';
import { Event, Emitter } from 'vs/base/common/event';
import { StorageMainService, IStorageChangeEvent } from 'vs/platform/storage/node/storageMainService';
import { IStorageChangeEvent, IStorageMainService } from 'vs/platform/storage/node/storageMainService';
import { IUpdateRequest, IStorageDatabase, IStorageItemsChangeEvent } from 'vs/base/parts/storage/common/storage';
import { mapToSerializable, serializableToMap, values } from 'vs/base/common/map';
import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle';
@@ -38,7 +38,7 @@ export class GlobalStorageDatabaseChannel extends Disposable implements IServerC
constructor(
private logService: ILogService,
private storageMainService: StorageMainService
private storageMainService: IStorageMainService
) {
super();
@@ -203,4 +203,4 @@ export class GlobalStorageDatabaseChannelClient extends Disposable implements IS
dispose(this.onDidChangeItemsOnMainListener);
}
}
}

View File

@@ -34,6 +34,16 @@ export interface IStorageMainService {
*/
readonly onWillSaveState: Event<void>;
/**
* Access to all cached items of this storage service.
*/
readonly items: Map<string, string>;
/**
* Required call to ensure the service can be used.
*/
initialize(): Promise<void>;
/**
* Retrieve an element stored with the given key from storage. Use
* the provided defaultValue if the element is null or undefined.

View File

@@ -16,18 +16,19 @@ import { cleanRemoteAuthority } from 'vs/platform/telemetry/common/telemetryUtil
export async function resolveWorkbenchCommonProperties(storageService: IStorageService, commit: string | undefined, version: string | undefined, machineId: string, remoteAuthority?: string): Promise<{ [name: string]: string | undefined }> {
const result: { [name: string]: string | undefined; } = Object.create(null);
const instanceId = storageService.get(instanceStorageKey, StorageScope.GLOBAL)!;
const firstSessionDate = storageService.get(firstSessionDateStorageKey, StorageScope.GLOBAL)!;
const lastSessionDate = storageService.get(lastSessionDateStorageKey, StorageScope.GLOBAL)!;
/**
* Note: In the web, session date information is fetched from browser storage, so these dates are tied to a specific
* browser and not the machine overall.
*/
// __GDPR__COMMON__ "common.firstSessionDate" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
result['common.firstSessionDate'] = firstSessionDate;
// __GDPR__COMMON__ "common.lastSessionDate" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
result['common.lastSessionDate'] = lastSessionDate || '';
// __GDPR__COMMON__ "common.isNewSession" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
result['common.isNewSession'] = !lastSessionDate ? '1' : '0';
// __GDPR__COMMON__ "common.instanceId" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
result['common.instanceId'] = instanceId;
// __GDPR__COMMON__ "common.remoteAuthority" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }
result['common.remoteAuthority'] = cleanRemoteAuthority(remoteAuthority);

View File

@@ -27,12 +27,16 @@ export class RelayURLService extends URLService implements IURLHandler {
openerService.registerOpener(this);
}
async open(uri: URI): Promise<boolean> {
if (uri.scheme !== product.urlProtocol) {
async open(resource: URI, options?: { openToSide?: boolean, openExternal?: boolean }): Promise<boolean> {
if (options && options.openExternal) {
return false;
}
return await this.urlService.open(uri);
if (resource.scheme !== product.urlProtocol) {
return false;
}
return await this.urlService.open(resource);
}
handleURL(uri: URI): Promise<boolean> {

View File

@@ -240,6 +240,8 @@ export interface IWindowService {
closeWorkspace(): Promise<void>;
updateTouchBar(items: ISerializableCommandAction[][]): Promise<void>;
enterWorkspace(path: URI): Promise<IEnterWorkspaceResult | undefined>;
// rationale: will eventually move to electron-browser
// tslint:disable-next-line: no-dom-globals
toggleFullScreen(target?: HTMLElement): Promise<void>;
setRepresentedFilename(fileName: string): Promise<void>;
getRecentlyOpened(): Promise<IRecentlyOpened>;

View File

@@ -343,11 +343,12 @@ suite('WorkspacesMainService', () => {
const untitledTwo = await createWorkspace([os.tmpdir(), process.cwd()]);
assert.ok(fs.existsSync(untitledTwo.configPath.fsPath));
assert.ok(fs.existsSync(untitledOne.configPath.fsPath), `Unexpected workspaces count of 1 (expected 2): ${untitledOne.configPath.fsPath} does not exist anymore?`);
const untitledHome = dirname(dirname(untitledTwo.configPath));
const beforeGettingUntitledWorkspaces = fs.readdirSync(untitledHome.fsPath).map(name => fs.readFileSync(joinPath(untitledHome, name, 'workspace.json').fsPath, 'utf8'));
untitled = service.getUntitledWorkspacesSync();
assert.ok(fs.existsSync(untitledOne.configPath.fsPath), `Unexpected workspaces count of 1 (expected 2): ${untitledOne.configPath.fsPath} does not exist anymore?`);
if (untitled.length === 1) {
const untitledHome = dirname(dirname(untitledTwo.configPath));
assert.fail(`Unexpected workspaces count of 1 (expected 2), all workspaces:\n ${fs.readdirSync(untitledHome.fsPath).map(name => fs.readFileSync(joinPath(untitledHome, name, 'workspace.json').fsPath, 'utf8'))}`);
assert.fail(`Unexpected workspaces count of 1 (expected 2), all workspaces:\n ${fs.readdirSync(untitledHome.fsPath).map(name => fs.readFileSync(joinPath(untitledHome, name, 'workspace.json').fsPath, 'utf8'))}, before getUntitledWorkspacesSync: ${beforeGettingUntitledWorkspaces}`);
}
assert.equal(2, untitled.length);