Skip to content

Commit

Permalink
$schema completion
Browse files Browse the repository at this point in the history
Tested on both neovim and vscode
  • Loading branch information
unix-unicorn committed Mar 14, 2024
1 parent 601e256 commit d4a96db
Showing 1 changed file with 81 additions and 12 deletions.
93 changes: 81 additions & 12 deletions language-server/src/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,21 @@ import {
ProposedFeatures,
SemanticTokensBuilder,
TextDocuments,
TextDocumentSyncKind
TextDocumentSyncKind,
CompletionItemKind
} from "vscode-languageserver/node.js";
import { TextDocument } from "vscode-languageserver-textdocument";

// Hyperjump
import { setMetaSchemaOutputFormat, setShouldValidateSchema } from "@hyperjump/json-schema";
import { hasDialect, DETAILED } from "@hyperjump/json-schema/experimental";
import {
setMetaSchemaOutputFormat,
setShouldValidateSchema
} from "@hyperjump/json-schema";
import {
hasDialect,
DETAILED,
getDialectIds
} from "@hyperjump/json-schema/experimental";
import "@hyperjump/json-schema/draft-2020-12";
import "@hyperjump/json-schema/draft-2019-09";
import "@hyperjump/json-schema/draft-07";
Expand All @@ -24,14 +32,21 @@ import "@hyperjump/json-schema/draft-04";
import { decomposeSchemaDocument, validate } from "./json-schema.js";
import { JsoncInstance } from "./jsonc-instance.js";
import { invalidNodes } from "./validation.js";
import { addWorkspaceFolders, workspaceSchemas, removeWorkspaceFolders, watchWorkspace, waitUntil } from "./workspace.js";
import {
addWorkspaceFolders,
workspaceSchemas,
removeWorkspaceFolders,
watchWorkspace,
waitUntil
} from "./workspace.js";
import { getSemanticTokens } from "./semantic-tokens.js";


setMetaSchemaOutputFormat(DETAILED);
setShouldValidateSchema(false);

const isSchema = RegExp.prototype.test.bind(/(?:\.|\/|^)schema\.json$/);
const availableSchemas = getDialectIds();

const connection = createConnection(ProposedFeatures.all);
connection.console.log("Starting JSON Schema service ...");
Expand All @@ -47,7 +62,8 @@ connection.onInitialize(({ capabilities, workspaceFolders }) => {
}

hasWorkspaceFolderCapability = !!capabilities.workspace?.workspaceFolders;
hasWorkspaceWatchCapability = !!capabilities.workspace?.didChangeWatchedFiles?.dynamicRegistration;
hasWorkspaceWatchCapability
= !!capabilities.workspace?.didChangeWatchedFiles?.dynamicRegistration;

const serverCapabilities = {
textDocumentSync: TextDocumentSyncKind.Incremental,
Expand All @@ -57,6 +73,10 @@ connection.onInitialize(({ capabilities, workspaceFolders }) => {
full: {
delta: true
}
},
completionProvider: {
resolveProvider: false,
triggerCharacters: ["\"", ":", " "]
}
};

Expand Down Expand Up @@ -179,17 +199,31 @@ const validateSchema = async (document) => {

const deprecations = annotations.annotatedWith("deprecated");
for (const deprecated of deprecations) {
if (deprecated.annotation("deprecated").some((deprecated) => deprecated)) {
const message = deprecated.annotation("x-deprecationMessage").join("\n") || "deprecated";
diagnostics.push(buildDiagnostic(deprecated.parent(), message, DiagnosticSeverity.Warning, [DiagnosticTag.Deprecated]));
if (
deprecated.annotation("deprecated").some((deprecated) => deprecated)
) {
const message
= deprecated.annotation("x-deprecationMessage").join("\n")
|| "deprecated";
diagnostics.push(buildDiagnostic(
deprecated.parent(),
message,
DiagnosticSeverity.Warning,
[DiagnosticTag.Deprecated]
));
}
}
}

connection.sendDiagnostics({ uri: document.uri, diagnostics });
};

const buildDiagnostic = (instance, message, severity = DiagnosticSeverity.Error, tags = []) => {
const buildDiagnostic = (
instance,
message,
severity = DiagnosticSeverity.Error,
tags = []
) => {
return {
severity: severity,
tags: tags,
Expand Down Expand Up @@ -228,13 +262,13 @@ const buildSemanticTokensLegend = (capability) => {
}

const clientTokenModifiers = new Set(capability.tokenModifiers);
const serverTokenModifiers = [
];
const serverTokenModifiers = [];

const tokenModifiers = [];
for (const tokenModifier of serverTokenModifiers) {
if (clientTokenModifiers.has(tokenModifier)) {
semanticTokensLegend.tokenModifiers[tokenModifier] = tokenModifiers.length;
semanticTokensLegend.tokenModifiers[tokenModifier]
= tokenModifiers.length;
tokenModifiers.push(tokenModifier);
}
}
Expand Down Expand Up @@ -304,4 +338,39 @@ connection.languages.semanticTokens.onDelta(({ textDocument, previousResultId })
return builder.buildEdits();
});

// $SCHEMA COMPLETION
function findPropertyAtPosition(instance, position) {
for (const [key, value] of instance.entries()) {
if (
position.line >= key.startPosition().line
&& position.character >= key.startPosition().character
&& position.line <= value.endPosition().line
&& position.character <= value.endPosition().character
) {
return { key, value };
}
}
return undefined;
}

connection.onCompletion((textDocumentPosition) => {
const doc = documents.get(textDocumentPosition.textDocument.uri);
if (!doc) {
return [];
}
const instance = JsoncInstance.fromTextDocument(doc);
const currentProperty = findPropertyAtPosition(
instance,
textDocumentPosition.position
);

if (currentProperty?.key.value() === "$schema") {
return availableSchemas.map((uri) => {
return {
label: uri,
kind: CompletionItemKind.Keyword
};
});
}
});
documents.listen(connection);

0 comments on commit d4a96db

Please sign in to comment.