TypeScript/src/services/shims.ts

911 lines
38 KiB
TypeScript
Raw Normal View History

2014-07-19 01:55:11 +02:00
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
2014-07-13 01:04:16 +02:00
2014-07-25 00:33:59 +02:00
/// <reference path='services.ts' />
/// <reference path='compiler\pathUtils.ts' />
/// <reference path='compiler\precompile.ts' />
2014-07-24 23:36:23 +02:00
var debugObjectHost = (<any>this);
2014-07-19 01:55:11 +02:00
module TypeScript.Services {
export interface ScriptSnapshotShim {
2014-07-13 01:04:16 +02:00
// Get's a portion of the script snapshot specified by [start, end).
getText(start: number, end: number): string;
// Get's the length of this script snapshot.
getLength(): number;
// This call returns the JSON encoded array of the type:
// number[]
getLineStartPositions(): string;
// Returns a JSON encoded value of the type:
// { span: { start: number; length: number }; newLength: number }
//
// Or null value if there was no change.
2014-07-19 01:55:11 +02:00
getTextChangeRangeSinceVersion(scriptVersion: number): string;
}
//
// Public interface of the host of a language service shim instance.
//
2014-07-25 01:01:51 +02:00
export interface LanguageServiceShimHost extends Logger {
2014-07-19 01:55:11 +02:00
getCompilationSettings(): string;
// Returns a JSON encoded value of the type:
// string[]
getScriptFileNames(): string;
getScriptVersion(fileName: string): number;
getScriptIsOpen(fileName: string): boolean;
getScriptByteOrderMark(fileName: string): number;
getScriptSnapshot(fileName: string): ScriptSnapshotShim;
2014-07-19 01:55:11 +02:00
resolveRelativePath(path: string, directory: string): string;
fileExists(path: string): boolean;
directoryExists(path: string): boolean;
getParentDirectory(path: string): string;
getLocalizedDiagnosticMessages(): string;
getCancellationToken(): ts.CancellationToken;
2014-07-19 01:55:11 +02:00
}
//
// Public interface of of a language service instance shim.
//
export interface ShimFactory {
registerShim(shim: Shim): void;
unregisterShim(shim: Shim): void;
2014-07-19 01:55:11 +02:00
}
export interface Shim {
2014-07-19 01:55:11 +02:00
dispose(dummy: any): void;
}
export interface LanguageServiceShim extends Shim {
2014-07-24 20:57:18 +02:00
languageService: LanguageService;
2014-07-19 01:55:11 +02:00
dispose(dummy: any): void;
refresh(throwOnError: boolean): void;
cleanupSemanticCache(): void;
getSyntacticDiagnostics(fileName: string): string;
getSemanticDiagnostics(fileName: string): string;
getCompilerOptionsDiagnostics(): string;
getCompletionsAtPosition(fileName: string, position: number, isMemberCompletion: boolean): string;
getCompletionEntryDetails(fileName: string, position: number, entryName: string): string;
getTypeAtPosition(fileName: string, position: number): string;
getNameOrDottedNameSpan(fileName: string, startPos: number, endPos: number): string;
getBreakpointStatementAtPosition(fileName: string, position: number): string;
getSignatureAtPosition(fileName: string, position: number): string;
// Returns a JSON encoded value of the type:
// { fileName: string; minChar: number; limChar: number; kind: string; name: string; containerKind: string; containerName: string }
//
// Or null value if no definition can be found.
getDefinitionAtPosition(fileName: string, position: number): string;
// Returns a JSON encoded value of the type:
// { fileName: string; minChar: number; limChar: number; isWriteAccess: boolean }[]
getReferencesAtPosition(fileName: string, position: number): string;
// Returns a JSON encoded value of the type:
// { fileName: string; minChar: number; limChar: number; isWriteAccess: boolean }[]
getOccurrencesAtPosition(fileName: string, position: number): string;
// Returns a JSON encoded value of the type:
// { fileName: string; minChar: number; limChar: number; isWriteAccess: boolean }[]
getImplementorsAtPosition(fileName: string, position: number): string;
// Returns a JSON encoded value of the type:
// { name: string; kind: string; kindModifiers: string; containerName: string; containerKind: string; matchKind: string; fileName: string; minChar: number; limChar: number; } [] = [];
getNavigateToItems(searchValue: string): string;
// Returns a JSON encoded value of the type:
// { name: string; kind: string; kindModifiers: string; containerName: string; containerKind: string; matchKind: string; fileName: string; minChar: number; limChar: number; } [] = [];
getScriptLexicalStructure(fileName: string): string;
// Returns a JSON encoded value of the type:
// { name: string; kind: string; kindModifiers: string; containerName: string; containerKind: string; matchKind: string; fileName: string; minChar: number; limChar: number; } [] = [];
getOutliningRegions(fileName: string): string;
getBraceMatchingAtPosition(fileName: string, position: number): string;
getIndentationAtPosition(fileName: string, position: number, options: string/*Services.EditorOptions*/): string;
getFormattingEditsForRange(fileName: string, minChar: number, limChar: number, options: string/*Services.FormatCodeOptions*/): string;
getFormattingEditsForDocument(fileName: string, minChar: number, limChar: number, options: string/*Services.FormatCodeOptions*/): string;
getFormattingEditsOnPaste(fileName: string, minChar: number, limChar: number, options: string/*Services.FormatCodeOptions*/): string;
getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: string/*Services.FormatCodeOptions*/): string;
getEmitOutput(fileName: string): string;
2014-07-13 01:04:16 +02:00
}
export interface ClassifierShim extends Shim {
2014-07-24 20:57:18 +02:00
getClassificationsForLine(text: string, lexState: EndOfLineState): string;
}
2014-07-19 01:55:11 +02:00
export interface CoreServicesShim extends Shim {
2014-07-24 20:57:18 +02:00
getPreProcessedFileInfo(fileName: string, sourceText: TypeScript.IScriptSnapshot): string;
getDefaultCompilationSettings(): string;
}
/// TODO: delete this, it is only needed untill the VS interface is updated
2014-07-19 01:55:11 +02:00
enum LanguageVersion {
EcmaScript3 = 0,
EcmaScript5 = 1,
}
enum ModuleGenTarget {
Unspecified = 0,
Synchronous = 1,
Asynchronous = 2,
}
interface CompilationSettings {
propagateEnumConstants?: boolean;
removeComments?: boolean;
watch?: boolean;
noResolve?: boolean;
allowAutomaticSemicolonInsertion?: boolean;
noImplicitAny?: boolean;
noLib?: boolean;
codeGenTarget?: LanguageVersion;
moduleGenTarget?: ModuleGenTarget;
outFileOption?: string;
outDirOption?: string;
mapSourceFiles?: boolean;
mapRoot?: string;
sourceRoot?: string;
generateDeclarationFiles?: boolean;
useCaseSensitiveFileResolution?: boolean;
gatherDiagnostics?: boolean;
codepage?: number;
}
function languageVersionToScriptTarget(languageVersion: LanguageVersion): ts.ScriptTarget {
switch (languageVersion) {
case LanguageVersion.EcmaScript3: return ts.ScriptTarget.ES3;
case LanguageVersion.EcmaScript5: return ts.ScriptTarget.ES5;
default: throw Error("unsuported LanguageVersion value: " + languageVersion);
}
}
function moduleGenTargetToModuleKind(moduleGenTarget: ModuleGenTarget): ts.ModuleKind {
switch (moduleGenTarget) {
case ModuleGenTarget.Asynchronous: return ts.ModuleKind.AMD;
case ModuleGenTarget.Synchronous: return ts.ModuleKind.CommonJS;
case ModuleGenTarget.Unspecified: return ts.ModuleKind.None;
default: throw Error("unsuported ModuleGenTarget value: " + moduleGenTarget);
}
}
function scriptTargetTolanguageVersion(scriptTarget: ts.ScriptTarget): LanguageVersion {
switch (scriptTarget) {
case ts.ScriptTarget.ES3: return LanguageVersion.EcmaScript3;
case ts.ScriptTarget.ES5: return LanguageVersion.EcmaScript5;
default: throw Error("unsuported ScriptTarget value: " + scriptTarget);
}
}
function moduleKindToModuleGenTarget(moduleKind: ts.ModuleKind): ModuleGenTarget {
switch (moduleKind) {
case ts.ModuleKind.AMD: return ModuleGenTarget.Asynchronous;
case ts.ModuleKind.CommonJS: return ModuleGenTarget.Synchronous;
case ts.ModuleKind.None: return ModuleGenTarget.Unspecified;
default: throw Error("unsuported ModuleKind value: " + moduleKind);
}
}
function compilationSettingsToCompilerOptions(settings: CompilationSettings): ts.CompilerOptions {
// TODO: we should not be converting, but use options all the way
var options: ts.CompilerOptions = {};
//options.propagateEnumConstants = settings.propagateEnumConstants;
options.removeComments = settings.removeComments;
options.noResolve = settings.noResolve;
options.noImplicitAny = settings.noImplicitAny;
options.noLib = settings.noLib;
options.target = languageVersionToScriptTarget(settings.codeGenTarget);
options.module = moduleGenTargetToModuleKind(settings.moduleGenTarget);
options.out = settings.outFileOption;
options.outDir = settings.outDirOption;
options.sourceMap = settings.mapSourceFiles;
options.mapRoot = settings.mapRoot;
options.sourceRoot = settings.sourceRoot;
options.declaration = settings.generateDeclarationFiles;
//options.useCaseSensitiveFileResolution = settings.useCaseSensitiveFileResolution;
options.codepage = settings.codepage;
return options;
}
function compilerOptionsToCompilationSettings(options: ts.CompilerOptions): CompilationSettings {
var settings: CompilationSettings = {};
//options.propagateEnumConstants = settings.propagateEnumConstants;
settings.removeComments = options.removeComments;
settings.noResolve = options.noResolve;
settings.noImplicitAny = options.noImplicitAny;
settings.noLib = options.noLib;
settings.codeGenTarget = scriptTargetTolanguageVersion(options.target);
settings.moduleGenTarget = moduleKindToModuleGenTarget(options.module);
settings.outFileOption = options.out;
settings.outDirOption = options.outDir;
settings.mapSourceFiles = options.sourceMap;
settings.mapRoot = options.mapRoot;
settings.sourceRoot = options.sourceRoot;
settings.generateDeclarationFiles = options.declaration;
// settings.useCaseSensitiveFileResolution = options.useCaseSensitiveFileResolution;
settings.codepage = options.codepage;
return settings;
}
2014-07-25 01:01:51 +02:00
function logInternalError(logger: Logger, err: Error) {
logger.log("*INTERNAL ERROR* - Exception in typescript services: " + err.message);
}
2014-07-19 01:55:11 +02:00
class ScriptSnapshotShimAdapter implements TypeScript.IScriptSnapshot {
2014-07-13 01:04:16 +02:00
private lineStartPositions: number[] = null;
constructor(private scriptSnapshotShim: ScriptSnapshotShim) {
2014-07-13 01:04:16 +02:00
}
public getText(start: number, end: number): string {
return this.scriptSnapshotShim.getText(start, end);
}
public getLength(): number {
return this.scriptSnapshotShim.getLength();
}
public getLineStartPositions(): number[] {
2014-07-13 01:04:16 +02:00
if (this.lineStartPositions == null) {
this.lineStartPositions = JSON.parse(this.scriptSnapshotShim.getLineStartPositions());
}
return this.lineStartPositions;
}
2014-07-19 01:55:11 +02:00
public getTextChangeRangeSinceVersion(scriptVersion: number): TypeScript.TextChangeRange {
var encoded = this.scriptSnapshotShim.getTextChangeRangeSinceVersion(scriptVersion);
2014-07-13 01:04:16 +02:00
if (encoded == null) {
return null;
}
var decoded: { span: { start: number; length: number; }; newLength: number; } = JSON.parse(encoded);
2014-07-19 01:55:11 +02:00
return new TypeScript.TextChangeRange(
new TypeScript.TextSpan(decoded.span.start, decoded.span.length), decoded.newLength);
2014-07-13 01:04:16 +02:00
}
}
2014-07-24 20:57:18 +02:00
class LanguageServiceShimHostAdapter implements LanguageServiceHost {
constructor(private shimHost: LanguageServiceShimHost) {
2014-07-19 01:55:11 +02:00
}
public information(): boolean {
return this.shimHost.information();
}
public debug(): boolean {
return this.shimHost.debug();
}
public warning(): boolean {
return this.shimHost.warning();
}
public error(): boolean {
return this.shimHost.error();
}
public fatal(): boolean {
return this.shimHost.fatal();
2014-07-13 01:04:16 +02:00
}
public log(s: string): void {
this.shimHost.log(s);
}
2014-07-19 01:55:11 +02:00
public getCompilationSettings(): ts.CompilerOptions {
2014-07-13 01:04:16 +02:00
var settingsJson = this.shimHost.getCompilationSettings();
if (settingsJson == null || settingsJson == "") {
2014-07-19 01:55:11 +02:00
throw Error("LanguageServiceShimHostAdapter.getCompilationSettings: empty compilationSettings");
return null;
2014-07-13 01:04:16 +02:00
}
2014-07-19 20:30:10 +02:00
var options = compilationSettingsToCompilerOptions(<ts.CompilerOptions>JSON.parse(<any>settingsJson));
/// TODO: this should be pushed into VS.
/// We can not ask the LS instance to resolve, as this will lead to asking the host about files it does not know about,
/// something it is not desinged to handle. for now make sure we never get a noresolve=true.
/// This value should not matter, as the host runs resolution logic independentlly
options.noResolve = true;
return options;
2014-07-13 01:04:16 +02:00
}
public getScriptFileNames(): string[] {
var encoded = this.shimHost.getScriptFileNames();
return JSON.parse(encoded);
}
2014-07-19 01:55:11 +02:00
public getScriptSnapshot(fileName: string): TypeScript.IScriptSnapshot {
2014-07-13 01:04:16 +02:00
return new ScriptSnapshotShimAdapter(this.shimHost.getScriptSnapshot(fileName));
}
2014-07-19 01:55:11 +02:00
public getScriptVersion(fileName: string): number {
2014-07-13 01:04:16 +02:00
return this.shimHost.getScriptVersion(fileName);
}
public getScriptIsOpen(fileName: string): boolean {
return this.shimHost.getScriptIsOpen(fileName);
}
public getScriptByteOrderMark(fileName: string): ts.ByteOrderMark {
2014-07-13 01:04:16 +02:00
return this.shimHost.getScriptByteOrderMark(fileName);
}
public getLocalizedDiagnosticMessages(): any {
var diagnosticMessagesJson = this.shimHost.getLocalizedDiagnosticMessages();
if (diagnosticMessagesJson == null || diagnosticMessagesJson == "") {
return null;
}
try {
return JSON.parse(diagnosticMessagesJson);
}
catch (e) {
this.log(e.description || "diagnosticMessages.generated.json has invalid JSON format");
return null;
}
}
public getCancellationToken(): ts.CancellationToken {
2014-07-19 01:55:11 +02:00
return this.shimHost.getCancellationToken();
}
// IReferenceResolverHost methods
public resolveRelativePath(path: string, directory: string): string {
return this.shimHost.resolveRelativePath(path, directory);
}
public fileExists(path: string): boolean {
return this.shimHost.fileExists(path);
}
public directoryExists(path: string): boolean {
return this.shimHost.directoryExists(path);
}
public getParentDirectory(path: string): string {
return this.shimHost.getParentDirectory(path);
}
}
2014-07-25 01:01:51 +02:00
function simpleForwardCall(logger: Logger, actionDescription: string, action: () => any): any {
2014-07-19 01:55:11 +02:00
logger.log(actionDescription);
var start = Date.now();
var result = action();
var end = Date.now();
logger.log(actionDescription + " completed in " + (end - start) + " msec");
if (typeof (result) === "string") {
var str = <string>result;
if (str.length > 128) {
str = str.substring(0, 128) + "...";
}
logger.log(" result.length=" + str.length + ", result='" + JSON.stringify(str) + "'");
}
return result;
}
2014-07-25 01:01:51 +02:00
function forwardJSONCall(logger: Logger, actionDescription: string, action: () => any): string {
2014-07-19 01:55:11 +02:00
try {
var result = simpleForwardCall(logger, actionDescription, action);
return JSON.stringify({ result: result });
}
catch (err) {
if (err instanceof OperationCanceledException) {
return JSON.stringify({ canceled: true });
}
2014-07-24 20:57:18 +02:00
logInternalError(logger, err);
2014-07-19 01:55:11 +02:00
err.description = actionDescription;
return JSON.stringify({ error: err });
}
}
class ShimBase implements Shim {
constructor(private factory: ShimFactory) {
2014-07-24 20:57:18 +02:00
factory.registerShim(this);
}
public dispose(dummy: any): void {
this.factory.unregisterShim(this);
}
}
class LanguageServiceShimObject extends ShimBase implements LanguageServiceShim {
2014-07-25 01:01:51 +02:00
private logger: Logger;
2014-07-19 01:55:11 +02:00
constructor(factory: ShimFactory,
private host: LanguageServiceShimHost,
2014-07-24 20:57:18 +02:00
public languageService: LanguageService) {
2014-07-19 01:55:11 +02:00
super(factory);
this.logger = this.host;
}
public forwardJSONCall(actionDescription: string, action: () => any): string {
2014-07-24 20:57:18 +02:00
return forwardJSONCall(this.logger, actionDescription, action);
2014-07-19 01:55:11 +02:00
}
// DISPOSE
// Ensure (almost) determinstic release of internal Javascript resources when
// some external native objects holds onto us (e.g. Com/Interop).
public dispose(dummy: any): void {
this.logger.log("dispose()");
this.languageService.dispose();
this.languageService = null;
// force a GC
if (debugObjectHost && debugObjectHost.CollectGarbage) {
debugObjectHost.CollectGarbage();
this.logger.log("CollectGarbage()");
}
this.logger = null;
super.dispose(dummy);
}
// REFRESH
// Update the list of scripts known to the compiler
public refresh(throwOnError: boolean): void {
this.forwardJSONCall(
"refresh(" + throwOnError + ")",
() => {
this.languageService.refresh();
return <any>null;
});
}
public cleanupSemanticCache(): void {
this.forwardJSONCall(
"cleanupSemanticCache()",
() => {
this.languageService.cleanupSemanticCache();
return <any>null;
});
}
/// SQUIGGLES
///
private static realizeDiagnostic(diagnostic: ts.Diagnostic): { message: string; start: number; length: number; category: string; } {
return {
message: diagnostic.messageText,
start: diagnostic.start,
length: diagnostic.length,
/// TODO: no need for the tolowerCase call
category: ts.DiagnosticCategory[diagnostic.category].toLowerCase()
};
}
private realizeDiagnosticWithFileName(diagnostic: ts.Diagnostic): { fileName: string; message: string; start: number; length: number; category: string; } {
return {
fileName: diagnostic.file.filename,
2014-07-19 01:55:11 +02:00
message: diagnostic.messageText,
start: diagnostic.start,
length: diagnostic.length,
/// TODO: no need for the tolowerCase call
category: ts.DiagnosticCategory[diagnostic.category].toLowerCase()
};
}
2014-07-13 01:04:16 +02:00
2014-07-19 01:55:11 +02:00
public getSyntacticDiagnostics(fileName: string): string {
return this.forwardJSONCall(
"getSyntacticDiagnostics(\"" + fileName + "\")",
() => {
var errors = this.languageService.getSyntacticDiagnostics(fileName);
return errors.map(LanguageServiceShimObject.realizeDiagnostic);
2014-07-19 01:55:11 +02:00
});
}
public getSemanticDiagnostics(fileName: string): string {
return this.forwardJSONCall(
"getSemanticDiagnostics(\"" + fileName + "\")",
() => {
var errors = this.languageService.getSemanticDiagnostics(fileName);
return errors.map(LanguageServiceShimObject.realizeDiagnostic);
2014-07-19 01:55:11 +02:00
});
}
public getCompilerOptionsDiagnostics(): string {
return this.forwardJSONCall(
"getCompilerOptionsDiagnostics()",
() => {
var errors = this.languageService.getCompilerOptionsDiagnostics();
return errors.map(d => this.realizeDiagnosticWithFileName(d))
});
}
/// QUICKINFO
/// Computes a string representation of the type at the requested position
/// in the active file.
public getTypeAtPosition(fileName: string, position: number): string {
return this.forwardJSONCall(
"getTypeAtPosition(\"" + fileName + "\", " + position + ")",
() => {
var typeInfo = this.languageService.getTypeAtPosition(fileName, position);
return typeInfo;
});
}
/// NAMEORDOTTEDNAMESPAN
/// Computes span information of the name or dotted name at the requested position
// in the active file.
public getNameOrDottedNameSpan(fileName: string, startPos: number, endPos: number): string {
return this.forwardJSONCall(
"getNameOrDottedNameSpan(\"" + fileName + "\", " + startPos + ", " + endPos + ")",
2014-07-19 01:55:11 +02:00
() => {
var spanInfo = this.languageService.getNameOrDottedNameSpan(fileName, startPos, endPos);
return spanInfo;
});
}
/// STATEMENTSPAN
/// Computes span information of statement at the requested position in the active file.
public getBreakpointStatementAtPosition(fileName: string, position: number): string {
return this.forwardJSONCall(
"getBreakpointStatementAtPosition(\"" + fileName + "\", " + position + ")",
() => {
var spanInfo = this.languageService.getBreakpointStatementAtPosition(fileName, position);
return spanInfo;
});
}
/// SIGNATUREHELP
/// Computes a string representation of the signatures at the requested position
/// in the active file.
public getSignatureAtPosition(fileName: string, position: number): string {
return this.forwardJSONCall(
"getSignatureAtPosition(\"" + fileName + "\", " + position + ")",
() => {
var signatureInfo = this.languageService.getSignatureAtPosition(fileName, position);
return signatureInfo;
});
}
/// GOTO DEFINITION
/// Computes the definition location and file for the symbol
/// at the requested position.
public getDefinitionAtPosition(fileName: string, position: number): string {
return this.forwardJSONCall(
"getDefinitionAtPosition(\"" + fileName + "\", " + position + ")",
() => {
return this.languageService.getDefinitionAtPosition(fileName, position);
});
}
/// GET BRACE MATCHING
public getBraceMatchingAtPosition(fileName: string, position: number): string {
return this.forwardJSONCall(
"getBraceMatchingAtPosition(\"" + fileName + "\", " + position + ")",
() => {
var textRanges = this.languageService.getBraceMatchingAtPosition(fileName, position);
return textRanges;
});
}
/// GET SMART INDENT
public getIndentationAtPosition(fileName: string, position: number, options: string /*Services.EditorOptions*/): string {
return this.forwardJSONCall(
"getIndentationAtPosition(\"" + fileName + "\", " + position + ")",
() => {
2014-07-24 20:57:18 +02:00
var localOptions: EditorOptions = JSON.parse(options);
2014-07-19 01:55:11 +02:00
var columnOffset = this.languageService.getIndentationAtPosition(fileName, position, localOptions);
return { value: columnOffset };
});
}
/// GET REFERENCES
/// Return references to a symbol at the requested position.
/// References are separated by "\n".
/// Each reference is a "fileindex min lim" sub-string.
public getReferencesAtPosition(fileName: string, position: number): string {
return this.forwardJSONCall(
"getReferencesAtPosition(\"" + fileName + "\", " + position + ")",
() => {
return this.languageService.getReferencesAtPosition(fileName, position);
});
}
2014-07-13 01:04:16 +02:00
2014-07-19 01:55:11 +02:00
public getOccurrencesAtPosition(fileName: string, position: number): string {
return this.forwardJSONCall(
"getOccurrencesAtPosition(\"" + fileName + "\", " + position + ")",
() => {
return this.languageService.getOccurrencesAtPosition(fileName, position);
});
}
/// GET IMPLEMENTORS
public getImplementorsAtPosition(fileName: string, position: number): string {
return this.forwardJSONCall(
"getImplementorsAtPosition(\"" + fileName + "\", " + position + ")",
() => {
return this.languageService.getImplementorsAtPosition(fileName, position);
});
}
/// COMPLETION LISTS
/// Get a string based representation of the completions
/// to provide at the given source position and providing a member completion
/// list if requested.
public getCompletionsAtPosition(fileName: string, position: number, isMemberCompletion: boolean) {
return this.forwardJSONCall(
"getCompletionsAtPosition(\"" + fileName + "\", " + position + ", " + isMemberCompletion + ")",
() => {
var completion = this.languageService.getCompletionsAtPosition(fileName, position, isMemberCompletion);
return completion;
});
}
/// Get a string based representation of a completion list entry details
public getCompletionEntryDetails(fileName: string, position: number, entryName: string) {
return this.forwardJSONCall(
"getCompletionEntryDetails(\"" + fileName + "\", " + position + ", " + entryName + ")",
() => {
var details = this.languageService.getCompletionEntryDetails(fileName, position, entryName);
return details;
});
}
/// FORMAT SELECTION
public getFormattingEditsForRange(fileName: string, minChar: number, limChar: number, options: string/*Services.FormatCodeOptions*/): string {
return this.forwardJSONCall(
"getFormattingEditsForRange(\"" + fileName + "\", " + minChar + ", " + limChar + ")",
() => {
2014-07-24 20:57:18 +02:00
var localOptions: FormatCodeOptions = JSON.parse(options);
2014-07-19 01:55:11 +02:00
var edits = this.languageService.getFormattingEditsForRange(fileName, minChar, limChar, localOptions);
return edits;
});
}
/// FORMAT DOCUMENT
public getFormattingEditsForDocument(fileName: string, minChar: number, limChar: number, options: string/*Services.FormatCodeOptions*/): string {
return this.forwardJSONCall(
"getFormattingEditsForDocument(\"" + fileName + "\", " + minChar + ", " + limChar + ")",
() => {
2014-07-24 20:57:18 +02:00
var localOptions: FormatCodeOptions = JSON.parse(options);
2014-07-19 01:55:11 +02:00
var edits = this.languageService.getFormattingEditsForDocument(fileName, minChar, limChar, localOptions);
return edits;
});
}
/// FORMAT ON PASTE
public getFormattingEditsOnPaste(fileName: string, minChar: number, limChar: number, options: string/*Services.FormatCodeOptions*/): string {
return this.forwardJSONCall(
"getFormattingEditsOnPaste(\"" + fileName + "\", " + minChar + ", " + limChar + ")",
() => {
2014-07-24 20:57:18 +02:00
var localOptions: FormatCodeOptions = JSON.parse(options);
2014-07-19 01:55:11 +02:00
var edits = this.languageService.getFormattingEditsOnPaste(fileName, minChar, limChar, localOptions);
return edits;
});
}
/// FORMAT
public getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: string/*Services.FormatCodeOptions*/): string {
return this.forwardJSONCall(
"getFormattingEditsAfterKeystroke(\"" + fileName + "\", " + position + ", \"" + key + "\")",
() => {
2014-07-24 20:57:18 +02:00
var localOptions: FormatCodeOptions = JSON.parse(options);
2014-07-19 01:55:11 +02:00
var edits = this.languageService.getFormattingEditsAfterKeystroke(fileName, position, key, localOptions);
return edits;
});
}
/// NAVIGATE TO
/// Return a list of symbols that are interesting to navigate to
public getNavigateToItems(searchValue: string): string {
return this.forwardJSONCall(
"getNavigateToItems(\"" + searchValue + "\")",
() => {
var items = this.languageService.getNavigateToItems(searchValue);
var result = this._navigateToItemsToString(items);
return result;
});
}
// GET SCRIPT LEXICAL STRUCTURE
//
public getScriptLexicalStructure(fileName: string): string {
return this.forwardJSONCall(
"getScriptLexicalStructure(\"" + fileName + "\")",
() => {
var items = this.languageService.getScriptLexicalStructure(fileName);
var result = this._navigateToItemsToString(items);
return result;
});
}
// GET OUTLINING REGIONS
//
public getOutliningRegions(fileName: string): string {
return this.forwardJSONCall(
"getOutliningRegions(\"" + fileName + "\")",
() => {
var items = this.languageService.getOutliningRegions(fileName);
return items;
});
}
/// Emit
public getEmitOutput(fileName: string): string {
return this.forwardJSONCall(
"getEmitOutput(\"" + fileName + "\")",
() => {
var output = this.languageService.getEmitOutput(fileName);
return output;
});
}
2014-07-24 20:57:18 +02:00
private _navigateToItemsToString(items: NavigateToItem[]): any {
2014-07-19 01:55:11 +02:00
var result: {
name: string;
kind: string;
kindModifiers: string;
containerName: string;
containerKind: string;
matchKind: string;
fileName: string;
minChar: number;
limChar: number;
additionalSpans?: { start: number; end: number; }[];
}[] = [];
for (var i = 0; i < items.length; i++) {
var item = items[i];
result.push({
name: item.name,
kind: item.kind,
kindModifiers: item.kindModifiers,
containerName: item.containerName,
containerKind: item.containerKind,
matchKind: item.matchKind,
fileName: item.fileName,
minChar: item.minChar,
limChar: item.limChar,
additionalSpans: item.additionalSpans ? item.additionalSpans.map(i => { return { start: i.minChar, end: i.limChar }; }) : undefined
});
}
return result;
}
}
class ClassifierShimObject extends ShimBase implements ClassifierShim {
2014-07-24 20:57:18 +02:00
public classifier: Classifier;
2014-07-19 01:55:11 +02:00
2014-07-24 23:26:29 +02:00
constructor(factory: ShimFactory, public host: Logger) {
2014-07-19 01:55:11 +02:00
super(factory);
2014-07-24 23:26:29 +02:00
this.classifier = createClassifier(this.host);
2014-07-19 01:55:11 +02:00
}
/// COLORIZATION
public getClassificationsForLine(text: string, lexState: EndOfLineState): string {
var classification = this.classifier.getClassificationsForLine(text, lexState);
var items = classification.entries;
var result = "";
for (var i = 0; i < items.length; i++) {
result += items[i].length + "\n";
result += items[i].classification + "\n";
}
result += classification.finalLexState;
return result;
}
}
class CoreServicesShimObject extends ShimBase implements CoreServicesShim {
2014-07-24 23:36:23 +02:00
constructor(factory: ShimFactory, public host: Logger) {
2014-07-19 01:55:11 +02:00
super(factory);
}
private forwardJSONCall(actionDescription: string, action: () => any): any {
2014-07-24 23:36:23 +02:00
return forwardJSONCall(this.host, actionDescription, action);
2014-07-19 01:55:11 +02:00
}
///
/// getPreProcessedFileInfo
///
public getPreProcessedFileInfo(fileName: string, sourceText: TypeScript.IScriptSnapshot): string {
return this.forwardJSONCall(
"getPreProcessedFileInfo(\"" + fileName + "\")",
() => {
2014-07-24 23:36:23 +02:00
var result = TypeScript.preProcessFile(fileName, sourceText);
2014-07-19 01:55:11 +02:00
return result;
});
}
///
/// getDefaultCompilationSettings
///
public getDefaultCompilationSettings(): string {
return this.forwardJSONCall(
"getDefaultCompilationSettings()",
() => {
2014-07-24 23:36:23 +02:00
return compilerOptionsToCompilationSettings(getDefaultCompilerOptions());
2014-07-19 01:55:11 +02:00
});
}
2014-07-13 01:04:16 +02:00
}
export class TypeScriptServicesFactory implements ShimFactory {
private _shims: Shim[] = [];
private documentRegistry: DocumentRegistry = new DocumentRegistry();
public createLanguageServiceShim(host: LanguageServiceShimHost): LanguageServiceShim {
try {
var hostAdapter = new LanguageServiceShimHostAdapter(host);
2014-07-24 23:26:29 +02:00
var pullLanguageService = createLanguageService(hostAdapter, this.documentRegistry);
return new LanguageServiceShimObject(this, host, pullLanguageService);
}
catch (err) {
2014-07-24 20:57:18 +02:00
logInternalError(host, err);
throw err;
}
}
2014-07-24 23:26:29 +02:00
public createClassifierShim(host: Logger): ClassifierShim {
try {
return new ClassifierShimObject(this, host);
}
catch (err) {
2014-07-24 20:57:18 +02:00
logInternalError(host, err);
throw err;
}
}
2014-07-24 23:36:23 +02:00
public createCoreServicesShim(host: Logger): CoreServicesShim {
try {
return new CoreServicesShimObject(this, host);
}
catch (err) {
2014-07-24 23:36:23 +02:00
logInternalError(host, err);
throw err;
}
}
public close(): void {
// Forget all the registered shims
this._shims = [];
this.documentRegistry = new DocumentRegistry();
}
public registerShim(shim: Shim): void {
this._shims.push(shim);
}
public unregisterShim(shim: Shim): void {
for (var i = 0, n = this._shims.length; i < n; i++) {
if (this._shims[i] === shim) {
delete this._shims[i];
return;
}
}
throw TypeScript.Errors.invalidOperation();
}
}
2014-07-19 01:55:11 +02:00
}
/// TODO: this is used by VS, clean this up on both sides of the interfrace
module Services {
2014-07-24 20:57:18 +02:00
export var TypeScriptServicesFactory = TypeScriptServicesFactory;
}