@@ -39,17 +39,20 @@ func NewServer(opts *ServerOptions) *Server {
39
39
newLine : opts .NewLine ,
40
40
fs : opts .FS ,
41
41
defaultLibraryPath : opts .DefaultLibraryPath ,
42
+ watchers : make (map [project.WatcherHandle ]struct {}),
42
43
}
43
44
}
44
45
45
46
var _ project.ServiceHost = (* Server )(nil )
47
+ var _ project.Client = (* Server )(nil )
46
48
47
49
type Server struct {
48
50
r * lsproto.BaseReader
49
51
w * lsproto.BaseWriter
50
52
51
53
stderr io.Writer
52
54
55
+ clientSeq int32
53
56
requestMethod string
54
57
requestTime time.Time
55
58
@@ -61,36 +64,95 @@ type Server struct {
61
64
initializeParams * lsproto.InitializeParams
62
65
positionEncoding lsproto.PositionEncodingKind
63
66
67
+ watcheEnabled bool
68
+ watcherID int
69
+ watchers map [project.WatcherHandle ]struct {}
64
70
logger * project.Logger
65
71
projectService * project.Service
66
72
converters * ls.Converters
67
73
}
68
74
69
- // FS implements project.ProjectServiceHost .
75
+ // FS implements project.ServiceHost .
70
76
func (s * Server ) FS () vfs.FS {
71
77
return s .fs
72
78
}
73
79
74
- // DefaultLibraryPath implements project.ProjectServiceHost .
80
+ // DefaultLibraryPath implements project.ServiceHost .
75
81
func (s * Server ) DefaultLibraryPath () string {
76
82
return s .defaultLibraryPath
77
83
}
78
84
79
- // GetCurrentDirectory implements project.ProjectServiceHost .
85
+ // GetCurrentDirectory implements project.ServiceHost .
80
86
func (s * Server ) GetCurrentDirectory () string {
81
87
return s .cwd
82
88
}
83
89
84
- // NewLine implements project.ProjectServiceHost .
90
+ // NewLine implements project.ServiceHost .
85
91
func (s * Server ) NewLine () string {
86
92
return s .newLine .GetNewLineCharacter ()
87
93
}
88
94
89
- // Trace implements project.ProjectServiceHost .
95
+ // Trace implements project.ServiceHost .
90
96
func (s * Server ) Trace (msg string ) {
91
97
s .Log (msg )
92
98
}
93
99
100
+ // Client implements project.ServiceHost.
101
+ func (s * Server ) Client () project.Client {
102
+ if ! s .watcheEnabled {
103
+ return nil
104
+ }
105
+ return s
106
+ }
107
+
108
+ // WatchFiles implements project.Client.
109
+ func (s * Server ) WatchFiles (watchers []lsproto.FileSystemWatcher ) (project.WatcherHandle , error ) {
110
+ watcherId := fmt .Sprintf ("watcher-%d" , s .watcherID )
111
+ if err := s .sendRequest (lsproto .MethodClientRegisterCapability , & lsproto.RegistrationParams {
112
+ Registrations : []lsproto.Registration {
113
+ {
114
+ Id : watcherId ,
115
+ Method : string (lsproto .MethodWorkspaceDidChangeWatchedFiles ),
116
+ RegisterOptions : ptrTo (lsproto .LSPAny (lsproto.DidChangeWatchedFilesRegistrationOptions {
117
+ Watchers : watchers ,
118
+ })),
119
+ },
120
+ },
121
+ }); err != nil {
122
+ return "" , fmt .Errorf ("failed to register file watcher: %w" , err )
123
+ }
124
+
125
+ handle := project .WatcherHandle (watcherId )
126
+ s .watchers [handle ] = struct {}{}
127
+ s .watcherID ++
128
+ return handle , nil
129
+ }
130
+
131
+ // UnwatchFiles implements project.Client.
132
+ func (s * Server ) UnwatchFiles (handle project.WatcherHandle ) error {
133
+ if _ , ok := s .watchers [handle ]; ok {
134
+ if err := s .sendRequest (lsproto .MethodClientUnregisterCapability , & lsproto.UnregistrationParams {
135
+ Unregisterations : []lsproto.Unregistration {
136
+ {
137
+ Id : string (handle ),
138
+ Method : string (lsproto .MethodWorkspaceDidChangeWatchedFiles ),
139
+ },
140
+ },
141
+ }); err != nil {
142
+ return fmt .Errorf ("failed to unregister file watcher: %w" , err )
143
+ }
144
+ delete (s .watchers , handle )
145
+ return nil
146
+ }
147
+
148
+ return fmt .Errorf ("no file watcher exists with ID %s" , handle )
149
+ }
150
+
151
+ // PublishDiagnostics implements project.Client.
152
+ func (s * Server ) PublishDiagnostics (params * lsproto.PublishDiagnosticsParams ) error {
153
+ return s .sendNotification (lsproto .MethodTextDocumentPublishDiagnostics , params )
154
+ }
155
+
94
156
func (s * Server ) Run () error {
95
157
for {
96
158
req , err := s .read ()
@@ -104,6 +166,11 @@ func (s *Server) Run() error {
104
166
return err
105
167
}
106
168
169
+ // TODO: handle response messages
170
+ if req == nil {
171
+ continue
172
+ }
173
+
107
174
if s .initializeParams == nil {
108
175
if req .Method == lsproto .MethodInitialize {
109
176
if err := s .handleInitialize (req ); err != nil {
@@ -131,12 +198,37 @@ func (s *Server) read() (*lsproto.RequestMessage, error) {
131
198
132
199
req := & lsproto.RequestMessage {}
133
200
if err := json .Unmarshal (data , req ); err != nil {
201
+ res := & lsproto.ResponseMessage {}
202
+ if err := json .Unmarshal (data , res ); err == nil {
203
+ // !!! TODO: handle response
204
+ return nil , nil
205
+ }
134
206
return nil , fmt .Errorf ("%w: %w" , lsproto .ErrInvalidRequest , err )
135
207
}
136
208
137
209
return req , nil
138
210
}
139
211
212
+ func (s * Server ) sendRequest (method lsproto.Method , params any ) error {
213
+ s .clientSeq ++
214
+ id := lsproto .NewIDString (fmt .Sprintf ("ts%d" , s .clientSeq ))
215
+ req := lsproto .NewRequestMessage (method , id , params )
216
+ data , err := json .Marshal (req )
217
+ if err != nil {
218
+ return err
219
+ }
220
+ return s .w .Write (data )
221
+ }
222
+
223
+ func (s * Server ) sendNotification (method lsproto.Method , params any ) error {
224
+ req := lsproto .NewRequestMessage (method , nil /*id*/ , params )
225
+ data , err := json .Marshal (req )
226
+ if err != nil {
227
+ return err
228
+ }
229
+ return s .w .Write (data )
230
+ }
231
+
140
232
func (s * Server ) sendResult (id * lsproto.ID , result any ) error {
141
233
return s .sendResponse (& lsproto.ResponseMessage {
142
234
ID : id ,
@@ -188,6 +280,8 @@ func (s *Server) handleMessage(req *lsproto.RequestMessage) error {
188
280
return s .handleDidSave (req )
189
281
case * lsproto.DidCloseTextDocumentParams :
190
282
return s .handleDidClose (req )
283
+ case * lsproto.DidChangeWatchedFilesParams :
284
+ return s .handleDidChangeWatchedFiles (req )
191
285
case * lsproto.DocumentDiagnosticParams :
192
286
return s .handleDocumentDiagnostic (req )
193
287
case * lsproto.HoverParams :
@@ -255,9 +349,14 @@ func (s *Server) handleInitialize(req *lsproto.RequestMessage) error {
255
349
}
256
350
257
351
func (s * Server ) handleInitialized (req * lsproto.RequestMessage ) error {
352
+ if s .initializeParams .Capabilities .Workspace .DidChangeWatchedFiles != nil && * s .initializeParams .Capabilities .Workspace .DidChangeWatchedFiles .DynamicRegistration {
353
+ s .watcheEnabled = true
354
+ }
355
+
258
356
s .logger = project .NewLogger ([]io.Writer {s .stderr }, "" /*file*/ , project .LogLevelVerbose )
259
357
s .projectService = project .NewService (s , project.ServiceOptions {
260
358
Logger : s .logger ,
359
+ WatchEnabled : s .watcheEnabled ,
261
360
PositionEncoding : s .positionEncoding ,
262
361
})
263
362
@@ -315,6 +414,12 @@ func (s *Server) handleDidClose(req *lsproto.RequestMessage) error {
315
414
return nil
316
415
}
317
416
417
+ func (s * Server ) handleDidChangeWatchedFiles (req * lsproto.RequestMessage ) error {
418
+ params := req .Params .(* lsproto.DidChangeWatchedFilesParams )
419
+ s .projectService .OnWatchedFilesChanged (params .Changes )
420
+ return nil
421
+ }
422
+
318
423
func (s * Server ) handleDocumentDiagnostic (req * lsproto.RequestMessage ) error {
319
424
params := req .Params .(* lsproto.DocumentDiagnosticParams )
320
425
file , project := s .getFileAndProject (params .TextDocument .Uri )
0 commit comments