@@ -29,6 +29,10 @@ use crate::{
2929 worker:: WorkspaceWorker ,
3030} ;
3131
32+ /// The Backend implements the LanguageServer trait to handle LSP requests and notifications.
33+ ///
34+ /// It manages multiple WorkspaceWorkers, each corresponding to a workspace folder.
35+ /// Depending on the client's capabilities, it can dynamically register features and start up other services.
3236pub struct Backend {
3337 client : Client ,
3438 // Each Workspace has it own worker with Linter (and in the future the formatter).
@@ -39,11 +43,21 @@ pub struct Backend {
3943 // 1. `initialize` request with workspace folders
4044 // 2. `workspace/didChangeWorkspaceFolders` request
4145 workspace_workers : Arc < RwLock < Vec < WorkspaceWorker > > > ,
46+ // Capabilities of the language server, set once during `initialize` request.
47+ // Depending on the client capabilities, the server supports different capabilities.
4248 capabilities : OnceCell < Capabilities > ,
49+ // A simple in-memory file system to store the content of open files.
50+ // The client will send the content of in-memory files on `textDocument/didOpen` and `textDocument/didChange`.
51+ // This is only needed when the client supports `textDocument/formatting` request,
4352 file_system : Arc < RwLock < LSPFileSystem > > ,
4453}
4554
4655impl LanguageServer for Backend {
56+ /// Initialize the language server with the given parameters.
57+ /// This method sets up workspace workers, capabilities, and starts the
58+ /// [WorkspaceWorker]s if the client sent the configuration with initialization options.
59+ ///
60+ /// @link <https://microsoft.github.io/language-server-protocol/specifications/specification-current/#initialize>
4761 #[ expect( deprecated) ] // `params.root_uri` is deprecated, we are only falling back to it if no workspace folder is provided
4862 async fn initialize ( & self , params : InitializeParams ) -> Result < InitializeResult > {
4963 let server_version = env ! ( "CARGO_PKG_VERSION" ) ;
@@ -134,6 +148,11 @@ impl LanguageServer for Backend {
134148 } )
135149 }
136150
151+ /// The `initialized` notification is sent from the client to the server after the `initialize` request.
152+ /// This method registers dynamic capabilities like file watchers and formatting if the client supports it.
153+ /// It also starts the [WorkspaceWorker]s if they did not start during initialization.
154+ ///
155+ /// @link <https://microsoft.github.io/language-server-protocol/specifications/specification-current/#initialized>
137156 async fn initialized ( & self , _params : InitializedParams ) {
138157 debug ! ( "oxc initialized." ) ;
139158 let Some ( capabilities) = self . capabilities . get ( ) else {
@@ -209,6 +228,10 @@ impl LanguageServer for Backend {
209228 }
210229 }
211230
231+ /// The `shutdown` request is sent from the client to the server to ask for a graceful shutdown.
232+ /// This method clears all diagnostics and the in-memory file system if dynamic formatting is enabled.
233+ ///
234+ /// @link <https://microsoft.github.io/language-server-protocol/specifications/specification-current/#shutdown>
212235 async fn shutdown ( & self ) -> Result < ( ) > {
213236 self . clear_all_diagnostics ( ) . await ;
214237 if self . capabilities . get ( ) . is_some_and ( |option| option. dynamic_formatting ) {
@@ -217,6 +240,12 @@ impl LanguageServer for Backend {
217240 Ok ( ( ) )
218241 }
219242
243+ /// The `workspace/didChangeConfiguration` notification is sent from the client to the server
244+ /// when the server configuration has changed in the client.
245+ /// This method updates the configuration of each [WorkspaceWorker] and restarts them if necessary.
246+ /// It also manages dynamic registrations for file watchers and formatting based on the new configuration.
247+ ///
248+ /// @link <https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_didChangeConfiguration>
220249 async fn did_change_configuration ( & self , params : DidChangeConfigurationParams ) {
221250 let workers = self . workspace_workers . read ( ) . await ;
222251 let new_diagnostics: papaya:: HashMap < String , Vec < Diagnostic > , FxBuildHasher > =
@@ -354,6 +383,10 @@ impl LanguageServer for Backend {
354383 }
355384 }
356385
386+ /// The `workspace/didChangeWatchedFiles` notification is sent from the client to the server.
387+ /// This notification is sent when a configuration file of a tool changes (example: `.oxlintrc.json`).
388+ ///
389+ /// @link <https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_didChangeWatchedFiles>
357390 async fn did_change_watched_files ( & self , params : DidChangeWatchedFilesParams ) {
358391 let workers = self . workspace_workers . read ( ) . await ;
359392 // ToDo: what if an empty changes flag is passed?
@@ -393,6 +426,13 @@ impl LanguageServer for Backend {
393426 self . publish_all_diagnostics ( x) . await ;
394427 }
395428
429+ /// The `workspace/didChangeWorkspaceFolders` notification is sent from the client to the server.
430+ /// The server will start new [WorkspaceWorker]s for added workspace folders
431+ /// and stop and remove [WorkspaceWorker]s for removed workspace folders including:
432+ /// - clearing diagnostics
433+ /// - unregistering file watchers
434+ ///
435+ /// @link <https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_didChangeWorkspaceFolders>
396436 async fn did_change_workspace_folders ( & self , params : DidChangeWorkspaceFoldersParams ) {
397437 let mut workers = self . workspace_workers . write ( ) . await ;
398438 let mut cleared_diagnostics = vec ! [ ] ;
@@ -471,6 +511,10 @@ impl LanguageServer for Backend {
471511 }
472512 }
473513
514+ /// The `textDocument/didSave` notification is sent from the client to the server.
515+ /// It will remove the in-memory file content, because the file is saved to disk.
516+ ///
517+ /// @link <https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_didSave>
474518 async fn did_save ( & self , params : DidSaveTextDocumentParams ) {
475519 debug ! ( "oxc server did save" ) ;
476520 let uri = & params. text_document . uri ;
@@ -495,8 +539,10 @@ impl LanguageServer for Backend {
495539 }
496540 }
497541
498- /// When the document changed, it may not be written to disk, so we should
499- /// get the file context from the language client
542+ /// The `textDocument/didChange` notification is sent from the client to the server.
543+ /// It will update the in-memory file content if the client supports dynamic formatting.
544+ ///
545+ /// @link <https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_didChange>
500546 async fn did_change ( & self , params : DidChangeTextDocumentParams ) {
501547 let uri = & params. text_document . uri ;
502548 let workers = self . workspace_workers . read ( ) . await ;
@@ -522,6 +568,10 @@ impl LanguageServer for Backend {
522568 }
523569 }
524570
571+ /// The `textDocument/didOpen` notification is sent from the client to the server.
572+ /// It will add the in-memory file content if the client supports dynamic formatting.
573+ ///
574+ /// @link <https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_didOpen>
525575 async fn did_open ( & self , params : DidOpenTextDocumentParams ) {
526576 let uri = & params. text_document . uri ;
527577 let workers = self . workspace_workers . read ( ) . await ;
@@ -548,6 +598,10 @@ impl LanguageServer for Backend {
548598 }
549599 }
550600
601+ /// The `textDocument/didClose` notification is sent from the client to the server.
602+ /// It will remove the in-memory file content if the client supports dynamic formatting.
603+ ///
604+ /// @link <https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_didClose>
551605 async fn did_close ( & self , params : DidCloseTextDocumentParams ) {
552606 let uri = & params. text_document . uri ;
553607 let workers = self . workspace_workers . read ( ) . await ;
@@ -560,6 +614,10 @@ impl LanguageServer for Backend {
560614 worker. remove_diagnostics ( & params. text_document . uri ) . await ;
561615 }
562616
617+ /// The `textDocument/codeAction` request is sent from the client to the server.
618+ /// It will return code actions or commands for the given range.
619+ ///
620+ /// @link <https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_codeAction>
563621 async fn code_action ( & self , params : CodeActionParams ) -> Result < Option < CodeActionResponse > > {
564622 let uri = & params. text_document . uri ;
565623 let workers = self . workspace_workers . read ( ) . await ;
@@ -582,6 +640,11 @@ impl LanguageServer for Backend {
582640 Ok ( Some ( code_actions) )
583641 }
584642
643+ /// The `workspace/executeCommand` request is sent from the client to the server.
644+ /// It will execute the given command with the provided arguments.
645+ /// Currently, only the `fixAll` command is supported.
646+ ///
647+ /// @link <https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_executeCommand>
585648 async fn execute_command (
586649 & self ,
587650 params : ExecuteCommandParams ,
@@ -618,6 +681,10 @@ impl LanguageServer for Backend {
618681 Err ( Error :: invalid_request ( ) )
619682 }
620683
684+ /// The `textDocument/formatting` request is sent from the client to the server.
685+ /// It will return text edits to format the document if formatting is enabled for the workspace.
686+ ///
687+ /// @link <https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting>
621688 async fn formatting ( & self , params : DocumentFormattingParams ) -> Result < Option < Vec < TextEdit > > > {
622689 let uri = & params. text_document . uri ;
623690 let workers = self . workspace_workers . read ( ) . await ;
@@ -629,6 +696,10 @@ impl LanguageServer for Backend {
629696}
630697
631698impl Backend {
699+ /// Create a new Backend with the given client.
700+ /// The Backend will manage multiple [WorkspaceWorker]s and their configurations.
701+ /// It also holds the capabilities of the language server and an in-memory file system.
702+ /// The client is used to communicate with the LSP client.
632703 pub fn new ( client : Client ) -> Self {
633704 Self {
634705 client,
@@ -670,7 +741,7 @@ impl Backend {
670741 options
671742 }
672743
673- // clears all diagnostics for workspace folders
744+ /// clears all diagnostics for workspace folders
674745 async fn clear_all_diagnostics ( & self ) {
675746 let mut cleared_diagnostics = vec ! [ ] ;
676747 let workers = & * self . workspace_workers . read ( ) . await ;
@@ -680,6 +751,7 @@ impl Backend {
680751 self . publish_all_diagnostics ( & cleared_diagnostics) . await ;
681752 }
682753
754+ /// Publish diagnostics for all files.
683755 async fn publish_all_diagnostics ( & self , result : & [ ( String , Vec < Diagnostic > ) ] ) {
684756 join_all ( result. iter ( ) . map ( |( path, diagnostics) | {
685757 self . client . publish_diagnostics ( Uri :: from_str ( path) . unwrap ( ) , diagnostics. clone ( ) , None )
0 commit comments