Merge pull request #1831 from Microsoft/joh/registerTextDocumentProvider

register text document provider
This commit is contained in:
Johannes Rieken 2016-01-11 16:54:37 +01:00
commit a19740d091
37 changed files with 630 additions and 393 deletions

View file

@ -11,4 +11,4 @@ build_script:
- gulp compile
test_script:
- mocha
- .\scripts\test.bat

View file

@ -33,7 +33,7 @@ var baseModules = [
'events', 'fs', 'getmac', 'glob', 'graceful-fs', 'http', 'http-proxy-agent',
'https', 'https-proxy-agent', 'iconv-lite', 'electron', 'net',
'os', 'path', 'readline', 'sax', 'semver', 'stream', 'string_decoder', 'url',
'vscode-textmate', 'winreg', 'yauzl', 'native-keymap'
'vscode-textmate', 'winreg', 'yauzl', 'native-keymap', 'weak'
];
// Build

View file

@ -119,6 +119,96 @@ suite('workspace-namespace', () => {
});
});
test('registerTextDocumentContentProvider, simple', function() {
let registration = workspace.registerTextDocumentContentProvider('foo', {
provideTextDocumentContent(uri) {
return uri.toString();
}
});
const uri = Uri.parse('foo://testing/virtual.js');
return workspace.openTextDocument(uri).then(doc => {
assert.equal(doc.getText(), uri.toString());
assert.equal(doc.isDirty, false);
assert.equal(doc.uri.toString(), uri.toString());
registration.dispose();
});
});
test('registerTextDocumentContentProvider, constrains', function() {
// built-in
assert.throws(function() {
workspace.registerTextDocumentContentProvider('untitled', { provideTextDocumentContent() { return null; } });
});
// built-in
assert.throws(function() {
workspace.registerTextDocumentContentProvider('file', { provideTextDocumentContent() { return null; } });
});
// duplicate registration
let registration = workspace.registerTextDocumentContentProvider('foo', {
provideTextDocumentContent(uri) {
return uri.toString();
}
});
assert.throws(function() {
workspace.registerTextDocumentContentProvider('foo', { provideTextDocumentContent() { return null; } });
});
// unregister & register
registration.dispose();
registration = workspace.registerTextDocumentContentProvider('foo', { provideTextDocumentContent() { return null; } });
registration.dispose();
// missing scheme
return workspace.openTextDocument(Uri.parse('notThere://foo/far/boo/bar')).then(() => {
assert.ok(false, 'expected failure')
}, err => {
// expected
})
});
test('registerTextDocumentContentProvider, show virtual document', function() {
let registration = workspace.registerTextDocumentContentProvider('foo', {
provideTextDocumentContent(uri) {
return 'I am virtual';
}
});
return workspace.openTextDocument(Uri.parse('foo://something/path')).then(doc => {
return window.showTextDocument(doc).then(editor => {
assert.ok(editor.document === doc);
assert.equal(editor.document.getText(), 'I am virtual');
registration.dispose();
})
});
});
test('registerTextDocumentContentProvider, open/open document', function() {
let callCount = 0;
let registration = workspace.registerTextDocumentContentProvider('foo', {
provideTextDocumentContent(uri) {
callCount += 1;
return 'I am virtual';
}
});
const uri = Uri.parse('foo://testing/path');
return Promise.all([workspace.openTextDocument(uri), workspace.openTextDocument(uri)]).then(docs => {
let [first, second] = docs;
assert.ok(first === second);
assert.ok(workspace.textDocuments.some(doc => doc.uri.toString() === uri.toString()));
assert.equal(callCount, 1);
registration.dispose();
});
});
test('findFiles', () => {
return workspace.findFiles('*.js', null).then((res) => {
assert.equal(res.length, 1);

5
npm-shrinkwrap.json generated
View file

@ -449,6 +449,11 @@
"from": "native-keymap@0.1.2",
"resolved": "https://registry.npmjs.org/native-keymap/-/native-keymap-0.1.2.tgz"
},
"weak":{
"version": "1.0.1",
"from": "weak@1.0.1",
"resolved": "https://registry.npmjs.org/weak/-/weak-1.0.1.tgz"
},
"winreg": {
"version": "0.0.12",
"from": "winreg@0.0.12",

View file

@ -29,6 +29,7 @@
"vscode-debugprotocol": "^1.2.1",
"vscode-textmate": "^1.0.9",
"native-keymap": "^0.1.2",
"weak": "^1.0.1",
"winreg": "0.0.12",
"yauzl": "^2.3.1"
},

View file

@ -3,5 +3,5 @@
set ATOM_SHELL_INTERNAL_RUN_AS_NODE=1
pushd %~dp0\..
.\.build\electron\Code.exe .\node_modules\mocha\bin\_mocha %*
.\.build\electron\CodeOSS.exe .\node_modules\mocha\bin\_mocha %*
popd

28
src/typings/weak.d.ts vendored Normal file
View file

@ -0,0 +1,28 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
declare namespace weak {
interface WeakRef {
// tagging
}
}
declare const weak: WeakFunction;
interface WeakFunction {
<T>(obj: T, callback?: () => any): T & weak.WeakRef;
(obj: any, callback?: () => any): any & weak.WeakRef;
get(ref: weak.WeakRef): any;
get<T>(ref: weak.WeakRef): T;
isDead(ref: weak.WeakRef): boolean;
isNearDeath(ref: weak.WeakRef): boolean;
isWeakRef(obj: any): boolean;
}
declare module 'weak' {
export = weak;
}

View file

@ -7,6 +7,26 @@
import * as errors from 'vs/base/common/errors';
import { Promise, TPromise, ValueCallback, ErrorCallback, ProgressCallback } from 'vs/base/common/winjs.base';
import * as platform from 'vs/base/common/platform';
import {CancellationToken, CancellationTokenSource} from 'vs/base/common/cancellation';
function isThenable<T>(obj: any): obj is Thenable<T> {
return obj && typeof (<Thenable<any>>obj).then === 'function';
}
export function asWinJsPromise<T>(callback: (token: CancellationToken) => T | Thenable<T>): TPromise<T> {
let source = new CancellationTokenSource();
return new TPromise<T>((resolve, reject) => {
let item = callback(source.token);
if (isThenable<T>(item)) {
item.then(resolve, reject);
} else {
resolve(item);
}
}, () => {
source.cancel();
});
}
export interface ITask<T> {
(): T;

View file

@ -0,0 +1,144 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import URI from 'vs/base/common/uri';
import {IModelContentChangedEvent2, IRange, IPosition} from 'vs/editor/common/editorCommon';
import {PrefixSumComputer} from 'vs/editor/common/viewModel/prefixSumComputer';
export class MirrorModel2 {
protected _uri: URI;
protected _lines: string[];
protected _eol: string;
protected _versionId: number;
protected _lineStarts: PrefixSumComputer;
constructor(uri: URI, lines: string[], eol: string, versionId: number) {
this._uri = uri;
this._lines = lines;
this._eol = eol;
this._versionId = versionId;
}
dispose(): void {
this._lines.length = 0;
}
get version(): number {
return this._versionId;
}
getText(): string {
return this._lines.join(this._eol);
}
onEvents(events: IModelContentChangedEvent2[]): void {
// Update my lines
let lastVersionId = -1;
for (let i = 0, len = events.length; i < len; i++) {
let e = events[i];
this._acceptDeleteRange(e.range);
this._acceptInsertText({
lineNumber: e.range.startLineNumber,
column: e.range.startColumn
}, e.text);
lastVersionId = Math.max(lastVersionId, e.versionId);
}
if (lastVersionId !== -1) {
this._versionId = lastVersionId;
}
}
protected _ensureLineStarts(): void {
if (!this._lineStarts) {
const lineStartValues:number[] = [];
const eolLength = this._eol.length;
for (let i = 0, len = this._lines.length; i < len; i++) {
lineStartValues.push(this._lines[i].length + eolLength);
}
this._lineStarts = new PrefixSumComputer(lineStartValues);
}
}
/**
* All changes to a line's text go through this method
*/
private _setLineText(lineIndex:number, newValue:string): void {
this._lines[lineIndex] = newValue;
if (this._lineStarts) {
// update prefix sum
this._lineStarts.changeValue(lineIndex, this._lines[lineIndex].length + this._eol.length);
}
}
private _acceptDeleteRange(range: IRange): void {
if (range.startLineNumber === range.endLineNumber) {
if (range.startColumn === range.endColumn) {
// Nothing to delete
return;
}
// Delete text on the affected line
this._setLineText(range.startLineNumber - 1,
this._lines[range.startLineNumber - 1].substring(0, range.startColumn - 1)
+ this._lines[range.startLineNumber - 1].substring(range.endColumn - 1)
);
return;
}
// Take remaining text on last line and append it to remaining text on first line
this._setLineText(range.startLineNumber - 1,
this._lines[range.startLineNumber - 1].substring(0, range.startColumn - 1)
+ this._lines[range.endLineNumber - 1].substring(range.endColumn - 1)
);
// Delete middle lines
this._lines.splice(range.startLineNumber, range.endLineNumber - range.startLineNumber);
if (this._lineStarts) {
// update prefix sum
this._lineStarts.removeValues(range.startLineNumber, range.endLineNumber - range.startLineNumber);
}
}
private _acceptInsertText(position: IPosition, insertText:string): void {
if (insertText.length === 0) {
// Nothing to insert
return;
}
let insertLines = insertText.split(/\r\n|\r|\n/);
if (insertLines.length === 1) {
// Inserting text on one line
this._setLineText(position.lineNumber - 1,
this._lines[position.lineNumber - 1].substring(0, position.column - 1)
+ insertLines[0]
+ this._lines[position.lineNumber - 1].substring(position.column - 1)
);
return;
}
// Append overflowing text from first line to the end of text to insert
insertLines[insertLines.length - 1] += this._lines[position.lineNumber - 1].substring(position.column - 1);
// Delete overflowing text from first line and insert text on first line
this._setLineText(position.lineNumber - 1,
this._lines[position.lineNumber - 1].substring(0, position.column - 1)
+ insertLines[0]
);
// Insert new lines & store lengths
let newLengths:number[] = new Array<number>(insertLines.length - 1);
for (let i = 1; i < insertLines.length; i++) {
this._lines.splice(position.lineNumber + i - 1, 0, insertLines[i]);
newLengths[i - 1] = insertLines[i].length + this._eol.length;
}
if (this._lineStarts) {
// update prefix sum
this._lineStarts.insertValues(position.lineNumber, newLengths);
}
}
}

View file

@ -12,7 +12,7 @@ import {EditableTextModel, IValidatedEditOperation} from 'vs/editor/common/model
import {TextModel} from 'vs/editor/common/model/textModel';
import {LineMarker, TextModelWithMarkers} from 'vs/editor/common/model/textModelWithMarkers';
import {ILineMarker} from 'vs/editor/common/model/modelLine';
import {ExtHostDocument} from 'vs/workbench/api/common/extHostDocuments';
import {MirrorModel2} from 'vs/editor/common/model/mirrorModel2';
import {MirrorModel, IMirrorModelEvents} from 'vs/editor/common/model/mirrorModel';
suite('EditorModel - EditableTextModel._getInverseEdits', () => {
@ -1185,7 +1185,7 @@ suite('EditorModel - EditableTextModel.applyEdits', () => {
var mirrorModel1 = new MirrorModel(null, model.getVersionId(), model.toRawText(), null);
var mirrorModel1PrevVersionId = model.getVersionId();
var mirrorModel2 = new ExtHostDocument(null, null, model.toRawText().lines, model.toRawText().EOL, null, model.getVersionId(), false);
var mirrorModel2 = new MirrorModel2(null, model.toRawText().lines, model.toRawText().EOL, model.getVersionId());
var mirrorModel2PrevVersionId = model.getVersionId();
model.addListener(EditorCommon.EventType.ModelContentChanged, (e:EditorCommon.IModelContentChangedEvent) => {
@ -1207,7 +1207,7 @@ suite('EditorModel - EditableTextModel.applyEdits', () => {
console.warn('Model version id did not advance between edits (2)');
}
mirrorModel2PrevVersionId = versionId;
mirrorModel2._acceptEvents([e]);
mirrorModel2.onEvents([e]);
});
var assertMirrorModels = () => {

22
src/vs/vscode.d.ts vendored
View file

@ -1017,6 +1017,23 @@ declare namespace vscode {
onDidDelete: Event<Uri>;
}
export interface TextDocumentContentProvider {
/**
* An event to signal a resource has changed.
*/
onDidChange?: Event<Uri>;
/**
* Provide textual content for a given uri.
*
* @param uri An uri which scheme matches the scheme this provider was [registered](#workspace.registerTextDocumentContentProvider) for.
* @param token A cancellation token.
* @return A string or a thenable that resolves to such.
*/
provideTextDocumentContent(uri: Uri, token: CancellationToken): string | Thenable<string>;
}
/**
* Represents an item that can be selected from
* a list of items.
@ -3004,6 +3021,11 @@ declare namespace vscode {
*/
export function openTextDocument(fileName: string): Thenable<TextDocument>;
/**
*
*/
export function registerTextDocumentContentProvider(scheme: string, provider: TextDocumentContentProvider): Disposable;
/**
* An event that is emitted when a [text document](#TextDocument) is opened.
*/

View file

@ -8,21 +8,21 @@ import {IBracketElectricCharacterContribution} from 'vs/editor/common/modes/supp
import {score} from 'vs/editor/common/modes/languageSelector';
import {Remotable, IThreadService} from 'vs/platform/thread/common/thread';
import * as errors from 'vs/base/common/errors';
import {ExtHostFileSystemEventService} from 'vs/workbench/api/common/extHostFileSystemEventService';
import {ExtHostModelService, setWordDefinitionFor} from 'vs/workbench/api/common/extHostDocuments';
import {ExtHostConfiguration} from 'vs/workbench/api/common/extHostConfiguration';
import {ExtHostDiagnostics} from 'vs/workbench/api/common/extHostDiagnostics';
import {ExtHostWorkspace} from 'vs/workbench/api/common/extHostWorkspace';
import {ExtHostQuickOpen} from 'vs/workbench/api/common/extHostQuickOpen';
import {ExtHostStatusBar} from 'vs/workbench/api/common/extHostStatusBar';
import {ExtHostCommands} from 'vs/workbench/api/common/extHostCommands';
import {ExtHostOutputService} from 'vs/workbench/api/common/extHostOutputService';
import {ExtHostMessageService} from 'vs/workbench/api/common/extHostMessageService';
import {ExtHostEditors} from 'vs/workbench/api/common/extHostEditors';
import {ExtHostLanguages} from 'vs/workbench/api/common/extHostLanguages';
import {ExtHostLanguageFeatures} from 'vs/workbench/api/common/extHostLanguageFeatures';
import {registerApiCommands} from 'vs/workbench/api/common/extHostApiCommands';
import * as extHostTypes from 'vs/workbench/api/common/extHostTypes';
import {ExtHostFileSystemEventService} from 'vs/workbench/api/node/extHostFileSystemEventService';
import {ExtHostModelService, setWordDefinitionFor} from 'vs/workbench/api/node/extHostDocuments';
import {ExtHostConfiguration} from 'vs/workbench/api/node/extHostConfiguration';
import {ExtHostDiagnostics} from 'vs/workbench/api/node/extHostDiagnostics';
import {ExtHostWorkspace} from 'vs/workbench/api/node/extHostWorkspace';
import {ExtHostQuickOpen} from 'vs/workbench/api/node/extHostQuickOpen';
import {ExtHostStatusBar} from 'vs/workbench/api/node/extHostStatusBar';
import {ExtHostCommands} from 'vs/workbench/api/node/extHostCommands';
import {ExtHostOutputService} from 'vs/workbench/api/node/extHostOutputService';
import {ExtHostMessageService} from 'vs/workbench/api/node/extHostMessageService';
import {ExtHostEditors} from 'vs/workbench/api/node/extHostEditors';
import {ExtHostLanguages} from 'vs/workbench/api/node/extHostLanguages';
import {ExtHostLanguageFeatures} from 'vs/workbench/api/node/extHostLanguageFeatures';
import {registerApiCommands} from 'vs/workbench/api/node/extHostApiCommands';
import * as extHostTypes from 'vs/workbench/api/node/extHostTypes';
import Modes = require('vs/editor/common/modes');
import {IModeService} from 'vs/editor/common/services/modeService';
import {ICommentsSupportContribution, ITokenTypeClassificationSupportContribution} from 'vs/editor/common/modes/supports';
@ -37,7 +37,7 @@ import {TPromise} from 'vs/base/common/winjs.base';
import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace';
import {CancellationTokenSource} from 'vs/base/common/cancellation';
import vscode = require('vscode');
import {TextEditorRevealType} from 'vs/workbench/api/common/mainThreadEditors';
import {TextEditorRevealType} from 'vs/workbench/api/node/mainThreadEditors';
import * as paths from 'vs/base/common/paths';
/**
@ -244,16 +244,27 @@ export class ExtHostAPIImplementation {
return pluginHostFileSystemEvent.createFileSystemWatcher(pattern, ignoreCreate, ignoreChange, ignoreDelete);
},
get textDocuments() {
return pluginHostDocuments.getDocuments();
return pluginHostDocuments.getAllDocumentData().map(data => data.document);
},
set textDocuments(value) {
throw errors.readonly();
},
// createTextDocument(text: string, fileName?: string, language?: string): Thenable<vscode.TextDocument> {
// return pluginHostDocuments.createDocument(text, fileName, language);
// },
openTextDocument(uriOrFileName:vscode.Uri | string) {
return pluginHostDocuments.openDocument(uriOrFileName);
openTextDocument(uriOrFileName: vscode.Uri | string) {
let uri: URI;
if (typeof uriOrFileName === 'string') {
uri = URI.file(uriOrFileName);
} else if (uriOrFileName instanceof URI) {
uri = <URI>uriOrFileName;
} else {
throw new Error('illegal argument - uriOrFileName');
}
return pluginHostDocuments.ensureDocumentData(uri).then(() => {
const data = pluginHostDocuments.getDocumentData(uri);
return data && data.document;
});
},
registerTextDocumentContentProvider(scheme: string, provider: vscode.TextDocumentContentProvider) {
return pluginHostDocuments.registerTextDocumentContentProvider(scheme, provider);
},
onDidOpenTextDocument: (listener, thisArgs?, disposables?) => {
return pluginHostDocuments.onDidAddDocument(listener, thisArgs, disposables);

View file

@ -8,12 +8,12 @@ import URI from 'vs/base/common/uri';
import {TPromise} from 'vs/base/common/winjs.base';
import {IDisposable} from 'vs/base/common/lifecycle';
import * as vscode from 'vscode';
import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters';
import * as types from 'vs/workbench/api/common/extHostTypes';
import * as typeConverters from 'vs/workbench/api/node/extHostTypeConverters';
import * as types from 'vs/workbench/api/node/extHostTypes';
import {ISingleEditOperation} from 'vs/editor/common/editorCommon';
import * as modes from 'vs/editor/common/modes';
import {ICommandHandlerDescription} from 'vs/platform/keybinding/common/keybindingService';
import {ExtHostCommands} from 'vs/workbench/api/common/extHostCommands';
import {ExtHostCommands} from 'vs/workbench/api/node/extHostCommands';
import {IQuickFix2} from 'vs/editor/contrib/quickFix/common/quickFix';
import {IOutline} from 'vs/editor/contrib/quickOpen/common/quickOpen';
import {ITypeBearing} from 'vs/workbench/parts/search/common/search';

View file

@ -9,9 +9,9 @@ import {validateConstraint} from 'vs/base/common/types';
import {KeybindingsRegistry} from 'vs/platform/keybinding/common/keybindingsRegistry';
import {IKeybindingService, ICommandHandlerDescription} from 'vs/platform/keybinding/common/keybindingService';
import {TPromise} from 'vs/base/common/winjs.base';
import {ExtHostEditors} from 'vs/workbench/api/common/extHostEditors';
import * as extHostTypes from 'vs/workbench/api/common/extHostTypes';
import * as extHostTypeConverter from 'vs/workbench/api/common/extHostTypeConverters';
import {ExtHostEditors} from 'vs/workbench/api/node/extHostEditors';
import * as extHostTypes from 'vs/workbench/api/node/extHostTypes';
import * as extHostTypeConverter from 'vs/workbench/api/node/extHostTypeConverters';
import {cloneAndChange} from 'vs/base/common/objects';
interface CommandHandler {

View file

@ -7,15 +7,16 @@
import {toErrorMessage} from 'vs/base/common/errors';
import {IEmitterEvent} from 'vs/base/common/eventEmitter';
import {IModelService} from 'vs/editor/common/services/modelService';
import {PrefixSumComputer, IPrefixSumIndexOfResult} from 'vs/editor/common/viewModel/prefixSumComputer';
import * as EditorCommon from 'vs/editor/common/editorCommon';
import {IPrefixSumIndexOfResult} from 'vs/editor/common/viewModel/prefixSumComputer';
import {MirrorModel2} from 'vs/editor/common/model/mirrorModel2';
import {Remotable, IThreadService} from 'vs/platform/thread/common/thread';
import Event, {Emitter} from 'vs/base/common/event';
import URI from 'vs/base/common/uri';
import {IDisposable, disposeAll} from 'vs/base/common/lifecycle';
import {Range, Position} from 'vs/workbench/api/common/extHostTypes';
import {Range, Position, Disposable} from 'vs/workbench/api/node/extHostTypes';
import {IEventService} from 'vs/platform/event/common/event';
import {IEditorService} from 'vs/platform/editor/common/editor';
import {IWorkbenchEditorService} from 'vs/workbench/services/editor/common/editorService';
import {EventType as FileEventType, LocalFileChangeEvent, ITextFileService} from 'vs/workbench/parts/files/common/files';
import * as TypeConverters from './extHostTypeConverters';
import {TPromise} from 'vs/base/common/winjs.base';
@ -23,6 +24,13 @@ import * as vscode from 'vscode';
import {WordHelper} from 'vs/editor/common/model/textModelWithTokensHelpers';
import {IFileService} from 'vs/platform/files/common/files';
import {IUntitledEditorService} from 'vs/workbench/services/untitled/common/untitledEditorService';
import {asWinJsPromise} from 'vs/base/common/async';
import {EditorModel, EditorInput} from 'vs/workbench/common/editor';
import {IEditorInput, IResourceInput} from 'vs/platform/editor/common/editor';
import {IMode} from 'vs/editor/common/modes';
import {IModeService} from 'vs/editor/common/services/modeService';
import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation';
import * as weak from 'weak';
export interface IModelAddedData {
url: URI;
@ -47,127 +55,157 @@ export function getWordDefinitionFor(modeId:string):RegExp {
@Remotable.PluginHostContext('ExtHostModelService')
export class ExtHostModelService {
private _onDidAddDocumentEventEmitter: Emitter<BaseTextDocument>;
public onDidAddDocument: Event<BaseTextDocument>;
private _onDidAddDocumentEventEmitter: Emitter<vscode.TextDocument>;
public onDidAddDocument: Event<vscode.TextDocument>;
private _onDidRemoveDocumentEventEmitter: Emitter<BaseTextDocument>;
public onDidRemoveDocument: Event<BaseTextDocument>;
private _onDidRemoveDocumentEventEmitter: Emitter<vscode.TextDocument>;
public onDidRemoveDocument: Event<vscode.TextDocument>;
private _onDidChangeDocumentEventEmitter: Emitter<vscode.TextDocumentChangeEvent>;
public onDidChangeDocument: Event<vscode.TextDocumentChangeEvent>;
private _onDidSaveDocumentEventEmitter: Emitter<BaseTextDocument>;
public onDidSaveDocument: Event<BaseTextDocument>;
private _onDidSaveDocumentEventEmitter: Emitter<vscode.TextDocument>;
public onDidSaveDocument: Event<vscode.TextDocument>;
private _documents: {[modelUri:string]:ExtHostDocument;};
private _documentData: { [modelUri: string]: ExtHostDocumentData; };
private _documentLoader: { [modelUri: string]: TPromise<ExtHostDocumentData> };
private _documentContentProviders: { [scheme: string]: vscode.TextDocumentContentProvider };
private _proxy: MainThreadDocuments;
constructor(@IThreadService threadService: IThreadService) {
this._proxy = threadService.getRemotable(MainThreadDocuments);
this._onDidAddDocumentEventEmitter = new Emitter<BaseTextDocument>();
this._onDidAddDocumentEventEmitter = new Emitter<vscode.TextDocument>();
this.onDidAddDocument = this._onDidAddDocumentEventEmitter.event;
this._onDidRemoveDocumentEventEmitter = new Emitter<BaseTextDocument>();
this._onDidRemoveDocumentEventEmitter = new Emitter<vscode.TextDocument>();
this.onDidRemoveDocument = this._onDidRemoveDocumentEventEmitter.event;
this._onDidChangeDocumentEventEmitter = new Emitter<vscode.TextDocumentChangeEvent>();
this.onDidChangeDocument = this._onDidChangeDocumentEventEmitter.event;
this._onDidSaveDocumentEventEmitter = new Emitter<BaseTextDocument>();
this._onDidSaveDocumentEventEmitter = new Emitter<vscode.TextDocument>();
this.onDidSaveDocument = this._onDidSaveDocumentEventEmitter.event;
this._documents = Object.create(null);
this._documentData = Object.create(null);
this._documentLoader = Object.create(null);
this._documentContentProviders = Object.create(null);
}
public getDocuments(): BaseTextDocument[] {
let r: BaseTextDocument[] = [];
for (let key in this._documents) {
r.push(this._documents[key]);
public getAllDocumentData(): ExtHostDocumentData[] {
const result: ExtHostDocumentData[] = [];
for (let key in this._documentData) {
result.push(this._documentData[key]);
}
return r;
return result;
}
public getDocument(resource: vscode.Uri): BaseTextDocument {
public getDocumentData(resource: vscode.Uri): ExtHostDocumentData {
if (!resource) {
return null;
return;
}
const data = this._documentData[resource.toString()];
if (data) {
return data;
}
return this._documents[resource.toString()] || null;
}
public openDocument(uriOrFileName: vscode.Uri | string): TPromise<vscode.TextDocument> {
public ensureDocumentData(uri: URI): TPromise<ExtHostDocumentData> {
let uri: URI;
if (typeof uriOrFileName === 'string') {
uri = URI.file(uriOrFileName);
} else if (uriOrFileName instanceof URI) {
uri = <URI>uriOrFileName;
} else {
throw new Error('illegal argument - uriOrFileName');
}
let cached = this._documents[uri.toString()];
let cached = this._documentData[uri.toString()];
if (cached) {
return TPromise.as(cached);
}
return this._proxy._tryOpenDocument(uri).then(() => {
return this._documents[uri.toString()];
let promise = this._documentLoader[uri.toString()];
if (!promise) {
promise = this._proxy._tryOpenDocument(uri).then(() => {
delete this._documentLoader[uri.toString()];
return this._documentData[uri.toString()];
}, err => {
delete this._documentLoader[uri.toString()];
return TPromise.wrapError(err);
});
this._documentLoader[uri.toString()] = promise;
}
return promise;
}
public registerTextDocumentContentProvider(scheme: string, provider: vscode.TextDocumentContentProvider): vscode.Disposable {
if (scheme === 'file' || scheme === 'untitled' || this._documentContentProviders[scheme]) {
throw new Error(`scheme '${scheme}' already registered`);
}
this._documentContentProviders[scheme] = provider;
return new Disposable(() => delete this._documentContentProviders[scheme]);
}
$provideTextDocumentContent(uri: URI): TPromise<string> {
const provider = this._documentContentProviders[uri.scheme];
if (!provider) {
return TPromise.wrapError<string>(`unsupported uri-scheme: ${uri.scheme}`);
}
return asWinJsPromise(token => provider.provideTextDocumentContent(uri, token)).then(value => {
if (typeof value !== 'string') {
return TPromise.wrapError('received illegal value from text document provider');
}
return value;
});
}
public _acceptModelAdd(data:IModelAddedData): void {
let document = new ExtHostDocument(this._proxy, data.url, data.value.lines, data.value.EOL, data.modeId, data.versionId, data.isDirty);
let key = document.uri.toString();
if (this._documents[key]) {
public _acceptModelAdd(initData:IModelAddedData): void {
let data = new ExtHostDocumentData(this._proxy, initData.url, initData.value.lines, initData.value.EOL, initData.modeId, initData.versionId, initData.isDirty);
let key = data.document.uri.toString();
if (this._documentData[key]) {
throw new Error('Document `' + key + '` already exists.');
}
this._documents[key] = document;
this._onDidAddDocumentEventEmitter.fire(document);
this._documentData[key] = data;
this._onDidAddDocumentEventEmitter.fire(data.document);
}
public _acceptModelModeChanged(url: URI, oldModeId:string, newModeId:string): void {
let document = this._documents[url.toString()];
let data = this._documentData[url.toString()];
// Treat a mode change as a remove + add
this._onDidRemoveDocumentEventEmitter.fire(document);
document._acceptLanguageId(newModeId);
this._onDidAddDocumentEventEmitter.fire(document);
this._onDidRemoveDocumentEventEmitter.fire(data.document);
data._acceptLanguageId(newModeId);
this._onDidAddDocumentEventEmitter.fire(data.document);
}
public _acceptModelSaved(url: URI): void {
let document = this._documents[url.toString()];
document._acceptIsDirty(false);
this._onDidSaveDocumentEventEmitter.fire(document);
let data = this._documentData[url.toString()];
data._acceptIsDirty(false);
this._onDidSaveDocumentEventEmitter.fire(data.document);
}
public _acceptModelDirty(url: URI): void {
let document = this._documents[url.toString()];
let document = this._documentData[url.toString()];
document._acceptIsDirty(true);
}
public _acceptModelReverted(url: URI): void {
let document = this._documents[url.toString()];
let document = this._documentData[url.toString()];
document._acceptIsDirty(false);
}
public _acceptModelRemoved(url: URI): void {
let key = url.toString();
if (!this._documents[key]) {
if (!this._documentData[key]) {
throw new Error('Document `' + key + '` does not exist.');
}
let document = this._documents[key];
delete this._documents[key];
this._onDidRemoveDocumentEventEmitter.fire(document);
document.dispose();
let data = this._documentData[key];
delete this._documentData[key];
this._onDidRemoveDocumentEventEmitter.fire(data.document);
data.dispose();
}
public _acceptModelChanged(url: URI, events: EditorCommon.IModelContentChangedEvent2[]): void {
let document = this._documents[url.toString()];
document._acceptEvents(events);
let data = this._documentData[url.toString()];
data.onEvents(events);
this._onDidChangeDocumentEventEmitter.fire({
document: document,
document: data.document,
contentChanges: events.map((e) => {
return {
range: TypeConverters.toRange(e.range),
@ -179,69 +217,72 @@ export class ExtHostModelService {
}
}
export class BaseTextDocument implements vscode.TextDocument {
protected _uri: URI;
protected _lines: string[];
protected _eol: string;
protected _languageId: string;
protected _versionId: number;
protected _isDirty: boolean;
protected _textLines: vscode.TextLine[];
protected _lineStarts: PrefixSumComputer;
export class ExtHostDocumentData extends MirrorModel2 {
constructor(uri: URI, lines: string[], eol: string, languageId: string, versionId: number, isDirty:boolean) {
this._uri = uri;
this._lines = lines;
this._textLines = [];
this._eol = eol;
private _proxy: MainThreadDocuments;
private _languageId: string;
private _isDirty: boolean;
private _textLines: vscode.TextLine[];
private _documentRef: weak.WeakRef & vscode.TextDocument;
constructor(proxy: MainThreadDocuments, uri: URI, lines: string[], eol: string,
languageId: string, versionId: number, isDirty: boolean) {
super(uri, lines, eol, versionId);
this._proxy = proxy;
this._languageId = languageId;
this._versionId = versionId;
this._isDirty = isDirty;
this._textLines = [];
}
dispose(): void {
this._lines.length = 0;
this._textLines.length = 0;
this._isDirty = false;
super.dispose();
}
get uri(): URI {
return this._uri;
}
get document(): vscode.TextDocument {
// dereferences or creates the actual document for this
// document data. keeps a weak reference only such that
// we later when a document isn't needed anymore
get fileName(): string {
return this._uri.fsPath;
}
get isUntitled(): boolean {
return this._uri.scheme !== 'file';
}
get languageId(): string {
return this._languageId;
}
get version(): number {
return this._versionId;
}
get isDirty(): boolean {
return this._isDirty;
}
save(): Thenable<boolean> {
return Promise.reject<boolean>('Not implemented');
}
getText(range?: Range): string {
if (range) {
return this._getTextInRange(range);
} else {
return this._lines.join(this._eol);
if (!this.isDocumentReferenced) {
const data = this;
const doc = {
get uri() { return data._uri },
get fileName() { return data._uri.fsPath },
get isUntitled() { return data._uri.scheme !== 'file' },
get languageId() { return data._languageId },
get version() { return data._versionId },
get isDirty() { return data._isDirty },
save() { return data._proxy._trySaveDocument(data._uri) },
getText(range?) { return range ? data._getTextInRange(range) : data.getText() },
get lineCount() { return data._lines.length },
lineAt(lineOrPos) { return data.lineAt(lineOrPos) },
offsetAt(pos) { return data.offsetAt(pos) },
positionAt(offset) { return data.positionAt(offset) },
validateRange(ran) { return data.validateRange(ran) },
validatePosition(pos) { return data.validatePosition(pos) },
getWordRangeAtPosition(pos) { return data.getWordRangeAtPosition(pos) }
};
this._documentRef = weak(doc);
}
return weak.get(this._documentRef);
}
private _getTextInRange(_range: Range): string {
get isDocumentReferenced(): boolean {
return this._documentRef && !weak.isDead(this._documentRef);
}
_acceptLanguageId(newLanguageId:string): void {
this._languageId = newLanguageId;
}
_acceptIsDirty(isDirty:boolean): void {
this._isDirty = isDirty;
}
private _getTextInRange(_range: vscode.Range): string {
let range = this.validateRange(_range);
if (range.isEmpty) {
@ -266,10 +307,6 @@ export class BaseTextDocument implements vscode.TextDocument {
return resultLines.join(lineEnding);
}
get lineCount(): number {
return this._lines.length;
}
lineAt(lineOrPosition: number | vscode.Position): vscode.TextLine {
let line: number;
@ -306,13 +343,13 @@ export class BaseTextDocument implements vscode.TextDocument {
return result;
}
offsetAt(position: Position): number {
offsetAt(position: vscode.Position): number {
position = this.validatePosition(position);
this._ensureLineStarts();
return this._lineStarts.getAccumulatedValue(position.line - 1) + position.character;
}
positionAt(offset: number): Position {
positionAt(offset: number): vscode.Position {
offset = Math.floor(offset);
offset = Math.max(0, offset);
@ -326,20 +363,9 @@ export class BaseTextDocument implements vscode.TextDocument {
return new Position(out.index, Math.min(out.remainder, lineLength));
}
private _ensureLineStarts(): void {
if (!this._lineStarts) {
const lineStartValues:number[] = [];
const eolLength = this._eol.length;
for (let i = 0, len = this._lines.length; i < len; i++) {
lineStartValues.push(this._lines[i].length + eolLength);
}
this._lineStarts = new PrefixSumComputer(lineStartValues);
}
}
// ---- range math
validateRange(range:Range): Range {
validateRange(range:vscode.Range): vscode.Range {
if (!(range instanceof Range)) {
throw new Error('Invalid argument');
}
@ -350,10 +376,10 @@ export class BaseTextDocument implements vscode.TextDocument {
if (start === range.start && end === range.end) {
return range;
}
return new Range(start, end);
return new Range(start.line, start.character, end.line, end.character);
}
validatePosition(position:Position): Position {
validatePosition(position:vscode.Position): vscode.Position {
if (!(position instanceof Position)) {
throw new Error('Invalid argument');
}
@ -388,7 +414,7 @@ export class BaseTextDocument implements vscode.TextDocument {
return new Position(line, character);
}
getWordRangeAtPosition(_position:Position): Range {
getWordRangeAtPosition(_position: vscode.Position): vscode.Range {
let position = this.validatePosition(_position);
let wordAtText = WordHelper._getWordAtText(
@ -404,129 +430,12 @@ export class BaseTextDocument implements vscode.TextDocument {
}
}
export class ExtHostDocument extends BaseTextDocument {
private _proxy: MainThreadDocuments;
constructor(proxy: MainThreadDocuments, uri: URI, lines: string[],
eol: string, languageId: string, versionId: number, isDirty:boolean) {
super(uri, lines, eol, languageId, versionId, isDirty);
this._proxy = proxy;
}
save(): Thenable<boolean> {
return this._proxy._trySaveDocument(this._uri);
}
_acceptLanguageId(newLanguageId:string): void {
this._languageId = newLanguageId;
}
_acceptIsDirty(isDirty:boolean): void {
this._isDirty = isDirty;
}
_acceptEvents(events: EditorCommon.IModelContentChangedEvent2[]): void {
// Update my lines
let lastVersionId = -1;
for (let i = 0, len = events.length; i < len; i++) {
let e = events[i];
this._acceptDeleteRange(e.range);
this._acceptInsertText({
lineNumber: e.range.startLineNumber,
column: e.range.startColumn
}, e.text);
lastVersionId = Math.max(lastVersionId, e.versionId);
}
if (lastVersionId !== -1) {
this._versionId = lastVersionId;
}
}
/**
* All changes to a line's text go through this method
*/
private _setLineText(lineIndex:number, newValue:string): void {
this._lines[lineIndex] = newValue;
if (this._lineStarts) {
// update prefix sum
this._lineStarts.changeValue(lineIndex, this._lines[lineIndex].length + this._eol.length);
}
}
private _acceptDeleteRange(range: EditorCommon.IRange): void {
if (range.startLineNumber === range.endLineNumber) {
if (range.startColumn === range.endColumn) {
// Nothing to delete
return;
}
// Delete text on the affected line
this._setLineText(range.startLineNumber - 1,
this._lines[range.startLineNumber - 1].substring(0, range.startColumn - 1)
+ this._lines[range.startLineNumber - 1].substring(range.endColumn - 1)
);
return;
}
// Take remaining text on last line and append it to remaining text on first line
this._setLineText(range.startLineNumber - 1,
this._lines[range.startLineNumber - 1].substring(0, range.startColumn - 1)
+ this._lines[range.endLineNumber - 1].substring(range.endColumn - 1)
);
// Delete middle lines
this._lines.splice(range.startLineNumber, range.endLineNumber - range.startLineNumber);
if (this._lineStarts) {
// update prefix sum
this._lineStarts.removeValues(range.startLineNumber, range.endLineNumber - range.startLineNumber);
}
}
private _acceptInsertText(position: EditorCommon.IPosition, insertText:string): void {
if (insertText.length === 0) {
// Nothing to insert
return;
}
let insertLines = insertText.split(/\r\n|\r|\n/);
if (insertLines.length === 1) {
// Inserting text on one line
this._setLineText(position.lineNumber - 1,
this._lines[position.lineNumber - 1].substring(0, position.column - 1)
+ insertLines[0]
+ this._lines[position.lineNumber - 1].substring(position.column - 1)
);
return;
}
// Append overflowing text from first line to the end of text to insert
insertLines[insertLines.length - 1] += this._lines[position.lineNumber - 1].substring(position.column - 1);
// Delete overflowing text from first line and insert text on first line
this._setLineText(position.lineNumber - 1,
this._lines[position.lineNumber - 1].substring(0, position.column - 1)
+ insertLines[0]
);
// Insert new lines & store lengths
let newLengths:number[] = new Array<number>(insertLines.length - 1);
for (let i = 1; i < insertLines.length; i++) {
this._lines.splice(position.lineNumber + i - 1, 0, insertLines[i]);
newLengths[i - 1] = insertLines[i].length + this._eol.length;
}
if (this._lineStarts) {
// update prefix sum
this._lineStarts.insertValues(position.lineNumber, newLengths);
}
}
}
@Remotable.MainContext('MainThreadDocuments')
export class MainThreadDocuments {
private _modelService: IModelService;
private _modeService: IModeService;
private _textFileService: ITextFileService;
private _editorService: IEditorService;
private _editorService: IWorkbenchEditorService;
private _fileService: IFileService;
private _untitledEditorService: IUntitledEditorService;
private _toDispose: IDisposable[];
@ -536,13 +445,16 @@ export class MainThreadDocuments {
constructor(
@IThreadService threadService: IThreadService,
@IModelService modelService:IModelService,
@IModelService modelService: IModelService,
@IModeService modeService: IModeService,
@IEventService eventService:IEventService,
@ITextFileService textFileService: ITextFileService,
@IEditorService editorService: IEditorService,
@IWorkbenchEditorService editorService: IWorkbenchEditorService,
@IFileService fileService: IFileService,
@IUntitledEditorService untitledEditorService: IUntitledEditorService
) {
this._modelService = modelService;
this._modeService = modeService;
this._textFileService = textFileService;
this._editorService = editorService;
this._fileService = fileService;
@ -650,7 +562,7 @@ export class MainThreadDocuments {
promise = this._handleUnititledScheme(uri);
break;
default:
promise = TPromise.wrapError<boolean>('unsupported URI-scheme: ' + uri.scheme);
promise = this._handleAnyScheme(uri);
break;
}
@ -686,4 +598,20 @@ export class MainThreadDocuments {
});
});
}
}
private _handleAnyScheme(uri: URI): TPromise<boolean> {
if (this._modelService.getModel(uri)) {
return TPromise.as(true);
}
return this._proxy.$provideTextDocumentContent(uri).then(value => {
const firstLineText = value.substr(0, 1 + value.search(/\r?\n/));
const mode = this._modeService.getOrCreateModeByFilenameOrFirstLine(uri.fsPath, firstLineText);
return this._modelService.createModel(value, mode, uri);
}).then(() => {
return true;
});
}
}

View file

@ -9,17 +9,18 @@ import Event, {Emitter} from 'vs/base/common/event';
import {IDisposable, disposeAll} from 'vs/base/common/lifecycle';
import {TPromise} from 'vs/base/common/winjs.base';
import {Remotable, IThreadService} from 'vs/platform/thread/common/thread';
import {ExtHostModelService} from 'vs/workbench/api/common/extHostDocuments';
import {ExtHostModelService, ExtHostDocumentData} from 'vs/workbench/api/node/extHostDocuments';
import {Selection, Range, Position, EditorOptions} from './extHostTypes';
import {ISingleEditOperation, ISelection, IRange, IInternalIndentationOptions, IEditor, EditorType, ICommonCodeEditor, ICommonDiffEditor, IDecorationRenderOptions, IRangeWithMessage} from 'vs/editor/common/editorCommon';
import {ICodeEditorService} from 'vs/editor/common/services/codeEditorService';
import {IWorkbenchEditorService} from 'vs/workbench/services/editor/common/editorService';
import {IEditor as IPlatformEditor, Position as EditorPosition} from 'vs/platform/editor/common/editor';
import {IModelService} from 'vs/editor/common/services/modelService';
import {MainThreadEditorsTracker, TextEditorRevealType, MainThreadTextEditor, ITextEditorConfiguration} from 'vs/workbench/api/common/mainThreadEditors';
import {MainThreadEditorsTracker, TextEditorRevealType, MainThreadTextEditor, ITextEditorConfiguration} from 'vs/workbench/api/node/mainThreadEditors';
import * as TypeConverters from './extHostTypeConverters';
import {TextDocument, TextEditorSelectionChangeEvent, TextEditorOptionsChangeEvent, TextEditorOptions, ViewColumn} from 'vscode';
import {EventType} from 'vs/workbench/common/events';
import {EditorOptions as WorkbenchEditorOptions} from 'vs/workbench/common/editor';
import {IEventService} from 'vs/platform/event/common/event';
import {equals as arrayEquals} from 'vs/base/common/arrays';
@ -93,7 +94,7 @@ export class ExtHostEditors {
// --- called from main thread
_acceptTextEditorAdd(data:ITextEditorAddData): void {
let document = this._modelService.getDocument(data.document);
let document = this._modelService.getDocumentData(data.document);
let newEditor = new ExtHostTextEditor(this._proxy, data.id, document, data.selections.map(TypeConverters.toSelection), data.options);
this._editors[data.id] = newEditor;
}
@ -267,20 +268,20 @@ class ExtHostTextEditor implements vscode.TextEditor {
private _proxy: MainThreadEditors;
private _id: string;
private _document: vscode.TextDocument;
private _documentData: ExtHostDocumentData;
private _selections: Selection[];
private _options: TextEditorOptions;
constructor(proxy: MainThreadEditors, id: string, document: TextDocument, selections: Selection[], options: EditorOptions) {
constructor(proxy: MainThreadEditors, id: string, document: ExtHostDocumentData, selections: Selection[], options: EditorOptions) {
this._proxy = proxy;
this._id = id;
this._document = document;
this._documentData = document;
this._selections = selections;
this._options = options;
}
dispose() {
this._document = null;
this._documentData = null;
}
@deprecated('TextEditor.show') show(column: vscode.ViewColumn) {
@ -294,7 +295,7 @@ class ExtHostTextEditor implements vscode.TextEditor {
// ---- the document
get document(): vscode.TextDocument {
return this._document;
return this._documentData.document;
}
set document(value) {
@ -378,7 +379,7 @@ class ExtHostTextEditor implements vscode.TextEditor {
// ---- editing
edit(callback:(edit:TextEditorEdit)=>void): Thenable<boolean> {
let edit = new TextEditorEdit(this._document);
let edit = new TextEditorEdit(this._documentData.document);
callback(edit);
return this._applyEdit(edit);
}
@ -527,8 +528,7 @@ export class MainThreadEditors {
_tryShowTextDocument(resource: URI, position: EditorPosition, preserveFocus: boolean): TPromise<string> {
// the input we want to open
let input = {
const input = {
resource,
options: { preserveFocus }
};

View file

@ -11,14 +11,14 @@ import {IDisposable, disposeAll} from 'vs/base/common/lifecycle';
import {Remotable, IThreadService} from 'vs/platform/thread/common/thread';
import {Range as EditorRange} from 'vs/editor/common/core/range';
import * as vscode from 'vscode';
import * as TypeConverters from 'vs/workbench/api/common/extHostTypeConverters';
import {Range, DocumentHighlightKind, Disposable, Diagnostic, SignatureHelp} from 'vs/workbench/api/common/extHostTypes';
import * as TypeConverters from 'vs/workbench/api/node/extHostTypeConverters';
import {Range, DocumentHighlightKind, Disposable, Diagnostic, SignatureHelp} from 'vs/workbench/api/node/extHostTypes';
import {IPosition, IRange, ISingleEditOperation} from 'vs/editor/common/editorCommon';
import * as modes from 'vs/editor/common/modes';
import {CancellationTokenSource} from 'vs/base/common/cancellation';
import {ExtHostModelService} from 'vs/workbench/api/common/extHostDocuments';
import {ExtHostModelService} from 'vs/workbench/api/node/extHostDocuments';
import {IMarkerService, IMarker} from 'vs/platform/markers/common/markers';
import {ExtHostCommands} from 'vs/workbench/api/common/extHostCommands';
import {ExtHostCommands} from 'vs/workbench/api/node/extHostCommands';
import {DeclarationRegistry} from 'vs/editor/contrib/goToDeclaration/common/goToDeclaration';
import {ExtraInfoRegistry} from 'vs/editor/contrib/hover/common/hover';
import {OccurrencesRegistry} from 'vs/editor/contrib/wordHighlighter/common/wordHighlighter';
@ -31,24 +31,7 @@ import {FormatRegistry, FormatOnTypeRegistry} from 'vs/editor/contrib/format/com
import {CodeLensRegistry} from 'vs/editor/contrib/codelens/common/codelens';
import {ParameterHintsRegistry} from 'vs/editor/contrib/parameterHints/common/parameterHints';
import {SuggestRegistry} from 'vs/editor/contrib/suggest/common/suggest';
function isThenable<T>(obj: any): obj is Thenable<T> {
return obj && typeof (<Thenable<any>>obj).then === 'function';
}
function asWinJsPromise<T>(callback: (token: vscode.CancellationToken) => T | Thenable<T>): TPromise<T> {
let source = new CancellationTokenSource();
return new TPromise<T>((resolve, reject) => {
let item = callback(source.token);
if (isThenable<T>(item)) {
item.then(resolve, reject);
} else {
resolve(item);
}
}, () => {
source.cancel();
});
}
import {asWinJsPromise} from 'vs/base/common/async';
// --- adapter
@ -63,7 +46,7 @@ class OutlineAdapter implements IOutlineSupport {
}
getOutline(resource: URI): TPromise<IOutlineEntry[]> {
let doc = this._documents.getDocument(resource);
let doc = this._documents.getDocumentData(resource).document;
return asWinJsPromise(token => this._provider.provideDocumentSymbols(doc, token)).then(value => {
if (Array.isArray(value)) {
return value.map(TypeConverters.SymbolInformation.toOutlineEntry);
@ -93,7 +76,7 @@ class CodeLensAdapter implements modes.ICodeLensSupport {
}
findCodeLensSymbols(resource: URI): TPromise<modes.ICodeLensSymbol[]> {
const doc = this._documents.getDocument(resource);
const doc = this._documents.getDocumentData(resource).document;
const version = doc.version;
const key = resource.toString();
@ -197,7 +180,7 @@ class DeclarationAdapter implements modes.IDeclarationSupport {
}
findDeclaration(resource: URI, position: IPosition): TPromise<modes.IReference[]> {
let doc = this._documents.getDocument(resource);
let doc = this._documents.getDocumentData(resource).document;
let pos = TypeConverters.toPosition(position);
return asWinJsPromise(token => this._provider.provideDefinition(doc, pos, token)).then(value => {
if (Array.isArray(value)) {
@ -231,7 +214,7 @@ class ExtraInfoAdapter implements modes.IExtraInfoSupport {
computeInfo(resource: URI, position: IPosition): TPromise<modes.IComputeExtraInfoResult> {
let doc = this._documents.getDocument(resource);
let doc = this._documents.getDocumentData(resource).document;
let pos = TypeConverters.toPosition(position);
return asWinJsPromise(token => this._provider.provideHover(doc, pos, token)).then(value => {
@ -262,7 +245,7 @@ class OccurrencesAdapter implements modes.IOccurrencesSupport {
findOccurrences(resource: URI, position: IPosition): TPromise<modes.IOccurence[]> {
let doc = this._documents.getDocument(resource);
let doc = this._documents.getDocumentData(resource).document;
let pos = TypeConverters.toPosition(position);
return asWinJsPromise(token => this._provider.provideDocumentHighlights(doc, pos, token)).then(value => {
@ -295,7 +278,7 @@ class ReferenceAdapter implements modes.IReferenceSupport {
}
findReferences(resource: URI, position: IPosition, includeDeclaration: boolean): TPromise<modes.IReference[]> {
let doc = this._documents.getDocument(resource);
let doc = this._documents.getDocumentData(resource).document;
let pos = TypeConverters.toPosition(position);
return asWinJsPromise(token => this._provider.provideReferences(doc, pos, { includeDeclaration }, token)).then(value => {
@ -329,7 +312,7 @@ class QuickFixAdapter implements modes.IQuickFixSupport {
getQuickFixes(resource: URI, range: IRange, markers?: IMarker[]): TPromise<modes.IQuickFix[]> {
const doc = this._documents.getDocument(resource);
const doc = this._documents.getDocumentData(resource).document;
const ran = TypeConverters.toRange(range);
const diagnostics = markers.map(marker => {
const diag = new Diagnostic(TypeConverters.toRange(marker), marker.message);
@ -372,7 +355,7 @@ class DocumentFormattingAdapter implements modes.IFormattingSupport {
formatDocument(resource: URI, options: modes.IFormattingOptions): TPromise<ISingleEditOperation[]> {
let doc = this._documents.getDocument(resource);
let doc = this._documents.getDocumentData(resource).document;
return asWinJsPromise(token => this._provider.provideDocumentFormattingEdits(doc, <any>options, token)).then(value => {
if (Array.isArray(value)) {
@ -394,7 +377,7 @@ class RangeFormattingAdapter implements modes.IFormattingSupport {
formatRange(resource: URI, range: IRange, options: modes.IFormattingOptions): TPromise<ISingleEditOperation[]> {
let doc = this._documents.getDocument(resource);
let doc = this._documents.getDocumentData(resource).document;
let ran = TypeConverters.toRange(range);
return asWinJsPromise(token => this._provider.provideDocumentRangeFormattingEdits(doc, ran, <any>options, token)).then(value => {
@ -419,7 +402,7 @@ class OnTypeFormattingAdapter implements modes.IFormattingSupport {
formatAfterKeystroke(resource: URI, position: IPosition, ch: string, options: modes.IFormattingOptions): TPromise<ISingleEditOperation[]> {
let doc = this._documents.getDocument(resource);
let doc = this._documents.getDocumentData(resource).document;
let pos = TypeConverters.toPosition(position);
return asWinJsPromise(token => this._provider.provideOnTypeFormattingEdits(doc, pos, ch, <any> options, token)).then(value => {
@ -459,7 +442,7 @@ class RenameAdapter implements modes.IRenameSupport {
rename(resource: URI, position: IPosition, newName: string): TPromise<modes.IRenameResult> {
let doc = this._documents.getDocument(resource);
let doc = this._documents.getDocumentData(resource).document;
let pos = TypeConverters.toPosition(position);
return asWinJsPromise(token => this._provider.provideRenameEdits(doc, pos, newName, token)).then(value => {
@ -514,7 +497,7 @@ class SuggestAdapter implements modes.ISuggestSupport {
suggest(resource: URI, position: IPosition): TPromise<modes.ISuggestResult[]> {
const doc = this._documents.getDocument(resource);
const doc = this._documents.getDocumentData(resource).document;
const pos = TypeConverters.toPosition(position);
const ran = doc.getWordRangeAtPosition(pos);
@ -525,7 +508,7 @@ class SuggestAdapter implements modes.ISuggestSupport {
let defaultSuggestions: modes.ISuggestResult = {
suggestions: [],
currentWord: ran ? doc.getText(new Range(ran.start, pos)) : '',
currentWord: ran ? doc.getText(new Range(ran.start.line, ran.start.character, pos.line, pos.character)) : '',
};
let allSuggestions: modes.ISuggestResult[] = [defaultSuggestions];
@ -613,7 +596,7 @@ class ParameterHintsAdapter implements modes.IParameterHintsSupport {
getParameterHints(resource: URI, position: IPosition, triggerCharacter?: string): TPromise<modes.IParameterHints> {
const doc = this._documents.getDocument(resource);
const doc = this._documents.getDocumentData(resource).document;
const pos = TypeConverters.toPosition(position);
return asWinJsPromise(token => this._provider.provideSignatureHelp(doc, pos, token)).then(value => {

View file

@ -10,7 +10,7 @@ import {Remotable, IThreadService} from 'vs/platform/thread/common/thread';
import {IOutputService, OUTPUT_EDITOR_INPUT_ID} from 'vs/workbench/parts/output/common/output';
import {IWorkbenchEditorService} from 'vs/workbench/services/editor/common/editorService';
import {Position} from 'vs/platform/editor/common/editor';
import * as TypeConverters from 'vs/workbench/api/common/extHostTypeConverters';
import * as TypeConverters from 'vs/workbench/api/node/extHostTypeConverters';
export class ExtHostOutputChannel implements vscode.OutputChannel {

View file

@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import {ExtHostCommands} from 'vs/workbench/api/common/extHostCommands';
import {ExtHostCommands} from 'vs/workbench/api/node/extHostCommands';
import Severity from 'vs/base/common/severity';
import {isFalsyOrEmpty} from 'vs/base/common/arrays';
import {IDisposable} from 'vs/base/common/lifecycle';

View file

@ -15,7 +15,7 @@ import {ITextFileService} from 'vs/workbench/parts/files/common/files';
import {ICommonCodeEditor} from 'vs/editor/common/editorCommon';
import {bulkEdit, IResourceEdit} from 'vs/editor/common/services/bulkEdit';
import {TPromise} from 'vs/base/common/winjs.base';
import {fromRange} from 'vs/workbench/api/common/extHostTypeConverters';
import {fromRange} from 'vs/workbench/api/node/extHostTypeConverters';
import {Uri, CancellationToken} from 'vscode';
export class ExtHostWorkspace {

View file

@ -49,26 +49,26 @@ import {IModelService} from 'vs/editor/common/services/modelService';
import {ModelServiceImpl} from 'vs/editor/common/services/modelServiceImpl';
import {CodeEditorServiceImpl} from 'vs/editor/browser/services/codeEditorServiceImpl';
import {ICodeEditorService} from 'vs/editor/common/services/codeEditorService';
import {MainProcessVSCodeAPIHelper} from 'vs/workbench/api/common/extHost.api.impl';
import {MainProcessVSCodeAPIHelper} from 'vs/workbench/api/node/extHost.api.impl';
import {MainProcessPluginService} from 'vs/platform/plugins/common/nativePluginService';
import {MainThreadDocuments} from 'vs/workbench/api/common/extHostDocuments';
import {MainThreadDocuments} from 'vs/workbench/api/node/extHostDocuments';
import {MainProcessTextMateSyntax} from 'vs/editor/node/textMate/TMSyntax';
import {MainProcessTextMateSnippet} from 'vs/editor/node/textMate/TMSnippets';
import {JSONValidationExtensionPoint} from 'vs/platform/jsonschemas/common/jsonValidationExtensionPoint';
import {LanguageConfigurationFileHandler} from 'vs/editor/node/languageConfiguration';
import {MainThreadFileSystemEventService} from 'vs/workbench/api/common/extHostFileSystemEventService';
import {MainThreadQuickOpen} from 'vs/workbench/api/common/extHostQuickOpen';
import {MainThreadStatusBar} from 'vs/workbench/api/common/extHostStatusBar';
import {MainThreadCommands} from 'vs/workbench/api/common/extHostCommands';
import {MainThreadFileSystemEventService} from 'vs/workbench/api/node/extHostFileSystemEventService';
import {MainThreadQuickOpen} from 'vs/workbench/api/node/extHostQuickOpen';
import {MainThreadStatusBar} from 'vs/workbench/api/node/extHostStatusBar';
import {MainThreadCommands} from 'vs/workbench/api/node/extHostCommands';
import {RemoteTelemetryServiceHelper} from 'vs/platform/telemetry/common/abstractRemoteTelemetryService';
import {MainThreadDiagnostics} from 'vs/workbench/api/common/extHostDiagnostics';
import {MainThreadOutputService} from 'vs/workbench/api/common/extHostOutputService';
import {MainThreadMessageService} from 'vs/workbench/api/common/extHostMessageService';
import {MainThreadLanguages} from 'vs/workbench/api/common/extHostLanguages';
import {MainThreadEditors} from 'vs/workbench/api/common/extHostEditors';
import {MainThreadWorkspace} from 'vs/workbench/api/common/extHostWorkspace';
import {MainThreadConfiguration} from 'vs/workbench/api/common/extHostConfiguration';
import {MainThreadLanguageFeatures} from 'vs/workbench/api/common/extHostLanguageFeatures';
import {MainThreadDiagnostics} from 'vs/workbench/api/node/extHostDiagnostics';
import {MainThreadOutputService} from 'vs/workbench/api/node/extHostOutputService';
import {MainThreadMessageService} from 'vs/workbench/api/node/extHostMessageService';
import {MainThreadLanguages} from 'vs/workbench/api/node/extHostLanguages';
import {MainThreadEditors} from 'vs/workbench/api/node/extHostEditors';
import {MainThreadWorkspace} from 'vs/workbench/api/node/extHostWorkspace';
import {MainThreadConfiguration} from 'vs/workbench/api/node/extHostConfiguration';
import {MainThreadLanguageFeatures} from 'vs/workbench/api/node/extHostLanguageFeatures';
import {EventService} from 'vs/platform/event/common/eventService';
import {IOptions} from 'vs/workbench/common/options';
import themes = require('vs/platform/theme/common/themes');

View file

@ -18,15 +18,15 @@ import {TPromise} from 'vs/base/common/winjs.base';
import paths = require('vs/base/common/paths');
import {IPluginService, IPluginDescription} from 'vs/platform/plugins/common/plugins';
import {PluginsRegistry, PluginsMessageCollector, IPluginsMessageCollector} from 'vs/platform/plugins/common/pluginsRegistry';
import {ExtHostAPIImplementation} from 'vs/workbench/api/common/extHost.api.impl';
import {ExtHostAPIImplementation} from 'vs/workbench/api/node/extHost.api.impl';
import { create as createIPC, IPluginsIPC } from 'vs/platform/plugins/common/ipcRemoteCom';
import {ExtHostModelService} from 'vs/workbench/api/common/extHostDocuments';
import {ExtHostModelService} from 'vs/workbench/api/node/extHostDocuments';
import {IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import InstantiationService = require('vs/platform/instantiation/common/instantiationService');
import {PluginHostPluginService} from 'vs/platform/plugins/common/nativePluginService';
import {PluginHostThreadService} from 'vs/platform/thread/common/pluginHostThreadService';
import marshalling = require('vs/base/common/marshalling');
import {ExtHostTelemetryService} from 'vs/workbench/api/common/extHostTelemetry';
import {ExtHostTelemetryService} from 'vs/workbench/api/node/extHostTelemetry';
import {BaseRequestService} from 'vs/platform/request/common/baseRequestService';
import {BaseWorkspaceContextService} from 'vs/platform/workspace/common/baseWorkspaceContextService';
import {ModeServiceImpl} from 'vs/editor/common/services/modeServiceImpl';

View file

@ -14,6 +14,7 @@ import {IDiffEditor, ICodeEditor} from 'vs/editor/browser/editorBrowser';
import {ICommonCodeEditor, IModel, EditorType, IEditor as ICommonEditor} from 'vs/editor/common/editorCommon';
import {BaseEditor, IEditorRegistry, Extensions} from 'vs/workbench/browser/parts/editor/baseEditor';
import {EditorInput, EditorOptions, IFileEditorInput, TextEditorOptions} from 'vs/workbench/common/editor';
import {ResourceEditorInput} from 'vs/workbench/common/editor/resourceEditorInput';
import {UntitledEditorInput} from 'vs/workbench/common/editor/untitledEditorInput';
import {DiffEditorInput} from 'vs/workbench/common/editor/diffEditorInput';
import {IUntitledEditorService} from 'vs/workbench/services/untitled/common/untitledEditorService';
@ -288,6 +289,10 @@ export class WorkbenchEditorService implements IWorkbenchEditorService {
return this.createFileInput(resourceInput.resource, resourceInput.mime);
}
else if (URI.isURI(resourceInput.resource)) {
return TPromise.as(this.instantiationService.createInstance(ResourceEditorInput, resourceInput.resource.fsPath, undefined, resourceInput.resource));
}
return TPromise.as<EditorInput>(null);
}

View file

@ -10,7 +10,7 @@ import {setUnexpectedErrorHandler, errorHandler} from 'vs/base/common/errors';
import {create} from 'vs/base/common/types';
import URI from 'vs/base/common/uri';
import {TPromise} from 'vs/base/common/winjs.base';
import * as types from 'vs/workbench/api/common/extHostTypes';
import * as types from 'vs/workbench/api/node/extHostTypes';
import {Range as CodeEditorRange} from 'vs/editor/common/core/range';
import * as EditorCommon from 'vs/editor/common/editorCommon';
import {Model as EditorModel} from 'vs/editor/common/model/model';
@ -22,10 +22,10 @@ import {IThreadService} from 'vs/platform/thread/common/thread';
import {IKeybindingService} from 'vs/platform/keybinding/common/keybindingService';
import {KeybindingsRegistry} from 'vs/platform/keybinding/common/keybindingsRegistry';
import {IModelService} from 'vs/editor/common/services/modelService';
import {ExtHostLanguageFeatures, MainThreadLanguageFeatures} from 'vs/workbench/api/common/extHostLanguageFeatures';
import {registerApiCommands} from 'vs/workbench/api/common/extHostApiCommands';
import {ExtHostCommands, MainThreadCommands} from 'vs/workbench/api/common/extHostCommands';
import {ExtHostModelService} from 'vs/workbench/api/common/extHostDocuments';
import {ExtHostLanguageFeatures, MainThreadLanguageFeatures} from 'vs/workbench/api/node/extHostLanguageFeatures';
import {registerApiCommands} from 'vs/workbench/api/node/extHostApiCommands';
import {ExtHostCommands, MainThreadCommands} from 'vs/workbench/api/node/extHostCommands';
import {ExtHostModelService} from 'vs/workbench/api/node/extHostDocuments';
const defaultSelector = { scheme: 'far' };
const model: EditorCommon.IModel = new EditorModel(

View file

@ -7,30 +7,30 @@
import * as assert from 'assert';
import URI from 'vs/base/common/uri';
import {ExtHostDocument} from 'vs/workbench/api/common/extHostDocuments';
import {Position} from 'vs/workbench/api/common/extHostTypes';
import {ExtHostDocumentData} from 'vs/workbench/api/node/extHostDocuments';
import {Position} from 'vs/workbench/api/node/extHostTypes';
import {Range as CodeEditorRange} from 'vs/editor/common/core/range';
import * as EditorCommon from 'vs/editor/common/editorCommon';
suite("PluginHostDocument", () => {
let doc: ExtHostDocument;
let data: ExtHostDocumentData;
function assertPositionAt(offset: number, line: number, character: number) {
let position = doc.positionAt(offset);
let position = data.positionAt(offset);
assert.equal(position.line, line);
assert.equal(position.character, character);
}
function assertOffsetAt(line: number, character: number, offset: number) {
let pos = new Position(line, character);
let actual = doc.offsetAt(pos);
let actual = data.offsetAt(pos);
assert.equal(actual, offset);
}
setup(function() {
doc = new ExtHostDocument(undefined, URI.file(''), [
data = new ExtHostDocumentData(undefined, URI.file(''), [
'This is line one', //16
'and this is line number two', //27
'it is followed by #3', //20
@ -40,33 +40,33 @@ suite("PluginHostDocument", () => {
test('readonly-ness', function() {
assert.throws(() => doc.uri = null);
assert.throws(() => doc.fileName = 'foofile');
assert.throws(() => doc.isDirty = false);
assert.throws(() => doc.isUntitled = false);
assert.throws(() => doc.languageId = 'dddd');
assert.throws(() => doc.lineCount = 9);
assert.throws(() => data.document.uri = null);
assert.throws(() => data.document.fileName = 'foofile');
assert.throws(() => data.document.isDirty = false);
assert.throws(() => data.document.isUntitled = false);
assert.throws(() => data.document.languageId = 'dddd');
assert.throws(() => data.document.lineCount = 9);
})
test('lines', function() {
assert.equal(doc.lineCount, 4);
assert.throws(() => doc.lineCount = 9);
assert.equal(data.document.lineCount, 4);
assert.throws(() => data.document.lineCount = 9);
assert.throws(() => doc.lineAt(-1));
assert.throws(() => doc.lineAt(doc.lineCount));
assert.throws(() => doc.lineAt(Number.MAX_VALUE));
assert.throws(() => doc.lineAt(Number.MIN_VALUE));
assert.throws(() => doc.lineAt(0.8));
assert.throws(() => data.lineAt(-1));
assert.throws(() => data.lineAt(data.document.lineCount));
assert.throws(() => data.lineAt(Number.MAX_VALUE));
assert.throws(() => data.lineAt(Number.MIN_VALUE));
assert.throws(() => data.lineAt(0.8));
let line = doc.lineAt(0);
let line = data.lineAt(0);
assert.equal(line.lineNumber, 0);
assert.equal(line.text.length, 16);
assert.equal(line.text, 'This is line one');
assert.equal(line.isEmptyOrWhitespace, false);
assert.equal(line.firstNonWhitespaceCharacterIndex, 0);
doc._acceptEvents([{
data.onEvents([{
range: { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 },
text: '\t ',
isRedoing: undefined,
@ -80,7 +80,7 @@ suite("PluginHostDocument", () => {
assert.equal(line.firstNonWhitespaceCharacterIndex, 0);
// fetch line again
line = doc.lineAt(0);
line = data.lineAt(0);
assert.equal(line.text, '\t This is line one');
assert.equal(line.firstNonWhitespaceCharacterIndex, 2);
});
@ -102,7 +102,7 @@ suite("PluginHostDocument", () => {
test('offsetAt, after remove', function() {
doc._acceptEvents([{
data.onEvents([{
range: { startLineNumber: 1, startColumn: 3, endLineNumber: 1, endColumn: 6 },
text: '',
isRedoing: undefined,
@ -118,7 +118,7 @@ suite("PluginHostDocument", () => {
test('offsetAt, after replace', function() {
doc._acceptEvents([{
data.onEvents([{
range: { startLineNumber: 1, startColumn: 3, endLineNumber: 1, endColumn: 6 },
text: 'is could be',
isRedoing: undefined,
@ -134,7 +134,7 @@ suite("PluginHostDocument", () => {
test('offsetAt, after insert line', function() {
doc._acceptEvents([{
data.onEvents([{
range: { startLineNumber: 1, startColumn: 3, endLineNumber: 1, endColumn: 6 },
text: 'is could be\na line with number',
isRedoing: undefined,
@ -153,7 +153,7 @@ suite("PluginHostDocument", () => {
test('offsetAt, after remove line', function() {
doc._acceptEvents([{
data.onEvents([{
range: { startLineNumber: 1, startColumn: 3, endLineNumber: 2, endColumn: 6 },
text: '',
isRedoing: undefined,
@ -189,11 +189,11 @@ enum AssertDocumentLineMappingDirection {
suite("PluginHostDocument updates line mapping", () => {
function positionToStr(position:Position): string {
function positionToStr(position: { line: number; character: number;}): string {
return '(' + position.line + ',' + position.character + ')';
}
function assertDocumentLineMapping(doc:ExtHostDocument, direction:AssertDocumentLineMappingDirection): void {
function assertDocumentLineMapping(doc:ExtHostDocumentData, direction:AssertDocumentLineMappingDirection): void {
let allText = doc.getText();
let line = 0, character = 0, previousIsCarriageReturn = false;
@ -234,10 +234,10 @@ suite("PluginHostDocument updates line mapping", () => {
}
function testLineMappingDirectionAfterEvents(lines:string[], eol: string, direction:AssertDocumentLineMappingDirection, events:EditorCommon.IModelContentChangedEvent2[]): void {
let myDocument = new ExtHostDocument(undefined, URI.file(''), lines.slice(0), eol, 'text', 1, false);
let myDocument = new ExtHostDocumentData(undefined, URI.file(''), lines.slice(0), eol, 'text', 1, false);
assertDocumentLineMapping(myDocument, direction);
myDocument._acceptEvents(events);
myDocument.onEvents(events);
assertDocumentLineMapping(myDocument, direction);
}

View file

@ -9,7 +9,7 @@ import * as assert from 'assert';
import {setUnexpectedErrorHandler, errorHandler} from 'vs/base/common/errors';
import {create} from 'vs/base/common/types';
import URI from 'vs/base/common/uri';
import * as types from 'vs/workbench/api/common/extHostTypes';
import * as types from 'vs/workbench/api/node/extHostTypes';
import {Range as CodeEditorRange} from 'vs/editor/common/core/range';
import * as EditorCommon from 'vs/editor/common/editorCommon';
import {Model as EditorModel} from 'vs/editor/common/model/model';
@ -18,9 +18,9 @@ import {create as createInstantiationService} from 'vs/platform/instantiation/co
import {MarkerService} from 'vs/platform/markers/common/markerService';
import {IMarkerService} from 'vs/platform/markers/common/markers';
import {IThreadService} from 'vs/platform/thread/common/thread';
import {ExtHostLanguageFeatures, MainThreadLanguageFeatures} from 'vs/workbench/api/common/extHostLanguageFeatures';
import {ExtHostCommands, MainThreadCommands} from 'vs/workbench/api/common/extHostCommands';
import {ExtHostModelService} from 'vs/workbench/api/common/extHostDocuments';
import {ExtHostLanguageFeatures, MainThreadLanguageFeatures} from 'vs/workbench/api/node/extHostLanguageFeatures';
import {ExtHostCommands, MainThreadCommands} from 'vs/workbench/api/node/extHostCommands';
import {ExtHostModelService} from 'vs/workbench/api/node/extHostDocuments';
import {OutlineRegistry, getOutlineEntries} from 'vs/editor/contrib/quickOpen/common/quickOpen';
import {getCodeLensData} from 'vs/editor/contrib/codelens/common/codelens';
import {getDeclarationsAtPosition} from 'vs/editor/contrib/goToDeclaration/common/goToDeclaration';

View file

@ -7,7 +7,7 @@
import * as assert from 'assert';
import URI from 'vs/base/common/uri';
import * as types from 'vs/workbench/api/common/extHostTypes';
import * as types from 'vs/workbench/api/node/extHostTypes';
function assertToJSON(a: any, expected: any) {
const raw = JSON.stringify(a);