Skip to content
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
28 changes: 28 additions & 0 deletions server/src/e2e/tolk/testcases/completion-select/top-level.test
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,31 @@ Static method completion
static<caret>
------------------------------------------------------------------------
fun Foo<caret>.name() {}

========================================================================
Function name completion with only fun
========================================================================
fun onIn<caret>
------------------------------------------------------------------------
fun onInternalMessage(in: InMessage) {<caret>}

========================================================================
Function name completion with all signature
========================================================================
fun ma<caret>(): int {}
------------------------------------------------------------------------
fun main<caret>(): int {}

========================================================================
Method name completion with only fun
========================================================================
fun int.pa<caret>
------------------------------------------------------------------------
fun int.packToBuilder(self, mutate b: builder) {<caret>}

========================================================================
Method name completion with all signature
========================================================================
fun int.pa<caret>() {}
------------------------------------------------------------------------
fun int.packToBuilder<caret>() {}
42 changes: 42 additions & 0 deletions server/src/e2e/tolk/testcases/completion/top-level.test
Original file line number Diff line number Diff line change
Expand Up @@ -261,3 +261,45 @@ fun foo() {
14 var
14 vart
14 while

========================================================================
Function name completion with only fun
========================================================================
fun <caret>
------------------------------------------------------------------------
2 main() {}
2 onBouncedMessage(in: InMessageBounced) {}
2 onExternalMessage(inMsg: slice) {}
2 onInternalMessage(in: InMessage) {}
2 onRunTickTock(isTock: bool) {}
2 onSplitInstall() {}
2 onSplitPrepare() {}

========================================================================
Function name completion with all signature
========================================================================
fun <caret>(): int {}
------------------------------------------------------------------------
2 main()
2 onBouncedMessage(in: InMessageBounced)
2 onExternalMessage(inMsg: slice)
2 onInternalMessage(in: InMessage)
2 onRunTickTock(isTock: bool)
2 onSplitInstall()
2 onSplitPrepare()

========================================================================
Method name completion with only fun
========================================================================
fun int.pa<caret>
------------------------------------------------------------------------
2 packToBuilder(self, mutate b: builder)
2 unpackFromSlice(mutate s: slice) {}

========================================================================
Method name completion with all signature
========================================================================
fun int.pa<caret>() {}
------------------------------------------------------------------------
2 packToBuilder(self, mutate b: builder)
2 unpackFromSlice(mutate s: slice)
18 changes: 18 additions & 0 deletions server/src/languages/tolk/completion/CompletionContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ export class CompletionContext {
public expectMatchArm: boolean = false
public catchVariable: boolean = false
public fieldInit: boolean = false
public isFunctionName: boolean = false
public isMethodName: boolean = false

// struct fields
public inNameOfFieldInit: boolean = false
Expand Down Expand Up @@ -67,6 +69,20 @@ export class CompletionContext {
}
}

if (
parent.type === "function_declaration" &&
parent.childForFieldName("name")?.equals(element.node)
) {
this.isFunctionName = true
}

if (
parent.type === "method_declaration" &&
parent.childForFieldName("name")?.equals(element.node)
) {
this.isMethodName = true
}

if (parent.type === "binary_operator" && parent.parent?.type === "match_arm") {
// match (a) {
// <caret>
Expand Down Expand Up @@ -141,6 +157,8 @@ export class CompletionContext {
!this.structTopLevel &&
!this.expectMatchArm &&
!this.catchVariable &&
!this.isFunctionName &&
!this.isMethodName &&
!this.isAnnotationName
)
}
Expand Down
2 changes: 2 additions & 0 deletions server/src/languages/tolk/completion/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {MatchArmsCompletionProvider} from "@server/languages/tolk/completion/pro
import {CompletionItemAdditionalInformation} from "@server/completion/CompletionItemAdditionalInformation"
import {StorageCompletionProvider} from "@server/languages/tolk/completion/providers/StorageCompletionProvider"
import {FieldInitCompletionProvider} from "@server/languages/tolk/completion/providers/FieldInitCompletionProvider"
import {FunctionNameCompletionProvider} from "@server/languages/tolk/completion/providers/FunctionNameCompletionProvider"

export async function provideTolkCompletion(
file: TolkFile,
Expand Down Expand Up @@ -114,6 +115,7 @@ export async function provideTolkCompletion(
new MatchArmsCompletionProvider(ref),
new StorageCompletionProvider(),
new FieldInitCompletionProvider(),
new FunctionNameCompletionProvider(),
]

for (const provider of providers) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
// SPDX-License-Identifier: MIT
// Copyright © 2025 TON Core
import type {CompletionProvider} from "@server/completion/CompletionProvider"
import {CompletionItemKind, InsertTextFormat} from "vscode-languageserver-types"
import type {CompletionContext} from "@server/languages/tolk/completion/CompletionContext"
import {CompletionResult, CompletionWeight} from "@server/completion/WeightedCompletionItem"

export class FunctionNameCompletionProvider implements CompletionProvider<CompletionContext> {
public isAvailable(ctx: CompletionContext): boolean {
return ctx.isFunctionName || ctx.isMethodName
}

public readonly functions: [string, string][] = [
["onInternalMessage", "in: InMessage"],
["onExternalMessage", "inMsg: slice"],
["onBouncedMessage", "in: InMessageBounced"],
["onRunTickTock", "isTock: bool"],
["onSplitPrepare", ""],
["onSplitInstall", ""],
["main", ""],
]

public addCompletion(ctx: CompletionContext, result: CompletionResult): void {
const definedFunctions = new Set(ctx.element.file.getFunctions().map(it => it.name()))

const fun = ctx.element.node.parent
if (!fun) return

const parameters = fun.childForFieldName("parameters")
const hasBodyAndParams = parameters != null && fun.childForFieldName("body") != null

if (ctx.isFunctionName) {
for (const [fun, signature] of this.functions) {
if (definedFunctions.has(fun)) continue

if (hasBodyAndParams) {
result.add({
label: fun,
labelDetails: {
detail: `(${signature})`,
},
kind: CompletionItemKind.Function,
insertTextFormat: InsertTextFormat.Snippet,
insertText: fun,
weight: CompletionWeight.FUNCTION,
})
} else {
result.add({
label: fun,
labelDetails: {
detail: `(${signature}) {}`,
},
kind: CompletionItemKind.Function,
insertTextFormat: InsertTextFormat.Snippet,
insertText: `${fun}(${signature}) {$0}`,
weight: CompletionWeight.FUNCTION,
})
}
}
}

if (ctx.isMethodName) {
if (hasBodyAndParams) {
result.add({
label: "unpackFromSlice",
labelDetails: {
detail: "(mutate s: slice)",
},
kind: CompletionItemKind.Function,
insertTextFormat: InsertTextFormat.Snippet,
insertText: "unpackFromSlice",
weight: CompletionWeight.FUNCTION,
})
} else {
result.add({
label: "unpackFromSlice",
labelDetails: {
detail: "(mutate s: slice) {}",
},
kind: CompletionItemKind.Function,
insertTextFormat: InsertTextFormat.Snippet,
insertText: "unpackFromSlice(mutate s: slice) {$0}",
weight: CompletionWeight.FUNCTION,
})
}

if (hasBodyAndParams) {
result.add({
label: "packToBuilder",
labelDetails: {
detail: "(self, mutate b: builder)",
},
kind: CompletionItemKind.Function,
insertTextFormat: InsertTextFormat.Snippet,
insertText: "packToBuilder",
weight: CompletionWeight.FUNCTION,
})
} else {
result.add({
label: "packToBuilder",
labelDetails: {
detail: "(self, mutate b: builder)",
},
kind: CompletionItemKind.Function,
insertTextFormat: InsertTextFormat.Snippet,
insertText: "packToBuilder(self, mutate b: builder) {$0}",
weight: CompletionWeight.FUNCTION,
})
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ export class ReferenceCompletionProvider implements CompletionProvider<Completio
!ctx.isAnnotationName &&
!ctx.structTopLevel &&
!ctx.catchVariable &&
!ctx.isFunctionName &&
!ctx.isMethodName &&
!ctx.expectMatchArm
)
}
Expand Down
12 changes: 6 additions & 6 deletions server/src/languages/tolk/tree-sitter-tolk/grammar.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,9 @@ const TOLK_GRAMMAR = {
"fun",
field("name", $.identifier),
optional(field("type_parameters", $.type_parameters)),
field("parameters", $.parameter_list),
optional(field("parameters", $.parameter_list)),
optional(seq(":", field("return_type", optional($._type_hint)))),
$._function_body,
optional($._function_body),
),

method_receiver: $ => seq(field("receiver_type", $._type_hint), "."),
Expand All @@ -139,19 +139,19 @@ const TOLK_GRAMMAR = {
field("receiver", $.method_receiver),
field("name", $.identifier),
optional(field("type_parameters", $.type_parameters)),
field("parameters", $.parameter_list),
optional(field("parameters", $.parameter_list)),
optional(seq(":", field("return_type", optional($._type_hint)))),
$._function_body,
optional($._function_body),
),
get_method_declaration: $ =>
seq(
optional(field("annotations", $.annotation_list)),
"get",
optional("fun"),
field("name", $.identifier),
field("parameters", $.parameter_list),
optional(field("parameters", $.parameter_list)),
optional(seq(":", field("return_type", optional($._type_hint)))),
field("body", $.block_statement),
optional(field("body", $.block_statement)),
),

annotation_list: $ => repeat1($.annotation),
Expand Down
Loading
Loading