mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-28 04:23:32 +01:00
move mainThread[A-F], #70319
This commit is contained in:
30
src/vs/workbench/api/browser/mainThreadClipboard.ts
Normal file
30
src/vs/workbench/api/browser/mainThreadClipboard.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { MainContext, MainThreadClipboardShape } from '../common/extHost.protocol';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadClipboard)
|
||||
export class MainThreadCommands implements MainThreadClipboardShape {
|
||||
|
||||
constructor(
|
||||
_context: any,
|
||||
@IClipboardService private readonly _clipboardService: IClipboardService,
|
||||
) { }
|
||||
|
||||
dispose(): void {
|
||||
// nothing
|
||||
}
|
||||
|
||||
$readText(): Promise<string> {
|
||||
return Promise.resolve(this._clipboardService.readText());
|
||||
}
|
||||
|
||||
$writeText(value: string): Promise<void> {
|
||||
this._clipboardService.writeText(value);
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
105
src/vs/workbench/api/browser/mainThreadCommands.ts
Normal file
105
src/vs/workbench/api/browser/mainThreadCommands.ts
Normal file
@@ -0,0 +1,105 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ICommandService, CommandsRegistry, ICommandHandlerDescription } from 'vs/platform/commands/common/commands';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { ExtHostContext, MainThreadCommandsShape, ExtHostCommandsShape, MainContext, IExtHostContext } from '../common/extHost.protocol';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { revive } from 'vs/base/common/marshalling';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadCommands)
|
||||
export class MainThreadCommands implements MainThreadCommandsShape {
|
||||
|
||||
private readonly _disposables = new Map<string, IDisposable>();
|
||||
private readonly _generateCommandsDocumentationRegistration: IDisposable;
|
||||
private readonly _proxy: ExtHostCommandsShape;
|
||||
|
||||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
@ICommandService private readonly _commandService: ICommandService,
|
||||
) {
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostCommands);
|
||||
|
||||
this._generateCommandsDocumentationRegistration = CommandsRegistry.registerCommand('_generateCommandsDocumentation', () => this._generateCommandsDocumentation());
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this._disposables.forEach(value => value.dispose());
|
||||
this._disposables.clear();
|
||||
|
||||
this._generateCommandsDocumentationRegistration.dispose();
|
||||
}
|
||||
|
||||
private _generateCommandsDocumentation(): Promise<void> {
|
||||
return this._proxy.$getContributedCommandHandlerDescriptions().then(result => {
|
||||
// add local commands
|
||||
const commands = CommandsRegistry.getCommands();
|
||||
for (let id in commands) {
|
||||
let { description } = commands[id];
|
||||
if (description) {
|
||||
result[id] = description;
|
||||
}
|
||||
}
|
||||
|
||||
// print all as markdown
|
||||
const all: string[] = [];
|
||||
for (let id in result) {
|
||||
all.push('`' + id + '` - ' + _generateMarkdown(result[id]));
|
||||
}
|
||||
console.log(all.join('\n'));
|
||||
});
|
||||
}
|
||||
|
||||
$registerCommand(id: string): void {
|
||||
this._disposables.set(
|
||||
id,
|
||||
CommandsRegistry.registerCommand(id, (accessor, ...args) => {
|
||||
return this._proxy.$executeContributedCommand(id, ...args).then(result => {
|
||||
return revive(result, 0);
|
||||
});
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
$unregisterCommand(id: string): void {
|
||||
const command = this._disposables.get(id);
|
||||
if (command) {
|
||||
command.dispose();
|
||||
this._disposables.delete(id);
|
||||
}
|
||||
}
|
||||
|
||||
$executeCommand<T>(id: string, args: any[]): Promise<T | undefined> {
|
||||
for (let i = 0; i < args.length; i++) {
|
||||
args[i] = revive(args[i], 0);
|
||||
}
|
||||
return this._commandService.executeCommand<T>(id, ...args);
|
||||
}
|
||||
|
||||
$getCommands(): Promise<string[]> {
|
||||
return Promise.resolve(Object.keys(CommandsRegistry.getCommands()));
|
||||
}
|
||||
}
|
||||
|
||||
// --- command doc
|
||||
|
||||
function _generateMarkdown(description: string | ICommandHandlerDescription): string {
|
||||
if (typeof description === 'string') {
|
||||
return description;
|
||||
} else {
|
||||
const parts = [description.description];
|
||||
parts.push('\n\n');
|
||||
if (description.args) {
|
||||
for (let arg of description.args) {
|
||||
parts.push(`* _${arg.name}_ - ${arg.description || ''}\n`);
|
||||
}
|
||||
}
|
||||
if (description.returns) {
|
||||
parts.push(`* _(returns)_ - ${description.returns}`);
|
||||
}
|
||||
parts.push('\n\n');
|
||||
return parts.join('');
|
||||
}
|
||||
}
|
||||
90
src/vs/workbench/api/browser/mainThreadConfiguration.ts
Normal file
90
src/vs/workbench/api/browser/mainThreadConfiguration.ts
Normal file
@@ -0,0 +1,90 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope, getScopes } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
|
||||
import { MainThreadConfigurationShape, MainContext, ExtHostContext, IExtHostContext, IWorkspaceConfigurationChangeEventData, IConfigurationInitData } from '../common/extHost.protocol';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { ConfigurationTarget, IConfigurationChangeEvent, IConfigurationModel, IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadConfiguration)
|
||||
export class MainThreadConfiguration implements MainThreadConfigurationShape {
|
||||
|
||||
private readonly _configurationListener: IDisposable;
|
||||
|
||||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
@IWorkspaceContextService private readonly _workspaceContextService: IWorkspaceContextService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@IEnvironmentService private readonly _environmentService: IEnvironmentService,
|
||||
) {
|
||||
const proxy = extHostContext.getProxy(ExtHostContext.ExtHostConfiguration);
|
||||
|
||||
proxy.$initializeConfiguration(this._getConfigurationData());
|
||||
this._configurationListener = configurationService.onDidChangeConfiguration(e => {
|
||||
proxy.$acceptConfigurationChanged(this._getConfigurationData(), this.toConfigurationChangeEventData(e));
|
||||
});
|
||||
}
|
||||
|
||||
private _getConfigurationData(): IConfigurationInitData {
|
||||
const configurationData: IConfigurationInitData = { ...(this.configurationService.getConfigurationData()!), configurationScopes: {} };
|
||||
// Send configurations scopes only in development mode.
|
||||
if (!this._environmentService.isBuilt || this._environmentService.isExtensionDevelopment) {
|
||||
configurationData.configurationScopes = getScopes();
|
||||
}
|
||||
return configurationData;
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this._configurationListener.dispose();
|
||||
}
|
||||
|
||||
$updateConfigurationOption(target: ConfigurationTarget | null, key: string, value: any, resourceUriComponenets: UriComponents | undefined): Promise<void> {
|
||||
const resource = resourceUriComponenets ? URI.revive(resourceUriComponenets) : null;
|
||||
return this.writeConfiguration(target, key, value, resource);
|
||||
}
|
||||
|
||||
$removeConfigurationOption(target: ConfigurationTarget | null, key: string, resourceUriComponenets: UriComponents | undefined): Promise<void> {
|
||||
const resource = resourceUriComponenets ? URI.revive(resourceUriComponenets) : null;
|
||||
return this.writeConfiguration(target, key, undefined, resource);
|
||||
}
|
||||
|
||||
private writeConfiguration(target: ConfigurationTarget | null, key: string, value: any, resource: URI | null): Promise<void> {
|
||||
target = target !== null && target !== undefined ? target : this.deriveConfigurationTarget(key, resource);
|
||||
return this.configurationService.updateValue(key, value, { resource }, target, true);
|
||||
}
|
||||
|
||||
private deriveConfigurationTarget(key: string, resource: URI | null): ConfigurationTarget {
|
||||
if (resource && this._workspaceContextService.getWorkbenchState() === WorkbenchState.WORKSPACE) {
|
||||
const configurationProperties = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration).getConfigurationProperties();
|
||||
if (configurationProperties[key] && configurationProperties[key].scope === ConfigurationScope.RESOURCE) {
|
||||
return ConfigurationTarget.WORKSPACE_FOLDER;
|
||||
}
|
||||
}
|
||||
return ConfigurationTarget.WORKSPACE;
|
||||
}
|
||||
|
||||
private toConfigurationChangeEventData(event: IConfigurationChangeEvent): IWorkspaceConfigurationChangeEventData {
|
||||
return {
|
||||
changedConfiguration: this.toJSONConfiguration(event.changedConfiguration),
|
||||
changedConfigurationByResource: event.changedConfigurationByResource.keys().reduce((result, resource) => {
|
||||
result[resource.toString()] = this.toJSONConfiguration(event.changedConfigurationByResource.get(resource));
|
||||
return result;
|
||||
}, Object.create({}))
|
||||
};
|
||||
}
|
||||
|
||||
private toJSONConfiguration({ contents, keys, overrides }: IConfigurationModel = { contents: {}, keys: [], overrides: [] }): IConfigurationModel {
|
||||
return {
|
||||
contents,
|
||||
keys,
|
||||
overrides
|
||||
};
|
||||
}
|
||||
}
|
||||
126
src/vs/workbench/api/browser/mainThreadDecorations.ts
Normal file
126
src/vs/workbench/api/browser/mainThreadDecorations.ts
Normal file
@@ -0,0 +1,126 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { ExtHostContext, MainContext, IExtHostContext, MainThreadDecorationsShape, ExtHostDecorationsShape, DecorationData, DecorationRequest } from '../common/extHost.protocol';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { IDecorationsService, IDecorationData } from 'vs/workbench/services/decorations/browser/decorations';
|
||||
import { values } from 'vs/base/common/collections';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
|
||||
class DecorationRequestsQueue {
|
||||
|
||||
private _idPool = 0;
|
||||
private _requests: { [id: number]: DecorationRequest } = Object.create(null);
|
||||
private _resolver: { [id: number]: (data: DecorationData) => any } = Object.create(null);
|
||||
|
||||
private _timer: any;
|
||||
|
||||
constructor(
|
||||
private readonly _proxy: ExtHostDecorationsShape
|
||||
) {
|
||||
//
|
||||
}
|
||||
|
||||
enqueue(handle: number, uri: URI, token: CancellationToken): Promise<DecorationData> {
|
||||
const id = ++this._idPool;
|
||||
const result = new Promise<DecorationData>(resolve => {
|
||||
this._requests[id] = { id, handle, uri };
|
||||
this._resolver[id] = resolve;
|
||||
this._processQueue();
|
||||
});
|
||||
token.onCancellationRequested(() => {
|
||||
delete this._requests[id];
|
||||
delete this._resolver[id];
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
private _processQueue(): void {
|
||||
if (typeof this._timer === 'number') {
|
||||
// already queued
|
||||
return;
|
||||
}
|
||||
this._timer = setTimeout(() => {
|
||||
// make request
|
||||
const requests = this._requests;
|
||||
const resolver = this._resolver;
|
||||
this._proxy.$provideDecorations(values(requests), CancellationToken.None).then(data => {
|
||||
for (const id in resolver) {
|
||||
resolver[id](data[id]);
|
||||
}
|
||||
});
|
||||
|
||||
// reset
|
||||
this._requests = [];
|
||||
this._resolver = [];
|
||||
this._timer = undefined;
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadDecorations)
|
||||
export class MainThreadDecorations implements MainThreadDecorationsShape {
|
||||
|
||||
private readonly _provider = new Map<number, [Emitter<URI[]>, IDisposable]>();
|
||||
private readonly _proxy: ExtHostDecorationsShape;
|
||||
private readonly _requestQueue: DecorationRequestsQueue;
|
||||
|
||||
constructor(
|
||||
context: IExtHostContext,
|
||||
@IDecorationsService private readonly _decorationsService: IDecorationsService
|
||||
) {
|
||||
this._proxy = context.getProxy(ExtHostContext.ExtHostDecorations);
|
||||
this._requestQueue = new DecorationRequestsQueue(this._proxy);
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this._provider.forEach(value => dispose(value));
|
||||
this._provider.clear();
|
||||
}
|
||||
|
||||
$registerDecorationProvider(handle: number, label: string): void {
|
||||
const emitter = new Emitter<URI[]>();
|
||||
const registration = this._decorationsService.registerDecorationsProvider({
|
||||
label,
|
||||
onDidChange: emitter.event,
|
||||
provideDecorations: (uri, token) => {
|
||||
return this._requestQueue.enqueue(handle, uri, token).then(data => {
|
||||
if (!data) {
|
||||
return undefined;
|
||||
}
|
||||
const [weight, bubble, tooltip, letter, themeColor, source] = data;
|
||||
return <IDecorationData>{
|
||||
weight: weight || 0,
|
||||
bubble: bubble || false,
|
||||
color: themeColor && themeColor.id,
|
||||
tooltip,
|
||||
letter,
|
||||
source,
|
||||
};
|
||||
});
|
||||
}
|
||||
});
|
||||
this._provider.set(handle, [emitter, registration]);
|
||||
}
|
||||
|
||||
$onDidChange(handle: number, resources: UriComponents[]): void {
|
||||
const provider = this._provider.get(handle);
|
||||
if (provider) {
|
||||
const [emitter] = provider;
|
||||
emitter.fire(resources && resources.map(URI.revive));
|
||||
}
|
||||
}
|
||||
|
||||
$unregisterDecorationProvider(handle: number): void {
|
||||
const provider = this._provider.get(handle);
|
||||
if (provider) {
|
||||
dispose(provider);
|
||||
this._provider.delete(handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
49
src/vs/workbench/api/browser/mainThreadDiagnostics.ts
Normal file
49
src/vs/workbench/api/browser/mainThreadDiagnostics.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IMarkerService, IMarkerData } from 'vs/platform/markers/common/markers';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { MainThreadDiagnosticsShape, MainContext, IExtHostContext } from '../common/extHost.protocol';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadDiagnostics)
|
||||
export class MainThreadDiagnostics implements MainThreadDiagnosticsShape {
|
||||
|
||||
private readonly _activeOwners = new Set<string>();
|
||||
private readonly _markerService: IMarkerService;
|
||||
|
||||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
@IMarkerService markerService: IMarkerService
|
||||
) {
|
||||
this._markerService = markerService;
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this._activeOwners.forEach(owner => this._markerService.changeAll(owner, []));
|
||||
}
|
||||
|
||||
$changeMany(owner: string, entries: [UriComponents, IMarkerData[]][]): void {
|
||||
for (let entry of entries) {
|
||||
let [uri, markers] = entry;
|
||||
if (markers) {
|
||||
for (const marker of markers) {
|
||||
if (marker.relatedInformation) {
|
||||
for (const relatedInformation of marker.relatedInformation) {
|
||||
relatedInformation.resource = URI.revive(relatedInformation.resource);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this._markerService.changeOne(owner, URI.revive(uri), markers);
|
||||
}
|
||||
this._activeOwners.add(owner);
|
||||
}
|
||||
|
||||
$clear(owner: string): void {
|
||||
this._markerService.changeAll(owner, []);
|
||||
this._activeOwners.delete(owner);
|
||||
}
|
||||
}
|
||||
60
src/vs/workbench/api/browser/mainThreadDialogs.ts
Normal file
60
src/vs/workbench/api/browser/mainThreadDialogs.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { MainThreadDiaglogsShape, MainContext, IExtHostContext, MainThreadDialogOpenOptions, MainThreadDialogSaveOptions } from '../common/extHost.protocol';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { forEach } from 'vs/base/common/collections';
|
||||
import { IFileDialogService, IOpenDialogOptions, ISaveDialogOptions } from 'vs/platform/dialogs/common/dialogs';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadDialogs)
|
||||
export class MainThreadDialogs implements MainThreadDiaglogsShape {
|
||||
|
||||
constructor(
|
||||
context: IExtHostContext,
|
||||
@IFileDialogService private readonly _fileDialogService: IFileDialogService,
|
||||
) {
|
||||
//
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
//
|
||||
}
|
||||
|
||||
$showOpenDialog(options: MainThreadDialogOpenOptions): Promise<URI[] | undefined> {
|
||||
return Promise.resolve(this._fileDialogService.showOpenDialog(MainThreadDialogs._convertOpenOptions(options)));
|
||||
}
|
||||
|
||||
$showSaveDialog(options: MainThreadDialogSaveOptions): Promise<URI | undefined> {
|
||||
return Promise.resolve(this._fileDialogService.showSaveDialog(MainThreadDialogs._convertSaveOptions(options)));
|
||||
}
|
||||
|
||||
private static _convertOpenOptions(options: MainThreadDialogOpenOptions): IOpenDialogOptions {
|
||||
const result: IOpenDialogOptions = {
|
||||
openLabel: options.openLabel,
|
||||
canSelectFiles: options.canSelectFiles || (!options.canSelectFiles && !options.canSelectFolders),
|
||||
canSelectFolders: options.canSelectFolders,
|
||||
canSelectMany: options.canSelectMany,
|
||||
defaultUri: URI.revive(options.defaultUri)
|
||||
};
|
||||
if (options.filters) {
|
||||
result.filters = [];
|
||||
forEach(options.filters, entry => result.filters!.push({ name: entry.key, extensions: entry.value }));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static _convertSaveOptions(options: MainThreadDialogSaveOptions): ISaveDialogOptions {
|
||||
const result: ISaveDialogOptions = {
|
||||
defaultUri: URI.revive(options.defaultUri),
|
||||
saveLabel: options.saveLabel
|
||||
};
|
||||
if (options.filters) {
|
||||
result.filters = [];
|
||||
forEach(options.filters, entry => result.filters!.push({ name: entry.key, extensions: entry.value }));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { EditOperation } from 'vs/editor/common/core/editOperation';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { ITextModelService } from 'vs/editor/common/services/resolverService';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { ExtHostContext, ExtHostDocumentContentProvidersShape, IExtHostContext, MainContext, MainThreadDocumentContentProvidersShape } from '../common/extHost.protocol';
|
||||
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadDocumentContentProviders)
|
||||
export class MainThreadDocumentContentProviders implements MainThreadDocumentContentProvidersShape {
|
||||
|
||||
private readonly _resourceContentProvider = new Map<number, IDisposable>();
|
||||
private readonly _pendingUpdate = new Map<string, CancellationTokenSource>();
|
||||
private readonly _proxy: ExtHostDocumentContentProvidersShape;
|
||||
|
||||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
@ITextModelService private readonly _textModelResolverService: ITextModelService,
|
||||
@IModeService private readonly _modeService: IModeService,
|
||||
@IModelService private readonly _modelService: IModelService,
|
||||
@IEditorWorkerService private readonly _editorWorkerService: IEditorWorkerService
|
||||
) {
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostDocumentContentProviders);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this._resourceContentProvider.forEach(p => p.dispose());
|
||||
this._pendingUpdate.forEach(source => source.dispose());
|
||||
}
|
||||
|
||||
$registerTextContentProvider(handle: number, scheme: string): void {
|
||||
const registration = this._textModelResolverService.registerTextModelContentProvider(scheme, {
|
||||
provideTextContent: (uri: URI): Promise<ITextModel | undefined> => {
|
||||
return this._proxy.$provideTextDocumentContent(handle, uri).then(value => {
|
||||
if (typeof value === 'string') {
|
||||
const firstLineText = value.substr(0, 1 + value.search(/\r?\n/));
|
||||
const languageSelection = this._modeService.createByFilepathOrFirstLine(uri.fsPath, firstLineText);
|
||||
return this._modelService.createModel(value, languageSelection, uri);
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
}
|
||||
});
|
||||
this._resourceContentProvider.set(handle, registration);
|
||||
}
|
||||
|
||||
$unregisterTextContentProvider(handle: number): void {
|
||||
const registration = this._resourceContentProvider.get(handle);
|
||||
if (registration) {
|
||||
registration.dispose();
|
||||
this._resourceContentProvider.delete(handle);
|
||||
}
|
||||
}
|
||||
|
||||
$onVirtualDocumentChange(uri: UriComponents, value: string): void {
|
||||
const model = this._modelService.getModel(URI.revive(uri));
|
||||
if (!model) {
|
||||
return;
|
||||
}
|
||||
|
||||
// cancel and dispose an existing update
|
||||
const pending = this._pendingUpdate.get(model.id);
|
||||
if (pending) {
|
||||
pending.cancel();
|
||||
}
|
||||
|
||||
// create and keep update token
|
||||
const myToken = new CancellationTokenSource();
|
||||
this._pendingUpdate.set(model.id, myToken);
|
||||
|
||||
this._editorWorkerService.computeMoreMinimalEdits(model.uri, [{ text: value, range: model.getFullModelRange() }]).then(edits => {
|
||||
// remove token
|
||||
this._pendingUpdate.delete(model.id);
|
||||
|
||||
if (myToken.token.isCancellationRequested) {
|
||||
// ignore this
|
||||
return;
|
||||
}
|
||||
if (edits && edits.length > 0) {
|
||||
// use the evil-edit as these models show in readonly-editor only
|
||||
model.applyEdits(edits.map(edit => EditOperation.replace(Range.lift(edit.range), edit.text)));
|
||||
}
|
||||
}).catch(onUnexpectedError);
|
||||
}
|
||||
}
|
||||
27
src/vs/workbench/api/browser/mainThreadErrors.ts
Normal file
27
src/vs/workbench/api/browser/mainThreadErrors.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { SerializedError, onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { MainContext, MainThreadErrorsShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadErrors)
|
||||
export class MainThreadErrors implements MainThreadErrorsShape {
|
||||
|
||||
dispose(): void {
|
||||
//
|
||||
}
|
||||
|
||||
$onUnexpectedError(err: any | SerializedError): void {
|
||||
if (err && err.$isError) {
|
||||
const { name, message, stack } = err;
|
||||
err = new Error();
|
||||
err.message = message;
|
||||
err.name = name;
|
||||
err.stack = stack;
|
||||
}
|
||||
onUnexpectedError(err);
|
||||
}
|
||||
}
|
||||
164
src/vs/workbench/api/browser/mainThreadFileSystem.ts
Normal file
164
src/vs/workbench/api/browser/mainThreadFileSystem.ts
Normal file
@@ -0,0 +1,164 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { FileWriteOptions, FileSystemProviderCapabilities, IFileChange, IFileService, IFileSystemProvider, IStat, IWatchOptions, FileType, FileOverwriteOptions, FileDeleteOptions, FileOpenOptions } from 'vs/platform/files/common/files';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { ExtHostContext, ExtHostFileSystemShape, IExtHostContext, IFileChangeDto, MainContext, MainThreadFileSystemShape } from '../common/extHost.protocol';
|
||||
import { ResourceLabelFormatter, ILabelService } from 'vs/platform/label/common/label';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadFileSystem)
|
||||
export class MainThreadFileSystem implements MainThreadFileSystemShape {
|
||||
|
||||
private readonly _proxy: ExtHostFileSystemShape;
|
||||
private readonly _fileProvider = new Map<number, RemoteFileSystemProvider>();
|
||||
private readonly _resourceLabelFormatters = new Map<number, IDisposable>();
|
||||
|
||||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
@IFileService private readonly _fileService: IFileService,
|
||||
@ILabelService private readonly _labelService: ILabelService
|
||||
) {
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostFileSystem);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this._fileProvider.forEach(value => value.dispose());
|
||||
this._fileProvider.clear();
|
||||
}
|
||||
|
||||
$registerFileSystemProvider(handle: number, scheme: string, capabilities: FileSystemProviderCapabilities): void {
|
||||
this._fileProvider.set(handle, new RemoteFileSystemProvider(this._fileService, scheme, capabilities, handle, this._proxy));
|
||||
}
|
||||
|
||||
$unregisterProvider(handle: number): void {
|
||||
dispose(this._fileProvider.get(handle));
|
||||
this._fileProvider.delete(handle);
|
||||
}
|
||||
|
||||
$registerResourceLabelFormatter(handle: number, formatter: ResourceLabelFormatter): void {
|
||||
// Dynamicily registered formatters should have priority over those contributed via package.json
|
||||
formatter.priority = true;
|
||||
const disposable = this._labelService.registerFormatter(formatter);
|
||||
this._resourceLabelFormatters.set(handle, disposable);
|
||||
}
|
||||
|
||||
$unregisterResourceLabelFormatter(handle: number): void {
|
||||
dispose(this._resourceLabelFormatters.get(handle));
|
||||
this._resourceLabelFormatters.delete(handle);
|
||||
}
|
||||
|
||||
$onFileSystemChange(handle: number, changes: IFileChangeDto[]): void {
|
||||
const fileProvider = this._fileProvider.get(handle);
|
||||
if (!fileProvider) {
|
||||
throw new Error('Unknown file provider');
|
||||
}
|
||||
fileProvider.$onFileSystemChange(changes);
|
||||
}
|
||||
}
|
||||
|
||||
class RemoteFileSystemProvider implements IFileSystemProvider {
|
||||
|
||||
private readonly _onDidChange = new Emitter<IFileChange[]>();
|
||||
private readonly _registration: IDisposable;
|
||||
|
||||
readonly onDidChangeFile: Event<IFileChange[]> = this._onDidChange.event;
|
||||
|
||||
readonly capabilities: FileSystemProviderCapabilities;
|
||||
readonly onDidChangeCapabilities: Event<void> = Event.None;
|
||||
|
||||
constructor(
|
||||
fileService: IFileService,
|
||||
scheme: string,
|
||||
capabilities: FileSystemProviderCapabilities,
|
||||
private readonly _handle: number,
|
||||
private readonly _proxy: ExtHostFileSystemShape
|
||||
) {
|
||||
this.capabilities = capabilities;
|
||||
this._registration = fileService.registerProvider(scheme, this);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this._registration.dispose();
|
||||
this._onDidChange.dispose();
|
||||
}
|
||||
|
||||
watch(resource: URI, opts: IWatchOptions) {
|
||||
const session = Math.random();
|
||||
this._proxy.$watch(this._handle, session, resource, opts);
|
||||
return toDisposable(() => {
|
||||
this._proxy.$unwatch(this._handle, session);
|
||||
});
|
||||
}
|
||||
|
||||
$onFileSystemChange(changes: IFileChangeDto[]): void {
|
||||
this._onDidChange.fire(changes.map(RemoteFileSystemProvider._createFileChange));
|
||||
}
|
||||
|
||||
private static _createFileChange(dto: IFileChangeDto): IFileChange {
|
||||
return { resource: URI.revive(dto.resource), type: dto.type };
|
||||
}
|
||||
|
||||
// --- forwarding calls
|
||||
|
||||
private static _asBuffer(data: Uint8Array): Buffer {
|
||||
return Buffer.isBuffer(data) ? data : Buffer.from(data.buffer, data.byteOffset, data.byteLength);
|
||||
}
|
||||
|
||||
stat(resource: URI): Promise<IStat> {
|
||||
return this._proxy.$stat(this._handle, resource).then(undefined, err => {
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
|
||||
readFile(resource: URI): Promise<Uint8Array> {
|
||||
return this._proxy.$readFile(this._handle, resource);
|
||||
}
|
||||
|
||||
writeFile(resource: URI, content: Uint8Array, opts: FileWriteOptions): Promise<void> {
|
||||
return this._proxy.$writeFile(this._handle, resource, RemoteFileSystemProvider._asBuffer(content), opts);
|
||||
}
|
||||
|
||||
delete(resource: URI, opts: FileDeleteOptions): Promise<void> {
|
||||
return this._proxy.$delete(this._handle, resource, opts);
|
||||
}
|
||||
|
||||
mkdir(resource: URI): Promise<void> {
|
||||
return this._proxy.$mkdir(this._handle, resource);
|
||||
}
|
||||
|
||||
readdir(resource: URI): Promise<[string, FileType][]> {
|
||||
return this._proxy.$readdir(this._handle, resource);
|
||||
}
|
||||
|
||||
rename(resource: URI, target: URI, opts: FileOverwriteOptions): Promise<void> {
|
||||
return this._proxy.$rename(this._handle, resource, target, opts);
|
||||
}
|
||||
|
||||
copy(resource: URI, target: URI, opts: FileOverwriteOptions): Promise<void> {
|
||||
return this._proxy.$copy(this._handle, resource, target, opts);
|
||||
}
|
||||
|
||||
open(resource: URI, opts: FileOpenOptions): Promise<number> {
|
||||
return this._proxy.$open(this._handle, resource, opts);
|
||||
}
|
||||
|
||||
close(fd: number): Promise<void> {
|
||||
return this._proxy.$close(this._handle, fd);
|
||||
}
|
||||
|
||||
read(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise<number> {
|
||||
return this._proxy.$read(this._handle, fd, pos, length).then(readData => {
|
||||
data.set(readData, offset);
|
||||
return readData.byteLength;
|
||||
});
|
||||
}
|
||||
|
||||
write(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise<number> {
|
||||
return this._proxy.$write(this._handle, fd, pos, Buffer.from(data, offset, length));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { FileChangeType, IFileService, FileOperation } from 'vs/platform/files/common/files';
|
||||
import { extHostCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { ExtHostContext, FileSystemEvents, IExtHostContext } from '../common/extHost.protocol';
|
||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
|
||||
@extHostCustomer
|
||||
export class MainThreadFileSystemEventService {
|
||||
|
||||
private readonly _listener = new Array<IDisposable>();
|
||||
|
||||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
@IFileService fileService: IFileService,
|
||||
@ITextFileService textfileService: ITextFileService,
|
||||
) {
|
||||
|
||||
const proxy = extHostContext.getProxy(ExtHostContext.ExtHostFileSystemEventService);
|
||||
|
||||
// file system events - (changes the editor and other make)
|
||||
const events: FileSystemEvents = {
|
||||
created: [],
|
||||
changed: [],
|
||||
deleted: []
|
||||
};
|
||||
fileService.onFileChanges(event => {
|
||||
for (let change of event.changes) {
|
||||
switch (change.type) {
|
||||
case FileChangeType.ADDED:
|
||||
events.created.push(change.resource);
|
||||
break;
|
||||
case FileChangeType.UPDATED:
|
||||
events.changed.push(change.resource);
|
||||
break;
|
||||
case FileChangeType.DELETED:
|
||||
events.deleted.push(change.resource);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
proxy.$onFileEvent(events);
|
||||
events.created.length = 0;
|
||||
events.changed.length = 0;
|
||||
events.deleted.length = 0;
|
||||
}, undefined, this._listener);
|
||||
|
||||
// file operation events - (changes the editor makes)
|
||||
fileService.onAfterOperation(e => {
|
||||
if (e.operation === FileOperation.MOVE) {
|
||||
proxy.$onFileRename(e.resource, e.target!.resource);
|
||||
}
|
||||
}, undefined, this._listener);
|
||||
|
||||
textfileService.onWillMove(e => {
|
||||
const promise = proxy.$onWillRename(e.oldResource, e.newResource);
|
||||
e.waitUntil(promise);
|
||||
}, undefined, this._listener);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
dispose(this._listener);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user