this repo has no description
www.jonmsterling.com/01HC/
1// SPDX-FileCopyrightText: 2025 The Project Pterodactyl Developers
2//
3// SPDX-License-Identifier: MPL-2.0
4
5import Foundation
6import JSONRPC
7import LanguageServer
8import LanguageServerProtocol
9import Logging
10import PterodactylBuild
11import PterodactylSyntax
12import TSCBasic
13import llbuild2fx
14
15final class EventHandler {
16 private let connection: JSONRPCClientConnection
17 private let buildEngine: FXEngine
18 private let casContext: TSCUtility.Context
19 private let casClient: LLBCASFSClient
20
21 var storedBlobs: [DocumentUri: (blobId: LLBDataID, version: Int?)] = [:]
22
23 init(connection: JSONRPCClientConnection) {
24 self.connection = connection
25
26 let group = LLBMakeDefaultDispatchGroup()
27 let db = LLBInMemoryCASDatabase(group: group)
28 let functionCache = FXInMemoryFunctionCache(group: group)
29 let executor = FXLocalExecutor()
30 self.buildEngine = FXEngine(group: group, db: db, functionCache: functionCache, executor: executor)
31 self.casClient = LLBCASFSClient(db)
32 self.casContext = Context()
33 }
34
35 func storeBlob(text: String, uri: DocumentUri, version: Int?) async throws -> LLBDataID {
36 if let stored = storedBlobs[uri], let version, let storedVersion = stored.version, storedVersion >= version {
37 return stored.blobId
38 }
39
40 let blobId: LLBDataID = try await casClient.store(LLBByteBuffer(string: text), casContext).get()
41 storedBlobs[uri] = (blobId: blobId, version: version)
42 return blobId
43 }
44
45 func publishLiveDiagnostics(blobId: LLBDataID, uri: DocumentUri, version: Int?) async throws {
46 let lineMap = try await buildEngine.build(key: Keys.Blob.GetLineMap(blobId: blobId), casContext).get()
47 let parseResult = try await buildEngine.build(key: Keys.Blob.ParseDocument(blobId: blobId), casContext).get()
48 let diagnostics = parseResult.diagnostics.map { $0.lspDiagnostic(lineMap: lineMap) }
49 let publishParams = PublishDiagnosticsParams(uri: uri, version: version, diagnostics: diagnostics)
50 try await connection.sendNotification(.textDocumentPublishDiagnostics(publishParams))
51 }
52}
53
54
55extension EventHandler: LanguageServer.EventHandler {
56 var textDocumentSinkOptions: TextDocumentSyncOptions {
57 TextDocumentSyncOptions(
58 openClose: true,
59 change: .full,
60
61 save: .optionA(false)
62 )
63 }
64
65 var completionOptions: CompletionOptions {
66 CompletionOptions(
67 workDoneProgress: false,
68 triggerCharacters: [], // TODO
69 allCommitCharacters: nil,
70 resolveProvider: false,
71 completionItem: nil
72 )
73 }
74
75 var semanticTokensLegend: SemanticTokensLegend {
76 SemanticTokensLegend(tokenTypes: SemanticTokenTypes.allStrings, tokenModifiers: SemanticTokenModifiers.allStrings)
77 }
78
79 var semanticTokensOptions: SemanticTokensOptions {
80 SemanticTokensOptions(legend: semanticTokensLegend, full: .optionB(SemanticTokensClientCapabilities.Requests.Full(delta: false)))
81 }
82
83 func initialize(id: JSONId, params: InitializeParams) async -> Response<InitializationResponse> {
84 Logger.shared.debug("Received initialize request")
85 var serverCapabilities = ServerCapabilities()
86 serverCapabilities.textDocumentSync = .optionA(textDocumentSinkOptions)
87 serverCapabilities.completionProvider = completionOptions
88 serverCapabilities.hoverProvider = .optionA(false)
89 serverCapabilities.semanticTokensProvider = .optionA(semanticTokensOptions)
90 serverCapabilities.foldingRangeProvider = .optionA(true)
91 let response = InitializationResponse(
92 capabilities: serverCapabilities,
93 serverInfo: nil
94 )
95 return .success(response)
96 }
97
98 func textDocumentDidChange(_ params: DidChangeTextDocumentParams) async {
99 guard let text = params.contentChanges.first?.text else { return }
100 do {
101 let blobId: LLBDataID = try await storeBlob(text: text, uri: params.textDocument.uri, version: params.textDocument.version)
102 try await publishLiveDiagnostics(blobId: blobId, uri: params.textDocument.uri, version: params.textDocument.version)
103 } catch {}
104 }
105
106 func textDocumentDidOpen(_ params: DidOpenTextDocumentParams) async {
107 let text = params.textDocument.text
108 do {
109 let blobId: LLBDataID = try await storeBlob(text: text, uri: params.textDocument.uri, version: params.textDocument.version)
110 try await publishLiveDiagnostics(blobId: blobId, uri: params.textDocument.uri, version: params.textDocument.version)
111 } catch {}
112 }
113
114 func semanticTokensFull(id: JSONId, params: SemanticTokensParams) async -> Response<SemanticTokensResponse> {
115 guard let storedBlob = storedBlobs[params.textDocument.uri] else { return .success(nil) }
116
117 do {
118 let lineMap = try await buildEngine.build(key: Keys.Blob.GetLineMap(blobId: storedBlob.blobId), casContext).get()
119 let parseResult = try await buildEngine.build(key: Keys.Blob.ParseDocument(blobId: storedBlob.blobId), casContext).get()
120 let cursor = SyntaxCursor(lineMap: lineMap, node: .tree(parseResult.tree), utf16Offset: 0)
121 return .success(SemanticTokensResponse(SemanticTokens(resultId: nil, tokens: cursor.semanticTokens)))
122 } catch {
123 return .success(nil)
124 }
125 }
126
127 func foldingRange(id: JSONId, params: FoldingRangeParams) async -> Response<FoldingRangeResponse> {
128 guard let storedBlob = storedBlobs[params.textDocument.uri] else { return .success(nil) }
129
130 do {
131 let lineMap = try await buildEngine.build(key: Keys.Blob.GetLineMap(blobId: storedBlob.blobId), casContext).get()
132 let parseResult = try await buildEngine.build(key: Keys.Blob.ParseDocument(blobId: storedBlob.blobId), casContext).get()
133 let cursor = SyntaxCursor(lineMap: lineMap, node: .tree(parseResult.tree), utf16Offset: 0)
134 return .success(FoldingRangeResponse(cursor.foldingRanges))
135 } catch {
136 return .success(nil)
137 }
138 }
139
140
141 func typeHierarchySupertypes(
142 id: JSONRPC.JSONId,
143 params: TypeHierarchySupertypesParams
144 ) async -> Response<TypeHierarchySupertypesResponse> {
145 .success(nil)
146 }
147
148 func typeHierarchySubtypes(
149 id: JSONId,
150 params: TypeHierarchySubtypesParams
151 ) async -> Response<TypeHierarchySubtypesResponse> {
152 .success(nil)
153 }
154
155 func internalError(_ error: any Error) async {
156 Logger.shared.error("Received error: \(error)")
157 }
158
159 func initialized(_ params: InitializedParams) async {
160
161 }
162
163 func exit() async {
164 Logger.shared.info("Received exit notification")
165 Foundation.exit(0)
166 }
167
168 func diagnostics(id: JSONId, params: DocumentDiagnosticParams) async -> Response<DocumentDiagnosticReport> {
169 return .success(.init(kind: .unchanged))
170 }
171
172
173
174 func textDocumentDidClose(_ params: DidCloseTextDocumentParams) async {
175
176 }
177
178 func textDocumentWillSave(_ params: WillSaveTextDocumentParams) async {
179
180 }
181
182 func textDocumentDidSave(_ params: DidSaveTextDocumentParams) async {
183
184 }
185
186 func protocolCancelRequest(_ params: CancelParams) async {
187
188 }
189
190 func protocolSetTrace(_ params: SetTraceParams) async {
191
192 }
193
194 func workspaceDidChangeWatchedFiles(_ params: DidChangeWatchedFilesParams) async {
195
196 }
197
198 func windowWorkDoneProgressCancel(_ params: WorkDoneProgressCancelParams) async {
199
200 }
201
202 func workspaceDidChangeWorkspaceFolders(_ params: DidChangeWorkspaceFoldersParams) async {
203
204 }
205
206 func workspaceDidChangeConfiguration(_ params: DidChangeConfigurationParams) async {
207
208 }
209
210 func workspaceDidCreateFiles(_ params: CreateFilesParams) async {
211
212 }
213
214 func workspaceDidRenameFiles(_ params: RenameFilesParams) async {
215
216 }
217
218 func workspaceDidDeleteFiles(_ params: DeleteFilesParams) async {
219
220 }
221
222 func shutdown(id: JSONId) async {}
223 func workspaceInlayHintRefresh(id: JSONId) async {}
224 func workspaceExecuteCommand(id: JSONId, params: ExecuteCommandParams) async -> Response<LSPAny?> { .success(nil) }
225 func workspaceWillCreateFiles(id: JSONId, params: CreateFilesParams) async -> Response<WorkspaceEdit?> { .success(nil) }
226 func workspaceWillRenameFiles(id: JSONId, params: RenameFilesParams) async -> Response<WorkspaceEdit?> { .success(nil) }
227 func workspaceWillDeleteFiles(id: JSONId, params: DeleteFilesParams) async -> Response<WorkspaceEdit?> { .success(nil) }
228 func workspaceSymbol(id: JSONId, params: WorkspaceSymbolParams) async -> Response<WorkspaceSymbolResponse> { .success(nil) }
229 // func workspaceSymbolResolve(id: JSONId, params: WorkspaceSymbol) async -> Response<WorkspaceSymbol> { .success(nil) }
230 func textDocumentWillSaveWaitUntil(id: JSONId, params: WillSaveTextDocumentParams) async -> Response<[TextEdit]?> { .success(nil) }
231 func completion(id: JSONId, params: CompletionParams) async -> Response<CompletionResponse> {
232 .success(CompletionResponse(.optionB(.init(isIncomplete: false, items: []))))
233 }
234 // func completionItemResolve(id: JSONId, params: CompletionItem) async -> Response<CompletionItem> { .success(nil) }
235 func hover(id: JSONId, params: TextDocumentPositionParams) async -> Response<HoverResponse> { .success(nil) }
236 func signatureHelp(id: JSONId, params: TextDocumentPositionParams) async -> Response<SignatureHelpResponse> { .success(nil) }
237 func declaration(id: JSONId, params: TextDocumentPositionParams) async -> Response<DeclarationResponse> { .success(nil) }
238 func definition(id: JSONId, params: TextDocumentPositionParams) async -> Response<DefinitionResponse> { .success(nil) }
239 func typeDefinition(id: JSONId, params: TextDocumentPositionParams) async -> Response<TypeDefinitionResponse> { .success(nil) }
240 func implementation(id: JSONId, params: TextDocumentPositionParams) async -> Response<ImplementationResponse> { .success(nil) }
241 func documentHighlight(id: JSONId, params: DocumentHighlightParams) async -> Response<DocumentHighlightResponse> { .success(nil) }
242 func documentSymbol(id: JSONId, params: DocumentSymbolParams) async -> Response<DocumentSymbolResponse> { .success(nil) }
243 func codeAction(id: JSONId, params: CodeActionParams) async -> Response<CodeActionResponse> { .success(nil) }
244 // func codeActionResolve(id: JSONId, params: CodeAction) async -> Response<CodeAction> { .success(nil) }
245 func codeLens(id: JSONId, params: CodeLensParams) async -> Response<CodeLensResponse> { .success(nil) }
246 // func codeLensResolve(id: JSONId, params: CodeLens) async -> Response<CodeLens> { .success(nil) }
247 func selectionRange(id: JSONId, params: SelectionRangeParams) async -> Response<SelectionRangeResponse> { .success(nil) }
248 func linkedEditingRange(id: JSONId, params: LinkedEditingRangeParams) async -> Response<LinkedEditingRangeResponse> { .success(nil) }
249 func prepareCallHierarchy(id: JSONId, params: CallHierarchyPrepareParams) async -> Response<CallHierarchyPrepareResponse> { .success(nil) }
250 func prepareRename(id: JSONId, params: PrepareRenameParams) async -> Response<PrepareRenameResponse> { .success(nil) }
251 func prepareTypeHeirarchy(id: JSONId, params: TypeHierarchyPrepareParams) async -> Response<PrepareTypeHeirarchyResponse> { .success(nil) }
252 func rename(id: JSONId, params: RenameParams) async -> Response<RenameResponse> { .success(nil) }
253 func inlayHint(id: JSONId, params: InlayHintParams) async -> Response<InlayHintResponse> { .success(nil) }
254 func inlayHintResolve(id: JSONId, params: InlayHint) async -> Response<InlayHintResponse> { .success(nil) }
255 func documentLink(id: JSONId, params: DocumentLinkParams) async -> Response<DocumentLinkResponse> { .success(nil) }
256 // func documentLinkResolve(id: JSONId, params: DocumentLink) async -> Response<DocumentLink> { .success(nil) }
257 // func documentColor(id: JSONId, params: DocumentColorParams) async -> Response<DocumentColorResponse> { .success(nil) }
258 // func colorPresentation(id: JSONId, params: ColorPresentationParams) async -> Response<ColorPresentationResponse> { .success(nil) }
259 func formatting(id: JSONId, params: DocumentFormattingParams) async -> Response<FormattingResult> { .success(nil) }
260 func rangeFormatting(id: JSONId, params: DocumentRangeFormattingParams) async -> Response<FormattingResult> { .success(nil) }
261 func onTypeFormatting(id: JSONId, params: DocumentOnTypeFormattingParams) async -> Response<FormattingResult> { .success(nil) }
262 func references(id: JSONId, params: ReferenceParams) async -> Response<ReferenceResponse> { .success(nil) }
263 func moniker(id: JSONId, params: MonikerParams) async -> Response<MonikerResponse> { .success(nil) }
264 func semanticTokensFullDelta(id: JSONId, params: SemanticTokensDeltaParams) async -> Response<SemanticTokensDeltaResponse> { .success(nil) }
265 func semanticTokensRange(id: JSONId, params: SemanticTokensRangeParams) async -> Response<SemanticTokensResponse> { .success(nil) }
266 func callHierarchyIncomingCalls(id: JSONId, params: CallHierarchyIncomingCallsParams) async -> Response<CallHierarchyIncomingCallsResponse> { .success(nil) }
267 func callHierarchyOutgoingCalls(id: JSONId, params: CallHierarchyOutgoingCallsParams) async -> Response<CallHierarchyOutgoingCallsResponse> { .success(nil) }
268 func custom(id: JSONId, method: String, params: LSPAny) async -> Response<LSPAny> { .success(nil) }
269}