Skip to content

Commit 79449e2

Browse files
authored
feat: initial FunC support (#26)
Fixes #27
1 parent a5566ac commit 79449e2

File tree

93 files changed

+30870
-23
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

93 files changed

+30870
-23
lines changed

.gitignore

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@ dist/
77
test-workspace/
88
.vscode-test/
99
*.wasm
10-
!tree-sitter-tolk/tree-sitter-tolk.wasm
11-
!tree-sitter-fift/tree-sitter-fift.wasm
12-
!tree-sitter-tlb/tree-sitter-tlb.wasm
10+
!**/tree-sitter-tolk/tree-sitter-tolk.wasm
11+
!**/tree-sitter-func/tree-sitter-func.wasm
12+
!**/tree-sitter-fift/tree-sitter-fift.wasm
13+
!**/tree-sitter-tlb/tree-sitter-tlb.wasm
1314

1415
# tests
1516
server/src/e2e/out

.vscodeignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
!dist/**/*.wasm
66
!dist/**/*.svg
77
!dist/**/*.tolk
8+
!dist/**/*.fc
89

910
# Include only this files
1011
!LICENSE

README-extension.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,15 @@ Tolk support includes:
3333

3434
FunC support includes:
3535

36-
- Basic syntax highlighting
36+
- Semantic syntax highlighting
37+
- Code completion, imports completion
38+
- Go to definition
39+
- Find all references, workspace symbol search, symbol renaming
40+
- Automatic import updates when renaming and moving files
41+
- Types and documentation on hover
42+
- Inlay hints for method id
43+
- On-the-fly inspections
44+
- Build and test projects based on Blueprint
3745

3846
Fift assembly support includes:
3947

README.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,15 @@ Tolk support includes:
3333

3434
FunC support includes:
3535

36-
- Basic syntax highlighting
36+
- Semantic syntax highlighting
37+
- Code completion, imports completion
38+
- Go to definition
39+
- Find all references, workspace symbol search, symbol renaming
40+
- Automatic import updates when renaming and moving files
41+
- Types and documentation on hover
42+
- Inlay hints for method id
43+
- On-the-fly inspections
44+
- Build and test projects based on Blueprint
3745

3846
Fift assembly support includes:
3947

client/src/extension.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,13 +80,14 @@ async function startServer(context: vscode.ExtensionContext): Promise<vscode.Dis
8080
revealOutputChannelOn: RevealOutputChannelOn.Never,
8181
documentSelector: [
8282
{scheme: "file", language: "tolk"},
83+
{scheme: "file", language: "func"},
8384
{scheme: "file", language: "fift"},
8485
{scheme: "file", language: "tlb"},
8586
{scheme: "untitled", language: "tolk"},
8687
],
8788
synchronize: {
8889
configurationSection: "ton",
89-
fileEvents: vscode.workspace.createFileSystemWatcher("**/*.{tolk,tlb}"),
90+
fileEvents: vscode.workspace.createFileSystemWatcher("**/*.{tolk,fc,func,tlb}"),
9091
},
9192
initializationOptions: {
9293
clientConfig: getClientConfiguration(),
@@ -96,6 +97,10 @@ async function startServer(context: vscode.ExtensionContext): Promise<vscode.Dis
9697
context.extensionUri,
9798
"./dist/tree-sitter-tolk.wasm",
9899
).fsPath,
100+
funcLangWasmUri: vscode_uri.joinPath(
101+
context.extensionUri,
102+
"./dist/tree-sitter-func.wasm",
103+
).fsPath,
99104
fiftLangWasmUri: vscode_uri.joinPath(
100105
context.extensionUri,
101106
"./dist/tree-sitter-fift.wasm",

client/src/languages/func-language-configuration.json

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,14 @@
2525
"increaseIndentPattern": "^(.*\\{[^}\"']*|.*\\([^\\)\"']*|.*\\[[^\\]\"']*)$",
2626
"decreaseIndentPattern": "^\\s*[\\}\\]\\)]"
2727
},
28-
"wordPattern": "`[^`]+`|[A-Za-z_$][^\\s+\\-*\\/%,.;(){}\\[\\]=<>|\\^~]*"
28+
"wordPattern": "`[^`]+`|[A-Za-z_$:][^\\s+\\-*\\/%,.;(){}\\[\\]=<>|\\^~]*",
29+
"onEnterRules": [
30+
{
31+
"beforeText": "^\\s*;;;.*$",
32+
"action": {
33+
"indent": "none",
34+
"appendText": ";;; "
35+
}
36+
}
37+
]
2938
}

