Skip to content

Commit 2b6f5f1

Browse files
authored
refactor(server): extract common language parts (#39)
1 parent 278ba22 commit 2b6f5f1

File tree

65 files changed

+524
-1066
lines changed

Some content is hidden

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

65 files changed

+524
-1066
lines changed

server/src/cache/cache.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
export class Cache<TKey, TValue> {
2+
private readonly data: Map<TKey, TValue>
3+
4+
public constructor() {
5+
this.data = new Map()
6+
}
7+
8+
public cached(key: TKey, cb: () => TValue): TValue {
9+
const cached = this.data.get(key)
10+
if (cached !== undefined) {
11+
return cached
12+
}
13+
14+
const value = cb()
15+
this.data.set(key, value)
16+
return value
17+
}
18+
19+
public clear(): void {
20+
this.data.clear()
21+
}
22+
23+
public get size(): number {
24+
return this.data.size
25+
}
26+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import {File} from "@server/psi/File"
2+
3+
export interface CompletionItemAdditionalInformation {
4+
readonly name: string | undefined
5+
readonly file: File | undefined
6+
readonly elementFile: File | undefined
7+
readonly language: "tolk" | "func" | undefined
8+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// SPDX-License-Identifier: MIT
2+
// Copyright © 2025 TON Studio
3+
import {CompletionResult} from "@server/completion/WeightedCompletionItem"
4+
5+
export interface CompletionProvider<Ctx> {
6+
isAvailable(ctx: Ctx): boolean
7+
8+
addCompletion(ctx: Ctx, result: CompletionResult): void
9+
}
10+
11+
export interface AsyncCompletionProvider<Ctx> {
12+
isAvailable(ctx: Ctx): boolean
13+
14+
addCompletion(ctx: Ctx, result: CompletionResult): Promise<void>
15+
}

server/src/files.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -153,9 +153,6 @@ export const isTlbFile = (
153153
event?: lsp.TextDocumentChangeEvent<TextDocument>,
154154
): boolean => event?.document.languageId === "tlb" || uri.endsWith(".tlb")
155155

156-
// export function filePathToUri(filePath: string): string {
157-
// return pathToFileURL(filePath).href
158-
// }
159156
export const filePathToUri = (filePath: string): string => {
160157
const url = pathToFileURL(filePath).toString()
161158
return url.replace(/c:/g, "c%3A").replace(/d:/g, "d%3A")

server/src/foldings/index.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import type {Point} from "web-tree-sitter"
2+
import type * as lsp from "vscode-languageserver"
3+
import {FoldingRangeKind} from "vscode-languageserver-types"
4+
5+
export function genericFolding(start: Point, end: Point): lsp.FoldingRange {
6+
return {
7+
kind: FoldingRangeKind.Region,
8+
startLine: start.row,
9+
endLine: end.row - 1,
10+
startCharacter: end.column,
11+
endCharacter: end.column,
12+
}
13+
}
Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,23 @@
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"
61
import {fileURLToPath} from "node:url"
7-
import {filePathToUri, findFuncFile} from "@server/files"
2+
import {glob} from "glob"
3+
import * as path from "node:path"
4+
import {filePathToUri} from "@server/files"
85

9-
export enum FuncIndexingRootKind {
6+
export enum IndexingRootKind {
107
Stdlib = "stdlib",
118
Workspace = "workspace",
129
}
1310

14-
export class FuncIndexingRoot {
15-
public constructor(
11+
export abstract class IndexingRoot {
12+
protected constructor(
1613
public root: string,
17-
public kind: FuncIndexingRootKind,
14+
public extensions: string[],
15+
public kind: IndexingRootKind,
1816
) {}
1917

2018
public async index(): Promise<void> {
2119
const ignore =
22-
this.kind === FuncIndexingRootKind.Stdlib
20+
this.kind === IndexingRootKind.Stdlib
2321
? []
2422
: [
2523
".git/**",
@@ -30,7 +28,11 @@ export class FuncIndexingRoot {
3028
]
3129

3230
const rootDir = fileURLToPath(this.root)
33-
const files = await glob("**/*.{fc,func}", {
31+
32+
const globPattern =
33+
this.extensions.length === 1 ? this.extensions[0] : `{${this.extensions.join(",")}}`
34+
35+
const files = await glob(`**/*.${globPattern}`, {
3436
cwd: rootDir,
3537
ignore: ignore,
3638
})
@@ -41,8 +43,9 @@ export class FuncIndexingRoot {
4143
console.info("Indexing:", filePath)
4244
const absPath = path.join(rootDir, filePath)
4345
const uri = filePathToUri(absPath)
44-
const file = await findFuncFile(uri)
45-
index.addFile(uri, file, false)
46+
await this.onFile(uri)
4647
}
4748
}
49+
50+
protected abstract onFile(uri: string): Promise<void>
4851
}

server/src/languages/fift/foldings/collect.ts

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,13 @@
11
// SPDX-License-Identifier: MIT
22
// Copyright © 2025 TON Studio
3-
import {FoldingRange, FoldingRangeKind} from "vscode-languageserver-types"
3+
import {FoldingRange} from "vscode-languageserver-types"
44
import {RecursiveVisitor} from "@server/visitor/visitor"
5-
import type {Point} from "web-tree-sitter"
6-
import type * as lsp from "vscode-languageserver"
75
import {FiftFile} from "@server/languages/fift/psi/FiftFile"
6+
import {genericFolding} from "@server/foldings"
87

98
export function provideFiftFoldingRanges(file: FiftFile): FoldingRange[] {
109
const result: FoldingRange[] = []
1110

12-
const genericFolding = (start: Point, end: Point): lsp.FoldingRange => {
13-
return {
14-
kind: FoldingRangeKind.Region,
15-
startLine: start.row,
16-
endLine: end.row - 1,
17-
startCharacter: end.column,
18-
endCharacter: end.column,
19-
}
20-
}
21-
2211
RecursiveVisitor.visit(file.rootNode, (n): boolean => {
2312
if (
2413
n.type === "program" ||

server/src/languages/fift/semantic-tokens/index.ts

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,34 +2,20 @@
22
// Copyright © 2025 TON Studio
33
import type {SemanticTokens} from "vscode-languageserver"
44
import {RecursiveVisitor} from "@server/visitor/visitor"
5-
import {SemanticTokensBuilder} from "vscode-languageserver/lib/common/semanticTokens"
65
import {SemanticTokenTypes} from "vscode-languageserver-protocol"
7-
import type {Node as SyntaxNode} from "web-tree-sitter"
8-
import * as lsp from "vscode-languageserver"
96
import {FiftReference} from "@server/languages/fift/psi/FiftReference"
107
import {FiftFile} from "@server/languages/fift/psi/FiftFile"
8+
import {Tokens} from "@server/semantic/tokens"
119

1210
export function provideFiftSemanticTokens(
1311
file: FiftFile,
1412
settings: {
1513
enabled: boolean
1614
},
1715
): SemanticTokens | null {
18-
if (!settings.enabled) {
19-
return null
20-
}
21-
22-
const builder = new SemanticTokensBuilder()
16+
if (!settings.enabled) return null
2317

24-
function pushToken(n: SyntaxNode, tokenType: lsp.SemanticTokenTypes): void {
25-
builder.push(
26-
n.startPosition.row,
27-
n.startPosition.column,
28-
n.endPosition.column - n.startPosition.column,
29-
Object.keys(lsp.SemanticTokenTypes).indexOf(tokenType.toString()),
30-
0,
31-
)
32-
}
18+
const tokens = new Tokens()
3319

3420
RecursiveVisitor.visit(file.rootNode, (node): boolean => {
3521
if (
@@ -41,7 +27,7 @@ export function provideFiftSemanticTokens(
4127
) {
4228
const nameNode = node.childForFieldName("name")
4329
if (nameNode) {
44-
pushToken(nameNode, SemanticTokenTypes.function)
30+
tokens.node(nameNode, SemanticTokenTypes.function)
4531
}
4632
}
4733

@@ -52,12 +38,15 @@ export function provideFiftSemanticTokens(
5238
) {
5339
const def = FiftReference.resolve(node, file)
5440
if (def) {
55-
pushToken(node, SemanticTokenTypes.function)
41+
tokens.node(node, SemanticTokenTypes.function)
5642
}
5743
}
5844

5945
return true
6046
})
6147

62-
return builder.build()
48+
return {
49+
resultId: Date.now().toString(),
50+
data: tokens.result(),
51+
}
6352
}

server/src/languages/func/cache.ts

Lines changed: 4 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,15 @@
11
// SPDX-License-Identifier: MIT
22
// Copyright © 2025 TON Core
33
import type {NamedNode} from "@server/languages/func/psi/FuncNode"
4+
import {Cache} from "@server/cache/cache"
45

5-
export class Cache<TKey, TValue> {
6-
private readonly data: Map<TKey, TValue>
7-
8-
public constructor() {
9-
this.data = new Map()
10-
}
11-
12-
public cached(key: TKey, cb: () => TValue): TValue {
13-
const cached = this.data.get(key)
14-
if (cached !== undefined) {
15-
return cached
16-
}
17-
18-
const value = cb()
19-
this.data.set(key, value)
20-
return value
21-
}
22-
23-
public clear(): void {
24-
this.data.clear()
25-
}
26-
27-
public get size(): number {
28-
return this.data.size
29-
}
30-
}
31-
32-
export class CacheManager {
33-
public readonly resolveCache: Cache<number, NamedNode | null>
34-
35-
public constructor() {
36-
this.resolveCache = new Cache()
37-
}
6+
export class FuncCache {
7+
public readonly resolveCache: Cache<number, NamedNode | null> = new Cache()
388

399
public clear(): void {
4010
console.info(`Clearing caches (resolve: ${this.resolveCache.size})`)
4111
this.resolveCache.clear()
4212
}
4313
}
4414

45-
export const FUNC_CACHE = new CacheManager()
15+
export const FUNC_CACHE = new FuncCache()

0 commit comments

Comments
 (0)