Skip to content

Commit

Permalink
Update hover to not use deprecated MarkedString
Browse files Browse the repository at this point in the history
  • Loading branch information
apexskier committed Oct 1, 2020
1 parent 9ac8f6e commit 33577eb
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 43 deletions.
6 changes: 3 additions & 3 deletions src/jsonContributions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Thenable, MarkedString, CompletionItem } from './jsonLanguageService';
import { Thenable, CompletionItem, Hover } from './jsonLanguageService';

export interface JSONWorkerContribution {
getInfoContribution(uri: string, location: JSONPath): Thenable<MarkedString[]>;
getInfoContribution(uri: string, location: JSONPath): Thenable<Hover["contents"]>;
collectPropertyCompletions(uri: string, location: JSONPath, currentWord: string, addValue: boolean, isLast: boolean, result: CompletionsCollector): Thenable<any>;
collectValueCompletions(uri: string, location: JSONPath, propertyKey: string, result: CompletionsCollector): Thenable<any>;
collectDefaultCompletions(uri: string, result: CompletionsCollector): Thenable<any>;
Expand All @@ -20,4 +20,4 @@ export interface CompletionsCollector {
log(message: string): void;
setAsIncomplete(): void;
getNumberOfProposals(): number;
}
}
61 changes: 36 additions & 25 deletions src/services/jsonHover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import * as Parser from '../parser/jsonParser';
import * as SchemaService from './jsonSchemaService';
import { JSONWorkerContribution } from '../jsonContributions';
import { TextDocument, PromiseConstructor, Thenable, Position, Range, Hover, MarkedString } from '../jsonLanguageTypes';
import { TextDocument, PromiseConstructor, Thenable, Position, Range, Hover, MarkupContent, MarkupKind } from '../jsonLanguageTypes';

