Skip to content

Commit 4c435e0

Browse files
Merge pull request #2981 from Microsoft/getClassifications1.5
Release-1.5: Add a common, dense, format for classification operations to lower cost of processing on the host side.
2 parents c233073 + 1c7600b commit 4c435e0

File tree

8 files changed

+387
-162
lines changed

8 files changed

+387
-162
lines changed

Diff for: src/harness/harnessLanguageService.ts

+9
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,9 @@ module Harness.LanguageService {
235235
class ClassifierShimProxy implements ts.Classifier {
236236
constructor(private shim: ts.ClassifierShim) {
237237
}
238+
getEncodedLexicalClassifications(text: string, lexState: ts.EndOfLineState, classifyKeywordsInGenerics?: boolean): ts.Classifications {
239+
throw new Error("NYI");
240+
}
238241
getClassificationsForLine(text: string, lexState: ts.EndOfLineState, classifyKeywordsInGenerics?: boolean): ts.ClassificationResult {
239242
var result = this.shim.getClassificationsForLine(text, lexState, classifyKeywordsInGenerics).split('\n');
240243
var entries: ts.ClassificationInfo[] = [];
@@ -300,6 +303,12 @@ module Harness.LanguageService {
300303
getSemanticClassifications(fileName: string, span: ts.TextSpan): ts.ClassifiedSpan[] {
301304
return unwrapJSONCallResult(this.shim.getSemanticClassifications(fileName, span.start, span.length));
302305
}
306+
getEncodedSyntacticClassifications(fileName: string, span: ts.TextSpan): ts.Classifications {
307+
return unwrapJSONCallResult(this.shim.getEncodedSyntacticClassifications(fileName, span.start, span.length));
308+
}
309+
getEncodedSemanticClassifications(fileName: string, span: ts.TextSpan): ts.Classifications {
310+
return unwrapJSONCallResult(this.shim.getEncodedSemanticClassifications(fileName, span.start, span.length));
311+
}
303312
getCompletionsAtPosition(fileName: string, position: number): ts.CompletionInfo {
304313
return unwrapJSONCallResult(this.shim.getCompletionsAtPosition(fileName, position));
305314
}

Diff for: src/server/client.ts

+8
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
}

Diff for: src/services/services.ts

+247-87
Large diffs are not rendered by default.

Diff for: src/services/shims.ts

+59-17
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ module ts {
9393

9494
getSyntacticClassifications(fileName: string, start: number, length: number): string;
9595
getSemanticClassifications(fileName: string, start: number, length: number): string;
96+
getEncodedSyntacticClassifications(fileName: string, start: number, length: number): string;
97+
getEncodedSemanticClassifications(fileName: string, start: number, length: number): string;
9698

9799
getCompletionsAtPosition(fileName: string, position: number): string;
98100
getCompletionEntryDetails(fileName: string, position: number, entryName: string): string;
@@ -183,6 +185,7 @@ module ts {
183185
}
184186

185187
export interface ClassifierShim extends Shim {
188+
getEncodedLexicalClassifications(text: string, lexState: EndOfLineState, syntacticClassifierAbsent?: boolean): string;
186189
getClassificationsForLine(text: string, lexState: EndOfLineState, syntacticClassifierAbsent?: boolean): string;
187190
}
188191

@@ -192,7 +195,9 @@ module ts {
192195
}
193196

194197
function logInternalError(logger: Logger, err: Error) {
195-
logger.log("*INTERNAL ERROR* - Exception in typescript services: " + err.message);
198+
if (logger) {
199+
logger.log("*INTERNAL ERROR* - Exception in typescript services: " + err.message);
200+
}
196201
}
197202

198203
class ScriptSnapshotShimAdapter implements IScriptSnapshot {
@@ -303,25 +308,32 @@ module ts {
303308
}
304309
}
305310

306-
function simpleForwardCall(logger: Logger, actionDescription: string, action: () => any): any {
307-
logger.log(actionDescription);
308-
var start = Date.now();
311+
function simpleForwardCall(logger: Logger, actionDescription: string, action: () => any, noPerfLogging: boolean): any {
312+
if (!noPerfLogging) {
313+
logger.log(actionDescription);
314+
var start = Date.now();
315+
}
316+
309317
var result = action();
310-
var end = Date.now();
311-
logger.log(actionDescription + " completed in " + (end - start) + " msec");
312-
if (typeof (result) === "string") {
313-
var str = <string>result;
314-
if (str.length > 128) {
315-
str = str.substring(0, 128) + "...";
318+
319+
if (!noPerfLogging) {
320+
var end = Date.now();
321+
logger.log(actionDescription + " completed in " + (end - start) + " msec");
322+
if (typeof (result) === "string") {
323+
var str = <string>result;
324+
if (str.length > 128) {
325+
str = str.substring(0, 128) + "...";
326+
}
327+
logger.log(" result.length=" + str.length + ", result='" + JSON.stringify(str) + "'");
316328
}
317-
logger.log(" result.length=" + str.length + ", result='" + JSON.stringify(str) + "'");
318329
}
330+
319331
return result;
320332
}
321333

322-
function forwardJSONCall(logger: Logger, actionDescription: string, action: () => any): string {
334+
function forwardJSONCall(logger: Logger, actionDescription: string, action: () => any, noPerfLogging: boolean): string {
323335
try {
324-
var result = simpleForwardCall(logger, actionDescription, action);
336+
var result = simpleForwardCall(logger, actionDescription, action, noPerfLogging);
325337
return JSON.stringify({ result: result });
326338
}
327339
catch (err) {
@@ -369,7 +381,7 @@ module ts {
369381
}
370382

371383
public forwardJSONCall(actionDescription: string, action: () => any): string {
372-
return forwardJSONCall(this.logger, actionDescription, action);
384+
return forwardJSONCall(this.logger, actionDescription, action, /*noPerfLogging:*/ false);
373385
}
374386

375387
/// DISPOSE
@@ -439,6 +451,26 @@ module ts {
439451
});
440452
}
441453

454+
public getEncodedSyntacticClassifications(fileName: string, start: number, length: number): string {
455+
return this.forwardJSONCall(
456+
"getEncodedSyntacticClassifications('" + fileName + "', " + start + ", " + length + ")",
457+
() => {
458+
// directly serialize the spans out to a string. This is much faster to decode
459+
// on the managed side versus a full JSON array.
460+
return convertClassifications(this.languageService.getEncodedSyntacticClassifications(fileName, createTextSpan(start, length)));
461+
});
462+
}
463+
464+
public getEncodedSemanticClassifications(fileName: string, start: number, length: number): string {
465+
return this.forwardJSONCall(
466+
"getEncodedSemanticClassifications('" + fileName + "', " + start + ", " + length + ")",
467+
() => {
468+
// directly serialize the spans out to a string. This is much faster to decode
469+
// on the managed side versus a full JSON array.
470+
return convertClassifications(this.languageService.getEncodedSemanticClassifications(fileName, createTextSpan(start, length)));
471+
});
472+
}
473+
442474
private getNewLine(): string {
443475
return this.host.getNewLine ? this.host.getNewLine() : "\r\n";
444476
}
@@ -718,14 +750,24 @@ module ts {
718750
}
719751
}
720752

753+
function convertClassifications(classifications: Classifications): { spans: string, endOfLineState: EndOfLineState } {
754+
return { spans: classifications.spans.join(","), endOfLineState: classifications.endOfLineState };
755+
}
756+
721757
class ClassifierShimObject extends ShimBase implements ClassifierShim {
722758
public classifier: Classifier;
723759

724-
constructor(factory: ShimFactory) {
760+
constructor(factory: ShimFactory, private logger: Logger) {
725761
super(factory);
726762
this.classifier = createClassifier();
727763
}
728764

765+
public getEncodedLexicalClassifications(text: string, lexState: EndOfLineState, syntacticClassifierAbsent?: boolean): string {
766+
return forwardJSONCall(this.logger, "getEncodedLexicalClassifications",
767+
() => convertClassifications(this.classifier.getEncodedLexicalClassifications(text, lexState, syntacticClassifierAbsent)),
768+
/*noPerfLogging:*/ true);
769+
}
770+
729771
/// COLORIZATION
730772
public getClassificationsForLine(text: string, lexState: EndOfLineState, classifyKeywordsInGenerics?: boolean): string {
731773
var classification = this.classifier.getClassificationsForLine(text, lexState, classifyKeywordsInGenerics);
@@ -746,7 +788,7 @@ module ts {
746788
}
747789

748790
private forwardJSONCall(actionDescription: string, action: () => any): any {
749-
return forwardJSONCall(this.logger, actionDescription, action);
791+
return forwardJSONCall(this.logger, actionDescription, action, /*noPerfLogging:*/ false);
750792
}
751793

752794
public getPreProcessedFileInfo(fileName: string, sourceTextSnapshot: IScriptSnapshot): string {
@@ -813,7 +855,7 @@ module ts {
813855

814856
public createClassifierShim(logger: Logger): ClassifierShim {
815857
try {
816-
return new ClassifierShimObject(this);
858+
return new ClassifierShimObject(this, logger);
817859
}
818860
catch (err) {
819861
logInternalError(logger, err);

Diff for: tests/cases/fourslash/fourslash.ts

+6-2
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) {

Diff for: tests/cases/fourslash/semanticClassificatonTypeAlias.ts

+5-5
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
);

Diff for: tests/cases/fourslash/syntacticClassificationsFunctionWithComments.ts

+1-1
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)