Skip to content

Commit fc5137d

Browse files
committed
Prevent lsp from printing notification handler not found errors
1 parent 9d54b1a commit fc5137d

File tree

2 files changed

+212
-9
lines changed

2 files changed

+212
-9
lines changed
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
import Foundation
2+
import JSONRPC
3+
import LanguageClient
4+
import LanguageServerProtocol
5+
6+
import ProcessEnv
7+
8+
/// A clone of the `LocalProcessServer`.
9+
/// We need it because the original one does not allow us to handle custom notifications.
10+
public class CopilotLocalProcessServer {
11+
private let transport: StdioDataTransport
12+
private let process: Process
13+
private var wrappedServer: CustomJSONRPCLanguageServer?
14+
public var terminationHandler: (() -> Void)?
15+
16+
public convenience init(
17+
path: String,
18+
arguments: [String],
19+
environment: [String: String]? = nil
20+
) {
21+
let params = Process.ExecutionParameters(
22+
path: path,
23+
arguments: arguments,
24+
environment: environment
25+
)
26+
27+
self.init(executionParameters: params)
28+
}
29+
30+
public init(executionParameters parameters: Process.ExecutionParameters) {
31+
transport = StdioDataTransport()
32+
wrappedServer = CustomJSONRPCLanguageServer(dataTransport: transport)
33+
34+
process = Process()
35+
36+
process.standardInput = transport.stdinPipe
37+
process.standardOutput = transport.stdoutPipe
38+
process.standardError = transport.stderrPipe
39+
40+
process.parameters = parameters
41+
42+
process.terminationHandler = { [unowned self] task in
43+
self.processTerminated(task)
44+
}
45+
46+
process.launch()
47+
}
48+
49+
deinit {
50+
process.terminationHandler = nil
51+
process.terminate()
52+
transport.close()
53+
}
54+
55+
private func processTerminated(_: Process) {
56+
transport.close()
57+
58+
// releasing the server here will short-circuit any pending requests,
59+
// which might otherwise take a while to time out, if ever.
60+
wrappedServer = nil
61+
terminationHandler?()
62+
}
63+
64+
public var logMessages: Bool {
65+
get { return wrappedServer?.logMessages ?? false }
66+
set { wrappedServer?.logMessages = newValue }
67+
}
68+
}
69+
70+
extension CopilotLocalProcessServer: LanguageServerProtocol.Server {
71+
public var requestHandler: RequestHandler? {
72+
get { return wrappedServer?.requestHandler }
73+
set { wrappedServer?.requestHandler = newValue }
74+
}
75+
76+
public var notificationHandler: NotificationHandler? {
77+
get { wrappedServer?.notificationHandler }
78+
set { wrappedServer?.notificationHandler = newValue }
79+
}
80+
81+
public func sendNotification(
82+
_ notif: ClientNotification,
83+
completionHandler: @escaping (ServerError?) -> Void
84+
) {
85+
guard let server = wrappedServer, process.isRunning else {
86+
completionHandler(.serverUnavailable)
87+
return
88+
}
89+
90+
server.sendNotification(notif, completionHandler: completionHandler)
91+
}
92+
93+
public func sendRequest<Response: Codable>(
94+
_ request: ClientRequest,
95+
completionHandler: @escaping (ServerResult<Response>) -> Void
96+
) {
97+
guard let server = wrappedServer, process.isRunning else {
98+
completionHandler(.failure(.serverUnavailable))
99+
return
100+
}
101+
102+
server.sendRequest(request, completionHandler: completionHandler)
103+
}
104+
}
105+
106+
final class CustomJSONRPCLanguageServer: Server {
107+
let internalServer: JSONRPCLanguageServer
108+
109+
typealias ProtocolResponse<T: Codable> = ProtocolTransport.ResponseResult<T>
110+
111+
private let protocolTransport: ProtocolTransport
112+
113+
public var requestHandler: RequestHandler?
114+
public var notificationHandler: NotificationHandler?
115+
116+
private var outOfBandError: Error?
117+
118+
init(protocolTransport: ProtocolTransport) {
119+
self.protocolTransport = protocolTransport
120+
internalServer = JSONRPCLanguageServer(protocolTransport: protocolTransport)
121+
122+
let previouseRequestHandler = protocolTransport.requestHandler
123+
let previouseNotificationHandler = protocolTransport.notificationHandler
124+
125+
protocolTransport
126+
.requestHandler = { [weak self] in
127+
guard let self else { return }
128+
if !self.handleRequest($0, data: $1, callback: $2) {
129+
previouseRequestHandler?($0, $1, $2)
130+
}
131+
}
132+
protocolTransport
133+
.notificationHandler = { [weak self] in
134+
guard let self else { return }
135+
if !self.handleNotification($0, data: $1, block: $2) {
136+
previouseNotificationHandler?($0, $1, $2)
137+
}
138+
}
139+
}
140+
141+
convenience init(dataTransport: DataTransport) {
142+
let framing = SeperatedHTTPHeaderMessageFraming()
143+
let messageTransport = MessageTransport(
144+
dataTransport: dataTransport,
145+
messageProtocol: framing
146+
)
147+
148+
self.init(protocolTransport: ProtocolTransport(dataTransport: messageTransport))
149+
}
150+
151+
deinit {
152+
protocolTransport.requestHandler = nil
153+
protocolTransport.notificationHandler = nil
154+
}
155+
156+
var logMessages: Bool {
157+
get { return internalServer.logMessages }
158+
set { internalServer.logMessages = newValue }
159+
}
160+
}
161+
162+
extension CustomJSONRPCLanguageServer {
163+
private func handleNotification(
164+
_ anyNotification: AnyJSONRPCNotification,
165+
data: Data,
166+
block: @escaping (Error?) -> Void
167+
) -> Bool {
168+
let methodName = anyNotification.method
169+
switch methodName {
170+
case "LogMessage":
171+
block(nil)
172+
return true
173+
case "statusNotification":
174+
block(nil)
175+
return true
176+
default:
177+
return false
178+
}
179+
}
180+
181+
public func sendNotification(
182+
_ notif: ClientNotification,
183+
completionHandler: @escaping (ServerError?) -> Void
184+
) {
185+
internalServer.sendNotification(notif, completionHandler: completionHandler)
186+
}
187+
}
188+
189+
extension CustomJSONRPCLanguageServer {
190+
private func handleRequest(
191+
_ request: AnyJSONRPCRequest,
192+
data: Data,
193+
callback: @escaping (AnyJSONRPCResponse) -> Void
194+
) -> Bool {
195+
return false
196+
}
197+
}
198+
199+
extension CustomJSONRPCLanguageServer {
200+
public func sendRequest<Response: Codable>(
201+
_ request: ClientRequest,
202+
completionHandler: @escaping (ServerResult<Response>) -> Void
203+
) {
204+
internalServer.sendRequest(request, completionHandler: completionHandler)
205+
}
206+
}

Core/Sources/CopilotService/CopilotService.swift

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,13 @@ public class CopilotBaseService {
6969
currentDirectoryURL: supportURL
7070
)
7171
}()
72-
let localServer = LocalProcessServer(executionParameters: executionParams)
72+
let localServer = CopilotLocalProcessServer(executionParameters: executionParams)
7373
localServer.logMessages = false
74-
let server = InitializingServer(server: localServer)
75-
server.notificationHandler = { _, respond in
76-
respond(nil)
74+
localServer.notificationHandler = { notification, respond in
75+
print(notification)
76+
respond(.timeout)
7777
}
78+
let server = InitializingServer(server: localServer)
7879

7980
server.initializeParamsProvider = {
8081
let capabilities = ClientCapabilities(
@@ -93,15 +94,11 @@ public class CopilotBaseService {
9394
rootUri: projectRootURL.path,
9495
initializationOptions: nil,
9596
capabilities: capabilities,
96-
trace: nil,
97+
trace: .off,
9798
workspaceFolders: nil
9899
)
99100
}
100101

101-
server.notificationHandler = { _, respond in
102-
respond(nil)
103-
}
104-
105102
return server
106103
}()
107104
}

0 commit comments

Comments
 (0)