export class JSONHover {

Expand Down Expand Up @@ -42,9 +42,9 @@ export class JSONHover {

const hoverRange = Range.create(document.positionAt(hoverRangeNode.offset), document.positionAt(hoverRangeNode.offset + hoverRangeNode.length));

var createHover = (contents: MarkedString[]) => {
var createHover = (contents: Hover["contents"]) => {
const result: Hover = {
contents: contents,
contents,
range: hoverRange
};
return result;
Expand All @@ -54,30 +54,38 @@ export class JSONHover {
for (let i = this.contributions.length - 1; i >= 0; i--) {
const contribution = this.contributions[i];
const promise = contribution.getInfoContribution(document.uri, location);
if (promise) {
return promise.then(htmlContent => createHover(htmlContent));
}
return promise?.then(htmlContent => createHover(htmlContent));
}

return this.schemaService.getSchemaForResource(document.uri, doc).then((schema) => {
if (schema && node) {
const matchingSchemas = doc.getMatchingSchemas(schema.schema, node.offset);

let markdownFormat: boolean = false;
let title: string | undefined = undefined;
let markdownDescription: string | undefined = undefined;
let markdownEnumValueDescription: string | undefined = undefined, enumValue: string | undefined = undefined;
let description: string | undefined = undefined;
let enumValueDescription: string | undefined = undefined, enumValue: string | undefined = undefined;
matchingSchemas.every((s) => {
if (s.node === node && !s.inverted && s.schema) {
title = title || s.schema.title;
markdownDescription = markdownDescription || s.schema.markdownDescription || toMarkdown(s.schema.description);
if (!description) {
if (s.schema.markdownDescription) {
markdownFormat = true;
description = s.schema.markdownDescription;
} else {
description = s.schema.description;
}
}
if (s.schema.enum) {
const idx = s.schema.enum.indexOf(Parser.getNodeValue(node));
if (s.schema.markdownEnumDescriptions) {
markdownEnumValueDescription = s.schema.markdownEnumDescriptions[idx];
enumValueDescription = s.schema.markdownEnumDescriptions[idx];
} else if (s.schema.enumDescriptions) {
markdownEnumValueDescription = toMarkdown(s.schema.enumDescriptions[idx]);
enumValueDescription = s.schema.enumDescriptions[idx];
}
if (markdownEnumValueDescription) {
if (enumValueDescription) {
// enums values are always wrapped as code blocks, so they'll always be presented as markdown
markdownFormat = true;
enumValue = s.schema.enum[idx];
if (typeof enumValue !== 'string') {
enumValue = JSON.stringify(enumValue);
Expand All @@ -87,23 +95,26 @@ export class JSONHover {
}
return true;
});
let result = '';
const result: MarkupContent = {
kind: markdownFormat ? MarkupKind.Markdown : MarkupKind.PlainText,
value: '',
};
if (title) {
result = toMarkdown(title);
result.value += markdownFormat ? toMarkdown(title) : title;
}
if (markdownDescription) {
if (result.length > 0) {
result += "\n\n";
if (description) {
if (result.value.length > 0) {
result.value += "\n\n";
}
result += markdownDescription;
result.value += description;
}
if (markdownEnumValueDescription) {
if (result.length > 0) {
result += "\n\n";
if (enumValueDescription) {
if (result.value.length > 0) {
result.value += "\n\n";
}
result += `\`${toMarkdownCodeBlock(enumValue!)}\`: ${markdownEnumValueDescription}`;
result.value += `\`${toMarkdownCodeBlock(enumValue!)}\`: ${enumValueDescription}`;
}
return createHover([result]);
return createHover(result);
}
return null;
});
Expand All @@ -121,8 +132,8 @@ function toMarkdown(plain: string | undefined): string | undefined {

function toMarkdownCodeBlock(content: string) {
// see https://daringfireball.net/projects/markdown/syntax#precode
if (content.indexOf('`') !== -1) {
if (content.includes('`')) {
return '`` ' + content + ' ``';
}
return content;
}
}
53 changes: 38 additions & 15 deletions src/test/hover.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import * as JsonSchema from '../jsonSchema';
import { JSONHover } from '../services/jsonHover';

import { Hover, Position, MarkedString, TextDocument } from '../jsonLanguageService';
import { MarkupKind } from "../jsonLanguageTypes";

suite('JSON Hover', () => {

Expand Down Expand Up @@ -52,16 +53,16 @@ suite('JSON Hover', () => {
}
};
await testComputeInfo(content, schema, { line: 0, character: 0 }).then((result) => {
assert.deepEqual(result.contents, [MarkedString.fromPlainText('a very special object')]);
assert.deepEqual(result.contents, { kind: MarkupKind.PlainText, value: MarkedString.fromPlainText('a very special object') });
});
await testComputeInfo(content, schema, { line: 0, character: 1 }).then((result) => {
assert.deepEqual(result.contents, [MarkedString.fromPlainText('A')]);
assert.deepEqual(result.contents, { kind: MarkupKind.PlainText, value: MarkedString.fromPlainText('A') });
});
await testComputeInfo(content, schema, { line: 0, character: 32 }).then((result) => {
assert.deepEqual(result.contents, [MarkedString.fromPlainText('C')]);
assert.deepEqual(result.contents, { kind: MarkupKind.PlainText, value: MarkedString.fromPlainText('C') });
});
await testComputeInfo(content, schema, { line: 0, character: 7 }).then((result) => {
assert.deepEqual(result.contents, [MarkedString.fromPlainText('A')]);
assert.deepEqual(result.contents, { kind: MarkupKind.PlainText, value: MarkedString.fromPlainText('A') });
});
});

Expand All @@ -88,13 +89,13 @@ suite('JSON Hover', () => {
}]
};
await testComputeInfo(content, schema, { line: 0, character: 0 }).then((result) => {
assert.deepEqual(result.contents, [MarkedString.fromPlainText('a very special object')]);
assert.deepEqual(result.contents, { kind: MarkupKind.PlainText, value: MarkedString.fromPlainText('a very special object') });
});
await testComputeInfo(content, schema, { line: 0, character: 1 }).then((result) => {
assert.deepEqual(result.contents, [MarkedString.fromPlainText('A')]);
assert.deepEqual(result.contents, { kind: MarkupKind.PlainText, value: MarkedString.fromPlainText('A') });
});
await testComputeInfo(content, schema, { line: 0, character: 10 }).then((result) => {
assert.deepEqual(result.contents, [MarkedString.fromPlainText('B\n\nIt\'s B')]);
assert.deepEqual(result.contents, { kind: MarkupKind.PlainText, value: MarkedString.fromPlainText('B\n\nIt\'s B') });
});
});

Expand Down Expand Up @@ -123,19 +124,19 @@ suite('JSON Hover', () => {
};

await testComputeInfo('{ "prop1": "e1', schema, { line: 0, character: 12 }).then(result => {
assert.deepEqual(result.contents, ['prop1\n\n`e1`: E1']);
assert.deepEqual(result.contents, { kind: MarkupKind.Markdown, value: 'prop1\n\n`e1`: E1' });
});
await testComputeInfo('{ "prop2": null', schema, { line: 0, character: 12 }).then(result => {
assert.deepEqual(result.contents, ['prop2\n\n`null`: null']);
assert.deepEqual(result.contents, { kind: MarkupKind.Markdown, value: 'prop2\n\n`null`: null' });
});
await testComputeInfo('{ "prop2": 1', schema, { line: 0, character: 11 }).then(result => {
assert.deepEqual(result.contents, ['prop2\n\n`1`: one']);
assert.deepEqual(result.contents, { kind: MarkupKind.Markdown, value: 'prop2\n\n`1`: one' });
});
await testComputeInfo('{ "prop2": false', schema, { line: 0, character: 12 }).then(result => {
assert.deepEqual(result.contents, ['prop2\n\n`false`: wrong']);
assert.deepEqual(result.contents, { kind: MarkupKind.Markdown, value: 'prop2\n\n`false`: wrong' });
});
await testComputeInfo('{ "prop3": null', schema, { line: 0, character: 12 }).then(result => {
assert.deepEqual(result.contents, ['title\n\n*prop3*\n\n`null`: Set to `null`']);
assert.deepEqual(result.contents, { kind: MarkupKind.Markdown, value: 'title\n\n*prop3*\n\n`null`: Set to `null`' });
});
});

Expand All @@ -153,10 +154,32 @@ suite('JSON Hover', () => {
};

await testComputeInfo('{ "prop1": "e1', schema, { line: 0, character: 12 }).then(result => {
assert.deepEqual(result.contents, ['line1\n\nline2\n\nline3\n\n\nline4\n']);
assert.deepEqual(result.contents, { kind: MarkupKind.PlainText, value: 'line1\nline2\n\nline3\n\n\nline4\n' });
});
await testComputeInfo('{ "prop2": "e1', schema, { line: 0, character: 12 }).then(result => {
assert.deepEqual(result.contents, ['line1\n\nline2\r\n\r\nline3']);
assert.deepEqual(result.contents, { kind: MarkupKind.PlainText, value: 'line1\r\nline2\r\n\r\nline3' });
});
});
});

test('Markdown descriptions', async function () {
const schema: JsonSchema.JSONSchema = {
type: 'object',
properties: {
'prop1': {
markdownDescription: "line1\nline2\n\n`line3`\n\n\nline4\n",
},
'prop2': {
title: `Title with *markdown* characters`,
markdownDescription: "line1\r\n*line2*\r\n\r\n`line3`",
}
}
};

await testComputeInfo('{ "prop1": "e1', schema, { line: 0, character: 12 }).then(result => {
assert.deepEqual(result.contents, { kind: MarkupKind.Markdown, value: 'line1\nline2\n\n`line3`\n\n\nline4\n' });
});
await testComputeInfo('{ "prop2": "e1', schema, { line: 0, character: 12 }).then(result => {
assert.deepEqual(result.contents, { kind: MarkupKind.Markdown, value: 'Title with \\*markdown\\* characters\n\nline1\r\n*line2*\r\n\r\n`line3`' });
});
});
});

0 comments on commit 33577eb

Please sign in to comment.