eslint.config.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export default tseslint.config(
3030
"server/src/languages/tolk/tree-sitter-tolk/",
3131
"server/src/languages/fift/tree-sitter-fift/",
3232
"server/src/languages/tolk/tree-sitter-tolk/",
33+
"server/src/languages/func/tree-sitter-func/",
3334
"server/src/languages/tlb/tree-sitter-tlb/",
3435
],
3536
},

package.json

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
"fmt:check": "prettier --check --cache .",
4444
"grammar:wasm": "yarn grammar:tolk:wasm && yarn grammar:fift:wasm && yarn grammar:tlb:wasm",
4545
"grammar:tolk:wasm": "cd server/src/languages/tolk/tree-sitter-tolk && tree-sitter generate && tree-sitter build --wasm",
46+
"grammar:func:wasm": "cd server/src/languages/func/tree-sitter-func && tree-sitter generate && tree-sitter build --wasm",
4647
"grammar:fift:wasm": "cd server/src/languages/fift/tree-sitter-fift && tree-sitter generate && tree-sitter build --wasm",
4748
"grammar:tlb:wasm": "cd server/src/languages/tlb/tree-sitter-tlb && tree-sitter generate && tree-sitter build --wasm",
4849
"watch": "webpack --watch",
@@ -363,7 +364,17 @@
363364
"ton.tolk.hints.showMethodId": {
364365
"type": "boolean",
365366
"default": true,
366-
"description": "Show method ID hints for contract functions"
367+
"description": "Show method ID hints for get methods"
368+
},
369+
"ton.func.hints.disable": {
370+
"type": "boolean",
371+
"default": false,
372+
"description": "Disable all inlay hints for FunC"
373+
},
374+
"ton.func.hints.showMethodId": {
375+
"type": "boolean",
376+
"default": true,
377+
"description": "Show method ID hints for functions with method_id"
367378
}
368379
}
369380
},
@@ -404,6 +415,20 @@
404415
"type-compatibility"
405416
],
406417
"description": "List of disabled code inspections. All inspections are enabled by default."
418+
},
419+
"ton.func.inspections.disabled": {
420+
"type": "array",
421+
"items": {
422+
"type": "string",
423+
"enum": [
424+
"unused-parameter",
425+
"unused-type-parameter",
426+
"unused-variable",
427+
"unused-import"
428+
]
429+
},
430+
"default": [],
431+
"description": "List of disabled code inspections for FunC. All inspections are enabled by default."
407432
}
408433
}
409434
},

server/src/files.ts

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
import * as lsp from "vscode-languageserver"
22
import {TextDocument} from "vscode-languageserver-textdocument"
33
import {pathToFileURL} from "node:url"
4-
import {createFiftParser, createTlbParser, createTolkParser} from "@server/parser"
4+
import {createFiftParser, createFuncParser, createTlbParser, createTolkParser} from "@server/parser"
55
import {readFileVFS, globalVFS} from "@server/vfs/files-adapter"
66
import {FiftFile} from "@server/languages/fift/psi/FiftFile"
77
import {TlbFile} from "@server/languages/tlb/psi/TlbFile"
88
import {URI} from "vscode-uri"
99
import {TolkFile} from "@server/languages/tolk/psi/TolkFile"
1010
import {measureTime} from "@server/psi/utils"
11+
import {FuncFile} from "@server/languages/func/psi/FuncFile"
1112

