@@ -43,14 +43,18 @@ func NewServer(opts *ServerOptions) *Server {
43
43
}
44
44
}
45
45
46
- var _ project.ServiceHost = (* Server )(nil )
46
+ var (
47
+ _ project.ServiceHost = (* Server )(nil )
48
+ _ project.Client = (* Server )(nil )
49
+ )
47
50
48
51
type Server struct {
49
52
r * lsproto.BaseReader
50
53
w * lsproto.BaseWriter
51
54
52
55
stderr io.Writer
53
56
57
+ clientSeq int32
54
58
requestMethod string
55
59
requestTime time.Time
56
60
@@ -62,36 +66,100 @@ type Server struct {
62
66
initializeParams * lsproto.InitializeParams
63
67
positionEncoding lsproto.PositionEncodingKind
64
68
69
+ watchEnabled bool
70
+ watcherID int
71
+ watchers core.Set [project.WatcherHandle ]
65
72
logger * project.Logger
66
73
projectService * project.Service
67
74
converters * ls.Converters
68
75
}
69
76
70
- // FS implements project.ProjectServiceHost .
77
+ // FS implements project.ServiceHost .
71
78
func (s * Server ) FS () vfs.FS {
72
79
return s .fs
73
80
}
74
81
75
- // DefaultLibraryPath implements project.ProjectServiceHost .
82
+ // DefaultLibraryPath implements project.ServiceHost .
76
83
func (s * Server ) DefaultLibraryPath () string {
77
84
return s .defaultLibraryPath
78
85
}
79
86
80
- // GetCurrentDirectory implements project.ProjectServiceHost .
87
+ // GetCurrentDirectory implements project.ServiceHost .
81
88
func (s * Server ) GetCurrentDirectory () string {
82
89
return s .cwd
83
90
}
84
91
85
- // NewLine implements project.ProjectServiceHost .
92
+ // NewLine implements project.ServiceHost .
86
93
func (s * Server ) NewLine () string {
87
94
return s .newLine .GetNewLineCharacter ()
88
95
}
89
96
90
- // Trace implements project.ProjectServiceHost .
97
+ // Trace implements project.ServiceHost .
91
98
func (s * Server ) Trace (msg string ) {
92
99
s .Log (msg )
93
100
}
94
101
102
+ // Client implements project.ServiceHost.
103
+ func (s * Server ) Client () project.Client {
104
+ if ! s .watchEnabled {
105
+ return nil
106
+ }
107
+ return s
108
+ }
109
+
110
+ // WatchFiles implements project.Client.
111
+ func (s * Server ) WatchFiles (watchers []* lsproto.FileSystemWatcher ) (project.WatcherHandle , error ) {
112
+ watcherId := fmt .Sprintf ("watcher-%d" , s .watcherID )
113
+ if err := s .sendRequest (lsproto .MethodClientRegisterCapability , & lsproto.RegistrationParams {
114
+ Registrations : []* lsproto.Registration {
115
+ {
116
+ Id : watcherId ,
117
+ Method : string (lsproto .MethodWorkspaceDidChangeWatchedFiles ),
118
+ RegisterOptions : ptrTo (any (lsproto.DidChangeWatchedFilesRegistrationOptions {
119
+ Watchers : watchers ,
120
+ })),
121
+ },
122
+ },
123
+ }); err != nil {
124
+ return "" , fmt .Errorf ("failed to register file watcher: %w" , err )
125
+ }
126
+
127
+ handle := project .WatcherHandle (watcherId )
128
+ s .watchers .Add (handle )
129
+ s .watcherID ++
130
+ return handle , nil
131
+ }
132
+
133
+ // UnwatchFiles implements project.Client.
134
+ func (s * Server ) UnwatchFiles (handle project.WatcherHandle ) error {
135
+ if s .watchers .Has (handle ) {
136
+ if err := s .sendRequest (lsproto .MethodClientUnregisterCapability , & lsproto.UnregistrationParams {
137
+ Unregisterations : []* lsproto.Unregistration {
138
+ {
139
+ Id : string (handle ),
140
+ Method : string (lsproto .MethodWorkspaceDidChangeWatchedFiles ),
141
+ },
142
+ },
143
+ }); err != nil {
144
+ return fmt .Errorf ("failed to unregister file watcher: %w" , err )
145
+ }
146
+ s .watchers .Delete (handle )
147
+ return nil
148
+ }
149
+
150
+ return fmt .Errorf ("no file watcher exists with ID %s" , handle )
151
+ }
152
+
153
+ // RefreshDiagnostics implements project.Client.
154
+ func (s * Server ) RefreshDiagnostics () error {
155
+ if ptrIsTrue (s .initializeParams .Capabilities .Workspace .Diagnostics .RefreshSupport ) {
156
+ if err := s .sendRequest (lsproto .MethodWorkspaceDiagnosticRefresh , nil ); err != nil {
157
+ return fmt .Errorf ("failed to refresh diagnostics: %w" , err )
158
+ }
159
+ }
160
+ return nil
161
+ }
162
+
95
163
func (s * Server ) Run () error {
96
164
for {
97
165
req , err := s .read ()
@@ -105,6 +173,11 @@ func (s *Server) Run() error {
105
173
return err
106
174
}
107
175
176
+ // TODO: handle response messages
177
+ if req == nil {
178
+ continue
179
+ }
180
+
108
181
if s .initializeParams == nil {
109
182
if req .Method == lsproto .MethodInitialize {
110
183
if err := s .handleInitialize (req ); err != nil {
@@ -132,12 +205,37 @@ func (s *Server) read() (*lsproto.RequestMessage, error) {
132
205
133
206
req := & lsproto.RequestMessage {}
134
207
if err := json .Unmarshal (data , req ); err != nil {
208
+ res := & lsproto.ResponseMessage {}
209
+ if err = json .Unmarshal (data , res ); err == nil {
210
+ // !!! TODO: handle response
211
+ return nil , nil
212
+ }
135
213
return nil , fmt .Errorf ("%w: %w" , lsproto .ErrInvalidRequest , err )
136
214
}
137
215
138
216
return req , nil
139
217
}
140
218
219
+ func (s * Server ) sendRequest (method lsproto.Method , params any ) error {
220
+ s .clientSeq ++
221
+ id := lsproto .NewIDString (fmt .Sprintf ("ts%d" , s .clientSeq ))
222
+ req := lsproto .NewRequestMessage (method , id , params )
223
+ data , err := json .Marshal (req )
224
+ if err != nil {
225
+ return err
226
+ }
227
+ return s .w .Write (data )
228
+ }
229
+
230
+ func (s * Server ) sendNotification (method lsproto.Method , params any ) error {
231
+ req := lsproto .NewRequestMessage (method , nil /*id*/ , params )
232
+ data , err := json .Marshal (req )
233
+ if err != nil {
234
+ return err
235
+ }
236
+ return s .w .Write (data )
237
+ }
238
+
141
239
func (s * Server ) sendResult (id * lsproto.ID , result any ) error {
142
240
return s .sendResponse (& lsproto.ResponseMessage {
143
241
ID : id ,
@@ -189,6 +287,8 @@ func (s *Server) handleMessage(req *lsproto.RequestMessage) error {
189
287
return s .handleDidSave (req )
190
288
case * lsproto.DidCloseTextDocumentParams :
191
289
return s .handleDidClose (req )
290
+ case * lsproto.DidChangeWatchedFilesParams :
291
+ return s .handleDidChangeWatchedFiles (req )
192
292
case * lsproto.DocumentDiagnosticParams :
193
293
return s .handleDocumentDiagnostic (req )
194
294
case * lsproto.HoverParams :
@@ -262,9 +362,14 @@ func (s *Server) handleInitialize(req *lsproto.RequestMessage) error {
262
362
}
263
363
264
364
func (s * Server ) handleInitialized (req * lsproto.RequestMessage ) error {
365
+ if s .initializeParams .Capabilities .Workspace .DidChangeWatchedFiles != nil && * s .initializeParams .Capabilities .Workspace .DidChangeWatchedFiles .DynamicRegistration {
366
+ s .watchEnabled = true
367
+ }
368
+
265
369
s .logger = project .NewLogger ([]io.Writer {s .stderr }, "" /*file*/ , project .LogLevelVerbose )
266
370
s .projectService = project .NewService (s , project.ServiceOptions {
267
371
Logger : s .logger ,
372
+ WatchEnabled : s .watchEnabled ,
268
373
PositionEncoding : s .positionEncoding ,
269
374
})
270
375
@@ -322,6 +427,11 @@ func (s *Server) handleDidClose(req *lsproto.RequestMessage) error {
322
427
return nil
323
428
}
324
429
430
+ func (s * Server ) handleDidChangeWatchedFiles (req * lsproto.RequestMessage ) error {
431
+ params := req .Params .(* lsproto.DidChangeWatchedFilesParams )
432
+ return s .projectService .OnWatchedFilesChanged (params .Changes )
433
+ }
434
+
325
435
func (s * Server ) handleDocumentDiagnostic (req * lsproto.RequestMessage ) error {
326
436
params := req .Params .(* lsproto.DocumentDiagnosticParams )
327
437
file , project := s .getFileAndProject (params .TextDocument .Uri )
@@ -445,3 +555,10 @@ func codeFence(lang string, code string) string {
445
555
func ptrTo [T any ](v T ) * T {
446
556
return & v
447
557
}
558
+
559
+ func ptrIsTrue (v * bool ) bool {
560
+ if v == nil {
561
+ return false
562
+ }
563
+ return * v
564
+ }
0 commit comments