Skip to content
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

Add hover syntax highlighting for types #2065

Merged
merged 1 commit into from
Dec 1, 2021
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
7 changes: 7 additions & 0 deletions .changeset/real-boxes-clap.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'graphql-language-service': patch
'graphql-language-service-interface': patch
'graphql-language-service-server': patch
---

Add an opt-in feature to generate markdown in hover elements, starting with highlighting type information. Enabled for the language server and also the language service and thus `monaco-graphql` as well.
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import {

import { Kind, parse, print } from 'graphql';
import { getAutocompleteSuggestions } from './getAutocompleteSuggestions';
import { getHoverInformation } from './getHoverInformation';
import { getHoverInformation, HoverConfig } from './getHoverInformation';
import { validateQuery, getRange, DIAGNOSTIC_SEVERITY } from './getDiagnostics';
import {
getDefinitionQueryResultForFragmentSpread,
Expand Down Expand Up @@ -250,12 +250,13 @@ export class GraphQLLanguageService {
query: string,
position: IPosition,
filePath: Uri,
options?: HoverConfig,
): Promise<Hover['contents']> {
const projectConfig = this.getConfigForURI(filePath);
const schema = await this._graphQLCache.getSchema(projectConfig.name);

if (schema) {
return getHoverInformation(schema, query, position);
return getHoverInformation(schema, query, position, undefined, options);
}
return '';
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,14 @@ import { AllTypeInfo, IPosition } from 'graphql-language-service-types';
import { Hover } from 'vscode-languageserver-types';
import { getTokenAtPosition, getTypeInfo } from './getAutocompleteSuggestions';

export type HoverConfig = { useMarkdown?: boolean };

export function getHoverInformation(
schema: GraphQLSchema,
queryText: string,
cursor: IPosition,
contextToken?: ContextToken,
config?: HoverConfig,
): Hover['contents'] {
const token = contextToken || getTokenAtPosition(queryText, cursor);

Expand All @@ -42,7 +45,7 @@ export function getHoverInformation(
const kind = state.kind;
const step = state.step;
const typeInfo = getTypeInfo(schema, token.state);
const options = { schema };
const options = { ...config, schema };

// Given a Schema and a Token, produce the contents of an info tooltip.
// To do this, create a div element that we will render "into" and then pass
Expand All @@ -52,17 +55,23 @@ export function getHoverInformation(
(kind === 'AliasedField' && step === 2 && typeInfo.fieldDef)
) {
const into: string[] = [];
renderMdCodeStart(into, options);
renderField(into, typeInfo, options);
renderMdCodeEnd(into, options);
renderDescription(into, options, typeInfo.fieldDef);
return into.join('').trim();
} else if (kind === 'Directive' && step === 1 && typeInfo.directiveDef) {
const into: string[] = [];
renderMdCodeStart(into, options);
renderDirective(into, typeInfo, options);
renderMdCodeEnd(into, options);
renderDescription(into, options, typeInfo.directiveDef);
return into.join('').trim();
} else if (kind === 'Argument' && step === 0 && typeInfo.argDef) {
const into: string[] = [];
renderMdCodeStart(into, options);
renderArg(into, typeInfo, options);
renderMdCodeEnd(into, options);
renderDescription(into, options, typeInfo.argDef);
return into.join('').trim();
} else if (
Expand All @@ -71,7 +80,9 @@ export function getHoverInformation(
'description' in typeInfo.enumValue
) {
const into: string[] = [];
renderMdCodeStart(into, options);
renderEnumValue(into, typeInfo, options);
renderMdCodeEnd(into, options);
renderDescription(into, options, typeInfo.enumValue);
return into.join('').trim();
} else if (
Expand All @@ -80,13 +91,26 @@ export function getHoverInformation(
'description' in typeInfo.type
) {
const into: string[] = [];
renderMdCodeStart(into, options);
renderType(into, typeInfo, options, typeInfo.type);
renderMdCodeEnd(into, options);
renderDescription(into, options, typeInfo.type);
return into.join('').trim();
}
return '';
}

function renderMdCodeStart(into: string[], options: any) {
if (options.useMarkdown) {
text(into, '```graphql\n');
}
}
function renderMdCodeEnd(into: string[], options: any) {
if (options.useMarkdown) {
text(into, '\n```');
}
}

function renderField(into: string[], typeInfo: AllTypeInfo, options: any) {
renderQualifiedField(into, typeInfo, options);
renderTypeAnnotation(into, typeInfo, options, typeInfo.type as GraphQLType);
Expand Down Expand Up @@ -168,6 +192,7 @@ function renderType(
if (!t) {
return;
}

if (t instanceof GraphQLNonNull) {
renderType(into, typeInfo, options, t.ofType);
text(into, '!');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,7 @@ export class MessageProcessor {
query,
toPosition(position),
textDocument.uri,
{ useMarkdown: true },
);

return {
Expand Down
4 changes: 4 additions & 0 deletions packages/graphql-language-service/src/LanguageService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
SchemaResponse,
defaultSchemaBuilder,
} from './schemaLoader';
import { HoverConfig } from 'graphql-language-service-interface/src/getHoverInformation';

export type GraphQLLanguageConfig = {
parser?: typeof parse;
Expand Down Expand Up @@ -203,10 +204,13 @@ export class LanguageService {
_uri: string,
documentText: string,
position: IPosition,
options?: HoverConfig,
) =>
getHoverInformation(
(await this.getSchema()) as GraphQLSchema,
documentText,
position,
undefined,
{ useMarkdown: true, ...options },
);
}