Skip to content

Commit 3bd4dd4

Browse files
Merge pull request #2977 from Microsoft/getClassifications2
Add a common, dense, format for classification operations to lower cost of processing on the host side.
2 parents a46a610 + 7769b4c commit 3bd4dd4

File tree

8 files changed

+387
-162
lines changed

8 files changed

+387
-162
lines changed

src/harness/harnessLanguageService.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,9 @@ module Harness.LanguageService {
241241
class ClassifierShimProxy implements ts.Classifier {
242242
constructor(private shim: ts.ClassifierShim) {
243243
}
244+
getEncodedLexicalClassifications(text: string, lexState: ts.EndOfLineState, classifyKeywordsInGenerics?: boolean): ts.Classifications {
245+
throw new Error("NYI");
246+
}
244247
getClassificationsForLine(text: string, lexState: ts.EndOfLineState, classifyKeywordsInGenerics?: boolean): ts.ClassificationResult {
245248
var result = this.shim.getClassificationsForLine(text, lexState, classifyKeywordsInGenerics).split('\n');
246249
var entries: ts.ClassificationInfo[] = [];
@@ -306,6 +309,12 @@ module Harness.LanguageService {
306309
getSemanticClassifications(fileName: string, span: ts.TextSpan): ts.ClassifiedSpan[] {
307310
return unwrapJSONCallResult(this.shim.getSemanticClassifications(fileName, span.start, span.length));
308311
}
312+
getEncodedSyntacticClassifications(fileName: string, span: ts.TextSpan): ts.Classifications {
313+
return unwrapJSONCallResult(this.shim.getEncodedSyntacticClassifications(fileName, span.start, span.length));
314+
}
315+
getEncodedSemanticClassifications(fileName: string, span: ts.TextSpan): ts.Classifications {
316+
return unwrapJSONCallResult(this.shim.getEncodedSemanticClassifications(fileName, span.start, span.length));
317+
}
309318
getCompletionsAtPosition(fileName: string, position: number): ts.CompletionInfo {
310319
return unwrapJSONCallResult(this.shim.getCompletionsAtPosition(fileName, position));
311320
}

src/server/client.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,14 @@ module ts.server {
533533
throw new Error("Not Implemented Yet.");
534534
}
535535

536+
getEncodedSyntacticClassifications(fileName: string, span: TextSpan): Classifications {
537+
throw new Error("Not Implemented Yet.");
538+
}
539+
540+
getEncodedSemanticClassifications(fileName: string, span: TextSpan): Classifications {
541+
throw new Error("Not Implemented Yet.");
542+
}
543+
536544
getProgram(): Program {
537545
throw new Error("SourceFile objects are not serializable through the server protocol.");
538546
}

src/services/services.ts

Lines changed: 247 additions & 87 deletions
Large diffs are not rendered by default.

src/services/shims.ts

Lines changed: 59 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ module ts {
9999

100100
getSyntacticClassifications(fileName: string, start: number, length: number): string;
101101
getSemanticClassifications(fileName: string, start: number, length: number): string;
102+
getEncodedSyntacticClassifications(fileName: string, start: number, length: number): string;
103+
getEncodedSemanticClassifications(fileName: string, start: number, length: number): string;
102104

103105
getCompletionsAtPosition(fileName: string, position: number): string;
104106
getCompletionEntryDetails(fileName: string, position: number, entryName: string): string;
@@ -189,6 +191,7 @@ module ts {
189191
}
190192

191193
export interface ClassifierShim extends Shim {
194+
getEncodedLexicalClassifications(text: string, lexState: EndOfLineState, syntacticClassifierAbsent?: boolean): string;
192195
getClassificationsForLine(text: string, lexState: EndOfLineState, syntacticClassifierAbsent?: boolean): string;
193196
}
194197

@@ -199,7 +202,9 @@ module ts {
199202
}
200203

201204
function logInternalError(logger: Logger, err: Error) {
202-
logger.log("*INTERNAL ERROR* - Exception in typescript services: " + err.message);
205+
if (logger) {
206+
logger.log("*INTERNAL ERROR* - Exception in typescript services: " + err.message);
207+
}
203208
}
204209

205210
class ScriptSnapshotShimAdapter implements IScriptSnapshot {
@@ -321,25 +326,32 @@ module ts {
321326
}
322327
}
323328

324-
function simpleForwardCall(logger: Logger, actionDescription: string, action: () => any): any {
325-
logger.log(actionDescription);
326-
var start = Date.now();
329+
function simpleForwardCall(logger: Logger, actionDescription: string, action: () => any, noPerfLogging: boolean): any {
330+
if (!noPerfLogging) {
331+
logger.log(actionDescription);
332+
var start = Date.now();
333+
}
334+
327335
var result = action();
328-
var end = Date.now();
329-
logger.log(actionDescription + " completed in " + (end - start) + " msec");
330-
if (typeof (result) === "string") {
331-
var str = <string>result;
332-
if (str.length > 128) {
333-
str = str.substring(0, 128) + "...";
336+
337+
if (!noPerfLogging) {
338+
var end = Date.now();
339+
logger.log(actionDescription + " completed in " + (end - start) + " msec");
340+
if (typeof (result) === "string") {
341+
var str = <string>result;
342+
if (str.length > 128) {
343+
str = str.substring(0, 128) + "...";
344+
}
345+
logger.log(" result.length=" + str.length + ", result='" + JSON.stringify(str) + "'");
334346
}
335-
logger.log(" result.length=" + str.length + ", result='" + JSON.stringify(str) + "'");
336347
}
348+
337349
return result;
338350
}
339351

340-
function forwardJSONCall(logger: Logger, actionDescription: string, action: () => any): string {
352+
function forwardJSONCall(logger: Logger, actionDescription: string, action: () => any, noPerfLogging: boolean): string {
341353
try {
342-
var result = simpleForwardCall(logger, actionDescription, action);
354+
var result = simpleForwardCall(logger, actionDescription, action, noPerfLogging);
343355
return JSON.stringify({ result: result });
344356
}
345357
catch (err) {
@@ -387,7 +399,7 @@ module ts {
387399
}
388400

389401
public forwardJSONCall(actionDescription: string, action: () => any): string {
390-
return forwardJSONCall(this.logger, actionDescription, action);
402+
return forwardJSONCall(this.logger, actionDescription, action, /*noPerfLogging:*/ false);
391403
}
392404

393405
/// DISPOSE
@@ -457,6 +469,26 @@ module ts {
457469
});
458470
}
459471

472+
public getEncodedSyntacticClassifications(fileName: string, start: number, length: number): string {
473+
return this.forwardJSONCall(
474+
"getEncodedSyntacticClassifications('" + fileName + "', " + start + ", " + length + ")",
475+
() => {
476+
// directly serialize the spans out to a string. This is much faster to decode
477+
// on the managed side versus a full JSON array.
478+
return convertClassifications(this.languageService.getEncodedSyntacticClassifications(fileName, createTextSpan(start, length)));
479+
});
480+
}
481+
482+
public getEncodedSemanticClassifications(fileName: string, start: number, length: number): string {
483+
return this.forwardJSONCall(
484+
"getEncodedSemanticClassifications('" + fileName + "', " + start + ", " + length + ")",
485+
() => {
486+
// directly serialize the spans out to a string. This is much faster to decode
487+
// on the managed side versus a full JSON array.
488+
return convertClassifications(this.languageService.getEncodedSemanticClassifications(fileName, createTextSpan(start, length)));
489+
});
490+
}
491+
460492
private getNewLine(): string {
461493
return this.host.getNewLine ? this.host.getNewLine() : "\r\n";
462494
}
@@ -736,14 +768,24 @@ module ts {
736768
}
737769
}
738770

771+
function convertClassifications(classifications: Classifications): { spans: string, endOfLineState: EndOfLineState } {
772+
return { spans: classifications.spans.join(","), endOfLineState: classifications.endOfLineState };
773+
}
774+
739775
class ClassifierShimObject extends ShimBase implements ClassifierShim {
740776
public classifier: Classifier;
741777

742-
constructor(factory: ShimFactory) {
778+
constructor(factory: ShimFactory, private logger: Logger) {
743779
super(factory);
744780
this.classifier = createClassifier();
745781
}
746782

783+
public getEncodedLexicalClassifications(text: string, lexState: EndOfLineState, syntacticClassifierAbsent?: boolean): string {
784+
return forwardJSONCall(this.logger, "getEncodedLexicalClassifications",
785+
() => convertClassifications(this.classifier.getEncodedLexicalClassifications(text, lexState, syntacticClassifierAbsent)),
786+
/*noPerfLogging:*/ true);
787+
}
788+
747789
/// COLORIZATION
748790
public getClassificationsForLine(text: string, lexState: EndOfLineState, classifyKeywordsInGenerics?: boolean): string {
749791
var classification = this.classifier.getClassificationsForLine(text, lexState, classifyKeywordsInGenerics);
@@ -765,7 +807,7 @@ module ts {
765807
}
766808

767809
private forwardJSONCall(actionDescription: string, action: () => any): any {
768-
return forwardJSONCall(this.logger, actionDescription, action);
810+
return forwardJSONCall(this.logger, actionDescription, action, /*noPerfLogging:*/ false);
769811
}
770812

771813
public getPreProcessedFileInfo(fileName: string, sourceTextSnapshot: IScriptSnapshot): string {
@@ -858,7 +900,7 @@ module ts {
858900

859901
public createClassifierShim(logger: Logger): ClassifierShim {
860902
try {
861-
return new ClassifierShimObject(this);
903+
return new ClassifierShimObject(this, logger);
862904
}
863905
catch (err) {
864906
logInternalError(logger, err);

tests/cases/fourslash/fourslash.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -651,8 +651,12 @@ module FourSlashInterface {
651651
return getClassification("typeParameterName", text, position);
652652
}
653653

654-
export function typeAlias(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } {
655-
return getClassification("typeAlias", text, position);
654+
export function parameterName(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } {
655+
return getClassification("parameterName", text, position);
656+
}
657+
658+
export function typeAliasName(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } {
659+
return getClassification("typeAliasName", text, position);
656660
}
657661

658662
function getClassification(type: string, text: string, position?: number) {

tests/cases/fourslash/semanticClassificatonTypeAlias.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77

88
var c = classification;
99
verify.semanticClassificationsAre(
10-
c.typeAlias("Alias", test.marker("0").position),
11-
c.typeAlias("Alias", test.marker("1").position),
12-
c.typeAlias("Alias", test.marker("2").position),
13-
c.typeAlias("Alias", test.marker("3").position),
14-
c.typeAlias("Alias", test.marker("4").position)
10+
c.typeAliasName("Alias", test.marker("0").position),
11+
c.typeAliasName("Alias", test.marker("1").position),
12+
c.typeAliasName("Alias", test.marker("2").position),
13+
c.typeAliasName("Alias", test.marker("3").position),
14+
c.typeAliasName("Alias", test.marker("4").position)
1515
);

tests/cases/fourslash/syntacticClassificationsFunctionWithComments.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ var firstCommentText =
1919
var c = classification;
2020
verify.syntacticClassificationsAre(
2121
c.comment(firstCommentText),
22-
c.keyword("function"), c.text("myFunction"), c.punctuation("("), c.comment("/* x */"), c.text("x"), c.punctuation(":"), c.keyword("any"), c.punctuation(")"), c.punctuation("{"),
22+
c.keyword("function"), c.text("myFunction"), c.punctuation("("), c.comment("/* x */"), c.parameterName("x"), c.punctuation(":"), c.keyword("any"), c.punctuation(")"), c.punctuation("{"),
2323
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(";"),
2424
c.punctuation("}"),
2525
c.comment("// end of file"));

0 commit comments

Comments
 (0)