-
Beta Was this translation helpful? Give feedback.
Answered by
MechMel
Feb 18, 2023
Replies: 1 comment 1 reply
-
Alright, I figured it out. This seems to be a VsCode specific feature, so it has to happen on the client. However, all the information we need is on the server. So what we do is, after the documents have been validated, send a message to the client with the positions of all the decorations to apply. mynx-decorator.ts:import { DocumentState, LangiumSharedServices, streamAst } from "langium";
import { exists } from "../utils";
import { inferType } from "./type-system/infer-type";
import { MynxType } from "./type-system/mynx-type";
import { isCodeBlockExpr, Model } from "./generated/ast";
import { DiagnosticSeverity, Position } from "vscode-languageserver";
export function attachDecorator(services: LangiumSharedServices) {
services.workspace.DocumentBuilder.onBuildPhase(
DocumentState.Validated,
(documents, cancellationToken) => {
/** This holds the information we will pass to the client. */
const returnsToDecorate: { [fsPath: string]: Position[] } = {};
/** I don't know which document is open, so currently I just go through all
* of them. There is probably a much better way to do this. */
for (const doc of documents) {
// Stop transpile on cancellation
if (cancellationToken.isCancellationRequested) return;
const documentHasErrors =
doc.diagnostics?.filter(
(e) => e.severity === DiagnosticSeverity.Error,
).length ?? 0 > 0;
if (!documentHasErrors) {
try {
const model = doc.parseResult?.value as Model;
streamAst(model).forEach((node) => {
if (isCodeBlockExpr(node)) {
if (
node.statements.length > 1 &&
inferType(node) !== MynxType.void
) {
const position =
node.statements[node.statements.length - 1].$cstNode?.range
.start;
if (exists(position)) {
const docPath = doc.uri.fsPath;
if (!exists(returnsToDecorate[docPath])) {
returnsToDecorate[docPath] = [];
}
returnsToDecorate[docPath].push(position);
}
}
}
});
} catch (e) {
console.error(e);
}
}
}
/** The client has to be the one to do the decorating. */
services.lsp.Connection?.sendNotification("mynx/decorate", {
returnsToDecorate,
});
},
);
} extension.ts: // Start the client. This will also launch the server
client.start().then(() => {
const decorationType = vscode.window.createTextEditorDecorationType({
before: {
color: "#999999",
margin: "0 0.145rem 0 0.34rem",
contentText: `>`,
},
rangeBehavior: vscode.DecorationRangeBehavior.ClosedOpen,
});
/** Listen to our custom notification from the server. */
client.onNotification("mynx/decorate", (params) => {
const editor = vscode.window.activeTextEditor;
if (!editor || !editor.document) return;
const filePath = editor.document.uri.fsPath;
const positions = params.returnsToDecorate[filePath];
if (exists(positions)) {
const decorations = positions.map((position: any) => ({
range: new vscode.Range(
new vscode.Position(position.line, position.character),
new vscode.Position(position.line, position.character),
),
hoverMessage: new vscode.MarkdownString(`Returns here.`),
}));
/** This is where the magic happens. */
editor.setDecorations(decorationType, decorations);
}
});
}); mynx-module.ts:export function createMynxServices(context: DefaultSharedModuleContext): {
shared: LangiumSharedServices;
Mynx: MynxServices;
} {
const shared = inject(
createDefaultSharedModule(context),
MynxGeneratedSharedModule,
);
const Mynx = inject(
createDefaultModule({ shared }),
MynxGeneratedModule,
MynxModule,
);
attachAutoTranspiler(shared);
/** Attatch our decorator here. */
attachDecorator(shared);
shared.ServiceRegistry.register(Mynx);
return { shared, Mynx };
} |
Beta Was this translation helpful? Give feedback.
1 reply
Answer selected by
MechMel
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Alright, I figured it out.
This seems to be a VsCode specific feature, so it has to happen on the client. However, all the information we need is on the server. So what we do is, after the documents have been validated, send a message to the client with the positions of all the decorations to apply.
mynx-decorator.ts: