Skip to content

Commit

Permalink
feat: Add first signature help derivation
Browse files Browse the repository at this point in the history
  • Loading branch information
famoser committed Feb 10, 2024
1 parent 8c7b9a7 commit 4e53f1e
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 0 deletions.
18 changes: 18 additions & 0 deletions server/src/parseTree/get_terminal_before_position.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import {ParseTree, TerminalNode} from "antlr4ts/tree";
import {Position} from "vscode-languageserver";
import {TokenStream} from "antlr4ts/TokenStream";
import {Token} from "antlr4ts";

export const getPositionOfTokenBefore = (tokens: TokenStream, position: Position): Position | undefined => {
let lastToken: Token|undefined = undefined

Check failure on line 7 in server/src/parseTree/get_terminal_before_position.ts

View workflow job for this annotation

GitHub Actions / Node

Missing semicolon
for (let i = 0; i < tokens.size; i++) {
const token = tokens.get(i) // lookup seems to be O(1)

Check failure on line 9 in server/src/parseTree/get_terminal_before_position.ts

View workflow job for this annotation

GitHub Actions / Node

Missing semicolon
if (token.line >= position.line + 1 && token.charPositionInLine >= position.character) {
break

Check failure on line 11 in server/src/parseTree/get_terminal_before_position.ts

View workflow job for this annotation

GitHub Actions / Node

Missing semicolon
}

lastToken = token;
}

return lastToken ? Position.create(lastToken.line-1, lastToken.charPositionInLine) : undefined

Check failure on line 17 in server/src/parseTree/get_terminal_before_position.ts

View workflow job for this annotation

GitHub Actions / Node

Missing semicolon
}

Check failure on line 18 in server/src/parseTree/get_terminal_before_position.ts

View workflow job for this annotation

GitHub Actions / Node

Missing semicolon
13 changes: 13 additions & 0 deletions server/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {rename} from "./rename";
import {getReferences} from "./references";
import {getSemanticTokens} from './semantic_token_provider';
import {getDocumentLinks} from "./document_links";
import {getSignatureHelp} from "./signature_help";

const connection = createConnection(ProposedFeatures.all);
const documents: TextDocuments<TextDocument> = new TextDocuments(TextDocument);
Expand Down Expand Up @@ -42,6 +43,7 @@ connection.onInitialize((params: InitializeParams) => {
documentLinkProvider: {},
referencesProvider: {},
renameProvider: { },
signatureHelpProvider: { triggerCharacters: ['('], retriggerCharacters: [',', ', '] }
/**
semanticTokensProvider: {
documentSelector: null, // use client-side definition
Expand Down Expand Up @@ -93,6 +95,17 @@ connection.onDocumentLinks(async params => {
return await getDocumentLinks(parseResult);
});

connection.onSignatureHelp(async params => {
console.log("calling", params)

Check failure on line 99 in server/src/server.ts

View workflow job for this annotation

GitHub Actions / Node

Missing semicolon
const signatureHelp = await getSignatureHelp(params.textDocument, params.position, documentManager)

Check failure on line 100 in server/src/server.ts

View workflow job for this annotation

GitHub Actions / Node

Missing semicolon
if (!signatureHelp) {
console.log("not found")

Check failure on line 102 in server/src/server.ts

View workflow job for this annotation

GitHub Actions / Node

Missing semicolon
return undefined

Check failure on line 103 in server/src/server.ts

View workflow job for this annotation

GitHub Actions / Node

Missing semicolon
}

return signatureHelp

Check failure on line 106 in server/src/server.ts

View workflow job for this annotation

GitHub Actions / Node

Missing semicolon
})

connection.languages.semanticTokens.on(async params => {
const parseResult = await documentManager.getParseResult(params.textDocument);
if (!parseResult) {
Expand Down
31 changes: 31 additions & 0 deletions server/src/signature_help.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import {
ParameterInformation,
Position,
SignatureHelp,
SignatureInformation,
TextDocumentIdentifier
} from "vscode-languageserver";
import {DocumentManagerInterface} from "./document_manager";
import {getDefinitionSymbolFromPosition} from "./go_to_definition";
import {getPositionOfTokenBefore} from "./parseTree/get_terminal_before_position";

export const getSignatureHelp = async (identifier: TextDocumentIdentifier, position: Position, documentManager: DocumentManagerInterface): Promise<SignatureHelp | undefined> => {
const parseResult = await documentManager.getParseResult(identifier);
if (!parseResult) {
return undefined;
}

const positionOfTokenBefore = getPositionOfTokenBefore(parseResult.parser.inputStream, position);
if (!positionOfTokenBefore) {
return undefined;
}

const definitionSymbol = await getDefinitionSymbolFromPosition(identifier, positionOfTokenBefore, documentManager);
if (!definitionSymbol) {
return undefined;
}

const parameters: ParameterInformation[] = (definitionSymbol.symbol.parameters ?? []).map(parameter => ({ label: parameter?.text ?? "" }))
const signature: SignatureInformation = { label: definitionSymbol.symbol.node.text, parameters, activeParameter: 0 }
return { signatures: [signature], activeSignature: 0, activeParameter: 0 }
}
36 changes: 36 additions & 0 deletions server/tests/signature_help.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import {assert, expect} from "chai";

import {Location, Position, Range} from "vscode-languageserver";
import {MockDocumentManager} from "./mocks/mock_document_manager";
import {getReferences} from "../src/references";
import {getSignatureHelp} from "../src/signature_help";

describe('references', function () {
const assertSignatureDefinitionFound = async (code: string, signatureInvoked: Position, parameters: string[], activeParameter: number) => {
const uri = 'main.pv';

const documentManager = new MockDocumentManager();
documentManager.parse(uri, code);
const signatureHelp = await getSignatureHelp({uri}, signatureInvoked, documentManager);

assert.isDefined(signatureHelp);
if (!signatureHelp) {
return;
}

expect(signatureHelp.signatures.length).to.equal(1)
const signature = signatureHelp.signatures[0]

expect(signature.parameters.length).to.equal(parameters.length);
expect(signature.parameters.map(parameter => parameter.label)).deep.equal(parameters);

expect(signature.activeParameter).to.equal(activeParameter);
};

it("finds table signature definition", async () => {
const code = `table Ids(nat).\nprocess \nget Ids(`;
const signatureInvoked = {line: 2, character: 8};

await assertSignatureDefinitionFound(code, signatureInvoked, ['nat'], 0);
});
});

0 comments on commit 4e53f1e

Please sign in to comment.