Skip to content

Release-1.5: Add a common, dense, format for classification operations to lower cost of processing on the host side. #2981

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
May 1, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/harness/harnessLanguageService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,9 @@ module Harness.LanguageService {
class ClassifierShimProxy implements ts.Classifier {
constructor(private shim: ts.ClassifierShim) {
}
getEncodedLexicalClassifications(text: string, lexState: ts.EndOfLineState, classifyKeywordsInGenerics?: boolean): ts.Classifications {
throw new Error("NYI");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this not implemented?

}
getClassificationsForLine(text: string, lexState: ts.EndOfLineState, classifyKeywordsInGenerics?: boolean): ts.ClassificationResult {
var result = this.shim.getClassificationsForLine(text, lexState, classifyKeywordsInGenerics).split('\n');
var entries: ts.ClassificationInfo[] = [];
Expand Down Expand Up @@ -300,6 +303,12 @@ module Harness.LanguageService {
getSemanticClassifications(fileName: string, span: ts.TextSpan): ts.ClassifiedSpan[] {
return unwrapJSONCallResult(this.shim.getSemanticClassifications(fileName, span.start, span.length));
}
getEncodedSyntacticClassifications(fileName: string, span: ts.TextSpan): ts.Classifications {
return unwrapJSONCallResult(this.shim.getEncodedSyntacticClassifications(fileName, span.start, span.length));
}
getEncodedSemanticClassifications(fileName: string, span: ts.TextSpan): ts.Classifications {
return unwrapJSONCallResult(this.shim.getEncodedSemanticClassifications(fileName, span.start, span.length));
}
getCompletionsAtPosition(fileName: string, position: number): ts.CompletionInfo {
return unwrapJSONCallResult(this.shim.getCompletionsAtPosition(fileName, position));
}
Expand Down
8 changes: 8 additions & 0 deletions src/server/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,14 @@ module ts.server {
throw new Error("Not Implemented Yet.");
}

getEncodedSyntacticClassifications(fileName: string, span: TextSpan): Classifications {
throw new Error("Not Implemented Yet.");
}

getEncodedSemanticClassifications(fileName: string, span: TextSpan): Classifications {
throw new Error("Not Implemented Yet.");
}

getProgram(): Program {
throw new Error("SourceFile objects are not serializable through the server protocol.");
}
Expand Down
334 changes: 247 additions & 87 deletions src/services/services.ts

Large diffs are not rendered by default.

76 changes: 59 additions & 17 deletions src/services/shims.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ module ts {

getSyntacticClassifications(fileName: string, start: number, length: number): string;
getSemanticClassifications(fileName: string, start: number, length: number): string;
getEncodedSyntacticClassifications(fileName: string, start: number, length: number): string;
getEncodedSemanticClassifications(fileName: string, start: number, length: number): string;

getCompletionsAtPosition(fileName: string, position: number): string;
getCompletionEntryDetails(fileName: string, position: number, entryName: string): string;
Expand Down Expand Up @@ -183,6 +185,7 @@ module ts {
}

export interface ClassifierShim extends Shim {
getEncodedLexicalClassifications(text: string, lexState: EndOfLineState, syntacticClassifierAbsent?: boolean): string;
getClassificationsForLine(text: string, lexState: EndOfLineState, syntacticClassifierAbsent?: boolean): string;
}

Expand All @@ -192,7 +195,9 @@ module ts {
}

function logInternalError(logger: Logger, err: Error) {
logger.log("*INTERNAL ERROR* - Exception in typescript services: " + err.message);
if (logger) {
logger.log("*INTERNAL ERROR* - Exception in typescript services: " + err.message);
}
}

class ScriptSnapshotShimAdapter implements IScriptSnapshot {
Expand Down Expand Up @@ -303,25 +308,32 @@ module ts {
}
}

function simpleForwardCall(logger: Logger, actionDescription: string, action: () => any): any {
logger.log(actionDescription);
var start = Date.now();
function simpleForwardCall(logger: Logger, actionDescription: string, action: () => any, noPerfLogging: boolean): any {
if (!noPerfLogging) {
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) + "...";

if (!noPerfLogging) {
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) + "'");
}
logger.log(" result.length=" + str.length + ", result='" + JSON.stringify(str) + "'");
}

return result;
}

function forwardJSONCall(logger: Logger, actionDescription: string, action: () => any): string {
function forwardJSONCall(logger: Logger, actionDescription: string, action: () => any, noPerfLogging: boolean): string {
try {
var result = simpleForwardCall(logger, actionDescription, action);
var result = simpleForwardCall(logger, actionDescription, action, noPerfLogging);
return JSON.stringify({ result: result });
}
catch (err) {
Expand Down Expand Up @@ -369,7 +381,7 @@ module ts {
}

public forwardJSONCall(actionDescription: string, action: () => any): string {
return forwardJSONCall(this.logger, actionDescription, action);
return forwardJSONCall(this.logger, actionDescription, action, /*noPerfLogging:*/ false);
}

/// DISPOSE
Expand Down Expand Up @@ -439,6 +451,26 @@ module ts {
});
}

public getEncodedSyntacticClassifications(fileName: string, start: number, length: number): string {
return this.forwardJSONCall(
"getEncodedSyntacticClassifications('" + fileName + "', " + start + ", " + length + ")",
() => {
// directly serialize the spans out to a string. This is much faster to decode
// on the managed side versus a full JSON array.
return convertClassifications(this.languageService.getEncodedSyntacticClassifications(fileName, createTextSpan(start, length)));
});
}

public getEncodedSemanticClassifications(fileName: string, start: number, length: number): string {
return this.forwardJSONCall(
"getEncodedSemanticClassifications('" + fileName + "', " + start + ", " + length + ")",
() => {
// directly serialize the spans out to a string. This is much faster to decode
// on the managed side versus a full JSON array.
return convertClassifications(this.languageService.getEncodedSemanticClassifications(fileName, createTextSpan(start, length)));
});
}

private getNewLine(): string {
return this.host.getNewLine ? this.host.getNewLine() : "\r\n";
}
Expand Down Expand Up @@ -718,14 +750,24 @@ module ts {
}
}

function convertClassifications(classifications: Classifications): { spans: string, endOfLineState: EndOfLineState } {
return { spans: classifications.spans.join(","), endOfLineState: classifications.endOfLineState };
}

class ClassifierShimObject extends ShimBase implements ClassifierShim {
public classifier: Classifier;

constructor(factory: ShimFactory) {
constructor(factory: ShimFactory, private logger: Logger) {
super(factory);
this.classifier = createClassifier();
}

public getEncodedLexicalClassifications(text: string, lexState: EndOfLineState, syntacticClassifierAbsent?: boolean): string {
return forwardJSONCall(this.logger, "getEncodedLexicalClassifications",
() => convertClassifications(this.classifier.getEncodedLexicalClassifications(text, lexState, syntacticClassifierAbsent)),
/*noPerfLogging:*/ true);
}

/// COLORIZATION
public getClassificationsForLine(text: string, lexState: EndOfLineState, classifyKeywordsInGenerics?: boolean): string {
var classification = this.classifier.getClassificationsForLine(text, lexState, classifyKeywordsInGenerics);
Expand All @@ -746,7 +788,7 @@ module ts {
}

private forwardJSONCall(actionDescription: string, action: () => any): any {
return forwardJSONCall(this.logger, actionDescription, action);
return forwardJSONCall(this.logger, actionDescription, action, /*noPerfLogging:*/ false);
}

public getPreProcessedFileInfo(fileName: string, sourceTextSnapshot: IScriptSnapshot): string {
Expand Down Expand Up @@ -813,7 +855,7 @@ module ts {

public createClassifierShim(logger: Logger): ClassifierShim {
try {
return new ClassifierShimObject(this);
return new ClassifierShimObject(this, logger);
}
catch (err) {
logInternalError(logger, err);
Expand Down
8 changes: 6 additions & 2 deletions tests/cases/fourslash/fourslash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -651,8 +651,12 @@ module FourSlashInterface {
return getClassification("typeParameterName", text, position);
}

export function typeAlias(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } {
return getClassification("typeAlias", text, position);
export function parameterName(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } {
return getClassification("parameterName", text, position);
}

export function typeAliasName(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } {
return getClassification("typeAliasName", text, position);
}

function getClassification(type: string, text: string, position?: number) {
Expand Down
10 changes: 5 additions & 5 deletions tests/cases/fourslash/semanticClassificatonTypeAlias.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@

var c = classification;
verify.semanticClassificationsAre(
c.typeAlias("Alias", test.marker("0").position),
c.typeAlias("Alias", test.marker("1").position),
c.typeAlias("Alias", test.marker("2").position),
c.typeAlias("Alias", test.marker("3").position),
c.typeAlias("Alias", test.marker("4").position)
c.typeAliasName("Alias", test.marker("0").position),
c.typeAliasName("Alias", test.marker("1").position),
c.typeAliasName("Alias", test.marker("2").position),
c.typeAliasName("Alias", test.marker("3").position),
c.typeAliasName("Alias", test.marker("4").position)
);
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ var firstCommentText =
var c = classification;
verify.syntacticClassificationsAre(
c.comment(firstCommentText),
c.keyword("function"), c.text("myFunction"), c.punctuation("("), c.comment("/* x */"), c.text("x"), c.punctuation(":"), c.keyword("any"), c.punctuation(")"), c.punctuation("{"),
c.keyword("function"), c.text("myFunction"), c.punctuation("("), c.comment("/* x */"), c.parameterName("x"), c.punctuation(":"), c.keyword("any"), c.punctuation(")"), c.punctuation("{"),
c.keyword("var"), c.text("y"), c.operator("="), c.text("x"), c.operator("?"), c.text("x"), c.operator("++"), c.operator(":"), c.operator("++"), c.text("x"), c.punctuation(";"),
c.punctuation("}"),
c.comment("// end of file"));
Loading