@@ -43,14 +43,18 @@ func NewServer(opts *ServerOptions) *Server {
4343 }
4444}
4545
46- var _ project.ServiceHost = (* Server )(nil )
46+ var (
47+ _ project.ServiceHost = (* Server )(nil )
48+ _ project.Client = (* Server )(nil )
49+ )
4750
4851type Server struct {
4952 r * lsproto.BaseReader
5053 w * lsproto.BaseWriter
5154
5255 stderr io.Writer
5356
57+ clientSeq int32
5458 requestMethod string
5559 requestTime time.Time
5660
@@ -62,36 +66,100 @@ type Server struct {
6266 initializeParams * lsproto.InitializeParams
6367 positionEncoding lsproto.PositionEncodingKind
6468
69+ watchEnabled bool
70+ watcherID int
71+ watchers core.Set [project.WatcherHandle ]
6572 logger * project.Logger
6673 projectService * project.Service
6774 converters * ls.Converters
6875}
6976
70- // FS implements project.ProjectServiceHost .
77+ // FS implements project.ServiceHost .
7178func (s * Server ) FS () vfs.FS {
7279 return s .fs
7380}
7481
75- // DefaultLibraryPath implements project.ProjectServiceHost .
82+ // DefaultLibraryPath implements project.ServiceHost .
7683func (s * Server ) DefaultLibraryPath () string {
7784 return s .defaultLibraryPath
7885}
7986
80- // GetCurrentDirectory implements project.ProjectServiceHost .
87+ // GetCurrentDirectory implements project.ServiceHost .
8188func (s * Server ) GetCurrentDirectory () string {
8289 return s .cwd
8390}
8491
85- // NewLine implements project.ProjectServiceHost .
92+ // NewLine implements project.ServiceHost .
8693func (s * Server ) NewLine () string {
8794 return s .newLine .GetNewLineCharacter ()
8895}
8996
90- // Trace implements project.ProjectServiceHost .
97+ // Trace implements project.ServiceHost .
9198func (s * Server ) Trace (msg string ) {
9299 s .Log (msg )
93100}
94101
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+
95163func (s * Server ) Run () error {
96164 for {
97165 req , err := s .read ()
@@ -105,6 +173,11 @@ func (s *Server) Run() error {
105173 return err
106174 }
107175
176+ // TODO: handle response messages
177+ if req == nil {
178+ continue
179+ }
180+
108181 if s .initializeParams == nil {
109182 if req .Method == lsproto .MethodInitialize {
110183 if err := s .handleInitialize (req ); err != nil {
@@ -132,12 +205,37 @@ func (s *Server) read() (*lsproto.RequestMessage, error) {
132205
133206 req := & lsproto.RequestMessage {}
134207 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+ }
135213 return nil , fmt .Errorf ("%w: %w" , lsproto .ErrInvalidRequest , err )
136214 }
137215
138216 return req , nil
139217}
140218
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+
141239func (s * Server ) sendResult (id * lsproto.ID , result any ) error {
142240 return s .sendResponse (& lsproto.ResponseMessage {
143241 ID : id ,
@@ -189,6 +287,8 @@ func (s *Server) handleMessage(req *lsproto.RequestMessage) error {
189287 return s .handleDidSave (req )
190288 case * lsproto.DidCloseTextDocumentParams :
191289 return s .handleDidClose (req )
290+ case * lsproto.DidChangeWatchedFilesParams :
291+ return s .handleDidChangeWatchedFiles (req )
192292 case * lsproto.DocumentDiagnosticParams :
193293 return s .handleDocumentDiagnostic (req )
194294 case * lsproto.HoverParams :
@@ -262,9 +362,14 @@ func (s *Server) handleInitialize(req *lsproto.RequestMessage) error {
262362}
263363
264364func (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+
265369 s .logger = project .NewLogger ([]io.Writer {s .stderr }, "" /*file*/ , project .LogLevelVerbose )
266370 s .projectService = project .NewService (s , project.ServiceOptions {
267371 Logger : s .logger ,
372+ WatchEnabled : s .watchEnabled ,
268373 PositionEncoding : s .positionEncoding ,
269374 })
270375
@@ -322,6 +427,11 @@ func (s *Server) handleDidClose(req *lsproto.RequestMessage) error {
322427 return nil
323428}
324429
430+ func (s * Server ) handleDidChangeWatchedFiles (req * lsproto.RequestMessage ) error {
431+ params := req .Params .(* lsproto.DidChangeWatchedFilesParams )
432+ return s .projectService .OnWatchedFilesChanged (params .Changes )
433+ }
434+
325435func (s * Server ) handleDocumentDiagnostic (req * lsproto.RequestMessage ) error {
326436 params := req .Params .(* lsproto.DocumentDiagnosticParams )
327437 file , project := s .getFileAndProject (params .TextDocument .Uri )
@@ -445,3 +555,10 @@ func codeFence(lang string, code string) string {
445555func ptrTo [T any ](v T ) * T {
446556 return & v
447557}
558+
559+ func ptrIsTrue (v * bool ) bool {
560+ if v == nil {
561+ return false
562+ }
563+ return * v
564+ }
0 commit comments