mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-03 01:25:38 -05:00
Merge VS Code 1.21 source code (#1067)
* Initial VS Code 1.21 file copy with patches * A few more merges * Post npm install * Fix batch of build breaks * Fix more build breaks * Fix more build errors * Fix more build breaks * Runtime fixes 1 * Get connection dialog working with some todos * Fix a few packaging issues * Copy several node_modules to package build to fix loader issues * Fix breaks from master * A few more fixes * Make tests pass * First pass of license header updates * Second pass of license header updates * Fix restore dialog issues * Remove add additional themes menu items * fix select box issues where the list doesn't show up * formatting * Fix editor dispose issue * Copy over node modules to correct location on all platforms
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
'use strict';
|
||||
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { ProxyIdentifier } from 'vs/workbench/services/thread/common/threadService';
|
||||
import { ProxyIdentifier } from 'vs/workbench/services/extensions/node/proxyIdentifier';
|
||||
import { IConstructorSignature1 } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IExtHostContext } from 'vs/workbench/api/node/extHost.protocol';
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
|
||||
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
|
||||
// --- other interested parties
|
||||
import { JSONValidationExtensionPoint } from 'vs/platform/jsonschemas/common/jsonValidationExtensionPoint';
|
||||
import { ColorExtensionPoint } from 'vs/platform/theme/common/colorExtensionPoint';
|
||||
import { JSONValidationExtensionPoint } from 'vs/workbench/services/jsonschemas/common/jsonValidationExtensionPoint';
|
||||
import { ColorExtensionPoint } from 'vs/workbench/services/themes/common/colorExtensionPoint';
|
||||
import { LanguageConfigurationFileHandler } from 'vs/workbench/parts/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint';
|
||||
|
||||
// --- mainThread participants
|
||||
@@ -49,6 +49,8 @@ import './mainThreadTask';
|
||||
import './mainThreadTelemetry';
|
||||
import './mainThreadTerminalService';
|
||||
import './mainThreadTreeViews';
|
||||
import './mainThreadLogService';
|
||||
import './mainThreadWebview';
|
||||
import './mainThreadWindow';
|
||||
import './mainThreadWorkspace';
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { ExtHostContext, MainThreadCommandsShape, ExtHostCommandsShape, MainContext, IExtHostContext } from '../node/extHost.protocol';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
|
||||
import { revive } from 'vs/base/common/marshalling';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadCommands)
|
||||
export class MainThreadCommands implements MainThreadCommandsShape {
|
||||
@@ -21,7 +22,7 @@ export class MainThreadCommands implements MainThreadCommandsShape {
|
||||
extHostContext: IExtHostContext,
|
||||
@ICommandService private readonly _commandService: ICommandService,
|
||||
) {
|
||||
this._proxy = extHostContext.get(ExtHostContext.ExtHostCommands);
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostCommands);
|
||||
|
||||
this._generateCommandsDocumentationRegistration = CommandsRegistry.registerCommand('_generateCommandsDocumentation', () => this._generateCommandsDocumentation());
|
||||
}
|
||||
@@ -33,7 +34,7 @@ export class MainThreadCommands implements MainThreadCommandsShape {
|
||||
this._generateCommandsDocumentationRegistration.dispose();
|
||||
}
|
||||
|
||||
private _generateCommandsDocumentation(): TPromise<void> {
|
||||
private _generateCommandsDocumentation(): Thenable<void> {
|
||||
return this._proxy.$getContributedCommandHandlerDescriptions().then(result => {
|
||||
// add local commands
|
||||
const commands = CommandsRegistry.getCommands();
|
||||
@@ -53,23 +54,28 @@ export class MainThreadCommands implements MainThreadCommandsShape {
|
||||
});
|
||||
}
|
||||
|
||||
$registerCommand(id: string): TPromise<any> {
|
||||
$registerCommand(id: string): void {
|
||||
this._disposables.set(
|
||||
id,
|
||||
CommandsRegistry.registerCommand(id, (accessor, ...args) => this._proxy.$executeContributedCommand(id, ...args))
|
||||
CommandsRegistry.registerCommand(id, (accessor, ...args) => {
|
||||
return this._proxy.$executeContributedCommand(id, ...args).then(result => {
|
||||
return revive(result, 0);
|
||||
});
|
||||
})
|
||||
);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
$unregisterCommand(id: string): TPromise<any> {
|
||||
$unregisterCommand(id: string): void {
|
||||
if (this._disposables.has(id)) {
|
||||
this._disposables.get(id).dispose();
|
||||
this._disposables.delete(id);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
$executeCommand<T>(id: string, args: any[]): Thenable<T> {
|
||||
for (let i = 0; i < args.length; i++) {
|
||||
args[i] = revive(args[i], 0);
|
||||
}
|
||||
return this._commandService.executeCommand<T>(id, ...args);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import URI from 'vs/base/common/uri';
|
||||
import URI, { UriComponents } from 'vs/base/common/uri';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
@@ -13,7 +13,7 @@ import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/
|
||||
import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration';
|
||||
import { MainThreadConfigurationShape, MainContext, ExtHostContext, IExtHostContext, IWorkspaceConfigurationChangeEventData } from '../node/extHost.protocol';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
|
||||
import { ConfigurationTarget, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration';
|
||||
import { ConfigurationTarget, IConfigurationChangeEvent, IConfigurationModel } from 'vs/platform/configuration/common/configuration';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadConfiguration)
|
||||
export class MainThreadConfiguration implements MainThreadConfigurationShape {
|
||||
@@ -25,7 +25,7 @@ export class MainThreadConfiguration implements MainThreadConfigurationShape {
|
||||
@IWorkspaceContextService private readonly _workspaceContextService: IWorkspaceContextService,
|
||||
@IWorkspaceConfigurationService private configurationService: IWorkspaceConfigurationService
|
||||
) {
|
||||
const proxy = extHostContext.get(ExtHostContext.ExtHostConfiguration);
|
||||
const proxy = extHostContext.getProxy(ExtHostContext.ExtHostConfiguration);
|
||||
|
||||
this._configurationListener = configurationService.onDidChangeConfiguration(e => {
|
||||
proxy.$acceptConfigurationChanged(configurationService.getConfigurationData(), this.toConfigurationChangeEventData(e));
|
||||
@@ -36,11 +36,13 @@ export class MainThreadConfiguration implements MainThreadConfigurationShape {
|
||||
this._configurationListener.dispose();
|
||||
}
|
||||
|
||||
$updateConfigurationOption(target: ConfigurationTarget, key: string, value: any, resource: URI): TPromise<void> {
|
||||
$updateConfigurationOption(target: ConfigurationTarget, key: string, value: any, resourceUriComponenets: UriComponents): TPromise<void> {
|
||||
const resource = resourceUriComponenets ? URI.revive(resourceUriComponenets) : null;
|
||||
return this.writeConfiguration(target, key, value, resource);
|
||||
}
|
||||
|
||||
$removeConfigurationOption(target: ConfigurationTarget, key: string, resource: URI): TPromise<void> {
|
||||
$removeConfigurationOption(target: ConfigurationTarget, key: string, resourceUriComponenets: UriComponents): TPromise<void> {
|
||||
const resource = resourceUriComponenets ? URI.revive(resourceUriComponenets) : null;
|
||||
return this.writeConfiguration(target, key, undefined, resource);
|
||||
}
|
||||
|
||||
@@ -61,11 +63,19 @@ export class MainThreadConfiguration implements MainThreadConfigurationShape {
|
||||
|
||||
private toConfigurationChangeEventData(event: IConfigurationChangeEvent): IWorkspaceConfigurationChangeEventData {
|
||||
return {
|
||||
changedConfiguration: event.changedConfiguration,
|
||||
changedConfiguration: this.toJSONConfiguration(event.changedConfiguration),
|
||||
changedConfigurationByResource: event.changedConfigurationByResource.keys().reduce((result, resource) => {
|
||||
result[resource.toString()] = event.changedConfigurationByResource.get(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
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,12 +6,15 @@
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
/*
|
||||
import URI from 'vs/base/common/uri';
|
||||
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { IDebugService, IConfig, IDebugConfigurationProvider } from 'vs/workbench/parts/debug/common/debug';
|
||||
import uri from 'vs/base/common/uri';
|
||||
import { IDebugService, IConfig, IDebugConfigurationProvider, IBreakpoint, IFunctionBreakpoint, IBreakpointData } from 'vs/workbench/parts/debug/common/debug';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { ExtHostContext, ExtHostDebugServiceShape, MainThreadDebugServiceShape, DebugSessionUUID, MainContext, IExtHostContext, IBreakpointsDelta, ISourceBreakpointData, IFunctionBreakpointData } from '../node/extHost.protocol';
|
||||
import {
|
||||
ExtHostContext, ExtHostDebugServiceShape, MainThreadDebugServiceShape, DebugSessionUUID, MainContext,
|
||||
IExtHostContext, IBreakpointsDeltaDto, ISourceMultiBreakpointDto, ISourceBreakpointDto, IFunctionBreakpointDto
|
||||
} from '../node/extHost.protocol';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
|
||||
import severity from 'vs/base/common/severity';
|
||||
|
||||
@@ -24,10 +27,9 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape {
|
||||
|
||||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
@IDebugService private debugService: IDebugService,
|
||||
@IWorkspaceContextService private contextService: IWorkspaceContextService,
|
||||
@IDebugService private debugService: IDebugService
|
||||
) {
|
||||
this._proxy = extHostContext.get(ExtHostContext.ExtHostDebugService);
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostDebugService);
|
||||
this._toDispose = [];
|
||||
this._toDispose.push(debugService.onDidNewProcess(proc => this._proxy.$acceptDebugSessionStarted(<DebugSessionUUID>proc.getId(), proc.configuration.type, proc.getName(false))));
|
||||
this._toDispose.push(debugService.onDidEndProcess(proc => this._proxy.$acceptDebugSessionTerminated(<DebugSessionUUID>proc.getId(), proc.configuration.type, proc.getName(false))));
|
||||
@@ -61,15 +63,15 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape {
|
||||
// set up a handler to send more
|
||||
this._toDispose.push(this.debugService.getModel().onDidChangeBreakpoints(e => {
|
||||
if (e) {
|
||||
const delta: IBreakpointsDelta = {};
|
||||
const delta: IBreakpointsDeltaDto = {};
|
||||
if (e.added) {
|
||||
delta.added = this.toWire(e.added);
|
||||
delta.added = this.convertToDto(e.added);
|
||||
}
|
||||
if (e.removed) {
|
||||
delta.removed = e.removed.map(x => x.getId());
|
||||
}
|
||||
if (e.changed) {
|
||||
delta.changed = this.toWire(e.changed);
|
||||
delta.changed = this.convertToDto(e.changed);
|
||||
}
|
||||
|
||||
if (delta.added || delta.removed || delta.changed) {
|
||||
@@ -83,7 +85,7 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape {
|
||||
const fbps = this.debugService.getModel().getFunctionBreakpoints();
|
||||
if (bps.length > 0 || fbps.length > 0) {
|
||||
this._proxy.$acceptBreakpointsDelta({
|
||||
added: this.toWire(bps).concat(this.toWire(fbps))
|
||||
added: this.convertToDto(bps).concat(this.convertToDto(fbps))
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -91,15 +93,42 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape {
|
||||
return TPromise.wrap<void>(undefined);
|
||||
}
|
||||
|
||||
private toWire(bps: (IBreakpoint | IFunctionBreakpoint)[]): (ISourceBreakpointData | IFunctionBreakpointData)[] {
|
||||
public $registerBreakpoints(DTOs: (ISourceMultiBreakpointDto | IFunctionBreakpointDto)[]): TPromise<void> {
|
||||
|
||||
for (let dto of DTOs) {
|
||||
if (dto.type === 'sourceMulti') {
|
||||
const rawbps = dto.lines.map(l =>
|
||||
<IBreakpointData>{
|
||||
id: l.id,
|
||||
enabled: l.enabled,
|
||||
lineNumber: l.line + 1,
|
||||
column: l.character > 0 ? l.character + 1 : 0,
|
||||
condition: l.condition,
|
||||
hitCondition: l.hitCondition
|
||||
}
|
||||
);
|
||||
this.debugService.addBreakpoints(uri.revive(dto.uri), rawbps);
|
||||
} else if (dto.type === 'function') {
|
||||
this.debugService.addFunctionBreakpoint(dto.functionName, dto.id);
|
||||
}
|
||||
}
|
||||
return void 0;
|
||||
}
|
||||
|
||||
public $unregisterBreakpoints(breakpointIds: string[], functionBreakpointIds: string[]): TPromise<void> {
|
||||
breakpointIds.forEach(id => this.debugService.removeBreakpoints(id));
|
||||
functionBreakpointIds.forEach(id => this.debugService.removeFunctionBreakpoints(id));
|
||||
return void 0;
|
||||
}
|
||||
|
||||
private convertToDto(bps: (IBreakpoint | IFunctionBreakpoint)[]): (ISourceBreakpointDto | IFunctionBreakpointDto)[] {
|
||||
return bps.map(bp => {
|
||||
if ('name' in bp) {
|
||||
const fbp = <IFunctionBreakpoint>bp;
|
||||
return <IFunctionBreakpointData>{
|
||||
return <IFunctionBreakpointDto>{
|
||||
type: 'function',
|
||||
id: bp.getId(),
|
||||
enabled: bp.enabled,
|
||||
id: fbp.getId(),
|
||||
enabled: fbp.enabled,
|
||||
functionName: fbp.name,
|
||||
hitCondition: bp.hitCondition,
|
||||
// {{SQL CARBON EDIT}}
|
||||
@@ -107,21 +136,21 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape {
|
||||
};
|
||||
} else {
|
||||
const sbp = <IBreakpoint>bp;
|
||||
return <ISourceBreakpointData>{
|
||||
return <ISourceBreakpointDto>{
|
||||
type: 'source',
|
||||
id: bp.getId(),
|
||||
enabled: bp.enabled,
|
||||
id: sbp.getId(),
|
||||
enabled: sbp.enabled,
|
||||
condition: sbp.condition,
|
||||
hitCondition: bp.hitCondition,
|
||||
hitCondition: sbp.hitCondition,
|
||||
uri: sbp.uri,
|
||||
line: sbp.lineNumber > 0 ? sbp.lineNumber - 1 : 0,
|
||||
character: (typeof sbp.column === 'number' && sbp.column > 0) ? sbp.column - 1 : 0
|
||||
character: (typeof sbp.column === 'number' && sbp.column > 0) ? sbp.column - 1 : 0,
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public $registerDebugConfigurationProvider(debugType: string, hasProvide: boolean, hasResolve: boolean, handle: number): TPromise<void> {
|
||||
public $registerDebugConfigurationProvider(debugType: string, hasProvide: boolean, hasResolve: boolean, hasDebugAdapterExecutable: boolean, handle: number): TPromise<void> {
|
||||
|
||||
const provider = <IDebugConfigurationProvider>{
|
||||
type: debugType
|
||||
@@ -136,6 +165,11 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape {
|
||||
return this._proxy.$resolveDebugConfiguration(handle, folder, debugConfiguration);
|
||||
};
|
||||
}
|
||||
if (hasDebugAdapterExecutable) {
|
||||
provider.debugAdapterExecutable = (folder) => {
|
||||
return this._proxy.$debugAdapterExecutable(handle, folder);
|
||||
};
|
||||
}
|
||||
this.debugService.getConfigurationManager().registerDebugConfigurationProvider(handle, provider);
|
||||
|
||||
return TPromise.wrap<void>(undefined);
|
||||
@@ -146,9 +180,10 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape {
|
||||
return TPromise.wrap<void>(undefined);
|
||||
}
|
||||
|
||||
public $startDebugging(folderUri: uri | undefined, nameOrConfiguration: string | IConfig): TPromise<boolean> {
|
||||
const folder = folderUri ? this.contextService.getWorkspace().folders.filter(wf => wf.uri.toString() === folderUri.toString()).pop() : undefined;
|
||||
return this.debugService.startDebugging(folder, nameOrConfiguration).then(x => {
|
||||
public $startDebugging(_folderUri: uri | undefined, nameOrConfiguration: string | IConfig): TPromise<boolean> {
|
||||
const folderUri = _folderUri ? uri.revive(_folderUri) : undefined;
|
||||
const launch = this.debugService.getConfigurationManager().getLaunch(folderUri);
|
||||
return this.debugService.startDebugging(launch, nameOrConfiguration).then(x => {
|
||||
return true;
|
||||
}, err => {
|
||||
return TPromise.wrapError(err && err.message ? err.message : 'cannot start debugging');
|
||||
@@ -159,10 +194,10 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape {
|
||||
const process = this.debugService.getModel().getProcesses().filter(p => p.getId() === sessionId).pop();
|
||||
if (process) {
|
||||
return process.session.custom(request, args).then(response => {
|
||||
if (response.success) {
|
||||
if (response && response.success) {
|
||||
return response.body;
|
||||
} else {
|
||||
return TPromise.wrapError(new Error(response.message));
|
||||
return TPromise.wrapError(new Error(response ? response.message : 'custom request failed'));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -4,24 +4,72 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import URI from 'vs/base/common/uri';
|
||||
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 } from '../node/extHost.protocol';
|
||||
import { ExtHostContext, MainContext, IExtHostContext, MainThreadDecorationsShape, ExtHostDecorationsShape, DecorationData, DecorationRequest } from '../node/extHost.protocol';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
|
||||
import { IDecorationsService, IDecorationData } from 'vs/workbench/services/decorations/browser/decorations';
|
||||
|
||||
class DecorationRequestsQueue {
|
||||
|
||||
private _idPool = 0;
|
||||
private _requests: DecorationRequest[] = [];
|
||||
private _resolver: { [id: number]: Function } = Object.create(null);
|
||||
|
||||
private _timer: number;
|
||||
|
||||
constructor(
|
||||
private _proxy: ExtHostDecorationsShape
|
||||
) {
|
||||
//
|
||||
}
|
||||
|
||||
enqueue(handle: number, uri: URI): Thenable<DecorationData> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const id = ++this._idPool;
|
||||
this._requests.push({ id, handle, uri });
|
||||
this._resolver[id] = resolve;
|
||||
this._processQueue();
|
||||
});
|
||||
}
|
||||
|
||||
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(requests).then(data => {
|
||||
for (const id in resolver) {
|
||||
resolver[id](data[id]);
|
||||
}
|
||||
});
|
||||
|
||||
// reset
|
||||
this._requests = [];
|
||||
this._resolver = [];
|
||||
this._timer = void 0;
|
||||
}, 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.get(ExtHostContext.ExtHostDecorations);
|
||||
this._proxy = context.getProxy(ExtHostContext.ExtHostDecorations);
|
||||
this._requestQueue = new DecorationRequestsQueue(this._proxy);
|
||||
}
|
||||
|
||||
dispose() {
|
||||
@@ -30,12 +78,12 @@ export class MainThreadDecorations implements MainThreadDecorationsShape {
|
||||
}
|
||||
|
||||
$registerDecorationProvider(handle: number, label: string): void {
|
||||
let emitter = new Emitter<URI[]>();
|
||||
let registration = this._decorationsService.registerDecorationsProvider({
|
||||
const emitter = new Emitter<URI[]>();
|
||||
const registration = this._decorationsService.registerDecorationsProvider({
|
||||
label,
|
||||
onDidChange: emitter.event,
|
||||
provideDecorations: (uri) => {
|
||||
return this._proxy.$providerDecorations(handle, uri).then(data => {
|
||||
return this._requestQueue.enqueue(handle, uri).then(data => {
|
||||
if (!data) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -54,9 +102,9 @@ export class MainThreadDecorations implements MainThreadDecorationsShape {
|
||||
this._provider.set(handle, [emitter, registration]);
|
||||
}
|
||||
|
||||
$onDidChange(handle: number, resources: URI[]): void {
|
||||
$onDidChange(handle: number, resources: UriComponents[]): void {
|
||||
const [emitter] = this._provider.get(handle);
|
||||
emitter.fire(resources);
|
||||
emitter.fire(resources && resources.map(URI.revive));
|
||||
}
|
||||
|
||||
$unregisterDecorationProvider(handle: number): void {
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
'use strict';
|
||||
|
||||
import { IMarkerService, IMarkerData } from 'vs/platform/markers/common/markers';
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import URI, { UriComponents } from 'vs/base/common/uri';
|
||||
import { MainThreadDiagnosticsShape, MainContext, IExtHostContext } from '../node/extHost.protocol';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
|
||||
|
||||
@@ -27,18 +26,16 @@ export class MainThreadDiagnostics implements MainThreadDiagnosticsShape {
|
||||
this._activeOwners.forEach(owner => this._markerService.changeAll(owner, undefined));
|
||||
}
|
||||
|
||||
$changeMany(owner: string, entries: [URI, IMarkerData[]][]): TPromise<any> {
|
||||
$changeMany(owner: string, entries: [UriComponents, IMarkerData[]][]): void {
|
||||
for (let entry of entries) {
|
||||
let [uri, markers] = entry;
|
||||
this._markerService.changeOne(owner, uri, markers);
|
||||
this._markerService.changeOne(owner, URI.revive(uri), markers);
|
||||
}
|
||||
this._activeOwners.add(owner);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
$clear(owner: string): TPromise<any> {
|
||||
$clear(owner: string): void {
|
||||
this._markerService.changeAll(owner, undefined);
|
||||
this._activeOwners.delete(owner);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { isFalsyOrEmpty } from 'vs/base/common/arrays';
|
||||
import { MainThreadDiaglogsShape, MainContext, IExtHostContext, MainThreadDialogOpenOptions, MainThreadDialogSaveOptions } from '../node/extHost.protocol';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
|
||||
@@ -25,30 +25,27 @@ export class MainThreadDialogs implements MainThreadDiaglogsShape {
|
||||
//
|
||||
}
|
||||
|
||||
$showOpenDialog(options: MainThreadDialogOpenOptions): TPromise<string[]> {
|
||||
$showOpenDialog(options: MainThreadDialogOpenOptions): Promise<string[]> {
|
||||
// TODO@joh what about remote dev setup?
|
||||
if (options.defaultUri && options.defaultUri.scheme !== 'file') {
|
||||
return TPromise.wrapError(new Error('Not supported - Open-dialogs can only be opened on `file`-uris.'));
|
||||
return <any>Promise.reject(new Error('Not supported - Open-dialogs can only be opened on `file`-uris.'));
|
||||
}
|
||||
return new TPromise<string[]>(resolve => {
|
||||
const filenames = this._windowService.showOpenDialog(
|
||||
return new Promise<string[]>(resolve => {
|
||||
this._windowService.showOpenDialog(
|
||||
MainThreadDialogs._convertOpenOptions(options)
|
||||
);
|
||||
|
||||
resolve(isFalsyOrEmpty(filenames) ? undefined : filenames);
|
||||
).then(filenames => resolve(isFalsyOrEmpty(filenames) ? undefined : filenames));
|
||||
});
|
||||
}
|
||||
|
||||
$showSaveDialog(options: MainThreadDialogSaveOptions): TPromise<string> {
|
||||
$showSaveDialog(options: MainThreadDialogSaveOptions): Promise<string> {
|
||||
// TODO@joh what about remote dev setup?
|
||||
if (options.defaultUri && options.defaultUri.scheme !== 'file') {
|
||||
return TPromise.wrapError(new Error('Not supported - Save-dialogs can only be opened on `file`-uris.'));
|
||||
return <any>Promise.reject(new Error('Not supported - Save-dialogs can only be opened on `file`-uris.'));
|
||||
}
|
||||
return new TPromise<string>(resolve => {
|
||||
const filename = this._windowService.showSaveDialog(
|
||||
return new Promise<string>(resolve => {
|
||||
this._windowService.showSaveDialog(
|
||||
MainThreadDialogs._convertSaveOptions(options)
|
||||
);
|
||||
resolve(!filename ? undefined : filename);
|
||||
).then(filename => resolve(!filename ? undefined : filename));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -60,7 +57,7 @@ export class MainThreadDialogs implements MainThreadDiaglogsShape {
|
||||
result.buttonLabel = options.openLabel;
|
||||
}
|
||||
if (options.defaultUri) {
|
||||
result.defaultPath = options.defaultUri.fsPath;
|
||||
result.defaultPath = URI.revive(options.defaultUri).fsPath;
|
||||
}
|
||||
if (!options.canSelectFiles && !options.canSelectFolders) {
|
||||
options.canSelectFiles = true;
|
||||
@@ -86,7 +83,7 @@ export class MainThreadDialogs implements MainThreadDiaglogsShape {
|
||||
|
||||
};
|
||||
if (options.defaultUri) {
|
||||
result.defaultPath = options.defaultUri.fsPath;
|
||||
result.defaultPath = URI.revive(options.defaultUri).fsPath;
|
||||
}
|
||||
if (options.saveLabel) {
|
||||
result.buttonLabel = options.saveLabel;
|
||||
|
||||
@@ -4,14 +4,14 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import URI from 'vs/base/common/uri';
|
||||
import URI, { UriComponents } from 'vs/base/common/uri';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { IModel } from 'vs/editor/common/editorCommon';
|
||||
import { ITextModel, DefaultEndOfLine } from 'vs/editor/common/model';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService';
|
||||
import { MainThreadDocumentContentProvidersShape, ExtHostContext, ExtHostDocumentContentProvidersShape, MainContext, IExtHostContext } from '../node/extHost.protocol';
|
||||
import { ITextSource } from 'vs/editor/common/model/textSource';
|
||||
import { createTextBuffer } from 'vs/editor/common/model/textModel';
|
||||
import { ITextModelService } from 'vs/editor/common/services/resolverService';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
@@ -31,7 +31,7 @@ export class MainThreadDocumentContentProviders implements MainThreadDocumentCon
|
||||
@ICodeEditorService codeEditorService: ICodeEditorService,
|
||||
@IEditorGroupService editorGroupService: IEditorGroupService
|
||||
) {
|
||||
this._proxy = extHostContext.get(ExtHostContext.ExtHostDocumentContentProviders);
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostDocumentContentProviders);
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
@@ -42,7 +42,7 @@ export class MainThreadDocumentContentProviders implements MainThreadDocumentCon
|
||||
|
||||
$registerTextContentProvider(handle: number, scheme: string): void {
|
||||
this._resourceContentProvider[handle] = this._textModelResolverService.registerTextModelContentProvider(scheme, {
|
||||
provideTextContent: (uri: URI): TPromise<IModel> => {
|
||||
provideTextContent: (uri: URI): TPromise<ITextModel> => {
|
||||
return this._proxy.$provideTextDocumentContent(handle, uri).then(value => {
|
||||
if (typeof value === 'string') {
|
||||
const firstLineText = value.substr(0, 1 + value.search(/\r?\n/));
|
||||
@@ -63,23 +63,16 @@ export class MainThreadDocumentContentProviders implements MainThreadDocumentCon
|
||||
}
|
||||
}
|
||||
|
||||
$onVirtualDocumentChange(uri: URI, value: ITextSource): void {
|
||||
const model = this._modelService.getModel(uri);
|
||||
$onVirtualDocumentChange(uri: UriComponents, value: string): void {
|
||||
const model = this._modelService.getModel(URI.revive(uri));
|
||||
if (!model) {
|
||||
return;
|
||||
}
|
||||
|
||||
const raw: ITextSource = {
|
||||
lines: value.lines,
|
||||
length: value.length,
|
||||
BOM: value.BOM,
|
||||
EOL: value.EOL,
|
||||
containsRTL: value.containsRTL,
|
||||
isBasicASCII: value.isBasicASCII,
|
||||
};
|
||||
const textBuffer = createTextBuffer(value, DefaultEndOfLine.CRLF);
|
||||
|
||||
if (!model.equals(raw)) {
|
||||
model.setValueFromTextSource(raw);
|
||||
if (!model.equalsTextBuffer(textBuffer)) {
|
||||
model.setValueFromTextBuffer(textBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import URI from 'vs/base/common/uri';
|
||||
import URI, { UriComponents } from 'vs/base/common/uri';
|
||||
import { toErrorMessage } from 'vs/base/common/errorMessage';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { IDisposable, dispose, IReference } from 'vs/base/common/lifecycle';
|
||||
@@ -16,8 +16,9 @@ import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/un
|
||||
import { ExtHostContext, MainThreadDocumentsShape, ExtHostDocumentsShape, IExtHostContext } from '../node/extHost.protocol';
|
||||
import { ITextModelService } from 'vs/editor/common/services/resolverService';
|
||||
import { MainThreadDocumentsAndEditors } from './mainThreadDocumentsAndEditors';
|
||||
import * as editorCommon from 'vs/editor/common/editorCommon';
|
||||
import { ITextEditorModel } from 'vs/workbench/common/editor';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
|
||||
export class BoundModelReferenceCollection {
|
||||
|
||||
@@ -93,7 +94,7 @@ export class MainThreadDocuments implements MainThreadDocumentsShape {
|
||||
this._fileService = fileService;
|
||||
this._untitledEditorService = untitledEditorService;
|
||||
|
||||
this._proxy = extHostContext.get(ExtHostContext.ExtHostDocuments);
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostDocuments);
|
||||
this._modelIsSynced = {};
|
||||
|
||||
this._toDispose = [];
|
||||
@@ -104,17 +105,17 @@ export class MainThreadDocuments implements MainThreadDocumentsShape {
|
||||
|
||||
this._toDispose.push(textFileService.models.onModelSaved(e => {
|
||||
if (this._shouldHandleFileEvent(e)) {
|
||||
this._proxy.$acceptModelSaved(e.resource.toString());
|
||||
this._proxy.$acceptModelSaved(e.resource);
|
||||
}
|
||||
}));
|
||||
this._toDispose.push(textFileService.models.onModelReverted(e => {
|
||||
if (this._shouldHandleFileEvent(e)) {
|
||||
this._proxy.$acceptDirtyStateChanged(e.resource.toString(), false);
|
||||
this._proxy.$acceptDirtyStateChanged(e.resource, false);
|
||||
}
|
||||
}));
|
||||
this._toDispose.push(textFileService.models.onModelDirty(e => {
|
||||
if (this._shouldHandleFileEvent(e)) {
|
||||
this._proxy.$acceptDirtyStateChanged(e.resource.toString(), true);
|
||||
this._proxy.$acceptDirtyStateChanged(e.resource, true);
|
||||
}
|
||||
}));
|
||||
|
||||
@@ -134,7 +135,7 @@ export class MainThreadDocuments implements MainThreadDocumentsShape {
|
||||
return model && !model.isTooLargeForHavingARichMode();
|
||||
}
|
||||
|
||||
private _onModelAdded(model: editorCommon.IModel): void {
|
||||
private _onModelAdded(model: ITextModel): void {
|
||||
// Same filter as in mainThreadEditorsTracker
|
||||
if (model.isTooLargeForHavingARichMode()) {
|
||||
// don't synchronize too large models
|
||||
@@ -143,47 +144,47 @@ export class MainThreadDocuments implements MainThreadDocumentsShape {
|
||||
let modelUrl = model.uri;
|
||||
this._modelIsSynced[modelUrl.toString()] = true;
|
||||
this._modelToDisposeMap[modelUrl.toString()] = model.onDidChangeContent((e) => {
|
||||
this._proxy.$acceptModelChanged(modelUrl.toString(), e, this._textFileService.isDirty(modelUrl));
|
||||
this._proxy.$acceptModelChanged(modelUrl, e, this._textFileService.isDirty(modelUrl));
|
||||
});
|
||||
}
|
||||
|
||||
private _onModelModeChanged(event: { model: editorCommon.IModel; oldModeId: string; }): void {
|
||||
private _onModelModeChanged(event: { model: ITextModel; oldModeId: string; }): void {
|
||||
let { model, oldModeId } = event;
|
||||
let modelUrl = model.uri;
|
||||
if (!this._modelIsSynced[modelUrl.toString()]) {
|
||||
return;
|
||||
}
|
||||
this._proxy.$acceptModelModeChanged(model.uri.toString(), oldModeId, model.getLanguageIdentifier().language);
|
||||
this._proxy.$acceptModelModeChanged(model.uri, oldModeId, model.getLanguageIdentifier().language);
|
||||
}
|
||||
|
||||
private _onModelRemoved(modelUrl: string): void {
|
||||
|
||||
if (!this._modelIsSynced[modelUrl]) {
|
||||
private _onModelRemoved(modelUrl: URI): void {
|
||||
let strModelUrl = modelUrl.toString();
|
||||
if (!this._modelIsSynced[strModelUrl]) {
|
||||
return;
|
||||
}
|
||||
delete this._modelIsSynced[modelUrl];
|
||||
this._modelToDisposeMap[modelUrl].dispose();
|
||||
delete this._modelToDisposeMap[modelUrl];
|
||||
delete this._modelIsSynced[strModelUrl];
|
||||
this._modelToDisposeMap[strModelUrl].dispose();
|
||||
delete this._modelToDisposeMap[strModelUrl];
|
||||
}
|
||||
|
||||
// --- from extension host process
|
||||
|
||||
$trySaveDocument(uri: URI): TPromise<boolean> {
|
||||
return this._textFileService.save(uri);
|
||||
$trySaveDocument(uri: UriComponents): TPromise<boolean> {
|
||||
return this._textFileService.save(URI.revive(uri));
|
||||
}
|
||||
|
||||
$tryOpenDocument(uri: URI): TPromise<any> {
|
||||
|
||||
$tryOpenDocument(_uri: UriComponents): TPromise<any> {
|
||||
const uri = URI.revive(_uri);
|
||||
if (!uri.scheme || !(uri.fsPath || uri.authority)) {
|
||||
return TPromise.wrapError(new Error(`Invalid uri. Scheme and authority or path must be set.`));
|
||||
}
|
||||
|
||||
let promise: TPromise<boolean>;
|
||||
switch (uri.scheme) {
|
||||
case 'untitled':
|
||||
case Schemas.untitled:
|
||||
promise = this._handleUnititledScheme(uri);
|
||||
break;
|
||||
case 'file':
|
||||
case Schemas.file:
|
||||
default:
|
||||
promise = this._handleAsResourceInput(uri);
|
||||
break;
|
||||
@@ -192,8 +193,11 @@ export class MainThreadDocuments implements MainThreadDocumentsShape {
|
||||
return promise.then(success => {
|
||||
if (!success) {
|
||||
return TPromise.wrapError(new Error('cannot open ' + uri.toString()));
|
||||
} else if (!this._modelIsSynced[uri.toString()]) {
|
||||
return TPromise.wrapError(new Error('cannot open ' + uri.toString() + '. Detail: Files above 50MB cannot be synchronized with extensions.'));
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
return undefined;
|
||||
}, err => {
|
||||
return TPromise.wrapError(new Error('cannot open ' + uri.toString() + '. Detail: ' + toErrorMessage(err)));
|
||||
});
|
||||
@@ -212,7 +216,7 @@ export class MainThreadDocuments implements MainThreadDocumentsShape {
|
||||
}
|
||||
|
||||
private _handleUnititledScheme(uri: URI): TPromise<boolean> {
|
||||
let asFileUri = uri.with({ scheme: 'file' });
|
||||
let asFileUri = uri.with({ scheme: Schemas.file });
|
||||
return this._fileService.resolveFile(asFileUri).then(stats => {
|
||||
// don't create a new file ontop of an existing file
|
||||
return TPromise.wrapError<boolean>(new Error('file already exists on disk'));
|
||||
@@ -227,7 +231,7 @@ export class MainThreadDocuments implements MainThreadDocumentsShape {
|
||||
throw new Error(`expected URI ${resource.toString()} to have come to LIFE`);
|
||||
}
|
||||
|
||||
this._proxy.$acceptDirtyStateChanged(resource.toString(), true); // mark as dirty
|
||||
this._proxy.$acceptDirtyStateChanged(resource, true); // mark as dirty
|
||||
|
||||
return resource;
|
||||
});
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
'use strict';
|
||||
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { IModel } from 'vs/editor/common/editorCommon';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
import Event, { Emitter } from 'vs/base/common/event';
|
||||
@@ -16,13 +16,14 @@ import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/edi
|
||||
import { Position as EditorPosition, IEditor } from 'vs/platform/editor/common/editor';
|
||||
import { extHostCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
|
||||
import { MainThreadDocuments } from 'vs/workbench/api/electron-browser/mainThreadDocuments';
|
||||
import { MainThreadEditors } from 'vs/workbench/api/electron-browser/mainThreadEditors';
|
||||
import { MainThreadTextEditors } from 'vs/workbench/api/electron-browser/mainThreadEditors';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { ITextModelService } from 'vs/editor/common/services/resolverService';
|
||||
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
|
||||
import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService';
|
||||
import { isCodeEditor, isDiffEditor, ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import URI from 'vs/base/common/uri';
|
||||
|
||||
namespace mapset {
|
||||
|
||||
@@ -76,7 +77,7 @@ namespace delta {
|
||||
}
|
||||
}
|
||||
|
||||
class EditorSnapshot {
|
||||
class TextEditorSnapshot {
|
||||
|
||||
readonly id: string;
|
||||
|
||||
@@ -92,10 +93,10 @@ class DocumentAndEditorStateDelta {
|
||||
readonly isEmpty: boolean;
|
||||
|
||||
constructor(
|
||||
readonly removedDocuments: IModel[],
|
||||
readonly addedDocuments: IModel[],
|
||||
readonly removedEditors: EditorSnapshot[],
|
||||
readonly addedEditors: EditorSnapshot[],
|
||||
readonly removedDocuments: ITextModel[],
|
||||
readonly addedDocuments: ITextModel[],
|
||||
readonly removedEditors: TextEditorSnapshot[],
|
||||
readonly addedEditors: TextEditorSnapshot[],
|
||||
readonly oldActiveEditor: string,
|
||||
readonly newActiveEditor: string,
|
||||
) {
|
||||
@@ -123,12 +124,12 @@ class DocumentAndEditorState {
|
||||
if (!before) {
|
||||
return new DocumentAndEditorStateDelta(
|
||||
[], mapset.setValues(after.documents),
|
||||
[], mapset.mapValues(after.editors),
|
||||
[], mapset.mapValues(after.textEditors),
|
||||
undefined, after.activeEditor
|
||||
);
|
||||
}
|
||||
const documentDelta = delta.ofSets(before.documents, after.documents);
|
||||
const editorDelta = delta.ofMaps(before.editors, after.editors);
|
||||
const editorDelta = delta.ofMaps(before.textEditors, after.textEditors);
|
||||
const oldActiveEditor = before.activeEditor !== after.activeEditor ? before.activeEditor : undefined;
|
||||
const newActiveEditor = before.activeEditor !== after.activeEditor ? after.activeEditor : undefined;
|
||||
|
||||
@@ -140,8 +141,8 @@ class DocumentAndEditorState {
|
||||
}
|
||||
|
||||
constructor(
|
||||
readonly documents: Set<IModel>,
|
||||
readonly editors: Map<string, EditorSnapshot>,
|
||||
readonly documents: Set<ITextModel>,
|
||||
readonly textEditors: Map<string, TextEditorSnapshot>,
|
||||
readonly activeEditor: string,
|
||||
) {
|
||||
//
|
||||
@@ -156,9 +157,9 @@ class MainThreadDocumentAndEditorStateComputer {
|
||||
|
||||
constructor(
|
||||
private readonly _onDidChangeState: (delta: DocumentAndEditorStateDelta) => void,
|
||||
@IModelService private _modelService: IModelService,
|
||||
@ICodeEditorService private _codeEditorService: ICodeEditorService,
|
||||
@IWorkbenchEditorService private _workbenchEditorService: IWorkbenchEditorService
|
||||
@IModelService private readonly _modelService: IModelService,
|
||||
@ICodeEditorService private readonly _codeEditorService: ICodeEditorService,
|
||||
@IWorkbenchEditorService private readonly _workbenchEditorService: IWorkbenchEditorService
|
||||
) {
|
||||
this._modelService.onModelAdded(this._updateStateOnModelAdd, this, this._toDispose);
|
||||
this._modelService.onModelRemoved(this._updateState, this, this._toDispose);
|
||||
@@ -190,7 +191,7 @@ class MainThreadDocumentAndEditorStateComputer {
|
||||
}
|
||||
}
|
||||
|
||||
private _updateStateOnModelAdd(model: IModel): void {
|
||||
private _updateStateOnModelAdd(model: ITextModel): void {
|
||||
if (model.isTooLargeForHavingARichMode()) {
|
||||
// ignore
|
||||
return;
|
||||
@@ -205,7 +206,7 @@ class MainThreadDocumentAndEditorStateComputer {
|
||||
// small (fast) delta
|
||||
this._currentState = new DocumentAndEditorState(
|
||||
this._currentState.documents.add(model),
|
||||
this._currentState.editors,
|
||||
this._currentState.textEditors,
|
||||
this._currentState.activeEditor
|
||||
);
|
||||
|
||||
@@ -219,7 +220,7 @@ class MainThreadDocumentAndEditorStateComputer {
|
||||
private _updateState(): void {
|
||||
|
||||
// models: ignore too large models
|
||||
const models = new Set<IModel>();
|
||||
const models = new Set<ITextModel>();
|
||||
for (const model of this._modelService.getModels()) {
|
||||
if (!model.isTooLargeForHavingARichMode()) {
|
||||
models.add(model);
|
||||
@@ -228,7 +229,7 @@ class MainThreadDocumentAndEditorStateComputer {
|
||||
|
||||
|
||||
// editor: only take those that have a not too large model
|
||||
const editors = new Map<string, EditorSnapshot>();
|
||||
const editors = new Map<string, TextEditorSnapshot>();
|
||||
let activeEditor: string = null;
|
||||
|
||||
for (const editor of this._codeEditorService.listCodeEditors()) {
|
||||
@@ -237,7 +238,7 @@ class MainThreadDocumentAndEditorStateComputer {
|
||||
&& !model.isDisposed() // model disposed
|
||||
&& Boolean(this._modelService.getModel(model.uri)) // model disposing, the flag didn't flip yet but the model service already removed it
|
||||
) {
|
||||
const apiEditor = new EditorSnapshot(editor);
|
||||
const apiEditor = new TextEditorSnapshot(editor);
|
||||
editors.set(apiEditor.id, apiEditor);
|
||||
if (editor.isFocused()) {
|
||||
activeEditor = apiEditor.id;
|
||||
@@ -284,23 +285,23 @@ export class MainThreadDocumentsAndEditors {
|
||||
private _toDispose: IDisposable[];
|
||||
private _proxy: ExtHostDocumentsAndEditorsShape;
|
||||
private _stateComputer: MainThreadDocumentAndEditorStateComputer;
|
||||
private _editors = <{ [id: string]: MainThreadTextEditor }>Object.create(null);
|
||||
private _textEditors = <{ [id: string]: MainThreadTextEditor }>Object.create(null);
|
||||
|
||||
private _onTextEditorAdd = new Emitter<MainThreadTextEditor[]>();
|
||||
private _onTextEditorRemove = new Emitter<string[]>();
|
||||
private _onDocumentAdd = new Emitter<IModel[]>();
|
||||
private _onDocumentRemove = new Emitter<string[]>();
|
||||
private _onDocumentAdd = new Emitter<ITextModel[]>();
|
||||
private _onDocumentRemove = new Emitter<URI[]>();
|
||||
|
||||
readonly onTextEditorAdd: Event<MainThreadTextEditor[]> = this._onTextEditorAdd.event;
|
||||
readonly onTextEditorRemove: Event<string[]> = this._onTextEditorRemove.event;
|
||||
readonly onDocumentAdd: Event<IModel[]> = this._onDocumentAdd.event;
|
||||
readonly onDocumentRemove: Event<string[]> = this._onDocumentRemove.event;
|
||||
readonly onDocumentAdd: Event<ITextModel[]> = this._onDocumentAdd.event;
|
||||
readonly onDocumentRemove: Event<URI[]> = this._onDocumentRemove.event;
|
||||
|
||||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
@IModelService private _modelService: IModelService,
|
||||
@ITextFileService private _textFileService: ITextFileService,
|
||||
@IWorkbenchEditorService private _workbenchEditorService: IWorkbenchEditorService,
|
||||
@IModelService private readonly _modelService: IModelService,
|
||||
@ITextFileService private readonly _textFileService: ITextFileService,
|
||||
@IWorkbenchEditorService private readonly _workbenchEditorService: IWorkbenchEditorService,
|
||||
@ICodeEditorService codeEditorService: ICodeEditorService,
|
||||
@IModeService modeService: IModeService,
|
||||
@IFileService fileService: IFileService,
|
||||
@@ -308,20 +309,20 @@ export class MainThreadDocumentsAndEditors {
|
||||
@IUntitledEditorService untitledEditorService: IUntitledEditorService,
|
||||
@IEditorGroupService editorGroupService: IEditorGroupService
|
||||
) {
|
||||
this._proxy = extHostContext.get(ExtHostContext.ExtHostDocumentsAndEditors);
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostDocumentsAndEditors);
|
||||
|
||||
const mainThreadDocuments = new MainThreadDocuments(this, extHostContext, this._modelService, modeService, this._textFileService, fileService, textModelResolverService, untitledEditorService);
|
||||
extHostContext.set(MainContext.MainThreadDocuments, mainThreadDocuments);
|
||||
|
||||
const mainThreadEditors = new MainThreadEditors(this, extHostContext, codeEditorService, this._workbenchEditorService, editorGroupService, textModelResolverService, fileService, this._modelService);
|
||||
extHostContext.set(MainContext.MainThreadEditors, mainThreadEditors);
|
||||
const mainThreadTextEditors = new MainThreadTextEditors(this, extHostContext, codeEditorService, this._workbenchEditorService, editorGroupService, textModelResolverService, fileService, this._modelService);
|
||||
extHostContext.set(MainContext.MainThreadTextEditors, mainThreadTextEditors);
|
||||
|
||||
// It is expected that the ctor of the state computer calls our `_onDelta`.
|
||||
this._stateComputer = new MainThreadDocumentAndEditorStateComputer(delta => this._onDelta(delta), _modelService, codeEditorService, _workbenchEditorService);
|
||||
|
||||
this._toDispose = [
|
||||
mainThreadDocuments,
|
||||
mainThreadEditors,
|
||||
mainThreadTextEditors,
|
||||
this._stateComputer,
|
||||
this._onTextEditorAdd,
|
||||
this._onTextEditorRemove,
|
||||
@@ -336,28 +337,28 @@ export class MainThreadDocumentsAndEditors {
|
||||
|
||||
private _onDelta(delta: DocumentAndEditorStateDelta): void {
|
||||
|
||||
let removedDocuments: string[];
|
||||
let removedDocuments: URI[];
|
||||
let removedEditors: string[] = [];
|
||||
let addedEditors: MainThreadTextEditor[] = [];
|
||||
|
||||
// removed models
|
||||
removedDocuments = delta.removedDocuments.map(m => m.uri.toString());
|
||||
removedDocuments = delta.removedDocuments.map(m => m.uri);
|
||||
|
||||
// added editors
|
||||
for (const apiEditor of delta.addedEditors) {
|
||||
const mainThreadEditor = new MainThreadTextEditor(apiEditor.id, apiEditor.editor.getModel(),
|
||||
apiEditor.editor, { onGainedFocus() { }, onLostFocus() { } }, this._modelService);
|
||||
|
||||
this._editors[apiEditor.id] = mainThreadEditor;
|
||||
this._textEditors[apiEditor.id] = mainThreadEditor;
|
||||
addedEditors.push(mainThreadEditor);
|
||||
}
|
||||
|
||||
// removed editors
|
||||
for (const { id } of delta.removedEditors) {
|
||||
const mainThreadEditor = this._editors[id];
|
||||
const mainThreadEditor = this._textEditors[id];
|
||||
if (mainThreadEditor) {
|
||||
mainThreadEditor.dispose();
|
||||
delete this._editors[id];
|
||||
delete this._textEditors[id];
|
||||
removedEditors.push(id);
|
||||
}
|
||||
}
|
||||
@@ -396,9 +397,9 @@ export class MainThreadDocumentsAndEditors {
|
||||
}
|
||||
}
|
||||
|
||||
private _toModelAddData(model: IModel): IModelAddedData {
|
||||
private _toModelAddData(model: ITextModel): IModelAddedData {
|
||||
return {
|
||||
url: model.uri,
|
||||
uri: model.uri,
|
||||
versionId: model.getVersionId(),
|
||||
lines: model.getLinesContent(),
|
||||
EOL: model.getEOL(),
|
||||
@@ -408,11 +409,13 @@ export class MainThreadDocumentsAndEditors {
|
||||
}
|
||||
|
||||
private _toTextEditorAddData(textEditor: MainThreadTextEditor): ITextEditorAddData {
|
||||
const props = textEditor.getProperties();
|
||||
return {
|
||||
id: textEditor.getId(),
|
||||
document: textEditor.getModel().uri,
|
||||
options: textEditor.getConfiguration(),
|
||||
selections: textEditor.getSelections(),
|
||||
documentUri: textEditor.getModel().uri,
|
||||
options: props.options,
|
||||
selections: props.selections,
|
||||
visibleRanges: props.visibleRanges,
|
||||
editorPosition: this._findEditorPosition(textEditor)
|
||||
};
|
||||
}
|
||||
@@ -427,8 +430,8 @@ export class MainThreadDocumentsAndEditors {
|
||||
}
|
||||
|
||||
findTextEditorIdFor(editor: IEditor): string {
|
||||
for (let id in this._editors) {
|
||||
if (this._editors[id].matches(editor)) {
|
||||
for (let id in this._textEditors) {
|
||||
if (this._textEditors[id].matches(editor)) {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
@@ -436,6 +439,6 @@ export class MainThreadDocumentsAndEditors {
|
||||
}
|
||||
|
||||
getEditor(id: string): MainThreadTextEditor {
|
||||
return this._editors[id];
|
||||
return this._textEditors[id];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import EditorCommon = require('vs/editor/common/editorCommon');
|
||||
import * as editorCommon from 'vs/editor/common/editorCommon';
|
||||
import Event, { Emitter } from 'vs/base/common/event';
|
||||
import { IEditor } from 'vs/platform/editor/common/editor';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
@@ -14,28 +14,162 @@ import { Selection, ISelection } from 'vs/editor/common/core/selection';
|
||||
import { SnippetController2 } from 'vs/editor/contrib/snippet/snippetController2';
|
||||
import { EndOfLine, TextEditorLineNumbersStyle } from 'vs/workbench/api/node/extHostTypes';
|
||||
import { TextEditorCursorStyle, cursorStyleToString, RenderLineNumbersType } from 'vs/editor/common/config/editorOptions';
|
||||
import { ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents';
|
||||
import { IResolvedTextEditorConfiguration, ISelectionChangeEvent, ITextEditorConfigurationUpdate, TextEditorRevealType, IApplyEditsOptions, IUndoStopOptions } from 'vs/workbench/api/node/extHost.protocol';
|
||||
import { IResolvedTextEditorConfiguration, ITextEditorConfigurationUpdate, TextEditorRevealType, IApplyEditsOptions, IUndoStopOptions, IEditorPropertiesChangeData } from 'vs/workbench/api/node/extHost.protocol';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
|
||||
function configurationsEqual(a: IResolvedTextEditorConfiguration, b: IResolvedTextEditorConfiguration) {
|
||||
if (a && !b || !a && b) {
|
||||
return false;
|
||||
}
|
||||
if (!a && !b) {
|
||||
return true;
|
||||
}
|
||||
return (
|
||||
a.tabSize === b.tabSize
|
||||
&& a.insertSpaces === b.insertSpaces
|
||||
);
|
||||
}
|
||||
import { ITextModel, ISingleEditOperation, EndOfLineSequence, IIdentifiedSingleEditOperation, ITextModelUpdateOptions } from 'vs/editor/common/model';
|
||||
|
||||
export interface IFocusTracker {
|
||||
onGainedFocus(): void;
|
||||
onLostFocus(): void;
|
||||
}
|
||||
|
||||
export class MainThreadTextEditorProperties {
|
||||
|
||||
public static readFromEditor(previousProperties: MainThreadTextEditorProperties, model: ITextModel, codeEditor: ICodeEditor): MainThreadTextEditorProperties {
|
||||
const selections = MainThreadTextEditorProperties._readSelectionsFromCodeEditor(previousProperties, codeEditor);
|
||||
const options = MainThreadTextEditorProperties._readOptionsFromCodeEditor(previousProperties, model, codeEditor);
|
||||
const visibleRanges = MainThreadTextEditorProperties._readVisibleRangesFromCodeEditor(previousProperties, codeEditor);
|
||||
return new MainThreadTextEditorProperties(selections, options, visibleRanges);
|
||||
}
|
||||
|
||||
private static _readSelectionsFromCodeEditor(previousProperties: MainThreadTextEditorProperties, codeEditor: ICodeEditor): Selection[] {
|
||||
let result: Selection[] = null;
|
||||
if (codeEditor) {
|
||||
result = codeEditor.getSelections();
|
||||
}
|
||||
if (!result && previousProperties) {
|
||||
result = previousProperties.selections;
|
||||
}
|
||||
if (!result) {
|
||||
result = [new Selection(1, 1, 1, 1)];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static _readOptionsFromCodeEditor(previousProperties: MainThreadTextEditorProperties, model: ITextModel, codeEditor: ICodeEditor): IResolvedTextEditorConfiguration {
|
||||
if (model.isDisposed()) {
|
||||
// shutdown time
|
||||
return previousProperties.options;
|
||||
}
|
||||
|
||||
let cursorStyle: TextEditorCursorStyle;
|
||||
let lineNumbers: TextEditorLineNumbersStyle;
|
||||
if (codeEditor) {
|
||||
const codeEditorOpts = codeEditor.getConfiguration();
|
||||
cursorStyle = codeEditorOpts.viewInfo.cursorStyle;
|
||||
|
||||
switch (codeEditorOpts.viewInfo.renderLineNumbers) {
|
||||
case RenderLineNumbersType.Off:
|
||||
lineNumbers = TextEditorLineNumbersStyle.Off;
|
||||
break;
|
||||
case RenderLineNumbersType.Relative:
|
||||
lineNumbers = TextEditorLineNumbersStyle.Relative;
|
||||
break;
|
||||
default:
|
||||
lineNumbers = TextEditorLineNumbersStyle.On;
|
||||
break;
|
||||
}
|
||||
} else if (previousProperties) {
|
||||
cursorStyle = previousProperties.options.cursorStyle;
|
||||
lineNumbers = previousProperties.options.lineNumbers;
|
||||
} else {
|
||||
cursorStyle = TextEditorCursorStyle.Line;
|
||||
lineNumbers = TextEditorLineNumbersStyle.On;
|
||||
}
|
||||
|
||||
const modelOptions = model.getOptions();
|
||||
return {
|
||||
insertSpaces: modelOptions.insertSpaces,
|
||||
tabSize: modelOptions.tabSize,
|
||||
cursorStyle: cursorStyle,
|
||||
lineNumbers: lineNumbers
|
||||
};
|
||||
}
|
||||
|
||||
private static _readVisibleRangesFromCodeEditor(previousProperties: MainThreadTextEditorProperties, codeEditor: ICodeEditor): Range[] {
|
||||
if (codeEditor) {
|
||||
return codeEditor.getVisibleRanges();
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
constructor(
|
||||
public readonly selections: Selection[],
|
||||
public readonly options: IResolvedTextEditorConfiguration,
|
||||
public readonly visibleRanges: Range[]
|
||||
) {
|
||||
}
|
||||
|
||||
public generateDelta(oldProps: MainThreadTextEditorProperties, selectionChangeSource: string): IEditorPropertiesChangeData {
|
||||
let delta: IEditorPropertiesChangeData = {
|
||||
options: null,
|
||||
selections: null,
|
||||
visibleRanges: null
|
||||
};
|
||||
|
||||
if (!oldProps || !MainThreadTextEditorProperties._selectionsEqual(oldProps.selections, this.selections)) {
|
||||
delta.selections = {
|
||||
selections: this.selections,
|
||||
source: selectionChangeSource
|
||||
};
|
||||
}
|
||||
|
||||
if (!oldProps || !MainThreadTextEditorProperties._optionsEqual(oldProps.options, this.options)) {
|
||||
delta.options = this.options;
|
||||
}
|
||||
|
||||
if (!oldProps || !MainThreadTextEditorProperties._rangesEqual(oldProps.visibleRanges, this.visibleRanges)) {
|
||||
delta.visibleRanges = this.visibleRanges;
|
||||
}
|
||||
|
||||
if (delta.selections || delta.options || delta.visibleRanges) {
|
||||
// something changed
|
||||
return delta;
|
||||
}
|
||||
// nothing changed
|
||||
return null;
|
||||
}
|
||||
|
||||
private static _selectionsEqual(a: Selection[], b: Selection[]): boolean {
|
||||
if (a.length !== b.length) {
|
||||
return false;
|
||||
}
|
||||
for (let i = 0; i < a.length; i++) {
|
||||
if (!a[i].equalsSelection(b[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static _rangesEqual(a: Range[], b: Range[]): boolean {
|
||||
if (a.length !== b.length) {
|
||||
return false;
|
||||
}
|
||||
for (let i = 0; i < a.length; i++) {
|
||||
if (!a[i].equalsRange(b[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static _optionsEqual(a: IResolvedTextEditorConfiguration, b: IResolvedTextEditorConfiguration): boolean {
|
||||
if (a && !b || !a && b) {
|
||||
return false;
|
||||
}
|
||||
if (!a && !b) {
|
||||
return true;
|
||||
}
|
||||
return (
|
||||
a.tabSize === b.tabSize
|
||||
&& a.insertSpaces === b.insertSpaces
|
||||
&& a.cursorStyle === b.cursorStyle
|
||||
&& a.lineNumbers === b.lineNumbers
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Text Editor that is permanently bound to the same model.
|
||||
* It can be bound or not to a CodeEditor.
|
||||
@@ -43,22 +177,19 @@ export interface IFocusTracker {
|
||||
export class MainThreadTextEditor {
|
||||
|
||||
private _id: string;
|
||||
private _model: EditorCommon.IModel;
|
||||
private _model: ITextModel;
|
||||
private _modelService: IModelService;
|
||||
private _modelListeners: IDisposable[];
|
||||
private _codeEditor: ICodeEditor;
|
||||
private _focusTracker: IFocusTracker;
|
||||
private _codeEditorListeners: IDisposable[];
|
||||
|
||||
private _lastSelection: Selection[];
|
||||
private _configuration: IResolvedTextEditorConfiguration;
|
||||
|
||||
private _onSelectionChanged: Emitter<ISelectionChangeEvent>;
|
||||
private _onConfigurationChanged: Emitter<IResolvedTextEditorConfiguration>;
|
||||
private _properties: MainThreadTextEditorProperties;
|
||||
private _onPropertiesChanged: Emitter<IEditorPropertiesChangeData>;
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
model: EditorCommon.IModel,
|
||||
model: ITextModel,
|
||||
codeEditor: ICodeEditor,
|
||||
focusTracker: IFocusTracker,
|
||||
modelService: IModelService
|
||||
@@ -70,17 +201,16 @@ export class MainThreadTextEditor {
|
||||
this._modelService = modelService;
|
||||
this._codeEditorListeners = [];
|
||||
|
||||
this._onSelectionChanged = new Emitter<ISelectionChangeEvent>();
|
||||
this._onConfigurationChanged = new Emitter<IResolvedTextEditorConfiguration>();
|
||||
this._properties = null;
|
||||
this._onPropertiesChanged = new Emitter<IEditorPropertiesChangeData>();
|
||||
|
||||
this._lastSelection = [new Selection(1, 1, 1, 1)];
|
||||
this._modelListeners = [];
|
||||
this._modelListeners.push(this._model.onDidChangeOptions((e) => {
|
||||
this._setConfiguration(this._readConfiguration(this._model, this._codeEditor));
|
||||
this._updatePropertiesNow(null);
|
||||
}));
|
||||
|
||||
this.setCodeEditor(codeEditor);
|
||||
this._setConfiguration(this._readConfiguration(this._model, this._codeEditor));
|
||||
this._updatePropertiesNow(null);
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
@@ -90,11 +220,26 @@ export class MainThreadTextEditor {
|
||||
this._codeEditorListeners = dispose(this._codeEditorListeners);
|
||||
}
|
||||
|
||||
private _updatePropertiesNow(selectionChangeSource: string): void {
|
||||
this._setProperties(
|
||||
MainThreadTextEditorProperties.readFromEditor(this._properties, this._model, this._codeEditor),
|
||||
selectionChangeSource
|
||||
);
|
||||
}
|
||||
|
||||
private _setProperties(newProperties: MainThreadTextEditorProperties, selectionChangeSource: string): void {
|
||||
const delta = newProperties.generateDelta(this._properties, selectionChangeSource);
|
||||
this._properties = newProperties;
|
||||
if (delta) {
|
||||
this._onPropertiesChanged.fire(delta);
|
||||
}
|
||||
}
|
||||
|
||||
public getId(): string {
|
||||
return this._id;
|
||||
}
|
||||
|
||||
public getModel(): EditorCommon.IModel {
|
||||
public getModel(): ITextModel {
|
||||
return this._model;
|
||||
}
|
||||
|
||||
@@ -121,27 +266,30 @@ export class MainThreadTextEditor {
|
||||
this.setCodeEditor(null);
|
||||
}));
|
||||
|
||||
let forwardSelection = (event?: ICursorSelectionChangedEvent) => {
|
||||
this._lastSelection = this._codeEditor.getSelections();
|
||||
this._onSelectionChanged.fire({
|
||||
selections: this._lastSelection,
|
||||
source: event && event.source
|
||||
});
|
||||
};
|
||||
this._codeEditorListeners.push(this._codeEditor.onDidChangeCursorSelection(forwardSelection));
|
||||
if (!Selection.selectionsArrEqual(this._lastSelection, this._codeEditor.getSelections())) {
|
||||
forwardSelection();
|
||||
}
|
||||
this._codeEditorListeners.push(this._codeEditor.onDidFocusEditor(() => {
|
||||
this._focusTracker.onGainedFocus();
|
||||
}));
|
||||
this._codeEditorListeners.push(this._codeEditor.onDidBlurEditor(() => {
|
||||
this._focusTracker.onLostFocus();
|
||||
}));
|
||||
this._codeEditorListeners.push(this._codeEditor.onDidChangeConfiguration(() => {
|
||||
this._setConfiguration(this._readConfiguration(this._model, this._codeEditor));
|
||||
|
||||
this._codeEditorListeners.push(this._codeEditor.onDidChangeCursorSelection((e) => {
|
||||
// selection
|
||||
this._updatePropertiesNow(e.source);
|
||||
}));
|
||||
this._setConfiguration(this._readConfiguration(this._model, this._codeEditor));
|
||||
this._codeEditorListeners.push(this._codeEditor.onDidChangeConfiguration(() => {
|
||||
// options
|
||||
this._updatePropertiesNow(null);
|
||||
}));
|
||||
this._codeEditorListeners.push(this._codeEditor.onDidLayoutChange(() => {
|
||||
// visibleRanges
|
||||
this._updatePropertiesNow(null);
|
||||
}));
|
||||
this._codeEditorListeners.push(this._codeEditor.onDidScrollChange(() => {
|
||||
// visibleRanges
|
||||
this._updatePropertiesNow(null);
|
||||
}));
|
||||
this._updatePropertiesNow(null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,19 +297,12 @@ export class MainThreadTextEditor {
|
||||
return !!this._codeEditor;
|
||||
}
|
||||
|
||||
public get onSelectionChanged(): Event<ISelectionChangeEvent> {
|
||||
return this._onSelectionChanged.event;
|
||||
public getProperties(): MainThreadTextEditorProperties {
|
||||
return this._properties;
|
||||
}
|
||||
|
||||
public get onConfigurationChanged(): Event<IResolvedTextEditorConfiguration> {
|
||||
return this._onConfigurationChanged.event;
|
||||
}
|
||||
|
||||
public getSelections(): Selection[] {
|
||||
if (this._codeEditor) {
|
||||
return this._codeEditor.getSelections();
|
||||
}
|
||||
return this._lastSelection;
|
||||
public get onPropertiesChanged(): Event<IEditorPropertiesChangeData> {
|
||||
return this._onPropertiesChanged.event;
|
||||
}
|
||||
|
||||
public setSelections(selections: ISelection[]): void {
|
||||
@@ -169,11 +310,12 @@ export class MainThreadTextEditor {
|
||||
this._codeEditor.setSelections(selections);
|
||||
return;
|
||||
}
|
||||
this._lastSelection = selections.map(Selection.liftSelection);
|
||||
}
|
||||
|
||||
public getConfiguration(): IResolvedTextEditorConfiguration {
|
||||
return this._configuration;
|
||||
const newSelections = selections.map(Selection.liftSelection);
|
||||
this._setProperties(
|
||||
new MainThreadTextEditorProperties(newSelections, this._properties.options, this._properties.visibleRanges),
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
private _setIndentConfiguration(newConfiguration: ITextEditorConfigurationUpdate): void {
|
||||
@@ -196,7 +338,7 @@ export class MainThreadTextEditor {
|
||||
return;
|
||||
}
|
||||
|
||||
let newOpts: EditorCommon.ITextModelUpdateOptions = {};
|
||||
let newOpts: ITextModelUpdateOptions = {};
|
||||
if (typeof newConfiguration.insertSpaces !== 'undefined') {
|
||||
newOpts.insertSpaces = newConfiguration.insertSpaces;
|
||||
}
|
||||
@@ -238,7 +380,7 @@ export class MainThreadTextEditor {
|
||||
}
|
||||
}
|
||||
|
||||
public setDecorations(key: string, ranges: EditorCommon.IDecorationOptions[]): void {
|
||||
public setDecorations(key: string, ranges: editorCommon.IDecorationOptions[]): void {
|
||||
if (!this._codeEditor) {
|
||||
return;
|
||||
}
|
||||
@@ -262,16 +404,16 @@ export class MainThreadTextEditor {
|
||||
}
|
||||
switch (revealType) {
|
||||
case TextEditorRevealType.Default:
|
||||
this._codeEditor.revealRange(range, EditorCommon.ScrollType.Smooth);
|
||||
this._codeEditor.revealRange(range, editorCommon.ScrollType.Smooth);
|
||||
break;
|
||||
case TextEditorRevealType.InCenter:
|
||||
this._codeEditor.revealRangeInCenter(range, EditorCommon.ScrollType.Smooth);
|
||||
this._codeEditor.revealRangeInCenter(range, editorCommon.ScrollType.Smooth);
|
||||
break;
|
||||
case TextEditorRevealType.InCenterIfOutsideViewport:
|
||||
this._codeEditor.revealRangeInCenterIfOutsideViewport(range, EditorCommon.ScrollType.Smooth);
|
||||
this._codeEditor.revealRangeInCenterIfOutsideViewport(range, editorCommon.ScrollType.Smooth);
|
||||
break;
|
||||
case TextEditorRevealType.AtTop:
|
||||
this._codeEditor.revealRangeAtTop(range, EditorCommon.ScrollType.Smooth);
|
||||
this._codeEditor.revealRangeAtTop(range, editorCommon.ScrollType.Smooth);
|
||||
break;
|
||||
default:
|
||||
console.warn(`Unknown revealType: ${revealType}`);
|
||||
@@ -279,47 +421,6 @@ export class MainThreadTextEditor {
|
||||
}
|
||||
}
|
||||
|
||||
private _readConfiguration(model: EditorCommon.IModel, codeEditor: ICodeEditor): IResolvedTextEditorConfiguration {
|
||||
if (model.isDisposed()) {
|
||||
// shutdown time
|
||||
return this._configuration;
|
||||
}
|
||||
let cursorStyle = this._configuration ? this._configuration.cursorStyle : TextEditorCursorStyle.Line;
|
||||
let lineNumbers: TextEditorLineNumbersStyle = this._configuration ? this._configuration.lineNumbers : TextEditorLineNumbersStyle.On;
|
||||
if (codeEditor) {
|
||||
let codeEditorOpts = codeEditor.getConfiguration();
|
||||
cursorStyle = codeEditorOpts.viewInfo.cursorStyle;
|
||||
|
||||
switch (codeEditorOpts.viewInfo.renderLineNumbers) {
|
||||
case RenderLineNumbersType.Off:
|
||||
lineNumbers = TextEditorLineNumbersStyle.Off;
|
||||
break;
|
||||
case RenderLineNumbersType.Relative:
|
||||
lineNumbers = TextEditorLineNumbersStyle.Relative;
|
||||
break;
|
||||
default:
|
||||
lineNumbers = TextEditorLineNumbersStyle.On;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let indent = model.getOptions();
|
||||
return {
|
||||
insertSpaces: indent.insertSpaces,
|
||||
tabSize: indent.tabSize,
|
||||
cursorStyle: cursorStyle,
|
||||
lineNumbers: lineNumbers
|
||||
};
|
||||
}
|
||||
|
||||
private _setConfiguration(newConfiguration: IResolvedTextEditorConfiguration): void {
|
||||
if (configurationsEqual(this._configuration, newConfiguration)) {
|
||||
return;
|
||||
}
|
||||
this._configuration = newConfiguration;
|
||||
this._onConfigurationChanged.fire(this._configuration);
|
||||
}
|
||||
|
||||
public isFocused(): boolean {
|
||||
if (this._codeEditor) {
|
||||
return this._codeEditor.isFocused();
|
||||
@@ -334,7 +435,7 @@ export class MainThreadTextEditor {
|
||||
return editor.getControl() === this._codeEditor;
|
||||
}
|
||||
|
||||
public applyEdits(versionIdCheck: number, edits: EditorCommon.ISingleEditOperation[], opts: IApplyEditsOptions): boolean {
|
||||
public applyEdits(versionIdCheck: number, edits: ISingleEditOperation[], opts: IApplyEditsOptions): boolean {
|
||||
if (this._model.getVersionId() !== versionIdCheck) {
|
||||
// throw new Error('Model has changed in the meantime!');
|
||||
// model changed in the meantime
|
||||
@@ -347,14 +448,13 @@ export class MainThreadTextEditor {
|
||||
}
|
||||
|
||||
if (opts.setEndOfLine === EndOfLine.CRLF) {
|
||||
this._model.setEOL(EditorCommon.EndOfLineSequence.CRLF);
|
||||
this._model.setEOL(EndOfLineSequence.CRLF);
|
||||
} else if (opts.setEndOfLine === EndOfLine.LF) {
|
||||
this._model.setEOL(EditorCommon.EndOfLineSequence.LF);
|
||||
this._model.setEOL(EndOfLineSequence.LF);
|
||||
}
|
||||
|
||||
let transformedEdits = edits.map((edit): EditorCommon.IIdentifiedSingleEditOperation => {
|
||||
let transformedEdits = edits.map((edit): IIdentifiedSingleEditOperation => {
|
||||
return {
|
||||
identifier: null,
|
||||
range: Range.lift(edit.range),
|
||||
text: edit.text,
|
||||
forceMoveMarkers: edit.forceMoveMarkers
|
||||
|
||||
@@ -4,29 +4,31 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import URI from 'vs/base/common/uri';
|
||||
import URI, { UriComponents } from 'vs/base/common/uri';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { disposed } from 'vs/base/common/errors';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { ISingleEditOperation, IDecorationRenderOptions, IDecorationOptions, ILineChange } from 'vs/editor/common/editorCommon';
|
||||
import { IDecorationRenderOptions, IDecorationOptions, ILineChange } from 'vs/editor/common/editorCommon';
|
||||
import { ISingleEditOperation } from 'vs/editor/common/model';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService';
|
||||
import { Position as EditorPosition, ITextEditorOptions } from 'vs/platform/editor/common/editor';
|
||||
import { MainThreadTextEditor } from './mainThreadEditor';
|
||||
import { ITextEditorConfigurationUpdate, TextEditorRevealType, IApplyEditsOptions, IUndoStopOptions } from 'vs/workbench/api/node/extHost.protocol';
|
||||
import { ITextEditorConfigurationUpdate, TextEditorRevealType, IApplyEditsOptions, IUndoStopOptions, WorkspaceEditDto, reviveWorkspaceEditDto } from 'vs/workbench/api/node/extHost.protocol';
|
||||
import { MainThreadDocumentsAndEditors } from './mainThreadDocumentsAndEditors';
|
||||
import { equals as objectEquals } from 'vs/base/common/objects';
|
||||
import { ExtHostContext, MainThreadEditorsShape, ExtHostEditorsShape, ITextDocumentShowOptions, ITextEditorPositionData, IExtHostContext, IWorkspaceResourceEdit } from '../node/extHost.protocol';
|
||||
import { ExtHostContext, MainThreadTextEditorsShape, ExtHostEditorsShape, ITextDocumentShowOptions, ITextEditorPositionData, IExtHostContext } from '../node/extHost.protocol';
|
||||
import { IRange } from 'vs/editor/common/core/range';
|
||||
import { ISelection } from 'vs/editor/common/core/selection';
|
||||
import { ITextModelService } from 'vs/editor/common/services/resolverService';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { bulkEdit, IResourceEdit } from 'vs/editor/browser/services/bulkEdit';
|
||||
import { BulkEdit } from 'vs/editor/browser/services/bulkEdit';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { isCodeEditor, ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { isResourceFileEdit } from 'vs/editor/common/modes';
|
||||
|
||||
export class MainThreadEditors implements MainThreadEditorsShape {
|
||||
export class MainThreadTextEditors implements MainThreadTextEditorsShape {
|
||||
|
||||
private _proxy: ExtHostEditorsShape;
|
||||
private _documentsAndEditors: MainThreadDocumentsAndEditors;
|
||||
@@ -39,14 +41,14 @@ export class MainThreadEditors implements MainThreadEditorsShape {
|
||||
constructor(
|
||||
documentsAndEditors: MainThreadDocumentsAndEditors,
|
||||
extHostContext: IExtHostContext,
|
||||
@ICodeEditorService private _codeEditorService: ICodeEditorService,
|
||||
@ICodeEditorService private readonly _codeEditorService: ICodeEditorService,
|
||||
@IWorkbenchEditorService workbenchEditorService: IWorkbenchEditorService,
|
||||
@IEditorGroupService editorGroupService: IEditorGroupService,
|
||||
@ITextModelService private readonly _textModelResolverService: ITextModelService,
|
||||
@IFileService private readonly _fileService: IFileService,
|
||||
@IModelService private readonly _modelService: IModelService,
|
||||
) {
|
||||
this._proxy = extHostContext.get(ExtHostContext.ExtHostEditors);
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostEditors);
|
||||
this._documentsAndEditors = documentsAndEditors;
|
||||
this._workbenchEditorService = workbenchEditorService;
|
||||
this._toDispose = [];
|
||||
@@ -77,11 +79,8 @@ export class MainThreadEditors implements MainThreadEditorsShape {
|
||||
private _onTextEditorAdd(textEditor: MainThreadTextEditor): void {
|
||||
let id = textEditor.getId();
|
||||
let toDispose: IDisposable[] = [];
|
||||
toDispose.push(textEditor.onConfigurationChanged((opts) => {
|
||||
this._proxy.$acceptOptionsChanged(id, opts);
|
||||
}));
|
||||
toDispose.push(textEditor.onSelectionChanged((event) => {
|
||||
this._proxy.$acceptSelectionsChanged(id, event);
|
||||
toDispose.push(textEditor.onPropertiesChanged((data) => {
|
||||
this._proxy.$acceptEditorPropertiesChanged(id, data);
|
||||
}));
|
||||
|
||||
this._textEditorsListenersMap[id] = toDispose;
|
||||
@@ -115,7 +114,9 @@ export class MainThreadEditors implements MainThreadEditorsShape {
|
||||
|
||||
// --- from extension host process
|
||||
|
||||
$tryShowTextDocument(resource: URI, options: ITextDocumentShowOptions): TPromise<string> {
|
||||
$tryShowTextDocument(resource: UriComponents, options: ITextDocumentShowOptions): TPromise<string> {
|
||||
const uri = URI.revive(resource);
|
||||
|
||||
const editorOptions: ITextEditorOptions = {
|
||||
preserveFocus: options.preserveFocus,
|
||||
pinned: options.pinned,
|
||||
@@ -123,7 +124,7 @@ export class MainThreadEditors implements MainThreadEditorsShape {
|
||||
};
|
||||
|
||||
const input = {
|
||||
resource,
|
||||
resource: uri,
|
||||
options: editorOptions
|
||||
};
|
||||
|
||||
@@ -160,7 +161,7 @@ export class MainThreadEditors implements MainThreadEditorsShape {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
$trySetSelections(id: string, selections: ISelection[]): TPromise<any> {
|
||||
$trySetSelections(id: string, selections: ISelection[]): TPromise<void> {
|
||||
if (!this._documentsAndEditors.getEditor(id)) {
|
||||
return TPromise.wrapError(disposed(`TextEditor(${id})`));
|
||||
}
|
||||
@@ -168,7 +169,7 @@ export class MainThreadEditors implements MainThreadEditorsShape {
|
||||
return TPromise.as(null);
|
||||
}
|
||||
|
||||
$trySetDecorations(id: string, key: string, ranges: IDecorationOptions[]): TPromise<any> {
|
||||
$trySetDecorations(id: string, key: string, ranges: IDecorationOptions[]): TPromise<void> {
|
||||
if (!this._documentsAndEditors.getEditor(id)) {
|
||||
return TPromise.wrapError(disposed(`TextEditor(${id})`));
|
||||
}
|
||||
@@ -176,15 +177,15 @@ export class MainThreadEditors implements MainThreadEditorsShape {
|
||||
return TPromise.as(null);
|
||||
}
|
||||
|
||||
$trySetDecorationsFast(id: string, key: string, ranges: string): TPromise<any> {
|
||||
$trySetDecorationsFast(id: string, key: string, ranges: number[]): TPromise<void> {
|
||||
if (!this._documentsAndEditors.getEditor(id)) {
|
||||
return TPromise.wrapError(disposed(`TextEditor(${id})`));
|
||||
}
|
||||
this._documentsAndEditors.getEditor(id).setDecorationsFast(key, /*TODO: marshaller is too slow*/JSON.parse(ranges));
|
||||
this._documentsAndEditors.getEditor(id).setDecorationsFast(key, ranges);
|
||||
return TPromise.as(null);
|
||||
}
|
||||
|
||||
$tryRevealRange(id: string, range: IRange, revealType: TextEditorRevealType): TPromise<any> {
|
||||
$tryRevealRange(id: string, range: IRange, revealType: TextEditorRevealType): TPromise<void> {
|
||||
if (!this._documentsAndEditors.getEditor(id)) {
|
||||
return TPromise.wrapError(disposed(`TextEditor(${id})`));
|
||||
}
|
||||
@@ -192,7 +193,7 @@ export class MainThreadEditors implements MainThreadEditorsShape {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
$trySetOptions(id: string, options: ITextEditorConfigurationUpdate): TPromise<any> {
|
||||
$trySetOptions(id: string, options: ITextEditorConfigurationUpdate): TPromise<void> {
|
||||
if (!this._documentsAndEditors.getEditor(id)) {
|
||||
return TPromise.wrapError(disposed(`TextEditor(${id})`));
|
||||
}
|
||||
@@ -207,39 +208,22 @@ export class MainThreadEditors implements MainThreadEditorsShape {
|
||||
return TPromise.as(this._documentsAndEditors.getEditor(id).applyEdits(modelVersionId, edits, opts));
|
||||
}
|
||||
|
||||
$tryApplyWorkspaceEdit(workspaceResourceEdits: IWorkspaceResourceEdit[]): TPromise<boolean> {
|
||||
$tryApplyWorkspaceEdit(dto: WorkspaceEditDto): TPromise<boolean> {
|
||||
|
||||
const { edits } = reviveWorkspaceEditDto(dto);
|
||||
|
||||
// First check if loaded models were not changed in the meantime
|
||||
for (let i = 0, len = workspaceResourceEdits.length; i < len; i++) {
|
||||
const workspaceResourceEdit = workspaceResourceEdits[i];
|
||||
if (workspaceResourceEdit.modelVersionId) {
|
||||
let model = this._modelService.getModel(workspaceResourceEdit.resource);
|
||||
if (model && model.getVersionId() !== workspaceResourceEdit.modelVersionId) {
|
||||
for (let i = 0, len = edits.length; i < len; i++) {
|
||||
const edit = edits[i];
|
||||
if (!isResourceFileEdit(edit) && edit.modelVersionId) {
|
||||
let model = this._modelService.getModel(edit.resource);
|
||||
if (model && model.getVersionId() !== edit.modelVersionId) {
|
||||
// model changed in the meantime
|
||||
return TPromise.as(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Convert to shape expected by bulkEdit below
|
||||
let resourceEdits: IResourceEdit[] = [];
|
||||
for (let i = 0, len = workspaceResourceEdits.length; i < len; i++) {
|
||||
const workspaceResourceEdit = workspaceResourceEdits[i];
|
||||
const uri = workspaceResourceEdit.resource;
|
||||
const edits = workspaceResourceEdit.edits;
|
||||
|
||||
for (let j = 0, lenJ = edits.length; j < lenJ; j++) {
|
||||
const edit = edits[j];
|
||||
|
||||
resourceEdits.push({
|
||||
resource: uri,
|
||||
newText: edit.newText,
|
||||
newEol: edit.newEol,
|
||||
range: edit.range
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let codeEditor: ICodeEditor;
|
||||
let editor = this._workbenchEditorService.getActiveEditor();
|
||||
if (editor) {
|
||||
@@ -249,8 +233,7 @@ export class MainThreadEditors implements MainThreadEditorsShape {
|
||||
}
|
||||
}
|
||||
|
||||
return bulkEdit(this._textModelResolverService, codeEditor, resourceEdits, this._fileService)
|
||||
.then(() => true);
|
||||
return BulkEdit.perform(edits, this._textModelResolverService, this._fileService, codeEditor).then(() => true);
|
||||
}
|
||||
|
||||
$tryInsertSnippet(id: string, template: string, ranges: IRange[], opts: IUndoStopOptions): TPromise<boolean> {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
'use strict';
|
||||
|
||||
import Severity from 'vs/base/common/severity';
|
||||
import { IExtensionService } from 'vs/platform/extensions/common/extensions';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { MainThreadExtensionServiceShape, MainContext, IExtHostContext } from '../node/extHost.protocol';
|
||||
import { ExtensionService } from 'vs/workbench/services/extensions/electron-browser/extensionService';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
|
||||
|
||||
@@ -4,22 +4,23 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import URI from 'vs/base/common/uri';
|
||||
import URI, { UriComponents } from 'vs/base/common/uri';
|
||||
import { TPromise, PPromise } from 'vs/base/common/winjs.base';
|
||||
import { ExtHostContext, MainContext, IExtHostContext, MainThreadFileSystemShape, ExtHostFileSystemShape } from '../node/extHost.protocol';
|
||||
import { ExtHostContext, MainContext, IExtHostContext, MainThreadFileSystemShape, ExtHostFileSystemShape, IFileChangeDto } from '../node/extHost.protocol';
|
||||
import { IFileService, IFileSystemProvider, IStat, IFileChange } from 'vs/platform/files/common/files';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import Event, { Emitter } from 'vs/base/common/event';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
|
||||
import { IProgress } from 'vs/platform/progress/common/progress';
|
||||
import { ISearchResultProvider, ISearchQuery, ISearchComplete, ISearchProgressItem, QueryType, IFileMatch, ISearchService } from 'vs/platform/search/common/search';
|
||||
import { ISearchResultProvider, ISearchQuery, ISearchComplete, ISearchProgressItem, QueryType, IFileMatch, ISearchService, ILineMatch } from 'vs/platform/search/common/search';
|
||||
import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { values } from 'vs/base/common/map';
|
||||
import { isFalsyOrEmpty } from 'vs/base/common/arrays';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadFileSystem)
|
||||
export class MainThreadFileSystem implements MainThreadFileSystemShape {
|
||||
|
||||
private readonly _toDispose: IDisposable[] = [];
|
||||
private readonly _proxy: ExtHostFileSystemShape;
|
||||
private readonly _provider = new Map<number, RemoteFileSystemProvider>();
|
||||
|
||||
@@ -29,11 +30,12 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape {
|
||||
@ISearchService private readonly _searchService: ISearchService,
|
||||
@IWorkspaceEditingService private readonly _workspaceEditingService: IWorkspaceEditingService
|
||||
) {
|
||||
this._proxy = extHostContext.get(ExtHostContext.ExtHostFileSystem);
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostFileSystem);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
dispose(this._toDispose);
|
||||
this._provider.forEach(value => dispose());
|
||||
this._provider.clear();
|
||||
}
|
||||
|
||||
$registerFileSystemProvider(handle: number, scheme: string): void {
|
||||
@@ -45,30 +47,56 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape {
|
||||
this._provider.delete(handle);
|
||||
}
|
||||
|
||||
$onDidAddFileSystemRoot(uri: URI): void {
|
||||
this._workspaceEditingService.addFolders([{ uri }], true).done(null, onUnexpectedError);
|
||||
$onDidAddFileSystemRoot(data: UriComponents): void {
|
||||
this._workspaceEditingService.addFolders([{ uri: URI.revive(data) }], true).done(null, onUnexpectedError);
|
||||
}
|
||||
|
||||
$onFileSystemChange(handle: number, changes: IFileChange[]): void {
|
||||
$onFileSystemChange(handle: number, changes: IFileChangeDto[]): void {
|
||||
this._provider.get(handle).$onFileSystemChange(changes);
|
||||
}
|
||||
|
||||
$reportFileChunk(handle: number, resource: URI, chunk: number[]): void {
|
||||
this._provider.get(handle).reportFileChunk(resource, chunk);
|
||||
$reportFileChunk(handle: number, session: number, chunk: number[]): void {
|
||||
this._provider.get(handle).reportFileChunk(session, chunk);
|
||||
}
|
||||
|
||||
// --- search
|
||||
|
||||
$handleSearchProgress(handle: number, session: number, resource: URI): void {
|
||||
this._provider.get(handle).handleSearchProgress(session, resource);
|
||||
$handleFindMatch(handle: number, session, data: UriComponents | [UriComponents, ILineMatch]): void {
|
||||
this._provider.get(handle).handleFindMatch(session, data);
|
||||
}
|
||||
}
|
||||
|
||||
class FileReadOperation {
|
||||
|
||||
private static _idPool = 0;
|
||||
|
||||
constructor(
|
||||
readonly progress: IProgress<Uint8Array>,
|
||||
readonly id: number = ++FileReadOperation._idPool
|
||||
) {
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
class SearchOperation {
|
||||
|
||||
private static _idPool = 0;
|
||||
|
||||
constructor(
|
||||
readonly progress: (match: IFileMatch) => any,
|
||||
readonly id: number = ++SearchOperation._idPool,
|
||||
readonly matches = new Map<string, IFileMatch>()
|
||||
) {
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
class RemoteFileSystemProvider implements IFileSystemProvider, ISearchResultProvider {
|
||||
|
||||
private readonly _onDidChange = new Emitter<IFileChange[]>();
|
||||
private readonly _reads = new Map<string, IProgress<Uint8Array>>();
|
||||
private readonly _registrations: IDisposable[];
|
||||
private readonly _reads = new Map<number, FileReadOperation>();
|
||||
private readonly _searches = new Map<number, SearchOperation>();
|
||||
|
||||
readonly onDidChange: Event<IFileChange[]> = this._onDidChange.event;
|
||||
|
||||
@@ -76,12 +104,12 @@ class RemoteFileSystemProvider implements IFileSystemProvider, ISearchResultProv
|
||||
constructor(
|
||||
fileService: IFileService,
|
||||
searchService: ISearchService,
|
||||
scheme: string,
|
||||
private readonly _scheme: string,
|
||||
private readonly _handle: number,
|
||||
private readonly _proxy: ExtHostFileSystemShape
|
||||
) {
|
||||
this._registrations = [
|
||||
fileService.registerProvider(scheme, this),
|
||||
fileService.registerProvider(_scheme, this),
|
||||
searchService.registerSearchResultProvider(this),
|
||||
];
|
||||
}
|
||||
@@ -91,8 +119,12 @@ class RemoteFileSystemProvider implements IFileSystemProvider, ISearchResultProv
|
||||
this._onDidChange.dispose();
|
||||
}
|
||||
|
||||
$onFileSystemChange(changes: IFileChange[]): void {
|
||||
this._onDidChange.fire(changes);
|
||||
$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
|
||||
@@ -104,11 +136,15 @@ class RemoteFileSystemProvider implements IFileSystemProvider, ISearchResultProv
|
||||
return this._proxy.$stat(this._handle, resource);
|
||||
}
|
||||
read(resource: URI, offset: number, count: number, progress: IProgress<Uint8Array>): TPromise<number, any> {
|
||||
this._reads.set(resource.toString(), progress);
|
||||
return this._proxy.$read(this._handle, offset, count, resource);
|
||||
const read = new FileReadOperation(progress);
|
||||
this._reads.set(read.id, read);
|
||||
return this._proxy.$read(this._handle, read.id, offset, count, resource).then(value => {
|
||||
this._reads.delete(read.id);
|
||||
return value;
|
||||
});
|
||||
}
|
||||
reportFileChunk(resource: URI, chunk: number[]): void {
|
||||
this._reads.get(resource.toString()).report(Buffer.from(chunk));
|
||||
reportFileChunk(session: number, chunk: number[]): void {
|
||||
this._reads.get(session).progress.report(Buffer.from(chunk));
|
||||
}
|
||||
write(resource: URI, content: Uint8Array): TPromise<void, any> {
|
||||
return this._proxy.$write(this._handle, resource, [].slice.call(content));
|
||||
@@ -123,7 +159,9 @@ class RemoteFileSystemProvider implements IFileSystemProvider, ISearchResultProv
|
||||
return this._proxy.$mkdir(this._handle, resource);
|
||||
}
|
||||
readdir(resource: URI): TPromise<[URI, IStat][], any> {
|
||||
return this._proxy.$readdir(this._handle, resource);
|
||||
return this._proxy.$readdir(this._handle, resource).then(data => {
|
||||
return data.map(tuple => <[URI, IStat]>[URI.revive(tuple[0]), tuple[1]]);
|
||||
});
|
||||
}
|
||||
rmdir(resource: URI): TPromise<void, any> {
|
||||
return this._proxy.$rmdir(this._handle, resource);
|
||||
@@ -131,33 +169,58 @@ class RemoteFileSystemProvider implements IFileSystemProvider, ISearchResultProv
|
||||
|
||||
// --- search
|
||||
|
||||
private _searches = new Map<number, (resource: URI) => void>();
|
||||
private _searchesIdPool = 0;
|
||||
|
||||
search(query: ISearchQuery): PPromise<ISearchComplete, ISearchProgressItem> {
|
||||
if (query.type === QueryType.Text) {
|
||||
return PPromise.as<ISearchComplete>({ results: [], stats: undefined });
|
||||
}
|
||||
const id = ++this._searchesIdPool;
|
||||
const matches: IFileMatch[] = [];
|
||||
return new PPromise((resolve, reject, report) => {
|
||||
this._proxy.$fileFiles(this._handle, id, query.filePattern).then(() => {
|
||||
this._searches.delete(id);
|
||||
resolve({
|
||||
results: matches,
|
||||
stats: undefined
|
||||
});
|
||||
}, reject);
|
||||
|
||||
this._searches.set(id, resource => {
|
||||
const match: IFileMatch = { resource };
|
||||
matches.push(match);
|
||||
report(match);
|
||||
if (isFalsyOrEmpty(query.folderQueries)) {
|
||||
return PPromise.as(undefined);
|
||||
}
|
||||
|
||||
let includes = { ...query.includePattern };
|
||||
let excludes = { ...query.excludePattern };
|
||||
|
||||
for (const folderQuery of query.folderQueries) {
|
||||
if (folderQuery.folder.scheme === this._scheme) {
|
||||
includes = { ...includes, ...folderQuery.includePattern };
|
||||
excludes = { ...excludes, ...folderQuery.excludePattern };
|
||||
}
|
||||
}
|
||||
|
||||
return new PPromise((resolve, reject, report) => {
|
||||
|
||||
const search = new SearchOperation(report);
|
||||
this._searches.set(search.id, search);
|
||||
|
||||
const promise = query.type === QueryType.File
|
||||
? this._proxy.$findFiles(this._handle, search.id, query.filePattern)
|
||||
: this._proxy.$provideTextSearchResults(this._handle, search.id, query.contentPattern, { excludes: Object.keys(excludes), includes: Object.keys(includes) });
|
||||
|
||||
promise.then(() => {
|
||||
this._searches.delete(search.id);
|
||||
resolve(({ results: values(search.matches), stats: undefined }));
|
||||
}, err => {
|
||||
this._searches.delete(search.id);
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
handleSearchProgress(session: number, resource: URI): void {
|
||||
this._searches.get(session)(resource);
|
||||
handleFindMatch(session: number, dataOrUri: UriComponents | [UriComponents, ILineMatch]): void {
|
||||
let resource: URI;
|
||||
let match: ILineMatch;
|
||||
|
||||
if (Array.isArray(dataOrUri)) {
|
||||
resource = URI.revive(dataOrUri[0]);
|
||||
match = dataOrUri[1];
|
||||
} else {
|
||||
resource = URI.revive(dataOrUri);
|
||||
}
|
||||
|
||||
const { matches } = this._searches.get(session);
|
||||
if (!matches.has(resource.toString())) {
|
||||
matches.set(resource.toString(), { resource, lineMatches: [] });
|
||||
}
|
||||
if (match) {
|
||||
matches.get(resource.toString()).lineMatches.push(match);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ export class MainThreadFileSystemEventService {
|
||||
@IFileService fileService: IFileService
|
||||
) {
|
||||
|
||||
const proxy: ExtHostFileSystemEventServiceShape = extHostContext.get(ExtHostContext.ExtHostFileSystemEventService);
|
||||
const proxy: ExtHostFileSystemEventServiceShape = extHostContext.getProxy(ExtHostContext.ExtHostFileSystemEventService);
|
||||
const events: FileSystemEvents = {
|
||||
created: [],
|
||||
changed: [],
|
||||
|
||||
@@ -5,14 +5,14 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { ExtHostContext, ObjectIdentifier, IExtHostContext } from '../node/extHost.protocol';
|
||||
import { consumeSignals, GCSignal } from 'gc-signals';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import Event, { Emitter } from 'vs/base/common/event';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { extHostCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
|
||||
import { isThenable } from 'vs/base/common/async';
|
||||
import { isNullOrUndefined } from 'util';
|
||||
|
||||
export const IHeapService = createDecorator<IHeapService>('heapService');
|
||||
|
||||
@@ -25,16 +25,9 @@ export interface IHeapService {
|
||||
* Track gc-collection for all new objects that
|
||||
* have the $ident-value set.
|
||||
*/
|
||||
trackRecursive<T>(p: TPromise<T>): TPromise<T>;
|
||||
|
||||
/**
|
||||
* Track gc-collection for all new objects that
|
||||
* have the $ident-value set.
|
||||
*/
|
||||
trackRecursive<T>(obj: T): T;
|
||||
trackRecursive<T>(obj: T | Thenable<T>): Thenable<T>;
|
||||
}
|
||||
|
||||
|
||||
export class HeapService implements IHeapService {
|
||||
|
||||
_serviceBrand: any;
|
||||
@@ -42,75 +35,85 @@ export class HeapService implements IHeapService {
|
||||
private _onGarbageCollection: Emitter<number[]> = new Emitter<number[]>();
|
||||
public readonly onGarbageCollection: Event<number[]> = this._onGarbageCollection.event;
|
||||
|
||||
private _activeSignals = new WeakMap<any, GCSignal>();
|
||||
private _activeSignals = new WeakMap<any, object>();
|
||||
private _activeIds = new Set<number>();
|
||||
private _consumeHandle: number;
|
||||
|
||||
constructor() {
|
||||
this._consumeHandle = setInterval(() => {
|
||||
const ids = consumeSignals();
|
||||
|
||||
if (ids.length > 0) {
|
||||
// local book-keeping
|
||||
for (const id of ids) {
|
||||
this._activeIds.delete(id);
|
||||
}
|
||||
|
||||
// fire event
|
||||
this._onGarbageCollection.fire(ids);
|
||||
}
|
||||
|
||||
}, 15 * 1000);
|
||||
//
|
||||
}
|
||||
|
||||
dispose() {
|
||||
clearInterval(this._consumeHandle);
|
||||
}
|
||||
|
||||
trackRecursive<T>(p: TPromise<T>): TPromise<T>;
|
||||
trackRecursive<T>(obj: T): T;
|
||||
trackRecursive(obj: any): any {
|
||||
if (TPromise.is(obj)) {
|
||||
trackRecursive<T>(obj: T | Thenable<T>): Thenable<T> {
|
||||
if (isThenable(obj)) {
|
||||
return obj.then(result => this.trackRecursive(result));
|
||||
} else {
|
||||
return this._doTrackRecursive(obj);
|
||||
}
|
||||
}
|
||||
|
||||
private _doTrackRecursive(obj: any): any {
|
||||
private _doTrackRecursive(obj: any): Promise<any> {
|
||||
|
||||
const stack = [obj];
|
||||
while (stack.length > 0) {
|
||||
if (isNullOrUndefined(obj)) {
|
||||
return Promise.resolve(obj);
|
||||
}
|
||||
|
||||
// remove first element
|
||||
let obj = stack.shift();
|
||||
return import('gc-signals').then(({ GCSignal, consumeSignals }) => {
|
||||
|
||||
if (!obj || typeof obj !== 'object') {
|
||||
continue;
|
||||
if (this._consumeHandle === void 0) {
|
||||
// ensure that there is one consumer of signals
|
||||
this._consumeHandle = setInterval(() => {
|
||||
const ids = consumeSignals();
|
||||
|
||||
if (ids.length > 0) {
|
||||
// local book-keeping
|
||||
for (const id of ids) {
|
||||
this._activeIds.delete(id);
|
||||
}
|
||||
|
||||
// fire event
|
||||
this._onGarbageCollection.fire(ids);
|
||||
}
|
||||
|
||||
}, 15 * 1000);
|
||||
}
|
||||
|
||||
for (let key in obj) {
|
||||
if (!Object.prototype.hasOwnProperty.call(obj, key)) {
|
||||
const stack = [obj];
|
||||
while (stack.length > 0) {
|
||||
|
||||
// remove first element
|
||||
let obj = stack.shift();
|
||||
|
||||
if (!obj || typeof obj !== 'object') {
|
||||
continue;
|
||||
}
|
||||
|
||||
const value = obj[key];
|
||||
// recurse -> object/array
|
||||
if (typeof value === 'object') {
|
||||
stack.push(value);
|
||||
for (let key in obj) {
|
||||
if (!Object.prototype.hasOwnProperty.call(obj, key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
} else if (key === ObjectIdentifier.name) {
|
||||
// track new $ident-objects
|
||||
const value = obj[key];
|
||||
// recurse -> object/array
|
||||
if (typeof value === 'object') {
|
||||
stack.push(value);
|
||||
|
||||
if (typeof value === 'number' && !this._activeIds.has(value)) {
|
||||
this._activeIds.add(value);
|
||||
this._activeSignals.set(obj, new GCSignal(value));
|
||||
} else if (key === ObjectIdentifier.name) {
|
||||
// track new $ident-objects
|
||||
|
||||
if (typeof value === 'number' && !this._activeIds.has(value)) {
|
||||
this._activeIds.add(value);
|
||||
this._activeSignals.set(obj, new GCSignal(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return obj;
|
||||
return obj;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,7 +126,7 @@ export class MainThreadHeapService {
|
||||
extHostContext: IExtHostContext,
|
||||
@IHeapService heapService: IHeapService,
|
||||
) {
|
||||
const proxy = extHostContext.get(ExtHostContext.ExtHostHeapService);
|
||||
const proxy = extHostContext.getProxy(ExtHostContext.ExtHostHeapService);
|
||||
this._toDispose = heapService.onGarbageCollection((ids) => {
|
||||
// send to ext host
|
||||
proxy.$onGarbageCollection(ids);
|
||||
|
||||
@@ -8,20 +8,21 @@ import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import * as vscode from 'vscode';
|
||||
import { IReadOnlyModel, ISingleEditOperation } from 'vs/editor/common/editorCommon';
|
||||
import { ITextModel, ISingleEditOperation } from 'vs/editor/common/model';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
import { WorkspaceSymbolProviderRegistry, IWorkspaceSymbolProvider } from 'vs/workbench/parts/search/common/search';
|
||||
import { wireCancellationToken } from 'vs/base/common/async';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { Position as EditorPosition } from 'vs/editor/common/core/position';
|
||||
import { Range as EditorRange } from 'vs/editor/common/core/range';
|
||||
import { ExtHostContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, MainContext, IExtHostContext } from '../node/extHost.protocol';
|
||||
import { ExtHostContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, MainContext, IExtHostContext, ISerializedLanguageConfiguration, ISerializedRegExp, ISerializedIndentationRule, ISerializedOnEnterRule, LocationDto, SymbolInformationDto, CodeActionDto, reviveWorkspaceEditDto } from '../node/extHost.protocol';
|
||||
import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';
|
||||
import { LanguageConfiguration } from 'vs/editor/common/modes/languageConfiguration';
|
||||
import { LanguageConfiguration, IndentationRule, OnEnterRule } from 'vs/editor/common/modes/languageConfiguration';
|
||||
import { IHeapService } from './mainThreadHeapService';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
|
||||
import { toLanguageSelector } from 'vs/workbench/api/node/extHostTypeConverters';
|
||||
import URI from 'vs/base/common/uri';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadLanguageFeatures)
|
||||
export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesShape {
|
||||
@@ -36,7 +37,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
@IHeapService heapService: IHeapService,
|
||||
@IModeService modeService: IModeService,
|
||||
) {
|
||||
this._proxy = extHostContext.get(ExtHostContext.ExtHostLanguageFeatures);
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostLanguageFeatures);
|
||||
this._heapService = heapService;
|
||||
this._modeService = modeService;
|
||||
}
|
||||
@@ -47,35 +48,72 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
}
|
||||
}
|
||||
|
||||
$unregister(handle: number): TPromise<any> {
|
||||
$unregister(handle: number): void {
|
||||
let registration = this._registrations[handle];
|
||||
if (registration) {
|
||||
registration.dispose();
|
||||
delete this._registrations[handle];
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
//#region --- revive functions
|
||||
|
||||
private static _reviveLocationDto(data: LocationDto): modes.Location;
|
||||
private static _reviveLocationDto(data: LocationDto[]): modes.Location[];
|
||||
private static _reviveLocationDto(data: LocationDto | LocationDto[]): modes.Location | modes.Location[] {
|
||||
if (!data) {
|
||||
return <modes.Location>data;
|
||||
} else if (Array.isArray(data)) {
|
||||
data.forEach(l => MainThreadLanguageFeatures._reviveLocationDto(l));
|
||||
return <modes.Location[]>data;
|
||||
} else {
|
||||
data.uri = URI.revive(data.uri);
|
||||
return <modes.Location>data;
|
||||
}
|
||||
}
|
||||
|
||||
private static _reviveSymbolInformationDto(data: SymbolInformationDto): modes.SymbolInformation;
|
||||
private static _reviveSymbolInformationDto(data: SymbolInformationDto[]): modes.SymbolInformation[];
|
||||
private static _reviveSymbolInformationDto(data: SymbolInformationDto | SymbolInformationDto[]): modes.SymbolInformation | modes.SymbolInformation[] {
|
||||
if (!data) {
|
||||
return <modes.SymbolInformation>data;
|
||||
} else if (Array.isArray(data)) {
|
||||
data.forEach(MainThreadLanguageFeatures._reviveSymbolInformationDto);
|
||||
return <modes.SymbolInformation[]>data;
|
||||
} else {
|
||||
data.location = MainThreadLanguageFeatures._reviveLocationDto(data.location);
|
||||
return <modes.SymbolInformation>data;
|
||||
}
|
||||
}
|
||||
|
||||
private static _reviveCodeActionDto(data: CodeActionDto[]): modes.CodeAction[] {
|
||||
if (data) {
|
||||
data.forEach(code => reviveWorkspaceEditDto(code.edit));
|
||||
}
|
||||
return <modes.CodeAction[]>data;
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
// --- outline
|
||||
|
||||
$registerOutlineSupport(handle: number, selector: vscode.DocumentSelector): TPromise<any> {
|
||||
$registerOutlineSupport(handle: number, selector: vscode.DocumentSelector): void {
|
||||
this._registrations[handle] = modes.DocumentSymbolProviderRegistry.register(toLanguageSelector(selector), <modes.DocumentSymbolProvider>{
|
||||
provideDocumentSymbols: (model: IReadOnlyModel, token: CancellationToken): Thenable<modes.SymbolInformation[]> => {
|
||||
return wireCancellationToken(token, this._proxy.$provideDocumentSymbols(handle, model.uri));
|
||||
provideDocumentSymbols: (model: ITextModel, token: CancellationToken): Thenable<modes.SymbolInformation[]> => {
|
||||
return wireCancellationToken(token, this._proxy.$provideDocumentSymbols(handle, model.uri)).then(MainThreadLanguageFeatures._reviveSymbolInformationDto);
|
||||
}
|
||||
});
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// --- code lens
|
||||
|
||||
$registerCodeLensSupport(handle: number, selector: vscode.DocumentSelector, eventHandle: number): TPromise<any> {
|
||||
$registerCodeLensSupport(handle: number, selector: vscode.DocumentSelector, eventHandle: number): void {
|
||||
|
||||
const provider = <modes.CodeLensProvider>{
|
||||
provideCodeLenses: (model: IReadOnlyModel, token: CancellationToken): modes.ICodeLensSymbol[] | Thenable<modes.ICodeLensSymbol[]> => {
|
||||
provideCodeLenses: (model: ITextModel, token: CancellationToken): modes.ICodeLensSymbol[] | Thenable<modes.ICodeLensSymbol[]> => {
|
||||
return this._heapService.trackRecursive(wireCancellationToken(token, this._proxy.$provideCodeLenses(handle, model.uri)));
|
||||
},
|
||||
resolveCodeLens: (model: IReadOnlyModel, codeLens: modes.ICodeLensSymbol, token: CancellationToken): modes.ICodeLensSymbol | Thenable<modes.ICodeLensSymbol> => {
|
||||
resolveCodeLens: (model: ITextModel, codeLens: modes.ICodeLensSymbol, token: CancellationToken): modes.ICodeLensSymbol | Thenable<modes.ICodeLensSymbol> => {
|
||||
return this._heapService.trackRecursive(wireCancellationToken(token, this._proxy.$resolveCodeLens(handle, model.uri, codeLens)));
|
||||
}
|
||||
};
|
||||
@@ -87,162 +125,149 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
}
|
||||
|
||||
this._registrations[handle] = modes.CodeLensProviderRegistry.register(toLanguageSelector(selector), provider);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
$emitCodeLensEvent(eventHandle: number, event?: any): TPromise<any> {
|
||||
$emitCodeLensEvent(eventHandle: number, event?: any): void {
|
||||
const obj = this._registrations[eventHandle];
|
||||
if (obj instanceof Emitter) {
|
||||
obj.fire(event);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// --- declaration
|
||||
|
||||
$registerDeclaractionSupport(handle: number, selector: vscode.DocumentSelector): TPromise<any> {
|
||||
$registerDeclaractionSupport(handle: number, selector: vscode.DocumentSelector): void {
|
||||
this._registrations[handle] = modes.DefinitionProviderRegistry.register(toLanguageSelector(selector), <modes.DefinitionProvider>{
|
||||
provideDefinition: (model, position, token): Thenable<modes.Definition> => {
|
||||
return wireCancellationToken(token, this._proxy.$provideDefinition(handle, model.uri, position));
|
||||
return wireCancellationToken(token, this._proxy.$provideDefinition(handle, model.uri, position)).then(MainThreadLanguageFeatures._reviveLocationDto);
|
||||
}
|
||||
});
|
||||
return undefined;
|
||||
}
|
||||
|
||||
$registerImplementationSupport(handle: number, selector: vscode.DocumentSelector): TPromise<any> {
|
||||
$registerImplementationSupport(handle: number, selector: vscode.DocumentSelector): void {
|
||||
this._registrations[handle] = modes.ImplementationProviderRegistry.register(toLanguageSelector(selector), <modes.ImplementationProvider>{
|
||||
provideImplementation: (model, position, token): Thenable<modes.Definition> => {
|
||||
return wireCancellationToken(token, this._proxy.$provideImplementation(handle, model.uri, position));
|
||||
return wireCancellationToken(token, this._proxy.$provideImplementation(handle, model.uri, position)).then(MainThreadLanguageFeatures._reviveLocationDto);
|
||||
}
|
||||
});
|
||||
return undefined;
|
||||
}
|
||||
|
||||
$registerTypeDefinitionSupport(handle: number, selector: vscode.DocumentSelector): TPromise<any> {
|
||||
$registerTypeDefinitionSupport(handle: number, selector: vscode.DocumentSelector): void {
|
||||
this._registrations[handle] = modes.TypeDefinitionProviderRegistry.register(toLanguageSelector(selector), <modes.TypeDefinitionProvider>{
|
||||
provideTypeDefinition: (model, position, token): Thenable<modes.Definition> => {
|
||||
return wireCancellationToken(token, this._proxy.$provideTypeDefinition(handle, model.uri, position));
|
||||
return wireCancellationToken(token, this._proxy.$provideTypeDefinition(handle, model.uri, position)).then(MainThreadLanguageFeatures._reviveLocationDto);
|
||||
}
|
||||
});
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// --- extra info
|
||||
|
||||
$registerHoverProvider(handle: number, selector: vscode.DocumentSelector): TPromise<any> {
|
||||
$registerHoverProvider(handle: number, selector: vscode.DocumentSelector): void {
|
||||
this._registrations[handle] = modes.HoverProviderRegistry.register(toLanguageSelector(selector), <modes.HoverProvider>{
|
||||
provideHover: (model: IReadOnlyModel, position: EditorPosition, token: CancellationToken): Thenable<modes.Hover> => {
|
||||
provideHover: (model: ITextModel, position: EditorPosition, token: CancellationToken): Thenable<modes.Hover> => {
|
||||
return wireCancellationToken(token, this._proxy.$provideHover(handle, model.uri, position));
|
||||
}
|
||||
});
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// --- occurrences
|
||||
|
||||
$registerDocumentHighlightProvider(handle: number, selector: vscode.DocumentSelector): TPromise<any> {
|
||||
$registerDocumentHighlightProvider(handle: number, selector: vscode.DocumentSelector): void {
|
||||
this._registrations[handle] = modes.DocumentHighlightProviderRegistry.register(toLanguageSelector(selector), <modes.DocumentHighlightProvider>{
|
||||
provideDocumentHighlights: (model: IReadOnlyModel, position: EditorPosition, token: CancellationToken): Thenable<modes.DocumentHighlight[]> => {
|
||||
provideDocumentHighlights: (model: ITextModel, position: EditorPosition, token: CancellationToken): Thenable<modes.DocumentHighlight[]> => {
|
||||
return wireCancellationToken(token, this._proxy.$provideDocumentHighlights(handle, model.uri, position));
|
||||
}
|
||||
});
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// --- references
|
||||
|
||||
$registerReferenceSupport(handle: number, selector: vscode.DocumentSelector): TPromise<any> {
|
||||
$registerReferenceSupport(handle: number, selector: vscode.DocumentSelector): void {
|
||||
this._registrations[handle] = modes.ReferenceProviderRegistry.register(toLanguageSelector(selector), <modes.ReferenceProvider>{
|
||||
provideReferences: (model: IReadOnlyModel, position: EditorPosition, context: modes.ReferenceContext, token: CancellationToken): Thenable<modes.Location[]> => {
|
||||
return wireCancellationToken(token, this._proxy.$provideReferences(handle, model.uri, position, context));
|
||||
provideReferences: (model: ITextModel, position: EditorPosition, context: modes.ReferenceContext, token: CancellationToken): Thenable<modes.Location[]> => {
|
||||
return wireCancellationToken(token, this._proxy.$provideReferences(handle, model.uri, position, context)).then(MainThreadLanguageFeatures._reviveLocationDto);
|
||||
}
|
||||
});
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// --- quick fix
|
||||
|
||||
$registerQuickFixSupport(handle: number, selector: vscode.DocumentSelector): TPromise<any> {
|
||||
$registerQuickFixSupport(handle: number, selector: vscode.DocumentSelector): void {
|
||||
this._registrations[handle] = modes.CodeActionProviderRegistry.register(toLanguageSelector(selector), <modes.CodeActionProvider>{
|
||||
provideCodeActions: (model: IReadOnlyModel, range: EditorRange, token: CancellationToken): Thenable<modes.CodeAction[]> => {
|
||||
return this._heapService.trackRecursive(wireCancellationToken(token, this._proxy.$provideCodeActions(handle, model.uri, range)));
|
||||
provideCodeActions: (model: ITextModel, range: EditorRange, context: modes.CodeActionContext, token: CancellationToken): Thenable<modes.CodeAction[]> => {
|
||||
return this._heapService.trackRecursive(wireCancellationToken(token, this._proxy.$provideCodeActions(handle, model.uri, range, context))).then(MainThreadLanguageFeatures._reviveCodeActionDto);
|
||||
}
|
||||
});
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// --- formatting
|
||||
|
||||
$registerDocumentFormattingSupport(handle: number, selector: vscode.DocumentSelector): TPromise<any> {
|
||||
$registerDocumentFormattingSupport(handle: number, selector: vscode.DocumentSelector): void {
|
||||
this._registrations[handle] = modes.DocumentFormattingEditProviderRegistry.register(toLanguageSelector(selector), <modes.DocumentFormattingEditProvider>{
|
||||
provideDocumentFormattingEdits: (model: IReadOnlyModel, options: modes.FormattingOptions, token: CancellationToken): Thenable<ISingleEditOperation[]> => {
|
||||
provideDocumentFormattingEdits: (model: ITextModel, options: modes.FormattingOptions, token: CancellationToken): Thenable<ISingleEditOperation[]> => {
|
||||
return wireCancellationToken(token, this._proxy.$provideDocumentFormattingEdits(handle, model.uri, options));
|
||||
}
|
||||
});
|
||||
return undefined;
|
||||
}
|
||||
|
||||
$registerRangeFormattingSupport(handle: number, selector: vscode.DocumentSelector): TPromise<any> {
|
||||
$registerRangeFormattingSupport(handle: number, selector: vscode.DocumentSelector): void {
|
||||
this._registrations[handle] = modes.DocumentRangeFormattingEditProviderRegistry.register(toLanguageSelector(selector), <modes.DocumentRangeFormattingEditProvider>{
|
||||
provideDocumentRangeFormattingEdits: (model: IReadOnlyModel, range: EditorRange, options: modes.FormattingOptions, token: CancellationToken): Thenable<ISingleEditOperation[]> => {
|
||||
provideDocumentRangeFormattingEdits: (model: ITextModel, range: EditorRange, options: modes.FormattingOptions, token: CancellationToken): Thenable<ISingleEditOperation[]> => {
|
||||
return wireCancellationToken(token, this._proxy.$provideDocumentRangeFormattingEdits(handle, model.uri, range, options));
|
||||
}
|
||||
});
|
||||
return undefined;
|
||||
}
|
||||
|
||||
$registerOnTypeFormattingSupport(handle: number, selector: vscode.DocumentSelector, autoFormatTriggerCharacters: string[]): TPromise<any> {
|
||||
$registerOnTypeFormattingSupport(handle: number, selector: vscode.DocumentSelector, autoFormatTriggerCharacters: string[]): void {
|
||||
this._registrations[handle] = modes.OnTypeFormattingEditProviderRegistry.register(toLanguageSelector(selector), <modes.OnTypeFormattingEditProvider>{
|
||||
|
||||
autoFormatTriggerCharacters,
|
||||
|
||||
provideOnTypeFormattingEdits: (model: IReadOnlyModel, position: EditorPosition, ch: string, options: modes.FormattingOptions, token: CancellationToken): Thenable<ISingleEditOperation[]> => {
|
||||
provideOnTypeFormattingEdits: (model: ITextModel, position: EditorPosition, ch: string, options: modes.FormattingOptions, token: CancellationToken): Thenable<ISingleEditOperation[]> => {
|
||||
return wireCancellationToken(token, this._proxy.$provideOnTypeFormattingEdits(handle, model.uri, position, ch, options));
|
||||
}
|
||||
});
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// --- navigate type
|
||||
|
||||
$registerNavigateTypeSupport(handle: number): TPromise<any> {
|
||||
$registerNavigateTypeSupport(handle: number): void {
|
||||
let lastResultId: number;
|
||||
this._registrations[handle] = WorkspaceSymbolProviderRegistry.register(<IWorkspaceSymbolProvider>{
|
||||
provideWorkspaceSymbols: (search: string): TPromise<modes.SymbolInformation[]> => {
|
||||
|
||||
return this._proxy.$provideWorkspaceSymbols(handle, search).then(result => {
|
||||
if (lastResultId !== undefined) {
|
||||
this._proxy.$releaseWorkspaceSymbols(handle, lastResultId);
|
||||
}
|
||||
lastResultId = result._id;
|
||||
return result.symbols;
|
||||
return MainThreadLanguageFeatures._reviveSymbolInformationDto(result.symbols);
|
||||
});
|
||||
},
|
||||
resolveWorkspaceSymbol: (item: modes.SymbolInformation): TPromise<modes.SymbolInformation> => {
|
||||
return this._proxy.$resolveWorkspaceSymbol(handle, item);
|
||||
return this._proxy.$resolveWorkspaceSymbol(handle, item).then(i => MainThreadLanguageFeatures._reviveSymbolInformationDto(i));
|
||||
}
|
||||
});
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// --- rename
|
||||
|
||||
$registerRenameSupport(handle: number, selector: vscode.DocumentSelector): TPromise<any> {
|
||||
$registerRenameSupport(handle: number, selector: vscode.DocumentSelector, supportsResolveInitialValues: boolean): void {
|
||||
this._registrations[handle] = modes.RenameProviderRegistry.register(toLanguageSelector(selector), <modes.RenameProvider>{
|
||||
provideRenameEdits: (model: IReadOnlyModel, position: EditorPosition, newName: string, token: CancellationToken): Thenable<modes.WorkspaceEdit> => {
|
||||
return wireCancellationToken(token, this._proxy.$provideRenameEdits(handle, model.uri, position, newName));
|
||||
}
|
||||
provideRenameEdits: (model: ITextModel, position: EditorPosition, newName: string, token: CancellationToken): Thenable<modes.WorkspaceEdit> => {
|
||||
return wireCancellationToken(token, this._proxy.$provideRenameEdits(handle, model.uri, position, newName)).then(reviveWorkspaceEditDto);
|
||||
},
|
||||
resolveInitialRenameValue: supportsResolveInitialValues
|
||||
? (model: ITextModel, position: EditorPosition, token: CancellationToken): Thenable<modes.RenameInitialValue> => wireCancellationToken(token, this._proxy.$resolveInitialRenameValue(handle, model.uri, position))
|
||||
: undefined
|
||||
});
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// --- suggest
|
||||
|
||||
$registerSuggestSupport(handle: number, selector: vscode.DocumentSelector, triggerCharacters: string[], supportsResolveDetails: boolean): TPromise<any> {
|
||||
|
||||
$registerSuggestSupport(handle: number, selector: vscode.DocumentSelector, triggerCharacters: string[], supportsResolveDetails: boolean): void {
|
||||
this._registrations[handle] = modes.SuggestRegistry.register(toLanguageSelector(selector), <modes.ISuggestSupport>{
|
||||
triggerCharacters,
|
||||
provideCompletionItems: (model: IReadOnlyModel, position: EditorPosition, context: modes.SuggestContext, token: CancellationToken): Thenable<modes.ISuggestResult> => {
|
||||
provideCompletionItems: (model: ITextModel, position: EditorPosition, context: modes.SuggestContext, token: CancellationToken): Thenable<modes.ISuggestResult> => {
|
||||
return wireCancellationToken(token, this._proxy.$provideCompletionItems(handle, model.uri, position, context)).then(result => {
|
||||
if (!result) {
|
||||
return result;
|
||||
@@ -258,27 +283,25 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
? (model, position, suggestion, token) => wireCancellationToken(token, this._proxy.$resolveCompletionItem(handle, model.uri, position, suggestion))
|
||||
: undefined
|
||||
});
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// --- parameter hints
|
||||
|
||||
$registerSignatureHelpProvider(handle: number, selector: vscode.DocumentSelector, triggerCharacter: string[]): TPromise<any> {
|
||||
$registerSignatureHelpProvider(handle: number, selector: vscode.DocumentSelector, triggerCharacter: string[]): void {
|
||||
this._registrations[handle] = modes.SignatureHelpProviderRegistry.register(toLanguageSelector(selector), <modes.SignatureHelpProvider>{
|
||||
|
||||
signatureHelpTriggerCharacters: triggerCharacter,
|
||||
|
||||
provideSignatureHelp: (model: IReadOnlyModel, position: EditorPosition, token: CancellationToken): Thenable<modes.SignatureHelp> => {
|
||||
provideSignatureHelp: (model: ITextModel, position: EditorPosition, token: CancellationToken): Thenable<modes.SignatureHelp> => {
|
||||
return wireCancellationToken(token, this._proxy.$provideSignatureHelp(handle, model.uri, position));
|
||||
}
|
||||
|
||||
});
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// --- links
|
||||
|
||||
$registerDocumentLinkProvider(handle: number, selector: vscode.DocumentSelector): TPromise<any> {
|
||||
$registerDocumentLinkProvider(handle: number, selector: vscode.DocumentSelector): void {
|
||||
this._registrations[handle] = modes.LinkProviderRegistry.register(toLanguageSelector(selector), <modes.LinkProvider>{
|
||||
provideLinks: (model, token) => {
|
||||
return this._heapService.trackRecursive(wireCancellationToken(token, this._proxy.$provideDocumentLinks(handle, model.uri)));
|
||||
@@ -287,12 +310,11 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
return wireCancellationToken(token, this._proxy.$resolveDocumentLink(handle, link));
|
||||
}
|
||||
});
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// --- colors
|
||||
|
||||
$registerDocumentColorProvider(handle: number, selector: vscode.DocumentSelector): TPromise<any> {
|
||||
$registerDocumentColorProvider(handle: number, selector: vscode.DocumentSelector): void {
|
||||
const proxy = this._proxy;
|
||||
this._registrations[handle] = modes.ColorProviderRegistry.register(toLanguageSelector(selector), <modes.DocumentColorProvider>{
|
||||
provideDocumentColors: (model, token) => {
|
||||
@@ -322,20 +344,72 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
}));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return TPromise.as(null);
|
||||
// --- folding
|
||||
|
||||
$registerFoldingProvider(handle: number, selector: vscode.DocumentSelector): void {
|
||||
const proxy = this._proxy;
|
||||
this._registrations[handle] = modes.FoldingProviderRegistry.register(toLanguageSelector(selector), <modes.FoldingProvider>{
|
||||
provideFoldingRanges: (model, token) => {
|
||||
return wireCancellationToken(token, proxy.$provideFoldingRanges(handle, model.uri));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// --- configuration
|
||||
|
||||
$setLanguageConfiguration(handle: number, languageId: string, _configuration: vscode.LanguageConfiguration): TPromise<any> {
|
||||
private static _reviveRegExp(regExp: ISerializedRegExp): RegExp {
|
||||
if (typeof regExp === 'undefined') {
|
||||
return undefined;
|
||||
}
|
||||
if (regExp === null) {
|
||||
return null;
|
||||
}
|
||||
return new RegExp(regExp.pattern, regExp.flags);
|
||||
}
|
||||
|
||||
private static _reviveIndentationRule(indentationRule: ISerializedIndentationRule): IndentationRule {
|
||||
if (typeof indentationRule === 'undefined') {
|
||||
return undefined;
|
||||
}
|
||||
if (indentationRule === null) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
decreaseIndentPattern: MainThreadLanguageFeatures._reviveRegExp(indentationRule.decreaseIndentPattern),
|
||||
increaseIndentPattern: MainThreadLanguageFeatures._reviveRegExp(indentationRule.increaseIndentPattern),
|
||||
indentNextLinePattern: MainThreadLanguageFeatures._reviveRegExp(indentationRule.indentNextLinePattern),
|
||||
unIndentedLinePattern: MainThreadLanguageFeatures._reviveRegExp(indentationRule.unIndentedLinePattern),
|
||||
};
|
||||
}
|
||||
|
||||
private static _reviveOnEnterRule(onEnterRule: ISerializedOnEnterRule): OnEnterRule {
|
||||
return {
|
||||
beforeText: MainThreadLanguageFeatures._reviveRegExp(onEnterRule.beforeText),
|
||||
afterText: MainThreadLanguageFeatures._reviveRegExp(onEnterRule.afterText),
|
||||
action: onEnterRule.action
|
||||
};
|
||||
}
|
||||
|
||||
private static _reviveOnEnterRules(onEnterRules: ISerializedOnEnterRule[]): OnEnterRule[] {
|
||||
if (typeof onEnterRules === 'undefined') {
|
||||
return undefined;
|
||||
}
|
||||
if (onEnterRules === null) {
|
||||
return null;
|
||||
}
|
||||
return onEnterRules.map(MainThreadLanguageFeatures._reviveOnEnterRule);
|
||||
}
|
||||
|
||||
$setLanguageConfiguration(handle: number, languageId: string, _configuration: ISerializedLanguageConfiguration): void {
|
||||
|
||||
let configuration: LanguageConfiguration = {
|
||||
comments: _configuration.comments,
|
||||
brackets: _configuration.brackets,
|
||||
wordPattern: _configuration.wordPattern,
|
||||
indentationRules: _configuration.indentationRules,
|
||||
onEnterRules: _configuration.onEnterRules,
|
||||
wordPattern: MainThreadLanguageFeatures._reviveRegExp(_configuration.wordPattern),
|
||||
indentationRules: MainThreadLanguageFeatures._reviveIndentationRule(_configuration.indentationRules),
|
||||
onEnterRules: MainThreadLanguageFeatures._reviveOnEnterRules(_configuration.onEnterRules),
|
||||
|
||||
autoClosingPairs: null,
|
||||
surroundingPairs: null,
|
||||
@@ -360,8 +434,6 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
if (languageIdentifier) {
|
||||
this._registrations[handle] = LanguageConfigurationRegistry.register(languageIdentifier, configuration);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { extHostCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IExtHostContext, ExtHostContext } from 'vs/workbench/api/node/extHost.protocol';
|
||||
|
||||
@extHostCustomer
|
||||
export class MainThreadLogService extends Disposable {
|
||||
|
||||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
@ILogService logService: ILogService,
|
||||
) {
|
||||
super();
|
||||
this._register(logService.onDidChangeLogLevel(level => extHostContext.getProxy(ExtHostContext.ExtHostLogService).$setLevel(level)));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,21 +5,27 @@
|
||||
'use strict';
|
||||
|
||||
import nls = require('vs/nls');
|
||||
import { IMessageService, IChoiceService } from 'vs/platform/message/common/message';
|
||||
import Severity from 'vs/base/common/severity';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { TPromise as Promise } from 'vs/base/common/winjs.base';
|
||||
import { Action, IAction } from 'vs/base/common/actions';
|
||||
import { MainThreadMessageServiceShape, MainContext, IExtHostContext, MainThreadMessageOptions } from '../node/extHost.protocol';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IChoiceService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { once } from 'vs/base/common/event';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadMessageService)
|
||||
export class MainThreadMessageService implements MainThreadMessageServiceShape {
|
||||
|
||||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
@IMessageService private readonly _messageService: IMessageService,
|
||||
@IChoiceService private readonly _choiceService: IChoiceService
|
||||
@INotificationService private readonly _notificationService: INotificationService,
|
||||
@ICommandService private readonly _commandService: ICommandService,
|
||||
@IChoiceService private readonly _choiceService: IChoiceService,
|
||||
@IEnvironmentService private readonly _environmentService: IEnvironmentService
|
||||
) {
|
||||
//
|
||||
}
|
||||
@@ -40,38 +46,54 @@ export class MainThreadMessageService implements MainThreadMessageServiceShape {
|
||||
|
||||
return new Promise<number>(resolve => {
|
||||
|
||||
let messageHide: Function;
|
||||
let actions: MessageItemAction[] = [];
|
||||
let hasCloseAffordance = false;
|
||||
let primaryActions: MessageItemAction[] = [];
|
||||
|
||||
class MessageItemAction extends Action {
|
||||
constructor(id: string, label: string, handle: number) {
|
||||
super(id, label, undefined, true, () => {
|
||||
resolve(handle);
|
||||
messageHide(); // triggers dispose! make sure promise is already resolved
|
||||
return undefined;
|
||||
});
|
||||
}
|
||||
dispose(): void {
|
||||
resolve(undefined);
|
||||
}
|
||||
|
||||
class ManageExtensionAction extends Action {
|
||||
constructor(id: string, label: string, commandService: ICommandService) {
|
||||
super(id, label, undefined, true, () => {
|
||||
return commandService.executeCommand('_extensions.manage', id);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
commands.forEach(command => {
|
||||
if (command.isCloseAffordance === true) {
|
||||
hasCloseAffordance = true;
|
||||
}
|
||||
actions.push(new MessageItemAction('_extension_message_handle_' + command.handle, command.title, command.handle));
|
||||
primaryActions.push(new MessageItemAction('_extension_message_handle_' + command.handle, command.title, command.handle));
|
||||
});
|
||||
|
||||
if (!hasCloseAffordance) {
|
||||
actions.push(new MessageItemAction('__close', nls.localize('close', "Close"), undefined));
|
||||
let source: string;
|
||||
if (extension) {
|
||||
source = localize('extensionSource', "{0} (Extension)", extension.displayName || extension.name);
|
||||
}
|
||||
|
||||
messageHide = this._messageService.show(severity, {
|
||||
if (!source) {
|
||||
source = localize('defaultSource', "Extension");
|
||||
}
|
||||
|
||||
const secondaryActions: IAction[] = [];
|
||||
if (extension && extension.extensionFolderPath !== this._environmentService.extensionDevelopmentPath) {
|
||||
secondaryActions.push(new ManageExtensionAction(extension.id, nls.localize('manageExtension', "Manage Extension"), this._commandService));
|
||||
}
|
||||
|
||||
const messageHandle = this._notificationService.notify({
|
||||
severity,
|
||||
message,
|
||||
actions,
|
||||
source: extension && `${extension.displayName || extension.name}`
|
||||
actions: { primary: primaryActions, secondary: secondaryActions },
|
||||
source
|
||||
});
|
||||
|
||||
// if promise has not been resolved yet, now is the time to ensure a return value
|
||||
// otherwise if already resolved it means the user clicked one of the buttons
|
||||
once(messageHandle.onDidDispose)(() => {
|
||||
resolve(undefined);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -45,7 +45,8 @@ export class MainThreadOutputService implements MainThreadOutputServiceShape {
|
||||
}
|
||||
|
||||
public $reveal(channelId: string, label: string, preserveFocus: boolean): TPromise<void> {
|
||||
this._getChannel(channelId, label).show(preserveFocus);
|
||||
const channel = this._getChannel(channelId, label);
|
||||
this._outputService.showChannel(channel.id, preserveFocus);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
'use strict';
|
||||
|
||||
import { IProgressService2, IProgress, IProgressOptions, IProgressStep } from 'vs/platform/progress/common/progress';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { MainThreadProgressShape, MainContext, IExtHostContext } from '../node/extHost.protocol';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
|
||||
|
||||
@@ -47,7 +46,7 @@ export class MainThreadProgress implements MainThreadProgressShape {
|
||||
|
||||
private _createTask(handle: number) {
|
||||
return (progress: IProgress<IProgressStep>) => {
|
||||
return new TPromise<any>(resolve => {
|
||||
return new Promise<any>(resolve => {
|
||||
this._progress.set(handle, { resolve, progress });
|
||||
});
|
||||
};
|
||||
|
||||
@@ -25,7 +25,7 @@ export class MainThreadQuickOpen implements MainThreadQuickOpenShape {
|
||||
extHostContext: IExtHostContext,
|
||||
@IQuickOpenService quickOpenService: IQuickOpenService
|
||||
) {
|
||||
this._proxy = extHostContext.get(ExtHostContext.ExtHostQuickOpen);
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostQuickOpen);
|
||||
this._quickOpenService = quickOpenService;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
'use strict';
|
||||
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import URI from 'vs/base/common/uri';
|
||||
import URI, { UriComponents } from 'vs/base/common/uri';
|
||||
import Event, { Emitter } from 'vs/base/common/event';
|
||||
import { assign } from 'vs/base/common/objects';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { ISCMService, ISCMRepository, ISCMProvider, ISCMResource, ISCMResourceGroup, ISCMResourceDecorations } from 'vs/workbench/services/scm/common/scm';
|
||||
import { ISCMService, ISCMRepository, ISCMProvider, ISCMResource, ISCMResourceGroup, ISCMResourceDecorations, IInputValidation } from 'vs/workbench/services/scm/common/scm';
|
||||
import { ExtHostContext, MainThreadSCMShape, ExtHostSCMShape, SCMProviderFeatures, SCMRawResourceSplices, SCMGroupFeatures, MainContext, IExtHostContext } from '../node/extHost.protocol';
|
||||
import { Command } from 'vs/editor/common/modes';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
|
||||
@@ -212,7 +212,7 @@ class MainThreadSCMProvider implements ISCMProvider {
|
||||
this.handle,
|
||||
groupHandle,
|
||||
handle,
|
||||
URI.parse(sourceUri),
|
||||
URI.revive(sourceUri),
|
||||
group,
|
||||
decorations
|
||||
);
|
||||
@@ -241,7 +241,8 @@ class MainThreadSCMProvider implements ISCMProvider {
|
||||
return TPromise.as(null);
|
||||
}
|
||||
|
||||
return this.proxy.$provideOriginalResource(this.handle, uri);
|
||||
return this.proxy.$provideOriginalResource(this.handle, uri)
|
||||
.then(result => result && URI.revive(result));
|
||||
}
|
||||
|
||||
toJSON(): any {
|
||||
@@ -268,7 +269,7 @@ export class MainThreadSCM implements MainThreadSCMShape {
|
||||
extHostContext: IExtHostContext,
|
||||
@ISCMService private scmService: ISCMService
|
||||
) {
|
||||
this._proxy = extHostContext.get(ExtHostContext.ExtHostSCM);
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostSCM);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
@@ -283,8 +284,8 @@ export class MainThreadSCM implements MainThreadSCMShape {
|
||||
this._disposables = dispose(this._disposables);
|
||||
}
|
||||
|
||||
$registerSourceControl(handle: number, id: string, label: string, rootUri: string | undefined): void {
|
||||
const provider = new MainThreadSCMProvider(this._proxy, handle, id, label, rootUri && URI.parse(rootUri), this.scmService);
|
||||
$registerSourceControl(handle: number, id: string, label: string, rootUri: UriComponents | undefined): void {
|
||||
const provider = new MainThreadSCMProvider(this._proxy, handle, id, label, rootUri && URI.revive(rootUri), this.scmService);
|
||||
const repository = this.scmService.registerSCMProvider(provider);
|
||||
this._repositories[handle] = repository;
|
||||
|
||||
@@ -391,4 +392,29 @@ export class MainThreadSCM implements MainThreadSCMShape {
|
||||
|
||||
repository.input.placeholder = placeholder;
|
||||
}
|
||||
|
||||
$setValidationProviderIsEnabled(sourceControlHandle: number, enabled: boolean): void {
|
||||
const repository = this._repositories[sourceControlHandle];
|
||||
|
||||
if (!repository) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (enabled) {
|
||||
repository.input.validateInput = async (value, pos): TPromise<IInputValidation | undefined> => {
|
||||
const result = await this._proxy.$validateInput(sourceControlHandle, value, pos);
|
||||
|
||||
if (!result) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
message: result[0],
|
||||
type: result[1]
|
||||
};
|
||||
};
|
||||
} else {
|
||||
repository.input.validateInput = () => TPromise.as(undefined);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,18 +5,17 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { sequence } from 'vs/base/common/async';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
import { ISaveParticipant, ITextFileEditorModel, SaveReason } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IModel, ISingleEditOperation, IIdentifiedSingleEditOperation } from 'vs/editor/common/editorCommon';
|
||||
import { ITextModel, ISingleEditOperation, IIdentifiedSingleEditOperation } from 'vs/editor/common/model';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { trimTrailingWhitespace } from 'vs/editor/common/commands/trimTrailingWhitespaceCommand';
|
||||
import { getDocumentFormattingEdits } from 'vs/editor/contrib/format/format';
|
||||
import { getDocumentFormattingEdits, NoProviderError } from 'vs/editor/contrib/format/format';
|
||||
import { EditOperationsCommand } from 'vs/editor/contrib/format/formatCommand';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel';
|
||||
@@ -25,8 +24,16 @@ import { EditOperation } from 'vs/editor/common/core/editOperation';
|
||||
import { extHostCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
|
||||
import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { IProgressService2, ProgressLocation } from 'vs/platform/progress/common/progress';
|
||||
import { localize } from 'vs/nls';
|
||||
import { isFalsyOrEmpty } from 'vs/base/common/arrays';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
|
||||
class TrimWhitespaceParticipant implements ISaveParticipant {
|
||||
export interface ISaveParticipantParticipant extends ISaveParticipant {
|
||||
// progressMessage: string;
|
||||
}
|
||||
|
||||
class TrimWhitespaceParticipant implements ISaveParticipantParticipant {
|
||||
|
||||
constructor(
|
||||
@IConfigurationService private configurationService: IConfigurationService,
|
||||
@@ -41,7 +48,7 @@ class TrimWhitespaceParticipant implements ISaveParticipant {
|
||||
}
|
||||
}
|
||||
|
||||
private doTrimTrailingWhitespace(model: IModel, isAutoSaved: boolean): void {
|
||||
private doTrimTrailingWhitespace(model: ITextModel, isAutoSaved: boolean): void {
|
||||
let prevSelection: Selection[] = [new Selection(1, 1, 1, 1)];
|
||||
const cursors: Position[] = [];
|
||||
|
||||
@@ -64,7 +71,7 @@ class TrimWhitespaceParticipant implements ISaveParticipant {
|
||||
}
|
||||
}
|
||||
|
||||
function findEditor(model: IModel, codeEditorService: ICodeEditorService): ICodeEditor {
|
||||
function findEditor(model: ITextModel, codeEditorService: ICodeEditorService): ICodeEditor {
|
||||
let candidate: ICodeEditor = null;
|
||||
|
||||
if (model.isAttachedToEditor()) {
|
||||
@@ -82,7 +89,7 @@ function findEditor(model: IModel, codeEditorService: ICodeEditorService): ICode
|
||||
return candidate;
|
||||
}
|
||||
|
||||
export class FinalNewLineParticipant implements ISaveParticipant {
|
||||
export class FinalNewLineParticipant implements ISaveParticipantParticipant {
|
||||
|
||||
constructor(
|
||||
@IConfigurationService private configurationService: IConfigurationService,
|
||||
@@ -97,7 +104,7 @@ export class FinalNewLineParticipant implements ISaveParticipant {
|
||||
}
|
||||
}
|
||||
|
||||
private doInsertFinalNewLine(model: IModel): void {
|
||||
private doInsertFinalNewLine(model: ITextModel): void {
|
||||
const lineCount = model.getLineCount();
|
||||
const lastLine = model.getLineContent(lineCount);
|
||||
const lastLineIsEmptyOrWhitespace = strings.lastNonWhitespaceIndex(lastLine) === -1;
|
||||
@@ -120,7 +127,7 @@ export class FinalNewLineParticipant implements ISaveParticipant {
|
||||
}
|
||||
}
|
||||
|
||||
export class TrimFinalNewLinesParticipant implements ISaveParticipant {
|
||||
export class TrimFinalNewLinesParticipant implements ISaveParticipantParticipant {
|
||||
|
||||
constructor(
|
||||
@IConfigurationService private configurationService: IConfigurationService,
|
||||
@@ -135,11 +142,11 @@ export class TrimFinalNewLinesParticipant implements ISaveParticipant {
|
||||
}
|
||||
}
|
||||
|
||||
private doTrimFinalNewLines(model: IModel): void {
|
||||
private doTrimFinalNewLines(model: ITextModel): void {
|
||||
const lineCount = model.getLineCount();
|
||||
|
||||
// Do not insert new line if file does not end with new line
|
||||
if (!lineCount) {
|
||||
if (lineCount === 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -157,7 +164,11 @@ export class TrimFinalNewLinesParticipant implements ISaveParticipant {
|
||||
currentLine = model.getLineContent(currentLineNumber);
|
||||
currentLineIsEmptyOrWhitespace = strings.lastNonWhitespaceIndex(currentLine) === -1;
|
||||
}
|
||||
model.pushEditOperations(prevSelection, [EditOperation.delete(new Range(currentLineNumber + 1, 1, lineCount + 1, 1))], edits => prevSelection);
|
||||
|
||||
const deletionRange = new Range(currentLineNumber + 1, 1, lineCount + 1, 1);
|
||||
if (!deletionRange.isEmpty()) {
|
||||
model.pushEditOperations(prevSelection, [EditOperation.delete(deletionRange)], edits => prevSelection);
|
||||
}
|
||||
|
||||
if (editor) {
|
||||
editor.setSelections(prevSelection);
|
||||
@@ -165,17 +176,17 @@ export class TrimFinalNewLinesParticipant implements ISaveParticipant {
|
||||
}
|
||||
}
|
||||
|
||||
class FormatOnSaveParticipant implements ISaveParticipant {
|
||||
class FormatOnSaveParticipant implements ISaveParticipantParticipant {
|
||||
|
||||
constructor(
|
||||
@ICodeEditorService private _editorService: ICodeEditorService,
|
||||
@IEditorWorkerService private _editorWorkerService: IEditorWorkerService,
|
||||
@IConfigurationService private _configurationService: IConfigurationService
|
||||
@ICodeEditorService private readonly _editorService: ICodeEditorService,
|
||||
@IEditorWorkerService private readonly _editorWorkerService: IEditorWorkerService,
|
||||
@IConfigurationService private readonly _configurationService: IConfigurationService
|
||||
) {
|
||||
// Nothing
|
||||
}
|
||||
|
||||
participate(editorModel: ITextFileEditorModel, env: { reason: SaveReason }): TPromise<void> {
|
||||
participate(editorModel: ITextFileEditorModel, env: { reason: SaveReason }): Promise<void> {
|
||||
|
||||
const model = editorModel.textEditorModel;
|
||||
if (env.reason === SaveReason.AUTO
|
||||
@@ -186,14 +197,20 @@ class FormatOnSaveParticipant implements ISaveParticipant {
|
||||
const versionNow = model.getVersionId();
|
||||
const { tabSize, insertSpaces } = model.getOptions();
|
||||
|
||||
return new TPromise<ISingleEditOperation[]>((resolve, reject) => {
|
||||
return new Promise<ISingleEditOperation[]>((resolve, reject) => {
|
||||
setTimeout(reject, 750);
|
||||
getDocumentFormattingEdits(model, { tabSize, insertSpaces })
|
||||
.then(edits => this._editorWorkerService.computeMoreMinimalEdits(model.uri, edits))
|
||||
.then(resolve, reject);
|
||||
.then(resolve, err => {
|
||||
if (!(err instanceof Error) || err.name !== NoProviderError.Name) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
|
||||
}).then(edits => {
|
||||
if (edits && versionNow === model.getVersionId()) {
|
||||
if (!isFalsyOrEmpty(edits) && versionNow === model.getVersionId()) {
|
||||
const editor = findEditor(model, this._editorService);
|
||||
if (editor) {
|
||||
this._editsWithEditor(editor, edits);
|
||||
@@ -205,10 +222,10 @@ class FormatOnSaveParticipant implements ISaveParticipant {
|
||||
}
|
||||
|
||||
private _editsWithEditor(editor: ICodeEditor, edits: ISingleEditOperation[]): void {
|
||||
EditOperationsCommand.execute(editor, edits);
|
||||
EditOperationsCommand.execute(editor, edits, false);
|
||||
}
|
||||
|
||||
private _editWithModel(model: IModel, edits: ISingleEditOperation[]): void {
|
||||
private _editWithModel(model: ITextModel, edits: ISingleEditOperation[]): void {
|
||||
|
||||
const [{ range }] = edits;
|
||||
const initialSelection = new Selection(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn);
|
||||
@@ -227,27 +244,33 @@ class FormatOnSaveParticipant implements ISaveParticipant {
|
||||
return {
|
||||
text,
|
||||
range: Range.lift(range),
|
||||
identifier: undefined,
|
||||
forceMoveMarkers: true
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class ExtHostSaveParticipant implements ISaveParticipant {
|
||||
class ExtHostSaveParticipant implements ISaveParticipantParticipant {
|
||||
|
||||
private _proxy: ExtHostDocumentSaveParticipantShape;
|
||||
|
||||
constructor(extHostContext: IExtHostContext) {
|
||||
this._proxy = extHostContext.get(ExtHostContext.ExtHostDocumentSaveParticipant);
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostDocumentSaveParticipant);
|
||||
}
|
||||
|
||||
participate(editorModel: ITextFileEditorModel, env: { reason: SaveReason }): TPromise<void> {
|
||||
return new TPromise<any>((resolve, reject) => {
|
||||
participate(editorModel: ITextFileEditorModel, env: { reason: SaveReason }): Promise<void> {
|
||||
|
||||
if (editorModel.textEditorModel.isTooLargeForHavingARichMode()) {
|
||||
// the model never made it to the extension
|
||||
// host meaning we cannot participate in its save
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return new Promise<any>((resolve, reject) => {
|
||||
setTimeout(reject, 1750);
|
||||
this._proxy.$participateInSave(editorModel.getResource(), env.reason).then(values => {
|
||||
for (const success of values) {
|
||||
if (!success) {
|
||||
return TPromise.wrapError(new Error('listener failed'));
|
||||
return Promise.reject(new Error('listener failed'));
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
@@ -260,24 +283,21 @@ class ExtHostSaveParticipant implements ISaveParticipant {
|
||||
@extHostCustomer
|
||||
export class SaveParticipant implements ISaveParticipant {
|
||||
|
||||
private _saveParticipants: ISaveParticipant[];
|
||||
private _saveParticipants: ISaveParticipantParticipant[];
|
||||
|
||||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@IConfigurationService configurationService: IConfigurationService,
|
||||
@ICodeEditorService codeEditorService: ICodeEditorService,
|
||||
@IEditorWorkerService editorWorkerService: IEditorWorkerService
|
||||
@IProgressService2 private readonly _progressService: IProgressService2,
|
||||
@ILogService private readonly _logService: ILogService
|
||||
) {
|
||||
|
||||
this._saveParticipants = [
|
||||
new TrimWhitespaceParticipant(configurationService, codeEditorService),
|
||||
new FormatOnSaveParticipant(codeEditorService, editorWorkerService, configurationService),
|
||||
new FinalNewLineParticipant(configurationService, codeEditorService),
|
||||
new TrimFinalNewLinesParticipant(configurationService, codeEditorService),
|
||||
new ExtHostSaveParticipant(extHostContext)
|
||||
instantiationService.createInstance(TrimWhitespaceParticipant),
|
||||
instantiationService.createInstance(FormatOnSaveParticipant),
|
||||
instantiationService.createInstance(FinalNewLineParticipant),
|
||||
instantiationService.createInstance(TrimFinalNewLinesParticipant),
|
||||
instantiationService.createInstance(ExtHostSaveParticipant, extHostContext),
|
||||
];
|
||||
|
||||
// Hook into model
|
||||
TextFileEditorModel.setSaveParticipant(this);
|
||||
}
|
||||
@@ -286,11 +306,13 @@ export class SaveParticipant implements ISaveParticipant {
|
||||
TextFileEditorModel.setSaveParticipant(undefined);
|
||||
}
|
||||
|
||||
participate(model: ITextFileEditorModel, env: { reason: SaveReason }): TPromise<void> {
|
||||
const promiseFactory = this._saveParticipants.map(p => () => {
|
||||
return TPromise.as(p.participate(model, env));
|
||||
participate(model: ITextFileEditorModel, env: { reason: SaveReason }): Thenable<void> {
|
||||
return this._progressService.withProgress({ location: ProgressLocation.Window }, progress => {
|
||||
progress.report({ message: localize('saveParticipants', "Running Save Participants...") });
|
||||
const promiseFactory = this._saveParticipants.map(p => () => {
|
||||
return Promise.resolve(p.participate(model, env));
|
||||
});
|
||||
return sequence(promiseFactory).then(() => { }, err => this._logService.error(err));
|
||||
});
|
||||
|
||||
return sequence(promiseFactory).then(() => { });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ export class MainThreadStorage implements MainThreadStorageShape {
|
||||
}
|
||||
}
|
||||
|
||||
$setValue(shared: boolean, key: string, value: any): TPromise<any> {
|
||||
$setValue(shared: boolean, key: string, value: any): TPromise<void> {
|
||||
let jsonValue: any;
|
||||
try {
|
||||
jsonValue = JSON.stringify(value);
|
||||
|
||||
@@ -13,6 +13,7 @@ import { ITaskService } from 'vs/workbench/parts/tasks/common/taskService';
|
||||
|
||||
import { ExtHostContext, MainThreadTaskShape, ExtHostTaskShape, MainContext, IExtHostContext } from '../node/extHost.protocol';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
|
||||
import URI from 'vs/base/common/uri';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadTask)
|
||||
export class MainThreadTask implements MainThreadTaskShape {
|
||||
@@ -22,10 +23,10 @@ export class MainThreadTask implements MainThreadTaskShape {
|
||||
|
||||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
@ITaskService private _taskService: ITaskService,
|
||||
@IWorkspaceContextService private _workspaceContextServer: IWorkspaceContextService
|
||||
@ITaskService private readonly _taskService: ITaskService,
|
||||
@IWorkspaceContextService private readonly _workspaceContextServer: IWorkspaceContextService
|
||||
) {
|
||||
this._proxy = extHostContext.get(ExtHostContext.ExtHostTask);
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostTask);
|
||||
this._activeHandles = Object.create(null);
|
||||
}
|
||||
|
||||
@@ -45,7 +46,7 @@ export class MainThreadTask implements MainThreadTaskShape {
|
||||
let uri = (task._source as any as ExtensionTaskSourceTransfer).__workspaceFolder;
|
||||
if (uri) {
|
||||
delete (task._source as any as ExtensionTaskSourceTransfer).__workspaceFolder;
|
||||
(task._source as any).workspaceFolder = this._workspaceContextServer.getWorkspaceFolder(uri);
|
||||
(task._source as any).workspaceFolder = this._workspaceContextServer.getWorkspaceFolder(URI.revive(uri));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -57,7 +58,7 @@ export class MainThreadTask implements MainThreadTaskShape {
|
||||
return TPromise.wrap<void>(undefined);
|
||||
}
|
||||
|
||||
public $unregisterTaskProvider(handle: number): TPromise<any> {
|
||||
public $unregisterTaskProvider(handle: number): TPromise<void> {
|
||||
this._taskService.unregisterTaskProvider(handle);
|
||||
delete this._activeHandles[handle];
|
||||
return TPromise.wrap<void>(undefined);
|
||||
|
||||
@@ -25,11 +25,7 @@ export class MainThreadTelemetry implements MainThreadTelemetryShape {
|
||||
}
|
||||
|
||||
$publicLog(eventName: string, data: any = Object.create(null)): void {
|
||||
/* __GDPR__FRAGMENT__
|
||||
"MainThreadData" : {
|
||||
"pluginHostTelemetry" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
}
|
||||
*/
|
||||
// __GDPR__COMMON__ "pluginHostTelemetry" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
data[MainThreadTelemetry._name] = true;
|
||||
this._telemetryService.publicLog(eventName, data);
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
||||
extHostContext: IExtHostContext,
|
||||
@ITerminalService private terminalService: ITerminalService
|
||||
) {
|
||||
this._proxy = extHostContext.get(ExtHostContext.ExtHostTerminalService);
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostTerminalService);
|
||||
this._toDispose = [];
|
||||
this._toDispose.push(terminalService.onInstanceDisposed((terminalInstance) => this._onTerminalDisposed(terminalInstance)));
|
||||
this._toDispose.push(terminalService.onInstanceProcessIdReady((terminalInstance) => this._onTerminalProcessIdReady(terminalInstance)));
|
||||
@@ -33,11 +33,12 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
||||
// when the extension host process goes down ?
|
||||
}
|
||||
|
||||
public $createTerminal(name?: string, shellPath?: string, shellArgs?: string[], env?: { [key: string]: string }, waitOnExit?: boolean): TPromise<number> {
|
||||
public $createTerminal(name?: string, shellPath?: string, shellArgs?: string[], cwd?: string, env?: { [key: string]: string }, waitOnExit?: boolean): TPromise<number> {
|
||||
const shellLaunchConfig: IShellLaunchConfig = {
|
||||
name,
|
||||
executable: shellPath,
|
||||
args: shellArgs,
|
||||
cwd,
|
||||
waitOnExit,
|
||||
ignoreConfigurationCwd: true,
|
||||
env
|
||||
|
||||
@@ -8,38 +8,49 @@ import Event, { Emitter } from 'vs/base/common/event';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { ExtHostContext, MainThreadTreeViewsShape, ExtHostTreeViewsShape, MainContext, IExtHostContext } from '../node/extHost.protocol';
|
||||
import { IMessageService, Severity } from 'vs/platform/message/common/message';
|
||||
import { ViewsRegistry } from 'vs/workbench/browser/parts/views/viewsRegistry';
|
||||
import { ITreeViewDataProvider, ITreeItem } from 'vs/workbench/common/views';
|
||||
import { ITreeViewDataProvider, ITreeItem, ICustomViewsService } from 'vs/workbench/common/views';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
|
||||
import { assign } from 'vs/base/common/objects';
|
||||
import { distinct } from 'vs/base/common/arrays';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadTreeViews)
|
||||
export class MainThreadTreeViews extends Disposable implements MainThreadTreeViewsShape {
|
||||
|
||||
private _proxy: ExtHostTreeViewsShape;
|
||||
private _dataProviders: Map<string, TreeViewDataProvider> = new Map<string, TreeViewDataProvider>();
|
||||
|
||||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
@IMessageService private messageService: IMessageService
|
||||
@ICustomViewsService private viewsService: ICustomViewsService,
|
||||
@INotificationService private notificationService: INotificationService
|
||||
) {
|
||||
super();
|
||||
this._proxy = extHostContext.get(ExtHostContext.ExtHostTreeViews);
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostTreeViews);
|
||||
}
|
||||
|
||||
$registerView(treeViewId: string): void {
|
||||
ViewsRegistry.registerTreeViewDataProvider(treeViewId, this._register(new TreeViewDataProvider(treeViewId, this._proxy, this.messageService)));
|
||||
$registerTreeViewDataProvider(treeViewId: string): void {
|
||||
const dataProvider = this._register(new TreeViewDataProvider(treeViewId, this._proxy, this.notificationService));
|
||||
this._dataProviders.set(treeViewId, dataProvider);
|
||||
this.viewsService.getTreeViewer(treeViewId).dataProvider = dataProvider;
|
||||
}
|
||||
|
||||
$reveal(treeViewId: string, item: ITreeItem, parentChain: ITreeItem[], options?: { select?: boolean }): TPromise<void> {
|
||||
return this.viewsService.openView(treeViewId)
|
||||
.then(() => {
|
||||
const viewer = this.viewsService.getTreeViewer(treeViewId);
|
||||
return viewer ? viewer.reveal(item, parentChain, options) : null;
|
||||
});
|
||||
}
|
||||
|
||||
$refresh(treeViewId: string, itemsToRefresh: { [treeItemHandle: string]: ITreeItem }): void {
|
||||
const treeViewDataProvider: TreeViewDataProvider = <TreeViewDataProvider>ViewsRegistry.getTreeViewDataProvider(treeViewId);
|
||||
if (treeViewDataProvider) {
|
||||
treeViewDataProvider.refresh(itemsToRefresh);
|
||||
const dataProvider = this._dataProviders.get(treeViewId);
|
||||
if (dataProvider) {
|
||||
dataProvider.refresh(itemsToRefresh);
|
||||
}
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
ViewsRegistry.deregisterTreeViewDataProviders();
|
||||
this._dataProviders.clear();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
@@ -58,30 +69,20 @@ class TreeViewDataProvider implements ITreeViewDataProvider {
|
||||
|
||||
constructor(private treeViewId: string,
|
||||
private _proxy: ExtHostTreeViewsShape,
|
||||
private messageService: IMessageService
|
||||
private notificationService: INotificationService
|
||||
) {
|
||||
}
|
||||
|
||||
getElements(): TPromise<ITreeItem[]> {
|
||||
return this._proxy.$getElements(this.treeViewId)
|
||||
.then(elements => {
|
||||
return this.postGetElements(elements);
|
||||
}, err => {
|
||||
this.messageService.show(Severity.Error, err);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
getChildren(treeItem: ITreeItem): TPromise<ITreeItem[]> {
|
||||
if (treeItem.children) {
|
||||
getChildren(treeItem?: ITreeItem): TPromise<ITreeItem[]> {
|
||||
if (treeItem && treeItem.children) {
|
||||
return TPromise.as(treeItem.children);
|
||||
}
|
||||
return this._proxy.$getChildren(this.treeViewId, treeItem.handle)
|
||||
return this._proxy.$getChildren(this.treeViewId, treeItem ? treeItem.handle : void 0)
|
||||
.then(children => {
|
||||
return this.postGetElements(children);
|
||||
return this.postGetChildren(children);
|
||||
}, err => {
|
||||
this.messageService.show(Severity.Error, err);
|
||||
return null;
|
||||
this.notificationService.error(err);
|
||||
return [];
|
||||
});
|
||||
}
|
||||
|
||||
@@ -112,23 +113,12 @@ class TreeViewDataProvider implements ITreeViewDataProvider {
|
||||
}
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this._onDispose.fire();
|
||||
}
|
||||
|
||||
private postGetElements(elements: ITreeItem[]): ITreeItem[] {
|
||||
private postGetChildren(elements: ITreeItem[]): ITreeItem[] {
|
||||
const result = [];
|
||||
if (elements) {
|
||||
for (const element of elements) {
|
||||
const currentTreeItem = this.itemsMap.get(element.handle);
|
||||
if (currentTreeItem) {
|
||||
// Update the current item with new item
|
||||
this.updateTreeItem(currentTreeItem, element);
|
||||
} else {
|
||||
this.itemsMap.set(element.handle, element);
|
||||
}
|
||||
// Always use the existing items
|
||||
result.push(this.itemsMap.get(element.handle));
|
||||
this.itemsMap.set(element.handle, element);
|
||||
result.push(element);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@@ -137,7 +127,14 @@ class TreeViewDataProvider implements ITreeViewDataProvider {
|
||||
private updateTreeItem(current: ITreeItem, treeItem: ITreeItem): void {
|
||||
treeItem.children = treeItem.children ? treeItem.children : null;
|
||||
if (current) {
|
||||
assign(current, treeItem);
|
||||
const properties = distinct([...Object.keys(current), ...Object.keys(treeItem)]);
|
||||
for (const property of properties) {
|
||||
current[property] = treeItem[property];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this._onDispose.fire();
|
||||
}
|
||||
}
|
||||
|
||||
558
src/vs/workbench/api/electron-browser/mainThreadWebview.ts
Normal file
558
src/vs/workbench/api/electron-browser/mainThreadWebview.ts
Normal file
@@ -0,0 +1,558 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import * as map from 'vs/base/common/map';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { MainThreadWebviewsShape, MainContext, IExtHostContext, ExtHostContext, ExtHostWebviewsShape, WebviewHandle } from 'vs/workbench/api/node/extHost.protocol';
|
||||
import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle';
|
||||
import { extHostNamedCustomer } from './extHostCustomers';
|
||||
import { EditorInput, EditorModel, EditorOptions } from 'vs/workbench/common/editor';
|
||||
import { IEditorModel, Position } from 'vs/platform/editor/common/editor';
|
||||
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { WebviewEditor as BaseWebviewEditor, KEYBINDING_CONTEXT_WEBVIEWEDITOR_FOCUS, KEYBINDING_CONTEXT_WEBVIEWEDITOR_FIND_WIDGET_INPUT_FOCUSED, KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE } from 'vs/workbench/parts/html/browser/webviewEditor';
|
||||
import { Builder, Dimension } from 'vs/base/browser/builder';
|
||||
import { Webview } from 'vs/workbench/parts/html/browser/webview';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { IPartService, Parts } from 'vs/workbench/services/part/common/partService';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IEditorRegistry, EditorDescriptor, Extensions as EditorExtensions } from 'vs/workbench/browser/editor';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import * as vscode from 'vscode';
|
||||
import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import URI from 'vs/base/common/uri';
|
||||
import DOM = require('vs/base/browser/dom');
|
||||
import Event, { Emitter } from 'vs/base/common/event';
|
||||
|
||||
|
||||
interface WebviewEvents {
|
||||
onMessage(message: any): void;
|
||||
onDidChangePosition(newPosition: Position): void;
|
||||
onDispose(): void;
|
||||
onDidClickLink(link: URI, options: vscode.WebviewOptions): void;
|
||||
}
|
||||
|
||||
class WebviewInput extends EditorInput {
|
||||
private static handlePool = 0;
|
||||
|
||||
private readonly _resource: URI;
|
||||
private _name: string;
|
||||
private _options: vscode.WebviewOptions;
|
||||
private _html: string;
|
||||
private _currentWebviewHtml: string = '';
|
||||
private _events: WebviewEvents | undefined;
|
||||
private _container: HTMLElement;
|
||||
private _webview: Webview | undefined;
|
||||
private _webviewOwner: any;
|
||||
private _webviewDisposables: IDisposable[] = [];
|
||||
private _position: Position;
|
||||
|
||||
|
||||
public static create(
|
||||
resource: URI,
|
||||
name: string,
|
||||
position: Position,
|
||||
options: vscode.WebviewOptions,
|
||||
html: string,
|
||||
events: WebviewEvents,
|
||||
partService: IPartService
|
||||
): WebviewInput {
|
||||
const id = WebviewInput.handlePool++;
|
||||
const webviewContainer = document.createElement('div');
|
||||
webviewContainer.id = `webview-${id}`;
|
||||
|
||||
partService.getContainer(Parts.EDITOR_PART).appendChild(webviewContainer);
|
||||
|
||||
return new WebviewInput(resource, name, position, options, html, events, webviewContainer, undefined);
|
||||
}
|
||||
|
||||
constructor(
|
||||
resource: URI,
|
||||
name: string,
|
||||
position: Position,
|
||||
options: vscode.WebviewOptions,
|
||||
html: string,
|
||||
events: WebviewEvents,
|
||||
container: HTMLElement,
|
||||
webview: Webview | undefined
|
||||
) {
|
||||
super();
|
||||
this._resource = resource;
|
||||
this._name = name;
|
||||
this._position = position;
|
||||
this._options = options;
|
||||
this._html = html;
|
||||
this._events = events;
|
||||
|
||||
this._container = container;
|
||||
this._webview = webview;
|
||||
}
|
||||
|
||||
public getTypeId(): string {
|
||||
return 'webview';
|
||||
}
|
||||
|
||||
public dispose() {
|
||||
this.disposeWebview();
|
||||
|
||||
if (this._container) {
|
||||
this._container.remove();
|
||||
this._container = undefined;
|
||||
}
|
||||
|
||||
if (this._events) {
|
||||
this._events.onDispose();
|
||||
this._events = undefined;
|
||||
}
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
public getResource(): URI {
|
||||
return this._resource;
|
||||
}
|
||||
|
||||
public getName(): string {
|
||||
return this._name;
|
||||
}
|
||||
|
||||
public setName(value: string): void {
|
||||
this._name = value;
|
||||
this._onDidChangeLabel.fire();
|
||||
}
|
||||
|
||||
public get position(): Position {
|
||||
return this._position;
|
||||
}
|
||||
|
||||
public get html(): string {
|
||||
return this._html;
|
||||
}
|
||||
|
||||
public setHtml(value: string): void {
|
||||
if (value === this._currentWebviewHtml) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._html = value;
|
||||
|
||||
if (this._webview) {
|
||||
this._webview.contents = value;
|
||||
this._currentWebviewHtml = value;
|
||||
}
|
||||
}
|
||||
|
||||
public get options(): vscode.WebviewOptions {
|
||||
return this._options;
|
||||
}
|
||||
|
||||
public set options(value: vscode.WebviewOptions) {
|
||||
this._options = value;
|
||||
}
|
||||
|
||||
public resolve(refresh?: boolean): TPromise<IEditorModel, any> {
|
||||
return TPromise.as(new EditorModel());
|
||||
}
|
||||
|
||||
public supportsSplitEditor() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public get container(): HTMLElement {
|
||||
return this._container;
|
||||
}
|
||||
|
||||
public get webview(): Webview | undefined {
|
||||
return this._webview;
|
||||
}
|
||||
|
||||
public set webview(value: Webview) {
|
||||
this._webviewDisposables = dispose(this._webviewDisposables);
|
||||
|
||||
this._webview = value;
|
||||
|
||||
this._webview.onDidClickLink(link => {
|
||||
if (this._events) {
|
||||
this._events.onDidClickLink(link, this._options);
|
||||
}
|
||||
}, null, this._webviewDisposables);
|
||||
|
||||
this._webview.onMessage(message => {
|
||||
if (this._events) {
|
||||
this._events.onMessage(message);
|
||||
}
|
||||
}, null, this._webviewDisposables);
|
||||
}
|
||||
|
||||
public claimWebview(owner: any) {
|
||||
this._webviewOwner = owner;
|
||||
}
|
||||
|
||||
public releaseWebview(owner: any) {
|
||||
if (this._webviewOwner === owner) {
|
||||
this._webviewOwner = undefined;
|
||||
if (this._options.retainContextWhenHidden) {
|
||||
this.container.style.visibility = 'hidden';
|
||||
} else {
|
||||
this.disposeWebview();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public disposeWebview() {
|
||||
// The input owns the webview and its parent
|
||||
if (this._webview) {
|
||||
this._webview.dispose();
|
||||
this._webview = undefined;
|
||||
}
|
||||
|
||||
this._webviewDisposables = dispose(this._webviewDisposables);
|
||||
|
||||
this._webviewOwner = undefined;
|
||||
this.container.style.visibility = 'hidden';
|
||||
|
||||
this._currentWebviewHtml = '';
|
||||
}
|
||||
|
||||
public onDidChangePosition(position: Position) {
|
||||
if (this._events) {
|
||||
this._events.onDidChangePosition(position);
|
||||
}
|
||||
this._position = position;
|
||||
}
|
||||
}
|
||||
|
||||
class WebviewEditor extends BaseWebviewEditor {
|
||||
|
||||
public static readonly ID = 'WebviewEditor';
|
||||
|
||||
private editorFrame: HTMLElement;
|
||||
private webviewContent: HTMLElement;
|
||||
private _onDidFocusWebview: Emitter<void>;
|
||||
private _webviewFocusTracker?: DOM.IFocusTracker;
|
||||
private _webviewFocusListenerDisposable?: IDisposable;
|
||||
|
||||
constructor(
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IStorageService storageService: IStorageService,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IContextKeyService private _contextKeyService: IContextKeyService,
|
||||
@IPartService private readonly _partService: IPartService,
|
||||
@IContextViewService private readonly _contextViewService: IContextViewService,
|
||||
@IEnvironmentService private readonly _environmentService: IEnvironmentService,
|
||||
@IWorkspaceContextService private readonly _contextService: IWorkspaceContextService
|
||||
) {
|
||||
super(WebviewEditor.ID, telemetryService, themeService, storageService, _contextKeyService);
|
||||
|
||||
this._onDidFocusWebview = new Emitter<void>();
|
||||
}
|
||||
|
||||
protected createEditor(parent: Builder): void {
|
||||
this.editorFrame = parent.getHTMLElement();
|
||||
this.content = document.createElement('div');
|
||||
parent.append(this.content);
|
||||
}
|
||||
|
||||
private doUpdateContainer() {
|
||||
const webviewContainer = this.input && (this.input as WebviewInput).container;
|
||||
if (webviewContainer) {
|
||||
const frameRect = this.editorFrame.getBoundingClientRect();
|
||||
const containerRect = webviewContainer.parentElement.getBoundingClientRect();
|
||||
|
||||
webviewContainer.style.position = 'absolute';
|
||||
webviewContainer.style.top = `${frameRect.top - containerRect.top}px`;
|
||||
webviewContainer.style.left = `${frameRect.left - containerRect.left}px`;
|
||||
webviewContainer.style.width = `${frameRect.width}px`;
|
||||
webviewContainer.style.height = `${frameRect.height}px`;
|
||||
}
|
||||
}
|
||||
|
||||
public layout(dimension: Dimension): void {
|
||||
if (this._webview) {
|
||||
this.doUpdateContainer();
|
||||
}
|
||||
super.layout(dimension);
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
// Let the editor input dispose of the webview.
|
||||
this._webview = undefined;
|
||||
this.webviewContent = undefined;
|
||||
|
||||
this._onDidFocusWebview.dispose();
|
||||
|
||||
if (this._webviewFocusTracker) {
|
||||
this._webviewFocusTracker.dispose();
|
||||
}
|
||||
|
||||
if (this._webviewFocusListenerDisposable) {
|
||||
this._webviewFocusListenerDisposable.dispose();
|
||||
}
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
public sendMessage(data: any): void {
|
||||
if (this._webview) {
|
||||
this._webview.sendMessage(data);
|
||||
}
|
||||
}
|
||||
|
||||
public get onDidFocus(): Event<any> {
|
||||
return this._onDidFocusWebview.event;
|
||||
}
|
||||
|
||||
protected setEditorVisible(visible: boolean, position?: Position): void {
|
||||
if (this.input && this.input instanceof WebviewInput) {
|
||||
if (visible) {
|
||||
this.input.claimWebview(this);
|
||||
} else {
|
||||
this.input.releaseWebview(this);
|
||||
}
|
||||
|
||||
this.updateWebview(this.input as WebviewInput);
|
||||
}
|
||||
|
||||
if (this.webviewContent) {
|
||||
if (visible) {
|
||||
this.webviewContent.style.visibility = 'visible';
|
||||
this.doUpdateContainer();
|
||||
} else {
|
||||
this.webviewContent.style.visibility = 'hidden';
|
||||
}
|
||||
}
|
||||
|
||||
super.setEditorVisible(visible, position);
|
||||
}
|
||||
|
||||
public clearInput() {
|
||||
if (this.input && this.input instanceof WebviewInput) {
|
||||
this.input.releaseWebview(this);
|
||||
}
|
||||
|
||||
this._webview = undefined;
|
||||
this.webviewContent = undefined;
|
||||
|
||||
super.clearInput();
|
||||
}
|
||||
|
||||
async setInput(input: WebviewInput, options: EditorOptions): TPromise<void> {
|
||||
if (this.input && this.input.matches(input)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (this.input && this.input.getResource().fsPath !== input.getResource().fsPath) {
|
||||
(this.input as WebviewInput).releaseWebview(this);
|
||||
this._webview = undefined;
|
||||
this.webviewContent = undefined;
|
||||
}
|
||||
|
||||
await super.setInput(input, options);
|
||||
|
||||
input.onDidChangePosition(this.position);
|
||||
this.updateWebview(input);
|
||||
}
|
||||
|
||||
private updateWebview(input: WebviewInput) {
|
||||
const webview = this.getWebview(input);
|
||||
input.claimWebview(this);
|
||||
webview.options = {
|
||||
allowScripts: input.options.enableScripts,
|
||||
enableWrappedPostMessage: true,
|
||||
useSameOriginForRoot: false,
|
||||
localResourceRoots: (input && input.options.localResourceRoots) || this._contextService.getWorkspace().folders.map(x => x.uri)
|
||||
};
|
||||
input.setHtml(input.html);
|
||||
this.webviewContent.style.visibility = 'visible';
|
||||
this.doUpdateContainer();
|
||||
}
|
||||
|
||||
private getWebview(input: WebviewInput): Webview {
|
||||
if (this._webview) {
|
||||
return this._webview;
|
||||
}
|
||||
|
||||
this.webviewContent = input.container;
|
||||
const existing = input.webview;
|
||||
if (existing) {
|
||||
this._webview = existing;
|
||||
return existing;
|
||||
}
|
||||
|
||||
this._webviewFocusTracker = DOM.trackFocus(this.webviewContent);
|
||||
this._webviewFocusListenerDisposable = this._webviewFocusTracker.onDidFocus(() => {
|
||||
this._onDidFocusWebview.fire();
|
||||
});
|
||||
|
||||
this._contextKeyService = this._contextKeyService.createScoped(this.webviewContent);
|
||||
this.contextKey = KEYBINDING_CONTEXT_WEBVIEWEDITOR_FOCUS.bindTo(this._contextKeyService);
|
||||
this.findInputFocusContextKey = KEYBINDING_CONTEXT_WEBVIEWEDITOR_FIND_WIDGET_INPUT_FOCUSED.bindTo(this._contextKeyService);
|
||||
this.findWidgetVisible = KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE.bindTo(this._contextKeyService);
|
||||
|
||||
this._webview = new Webview(
|
||||
this.webviewContent,
|
||||
this._partService.getContainer(Parts.EDITOR_PART),
|
||||
this.themeService,
|
||||
this._environmentService,
|
||||
this._contextViewService,
|
||||
this.contextKey,
|
||||
this.findInputFocusContextKey,
|
||||
{
|
||||
enableWrappedPostMessage: true,
|
||||
useSameOriginForRoot: false
|
||||
});
|
||||
input.webview = this._webview;
|
||||
|
||||
this.content.setAttribute('aria-flowto', this.webviewContent.id);
|
||||
|
||||
this.doUpdateContainer();
|
||||
return this._webview;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadWebviews)
|
||||
export class MainThreadWebviews implements MainThreadWebviewsShape {
|
||||
private static readonly standardSupportedLinkSchemes = ['http', 'https', 'mailto'];
|
||||
|
||||
private _toDispose: Disposable[] = [];
|
||||
|
||||
private readonly _proxy: ExtHostWebviewsShape;
|
||||
private readonly _webviews = new Map<WebviewHandle, WebviewInput>();
|
||||
|
||||
private _activeWebview: WebviewInput | undefined = undefined;
|
||||
|
||||
constructor(
|
||||
context: IExtHostContext,
|
||||
@IContextKeyService _contextKeyService: IContextKeyService,
|
||||
@IPartService private readonly _partService: IPartService,
|
||||
@IWorkbenchEditorService private readonly _editorService: IWorkbenchEditorService,
|
||||
@IEditorGroupService private readonly _editorGroupService: IEditorGroupService,
|
||||
@IOpenerService private readonly _openerService: IOpenerService
|
||||
) {
|
||||
this._proxy = context.getProxy(ExtHostContext.ExtHostWebviews);
|
||||
_editorGroupService.onEditorsChanged(this.onEditorsChanged, this, this._toDispose);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this._toDispose = dispose(this._toDispose);
|
||||
}
|
||||
|
||||
$createWebview(handle: WebviewHandle, uri: URI, title: string, column: Position, options: vscode.WebviewOptions): void {
|
||||
const webviewInput = WebviewInput.create(URI.revive(uri), title, column, options, '', {
|
||||
onMessage: message => this._proxy.$onMessage(handle, message),
|
||||
onDidChangePosition: position => this._proxy.$onDidChangePosition(handle, position),
|
||||
onDispose: () => {
|
||||
this._proxy.$onDidDisposeWeview(handle).then(() => {
|
||||
this._webviews.delete(handle);
|
||||
});
|
||||
},
|
||||
onDidClickLink: (link, options) => this.onDidClickLink(link, options)
|
||||
}, this._partService);
|
||||
|
||||
this._webviews.set(handle, webviewInput);
|
||||
|
||||
this._editorService.openEditor(webviewInput, { pinned: true }, column);
|
||||
}
|
||||
|
||||
$disposeWebview(handle: WebviewHandle): void {
|
||||
const webview = this.getWebview(handle);
|
||||
if (webview) {
|
||||
this._editorService.closeEditor(webview.position, webview);
|
||||
}
|
||||
}
|
||||
|
||||
$setTitle(handle: WebviewHandle, value: string): void {
|
||||
const webview = this.getWebview(handle);
|
||||
webview.setName(value);
|
||||
}
|
||||
|
||||
$setHtml(handle: WebviewHandle, value: string): void {
|
||||
const webview = this.getWebview(handle);
|
||||
webview.setHtml(value);
|
||||
}
|
||||
|
||||
$show(handle: WebviewHandle, column: Position): void {
|
||||
const webviewInput = this.getWebview(handle);
|
||||
if (webviewInput.position === column) {
|
||||
this._editorService.openEditor(webviewInput, { preserveFocus: true }, column);
|
||||
} else {
|
||||
this._editorGroupService.moveEditor(webviewInput, webviewInput.position, column, { preserveFocus: true });
|
||||
}
|
||||
}
|
||||
|
||||
async $sendMessage(handle: WebviewHandle, message: any): Promise<boolean> {
|
||||
const webviewInput = this.getWebview(handle);
|
||||
const editors = this._editorService.getVisibleEditors()
|
||||
.filter(e => e instanceof WebviewEditor)
|
||||
.map(e => e as WebviewEditor)
|
||||
.filter(e => e.input.matches(webviewInput));
|
||||
|
||||
for (const editor of editors) {
|
||||
editor.sendMessage(message);
|
||||
}
|
||||
|
||||
return (editors.length > 0);
|
||||
}
|
||||
|
||||
private getWebview(handle: number): WebviewInput {
|
||||
const webviewInput = this._webviews.get(handle);
|
||||
if (!webviewInput) {
|
||||
throw new Error('Unknown webview handle:' + handle);
|
||||
}
|
||||
return webviewInput;
|
||||
}
|
||||
|
||||
private onEditorsChanged() {
|
||||
const activeEditor = this._editorService.getActiveEditor();
|
||||
let newActiveWebview: { input: WebviewInput, handle: WebviewHandle } | undefined = undefined;
|
||||
if (activeEditor && activeEditor.input instanceof WebviewInput) {
|
||||
for (const handle of map.keys(this._webviews)) {
|
||||
const input = this._webviews.get(handle);
|
||||
if (input.matches(activeEditor.input)) {
|
||||
newActiveWebview = { input, handle };
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (newActiveWebview) {
|
||||
if (!this._activeWebview || !newActiveWebview.input.matches(this._activeWebview)) {
|
||||
this._proxy.$onDidChangeActiveWeview(newActiveWebview.handle);
|
||||
this._activeWebview = newActiveWebview.input;
|
||||
}
|
||||
} else {
|
||||
if (this._activeWebview) {
|
||||
this._proxy.$onDidChangeActiveWeview(undefined);
|
||||
this._activeWebview = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private onDidClickLink(link: URI, options: vscode.WebviewOptions): void {
|
||||
if (!link) {
|
||||
return;
|
||||
}
|
||||
|
||||
const enableCommandUris = options.enableCommandUris;
|
||||
if (MainThreadWebviews.standardSupportedLinkSchemes.indexOf(link.scheme) >= 0 || enableCommandUris && link.scheme === 'command') {
|
||||
this._openerService.open(link);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(<IEditorRegistry>Registry.as(EditorExtensions.Editors)).registerEditor(new EditorDescriptor(
|
||||
WebviewEditor,
|
||||
WebviewEditor.ID,
|
||||
localize('webview.editor.label', "webview editor")),
|
||||
[new SyncDescriptor(WebviewInput)]);
|
||||
@@ -20,7 +20,7 @@ export class MainThreadWindow implements MainThreadWindowShape {
|
||||
extHostContext: IExtHostContext,
|
||||
@IWindowService private windowService: IWindowService
|
||||
) {
|
||||
this.proxy = extHostContext.get(ExtHostContext.ExtHostWindow);
|
||||
this.proxy = extHostContext.getProxy(ExtHostContext.ExtHostWindow);
|
||||
|
||||
windowService.onDidChangeFocus(this.proxy.$onDidChangeWindowFocus, this.proxy, this.disposables);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
'use strict';
|
||||
|
||||
import { isPromiseCanceledError } from 'vs/base/common/errors';
|
||||
import URI from 'vs/base/common/uri';
|
||||
import URI, { UriComponents } from 'vs/base/common/uri';
|
||||
import { ISearchService, QueryType, ISearchQuery, IFolderQuery, ISearchConfiguration } from 'vs/platform/search/common/search';
|
||||
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
|
||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
@@ -14,6 +14,9 @@ import { MainThreadWorkspaceShape, ExtHostWorkspaceShape, ExtHostContext, MainCo
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadWorkspace)
|
||||
export class MainThreadWorkspace implements MainThreadWorkspaceShape {
|
||||
@@ -27,9 +30,11 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {
|
||||
@ISearchService private readonly _searchService: ISearchService,
|
||||
@IWorkspaceContextService private readonly _contextService: IWorkspaceContextService,
|
||||
@ITextFileService private readonly _textFileService: ITextFileService,
|
||||
@IConfigurationService private _configurationService: IConfigurationService
|
||||
@IConfigurationService private readonly _configurationService: IConfigurationService,
|
||||
@IWorkspaceEditingService private readonly _workspaceEditingService: IWorkspaceEditingService,
|
||||
@IStatusbarService private readonly _statusbarService: IStatusbarService
|
||||
) {
|
||||
this._proxy = extHostContext.get(ExtHostContext.ExtHostWorkspace);
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostWorkspace);
|
||||
this._contextService.onDidChangeWorkspaceFolders(this._onDidChangeWorkspace, this, this._toDispose);
|
||||
this._contextService.onDidChangeWorkbenchState(this._onDidChangeWorkspace, this, this._toDispose);
|
||||
}
|
||||
@@ -45,13 +50,54 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {
|
||||
|
||||
// --- workspace ---
|
||||
|
||||
$updateWorkspaceFolders(extensionName: string, index: number, deleteCount: number, foldersToAdd: { uri: UriComponents, name?: string }[]): Thenable<void> {
|
||||
const workspaceFoldersToAdd = foldersToAdd.map(f => ({ uri: URI.revive(f.uri), name: f.name }));
|
||||
|
||||
// Indicate in status message
|
||||
this._statusbarService.setStatusMessage(this.getStatusMessage(extensionName, workspaceFoldersToAdd.length, deleteCount), 10 * 1000 /* 10s */);
|
||||
|
||||
return this._workspaceEditingService.updateFolders(index, deleteCount, workspaceFoldersToAdd, true);
|
||||
}
|
||||
|
||||
private getStatusMessage(extensionName: string, addCount: number, removeCount: number): string {
|
||||
let message: string;
|
||||
|
||||
const wantsToAdd = addCount > 0;
|
||||
const wantsToDelete = removeCount > 0;
|
||||
|
||||
// Add Folders
|
||||
if (wantsToAdd && !wantsToDelete) {
|
||||
if (addCount === 1) {
|
||||
message = localize('folderStatusMessageAddSingleFolder', "Extension '{0}' added 1 folder to the workspace", extensionName);
|
||||
} else {
|
||||
message = localize('folderStatusMessageAddMultipleFolders', "Extension '{0}' added {1} folders to the workspace", extensionName, addCount);
|
||||
}
|
||||
}
|
||||
|
||||
// Delete Folders
|
||||
else if (wantsToDelete && !wantsToAdd) {
|
||||
if (removeCount === 1) {
|
||||
message = localize('folderStatusMessageRemoveSingleFolder', "Extension '{0}' removed 1 folder from the workspace", extensionName);
|
||||
} else {
|
||||
message = localize('folderStatusMessageRemoveMultipleFolders', "Extension '{0}' removed {1} folders from the workspace", extensionName, removeCount);
|
||||
}
|
||||
}
|
||||
|
||||
// Change Folders
|
||||
else {
|
||||
message = localize('folderStatusChangeFolder', "Extension '{0}' changed folders of the workspace", extensionName);
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
private _onDidChangeWorkspace(): void {
|
||||
this._proxy.$acceptWorkspaceData(this._contextService.getWorkbenchState() === WorkbenchState.EMPTY ? null : this._contextService.getWorkspace());
|
||||
}
|
||||
|
||||
// --- search ---
|
||||
|
||||
$startSearch(includePattern: string, includeFolder: string, excludePattern: string, maxResults: number, requestId: number): Thenable<URI[]> {
|
||||
$startSearch(includePattern: string, includeFolder: string, excludePatternOrDisregardExcludes: string | false, maxResults: number, requestId: number): Thenable<URI[]> {
|
||||
const workspace = this._contextService.getWorkspace();
|
||||
if (!workspace.folders.length) {
|
||||
return undefined;
|
||||
@@ -83,7 +129,8 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {
|
||||
type: QueryType.File,
|
||||
maxResults,
|
||||
includePattern: { [typeof includePattern === 'string' ? includePattern : undefined]: true },
|
||||
excludePattern: { [typeof excludePattern === 'string' ? excludePattern : undefined]: true },
|
||||
excludePattern: { [typeof excludePatternOrDisregardExcludes === 'string' ? excludePatternOrDisregardExcludes : undefined]: true },
|
||||
disregardExcludeSettings: excludePatternOrDisregardExcludes === false,
|
||||
useRipgrep,
|
||||
ignoreSymlinks
|
||||
};
|
||||
@@ -123,4 +170,3 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user