Skip to content

Commit

Permalink
Push markdown creation out of tsserver
Browse files Browse the repository at this point in the history
  • Loading branch information
weswigham committed May 14, 2019
1 parent 2e10220 commit 8436dd8
Show file tree
Hide file tree
Showing 8 changed files with 196 additions and 98 deletions.
47 changes: 18 additions & 29 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -379,45 +379,34 @@ namespace ts {
},

getLocalTypeParametersOfClassOrInterfaceOrTypeAlias,
getPlainDiagnosticRenderingContext: flags => {
return {
typeToString: t => typeToString(t, /*enclosingDeclaration*/ undefined, getTypeFormatFlagsFromRenderFlags(flags)),
symbolToString: s => symbolToString(s),
getDiagnosticRenderingContext: flags => {
let spans: AnnotationSpan[] | undefined;
let offset = 0;
const captureSymbolSpan = (original: string, symbol: Symbol): string => {
(spans || (spans = [])).push({ kind: "symbol", symbol, start: offset + typeWriter.getTextPos(), length: original.length });
return original;
};
},
getMarkdownDiagnosticRenderingContext: flags => {
const typeWriter = createTextWriter("", renderIntoMarkdown);
const typeWriter = createTextWriter("", captureSymbolSpan);
const typeFormatFlags = getTypeFormatFlagsFromRenderFlags(flags);
return {
typeToString: type => {
typeToString: (type, symbolOffset) => {
offset = symbolOffset;
typeWriter.clear();
typeToString(type, /*enclosingDeclaration*/ undefined, typeFormatFlags, typeWriter);
return typeWriter.getText();
return typeToString(type, /*enclosingDeclaration*/ undefined, typeFormatFlags, typeWriter);
},
symbolToString: symbol => {
symbolToString: (symbol, symbolOffset) => {
offset = symbolOffset;
typeWriter.clear();
symbolToString(symbol, /*enclosingDeclaration*/ undefined, /*meaning*/ undefined, /*flags*/ undefined, typeWriter);
return typeWriter.getText();
return symbolToString(symbol, /*enclosingDeclaration*/ undefined, /*meaning*/ undefined, /*flags*/ undefined, typeWriter);
},
getPendingAnnotationSpans: () => {
const result = spans;
spans = undefined;
return result;
}
};
},
};
const renderIntoMarkdown = (original: string, s: Symbol): string => {
const d = firstOrUndefined(s.declarations);
if (!d) {
return original;
}
const f = getSourceFileOfNode(d);
if (!f) {
return original;
}
const pos = getNameOfDeclaration(d) || d;
const p = getLineAndCharacterOfPosition(f, skipTrivia(f.text, pos.pos));
return `[${original}](command:editor.action.peekDefinition?${encodeURIComponent(JSON.stringify({
resource: { $mid: 1, scheme: "file", authority: "", path: startsWith(f.path, "/") ? f.path : `/${f.path}`},
position: { lineNumber: p.line + 1, column: p.character + 1 }
}))})`;
};

function getTypeFormatFlagsFromRenderFlags(flags: DiagnosticRendererFlags) {
// Setting a flag disables the default `TypeFormatFlags.AllowUniqueESSymbolType | TypeFormatFlags.UseAliasDefinedOutsideCurrentScope` flags
Expand Down
32 changes: 30 additions & 2 deletions src/compiler/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,35 @@ namespace ts {
return output;
}

export function flattenDiagnosticMessageText(messageText: string | DiagnosticMessageChain | undefined, newLine: string, flattenMarkdown?: boolean): string {
/* @internal */
export function flattenDiagnosticAnnotationSpans(spans: AnnotationSpan[] | DiagnosticMessageChain | undefined, newLine: string): AnnotationSpan[] | undefined {
if (!spans || isArray(spans)) {
return spans;
}
let results: SymbolSpan[] | undefined;
let diagnosticChain: DiagnosticMessageChain | undefined = spans;
let offset = 0;

let indent = 0;
while (diagnosticChain) {
if (indent) {
offset += newLine.length;

for (let i = 0; i < indent; i++) {
offset += " ".length;
}
}
if (diagnosticChain.annotations) {
results = concatenate(results, map(diagnosticChain.annotations, d => ({ ...d, start: d.start + offset })));
}
offset += diagnosticChain.messageText.length;
indent++;
diagnosticChain = diagnosticChain.next;
}
return results;
}

export function flattenDiagnosticMessageText(messageText: string | DiagnosticMessageChain | undefined, newLine: string): string {
if (isString(messageText)) {
return messageText;
}
Expand All @@ -519,7 +547,7 @@ namespace ts {
result += " ";
}
}
result += flattenMarkdown && diagnosticChain.markdownText ? diagnosticChain.markdownText : diagnosticChain.messageText;
result += diagnosticChain.messageText;
indent++;
diagnosticChain = diagnosticChain.next;
}
Expand Down
21 changes: 15 additions & 6 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3320,8 +3320,7 @@ namespace ts {

/* @internal */ getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol: Symbol): ReadonlyArray<TypeParameter> | undefined;

/* @internal */ getPlainDiagnosticRenderingContext(flags: DiagnosticRendererFlags): DiagnosticRenderContext;
/* @internal */ getMarkdownDiagnosticRenderingContext(flags: DiagnosticRendererFlags): DiagnosticRenderContext;
/* @internal */ getDiagnosticRenderingContext(flags: DiagnosticRendererFlags): DiagnosticRenderContext;
}


Expand All @@ -3331,10 +3330,20 @@ namespace ts {
UseFullyQualifiedTypes = 1 << 0,
}

export type AnnotationSpan = SymbolSpan;

export interface SymbolSpan {
kind: "symbol";
symbol: Symbol;
start: number;
length: number;
}

/** @internal */
export interface DiagnosticRenderContext {
typeToString(type: Type): string;
symbolToString(symbol: Symbol): string;
typeToString(type: Type, symbolOffset: number): string;
symbolToString(symbol: Symbol, symbolOffset: number): string;
getPendingAnnotationSpans(): AnnotationSpan[] | undefined;
}

/* @internal */
Expand Down Expand Up @@ -4564,7 +4573,7 @@ namespace ts {
*/
export interface DiagnosticMessageChain {
messageText: string;
markdownText?: string;
annotations?: AnnotationSpan[];
category: DiagnosticCategory;
code: number;
next?: DiagnosticMessageChain;
Expand All @@ -4583,7 +4592,7 @@ namespace ts {
start: number | undefined;
length: number | undefined;
messageText: string | DiagnosticMessageChain;
markdownText?: string | DiagnosticMessageChain;
annotations?: AnnotationSpan[];
}
export interface DiagnosticWithLocation extends Diagnostic {
file: SourceFile;
Expand Down
44 changes: 22 additions & 22 deletions src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -865,8 +865,8 @@ namespace ts {
code: messageChain.code,
category: messageChain.category,
messageText: messageChain.next ? messageChain : messageChain.messageText,
markdownText: messageChain.next ? messageChain : messageChain.markdownText,
relatedInformation
relatedInformation,
...(!messageChain.next && messageChain.annotations ? { annotations: messageChain.annotations } : {})
};
}

Expand Down Expand Up @@ -7108,21 +7108,27 @@ namespace ts {
getSourceMapSourceConstructor: () => <any>SourceMapSource,
};

function renderForOutput(arg: string | number | Type | Symbol, renderContext: DiagnosticRenderContext | undefined) {
function renderForOutput(arg: string | number | Type | Symbol, renderContext: DiagnosticRenderContext | undefined, offset: number) {
Debug.assertDefined(arg);
if (typeof arg === "string" || typeof arg === "number") {
return arg;
}
if (!renderContext) {
return Debug.fail("Type or symbol passed into diagnostic rendering pipeline with no renderer provided.");
}
if (arg.checker) {
return renderContext.typeToString(arg);
return renderContext.typeToString(arg, offset);
}
return renderContext.symbolToString(arg);
return renderContext.symbolToString(arg, offset);
}

export function formatStringFromArgs(text: string, args: ArrayLike<string | number | Type | Symbol>, baseIndex = 0, renderContext?: DiagnosticRenderContext): string {
return text.replace(/{(\d+)}/g, (_match, index: string) => "" + Debug.assertDefined(renderForOutput(args[+index + baseIndex], renderContext)));
let offsetAdjustmentFromReplacement = 0;
return text.replace(/{(\d+)}/g, (match: string, index: string, offset: number) => {
const text = "" + renderForOutput(args[+index + baseIndex], renderContext, offset + offsetAdjustmentFromReplacement);
offsetAdjustmentFromReplacement += text.length - match.length;
return text;
});
}

export let localizedDiagnosticMessages: MapLike<string> | undefined;
Expand Down Expand Up @@ -7193,15 +7199,12 @@ namespace ts {
export function createRenderedCompilerDiagnostic(checker: TypeChecker, flags: DiagnosticRendererFlags, message: DiagnosticMessage, ...args: (string | number | Type | Symbol | undefined)[]): Diagnostic;
export function createRenderedCompilerDiagnostic(checker: TypeChecker, flags: DiagnosticRendererFlags, message: DiagnosticMessage): Diagnostic {
let text = getLocaleSpecificMessage(message);
let markdown: string | undefined;
let spans: SymbolSpan[] | undefined;

if (arguments.length > 3) {
const unformatted = text;
text = formatStringFromArgs(unformatted, arguments, 3, checker.getPlainDiagnosticRenderingContext(flags));
const candidateMarkdown = formatStringFromArgs(unformatted, arguments, 3, checker.getMarkdownDiagnosticRenderingContext(flags));
if (candidateMarkdown !== text) {
markdown = candidateMarkdown;
}
const ctx = checker.getDiagnosticRenderingContext(flags);
text = formatStringFromArgs(text, arguments, 3, ctx);
spans = ctx.getPendingAnnotationSpans();
}

return {
Expand All @@ -7213,7 +7216,7 @@ namespace ts {
category: message.category,
code: message.code,
reportsUnnecessary: message.reportsUnnecessary,
...(typeof markdown === "string" ? { markdownText: markdown } : {})
...(typeof spans === "undefined" ? {} : { annotations: spans })
};
}

Expand Down Expand Up @@ -7249,15 +7252,12 @@ namespace ts {
export function chainRenderedDiagnosticMessages(checker: TypeChecker, flags: DiagnosticRendererFlags, details: DiagnosticMessageChain | undefined, message: DiagnosticMessage, ...args: (string | number | Type | Symbol | undefined)[]): DiagnosticMessageChain;
export function chainRenderedDiagnosticMessages(checker: TypeChecker, flags: DiagnosticRendererFlags, details: DiagnosticMessageChain | undefined, message: DiagnosticMessage): DiagnosticMessageChain {
let text = getLocaleSpecificMessage(message);
let markdown: string | undefined;
let spans: SymbolSpan[] | undefined;

if (arguments.length > 4) {
const unformatted = text;
text = formatStringFromArgs(unformatted, arguments, 4, checker.getPlainDiagnosticRenderingContext(flags));
const candidateMarkdown = formatStringFromArgs(unformatted, arguments, 4, checker.getMarkdownDiagnosticRenderingContext(flags));
if (candidateMarkdown !== text) {
markdown = candidateMarkdown;
}
const ctx = checker.getDiagnosticRenderingContext(flags);
text = formatStringFromArgs(text, arguments, 4, ctx);
spans = ctx.getPendingAnnotationSpans();
}

return {
Expand All @@ -7266,7 +7266,7 @@ namespace ts {
code: message.code,

next: details,
...(typeof markdown === "string" ? { markdownText: markdown } : {})
...(typeof spans === "undefined" ? {} : { annotations: spans })
};
}

Expand Down
18 changes: 14 additions & 4 deletions src/server/protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -479,9 +479,19 @@ namespace ts.server.protocol {
reportsUnnecessary?: {};
relatedInformation?: DiagnosticRelatedInformation[];
/**
* Markdown containing variation of the message
* List of spans of the message that have associated information
*/
markdown?: string;
annotations?: DiagnosticAnnotationSpan[];
}

export type DiagnosticAnnotationSpan = DiagnosticSymbolSpan;

export interface DiagnosticSymbolSpan {
kind: "symbol";
start: number;
length: number;
file: string;
location: Location;
}

/**
Expand Down Expand Up @@ -2390,9 +2400,9 @@ namespace ts.server.protocol {
*/
source?: string;
/**
* Markdown containing variation of the message
* List of spans of the message that have associated information
*/
markdown?: string;
annotations?: DiagnosticAnnotationSpan[];
}

export interface DiagnosticWithFileName extends Diagnostic {
Expand Down
Loading

0 comments on commit 8436dd8

Please sign in to comment.