提交 f365b61c 编写于 作者: D Dirk Baeumer

Multiplex between JavaScript and TypeScript

上级 d253e034
......@@ -75,6 +75,11 @@
"type": ["string", "null"],
"default": null,
"description": "%typescript.tsdk.desc%"
},
"javascript.validate.enable": {
"type": "boolean",
"default": true,
"description": "%javascript.validate.enable%"
}
}
},
......
......@@ -3,5 +3,6 @@
"javascript.reloadProjects.title": "Reload JavaScript Project",
"configuration.typescript": "TypeScript configuration",
"typescript.useCodeSnippetsOnMethodSuggest.dec": "Complete functions with their parameter signature.",
"typescript.tsdk.desc": "Specifies the folder path containing the tsserver and lib*.d.ts files to use."
"typescript.tsdk.desc": "Specifies the folder path containing the tsserver and lib*.d.ts files to use.",
"javascript.validate.enable": "Enable / disable JavaScript validation"
}
\ No newline at end of file
......@@ -71,16 +71,17 @@ export default class BufferSyncSupport {
private client: ITypescriptServiceClient;
private modeId: string;
private modeIds: Map<boolean>;
private disposables: Disposable[] = [];
private syncedBuffers: { [key: string]: SyncedBuffer };
private pendingDiagnostics: { [key: string]: number; };
private diagnosticDelayer: Delayer<any>;
constructor(client: ITypescriptServiceClient, modeId: string) {
constructor(client: ITypescriptServiceClient, modeIds: string[]) {
this.client = client;
this.modeId = modeId;
this.modeIds = Object.create(null);
modeIds.forEach(modeId => this.modeIds[modeId] = true);
this.pendingDiagnostics = Object.create(null);
this.diagnosticDelayer = new Delayer<any>(100);
......@@ -92,6 +93,10 @@ export default class BufferSyncSupport {
workspace.textDocuments.forEach(this.onDidAddDocument, this);
}
public handles(file: string): boolean {
return !!this.syncedBuffers[file];
}
public reOpenDocuments(): void {
Object.keys(this.syncedBuffers).forEach(key => {
this.syncedBuffers[key].open();
......@@ -105,7 +110,7 @@ export default class BufferSyncSupport {
}
private onDidAddDocument(document: TextDocument): void {
if (document.languageId !== this.modeId) {
if (!this.modeIds[document.languageId]) {
return;
}
if (document.isUntitled) {
......
......@@ -33,6 +33,11 @@ import * as VersionStatus from './utils/versionStatus';
import * as nls from 'vscode-nls';
interface LanguageDescription {
id: string;
modeIds: string[];
}
export function activate(context: ExtensionContext): void {
nls.config({locale: env.language});
......@@ -41,7 +46,17 @@ export function activate(context: ExtensionContext): void {
let MODE_ID_JS = 'javascript';
let MODE_ID_JSX = 'javascriptreact';
let clientHost = new TypeScriptServiceClientHost();
let clientHost = new TypeScriptServiceClientHost([
{
id: 'typescript',
modeIds: [MODE_ID_TS, MODE_ID_TSX]
},
{
id: 'javascript',
modeIds: [MODE_ID_JS, MODE_ID_JSX]
}
]);
let client = clientHost.serviceClient;
context.subscriptions.push(commands.registerCommand('typescript.reloadProjects', () => {
......@@ -135,8 +150,6 @@ function registerSupports(modeID: string, host: TypeScriptServiceClientHost, cli
}
});
host.addBufferSyncSupport(new BufferSyncSupport(client, modeID));
// Register suggest support as soon as possible and load configuration lazily
let completionItemProvider = new CompletionItemProvider(client);
languages.registerCompletionItemProvider(modeID, completionItemProvider, '.');
......@@ -149,16 +162,76 @@ function registerSupports(modeID: string, host: TypeScriptServiceClientHost, cli
reloadConfig();
}
class TypeScriptServiceClientHost implements ITypescriptServiceClientHost {
private client: TypeScriptServiceClient;
class LanguageManager {
private syntaxDiagnostics: { [key: string]: Diagnostic[] };
private description: LanguageDescription;
private syntaxDiagnostics: Map<Diagnostic[]>;
private currentDiagnostics: DiagnosticCollection;
private bufferSyncSupports: BufferSyncSupport[];
private bufferSyncSupport: BufferSyncSupport;
private _validate: boolean;
constructor(client: TypeScriptServiceClient, description: LanguageDescription, validate: boolean = true) {
this.description = description;
this.bufferSyncSupport = new BufferSyncSupport(client, description.modeIds);
this.syntaxDiagnostics = Object.create(null);
this.currentDiagnostics = languages.createDiagnosticCollection(description.id);
this._validate = validate;
}
public handles(file: string): boolean {
return this.bufferSyncSupport.handles(file);
}
public get validate(): boolean {
return this._validate;
}
public set validate(value: boolean) {
this._validate = value;
if (value) {
this.triggerAllDiagnostics();
} else {
this.syntaxDiagnostics = Object.create(null);
this.currentDiagnostics.clear();
}
}
public reInitialize(): void {
this.currentDiagnostics.clear();
this.syntaxDiagnostics = Object.create(null);
this.bufferSyncSupport.reOpenDocuments();
this.bufferSyncSupport.requestAllDiagnostics();
}
public triggerAllDiagnostics(): void {
if (!this._validate) {
return;
}
this.bufferSyncSupport.requestAllDiagnostics();
}
public syntaxDiagnosticsReceived(file: string, diagnostics: Diagnostic[]): void {
this.syntaxDiagnostics[file] = diagnostics;
}
public semanticDiagnosticsReceived(file: string, diagnostics: Diagnostic[]): void {
let syntaxMarkers = this.syntaxDiagnostics[file];
if (syntaxMarkers) {
delete this.syntaxDiagnostics[file];
diagnostics = syntaxMarkers.concat(diagnostics);
}
this.currentDiagnostics.set(Uri.file(file), diagnostics);
}
}
class TypeScriptServiceClientHost implements ITypescriptServiceClientHost {
private client: TypeScriptServiceClient;
private languages: LanguageManager[];
private languagePerId: Map<LanguageManager>;
constructor() {
this.bufferSyncSupports = [];
this.currentDiagnostics = languages.createDiagnosticCollection('typescript');
constructor(descriptions: LanguageDescription[]) {
let handleProjectCreateOrDelete = () => {
this.client.execute('reloadProjects', null, false);
this.triggerAllDiagnostics();
......@@ -174,7 +247,13 @@ class TypeScriptServiceClientHost implements ITypescriptServiceClientHost {
watcher.onDidChange(handleProjectChange);
this.client = new TypeScriptServiceClient(this);
this.syntaxDiagnostics = Object.create(null);
this.languages = [];
this.languagePerId = Object.create(null);
descriptions.forEach(description => {
let manager = new LanguageManager(this.client, description);
this.languages.push(manager);
this.languagePerId[description.id] = manager;
});
}
public get serviceClient(): TypeScriptServiceClient {
......@@ -186,51 +265,51 @@ class TypeScriptServiceClientHost implements ITypescriptServiceClientHost {
this.triggerAllDiagnostics();
}
public addBufferSyncSupport(support: BufferSyncSupport): void {
this.bufferSyncSupports.push(support);
private findLanguage(file: string): LanguageManager {
for (let i = 0; i < this.languages.length; i++) {
let language = this.languages[i];
if (language.handles(file)) {
return language;
}
}
return null;
}
private triggerAllDiagnostics() {
this.bufferSyncSupports.forEach(support => support.requestAllDiagnostics());
Object.keys(this.languagePerId).forEach(key => this.languagePerId[key].triggerAllDiagnostics());
}
/* internal */ populateService(): void {
this.currentDiagnostics.clear();
this.syntaxDiagnostics = Object.create(null);
// See https://github.com/Microsoft/TypeScript/issues/5530
workspace.saveAll(false).then((value) => {
this.bufferSyncSupports.forEach(support => {
support.reOpenDocuments();
support.requestAllDiagnostics();
});
Object.keys(this.languagePerId).forEach(key => this.languagePerId[key].reInitialize());
});
}
/* internal */ syntaxDiagnosticsReceived(event: Proto.DiagnosticEvent): void {
let body = event.body;
if (body.diagnostics) {
let markers = this.createMarkerDatas(body.diagnostics);
this.syntaxDiagnostics[body.file] = markers;
let language = this.findLanguage(body.file);
if (language) {
language.syntaxDiagnosticsReceived(body.file, this.createMarkerDatas(body.diagnostics));
}
}
}
/* internal */ semanticDiagnosticsReceived(event: Proto.DiagnosticEvent): void {
let body = event.body;
if (body.diagnostics) {
let diagnostics = this.createMarkerDatas(body.diagnostics);
let syntaxMarkers = this.syntaxDiagnostics[body.file];
if (syntaxMarkers) {
delete this.syntaxDiagnostics[body.file];
diagnostics = syntaxMarkers.concat(diagnostics);
let language = this.findLanguage(body.file);
if (language) {
language.semanticDiagnosticsReceived(body.file, this.createMarkerDatas(body.diagnostics));
}
this.currentDiagnostics.set(Uri.file(body.file), diagnostics);
}
}
private createMarkerDatas(diagnostics: Proto.Diagnostic[]): Diagnostic[] {
let result: Diagnostic[] = [];
for (let diagnostic of diagnostics) {
let {start, end, text} = diagnostic;
let { start, end, text } = diagnostic;
let range = new Range(start.line - 1, start.offset - 1, end.line - 1, end.offset - 1);
result.push(new Diagnostic(range, text));
}
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
interface Map<V> {
[key: string]: V;
}
\ No newline at end of file
......@@ -3,10 +3,11 @@
"noLib": true,
"target": "es5",
"module": "commonjs",
"sourceMap": false,
"sourceMap": true,
"outDir": "../out"
},
"exclude": [
"node_modules"
"node_modules",
"server"
]
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册