1213
export const TOLK_PARSED_FILES_CACHE: Map<string, TolkFile> = new Map()
14+
export const FUNC_PARSED_FILES_CACHE: Map<string, FuncFile> = new Map()
1315
export const FIFT_PARSED_FILES_CACHE: Map<string, FiftFile> = new Map()
1416
export const TLB_PARSED_FILES_CACHE: Map<string, TlbFile> = new Map()
1517

@@ -41,6 +43,34 @@ export function reparseTolkFile(uri: string, content: string): TolkFile {
4143
return file
4244
}
4345

46+
export async function findFuncFile(uri: string, changed: boolean = false): Promise<FuncFile> {
47+
const cached = FUNC_PARSED_FILES_CACHE.get(uri)
48+
if (cached !== undefined && !changed) {
49+
return cached
50+
}
51+
52+
const rawContent = await readOrUndefined(uri)
53+
if (rawContent === undefined) {
54+
console.error(`cannot read ${uri} file`)
55+
}
56+
57+
const content = rawContent ?? ""
58+
return measureTime(`reparse ${uri}`, () => reparseFuncFile(uri, content))
59+
}
60+
61+
export function reparseFuncFile(uri: string, content: string): FuncFile {
62+
const parser = createFuncParser()
63+
const tree = parser.parse(content)
64+
if (!tree) {
65+
throw new Error(`FATAL ERROR: cannot parse ${uri} file`)
66+
}
67+
68+
// TODO: why we have %40 here?
69+
const file = new FuncFile(uri.replace("%40", "@"), tree, content)
70+
FUNC_PARSED_FILES_CACHE.set(uri, file)
71+
return file
72+
}
73+
4474
export async function findFiftFile(uri: string): Promise<FiftFile> {
4575
const cached = FIFT_PARSED_FILES_CACHE.get(uri)
4676
if (cached !== undefined) {
@@ -108,6 +138,11 @@ export const isTolkFile = (
108138
event?: lsp.TextDocumentChangeEvent<TextDocument>,
109139
): boolean => event?.document.languageId === "tolk" || uri.endsWith(".tolk")
110140

141+
export const isFuncFile = (
142+
uri: string,
143+
event?: lsp.TextDocumentChangeEvent<TextDocument>,
144+
): boolean => event?.document.languageId === "func" || uri.endsWith(".fc") || uri.endsWith(".func")
145+
111146
export const isFiftFile = (
112147
uri: string,
113148
event?: lsp.TextDocumentChangeEvent<TextDocument>,

server/src/func-indexing-root.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// SPDX-License-Identifier: MIT
2+
// Copyright © 2025 TON Studio
3+
import * as path from "node:path"
4+
import {glob} from "glob"
5+
import {index} from "@server/languages/func/indexes"
6+
import {fileURLToPath} from "node:url"
7+
import {filePathToUri, findFuncFile} from "@server/files"
8+
9+
export enum FuncIndexingRootKind {
10+
Stdlib = "stdlib",
11+
Workspace = "workspace",
12+
}
13+
14+
export class FuncIndexingRoot {
15+
public constructor(
16+
public root: string,
17+
public kind: FuncIndexingRootKind,
18+
) {}
19+
20+
public async index(): Promise<void> {
21+
const ignore =
22+
this.kind === FuncIndexingRootKind.Stdlib
23+
? []
24+
: [
25+
".git/**",
26+
"allure-results/**",
27+
"**/node_modules/**",
28+
"**/dist/**",
29+
"**/__testdata/**",
30+
]
31+
32+
const rootDir = fileURLToPath(this.root)
33+
const files = await glob("**/*.{fc,func}", {
34+
cwd: rootDir,
35+
ignore: ignore,
36+
})
37+
if (files.length === 0) {
38+
console.warn(`No file to index in ${this.root}`)
39+
}
40+
for (const filePath of files) {
41+
console.info("Indexing:", filePath)
42+
const absPath = path.join(rootDir, filePath)
43+
const uri = filePathToUri(absPath)
44+
const file = await findFuncFile(uri)
45+
index.addFile(uri, file, false)
46+
}
47+
}
48+
}

0 commit comments

Comments
 (0)