@@ -29,7 +29,23 @@ 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.
36+ /// The Client will sent requests and notifications to the Backend, which will delegate them to the appropriate WorkspaceWorker.
37+ /// The Backend also manages the in-memory file system for open files.
38+ ///
39+ /// A basic flow of a Editor and Server interaction is as follows:
40+ /// - Editor sends `initialize` request with workspace folders and client capabilities.
41+ /// - Server responds with its capabilities.
42+ /// - Editor sends `initialized` notification.
43+ /// - Server registers dynamic capabilities like file watchers.
44+ /// - Editor sends `textDocument/didOpen`, `textDocument/didChange`, `textDocument/didSave`, and `textDocument/didClose` notifications.
45+ /// - Editor sends `shutdown` request when the user closes the editor.
46+ /// - Editor sends `exit` notification and the server exits.
3247pub struct Backend {
48+ // The LSP client to communicate with the editor or IDE.
3349 client : Client ,
3450 // Each Workspace has it own worker with Linter (and in the future the formatter).
3551 // We must respect each program inside with its own root folder
@@ -39,11 +55,21 @@ pub struct Backend {
3955 // 1. `initialize` request with workspace folders
4056 // 2. `workspace/didChangeWorkspaceFolders` request
4157 workspace_workers : Arc < RwLock < Vec < WorkspaceWorker > > > ,
58+ // Capabilities of the language server, set once during `initialize` request.
59+ // Depending on the client capabilities, the server supports different capabilities.
4260 capabilities : OnceCell < Capabilities > ,
61+ // A simple in-memory file system to store the content of open files.
62+ // The client will send the content of in-memory files on `textDocument/didOpen` and `textDocument/didChange`.
63+ // This is only needed when the client supports `textDocument/formatting` request,
4364 file_system : Arc < RwLock < LSPFileSystem > > ,
4465}
4566
4667impl LanguageServer for Backend {
68+ /// Initialize the language server with the given parameters.
69+ /// This method sets up workspace workers, capabilities, and starts the
70+ /// [WorkspaceWorker]s if the client sent the configuration with initialization options.
71+ ///
72+ /// @link <https://microsoft.github.io/language-server-protocol/specifications/specification-current/#initialize>
4773 #[ expect( deprecated) ] // `params.root_uri` is deprecated, we are only falling back to it if no workspace folder is provided
4874 async fn initialize ( & self , params : InitializeParams ) -> Result < InitializeResult > {
4975 let server_version = env ! ( "CARGO_PKG_VERSION" ) ;
@@ -134,6 +160,12 @@ impl LanguageServer for Backend {
134160 } )
135161 }
136162
163+ /// It registers dynamic capabilities like file watchers and formatting if the client supports it.
164+ /// It also starts the [WorkspaceWorker]s if they did not start during initialization.
165+ /// If the client supports `workspace/configuration` request, it will request the configuration for each workspace folder
166+ /// and start the [WorkspaceWorker]s with the received configuration.
167+ ///
168+ /// @link <https://microsoft.github.io/language-server-protocol/specifications/specification-current/#initialized>
137169 async fn initialized ( & self , _params : InitializedParams ) {
138170 debug ! ( "oxc initialized." ) ;
139171 let Some ( capabilities) = self . capabilities . get ( ) else {
@@ -209,6 +241,9 @@ impl LanguageServer for Backend {
209241 }
210242 }
211243
244+ /// This method clears all diagnostics and the in-memory file system if dynamic formatting is enabled.
245+ ///
246+ /// @link <https://microsoft.github.io/language-server-protocol/specifications/specification-current/#shutdown>
212247 async fn shutdown ( & self ) -> Result < ( ) > {
213248 self . clear_all_diagnostics ( ) . await ;
214249 if self . capabilities . get ( ) . is_some_and ( |option| option. dynamic_formatting ) {
@@ -217,6 +252,12 @@ impl LanguageServer for Backend {
217252 Ok ( ( ) )
218253 }
219254
255+ /// This method updates the configuration of each [WorkspaceWorker] and restarts them if necessary.
256+ /// It also manages dynamic registrations for file watchers and formatting based on the new configuration.
257+ /// It will remove/add dynamic registrations if the client supports it.
258+ /// As an example, if a workspace changes the configuration file path, the file watcher will be updated.
259+ ///
260+ /// @link <https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_didChangeConfiguration>
220261 async fn did_change_configuration ( & self , params : DidChangeConfigurationParams ) {
221262 let workers = self . workspace_workers . read ( ) . await ;
222263 let new_diagnostics: papaya:: HashMap < String , Vec < Diagnostic > , FxBuildHasher > =
@@ -354,6 +395,10 @@ impl LanguageServer for Backend {
354395 }
355396 }
356397
398+ /// This notification is sent when a configuration file of a tool changes (example: `.oxlintrc.json`).
399+ /// The server will re-lint the affected files and send updated diagnostics.
400+ ///
401+ /// @link <https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_didChangeWatchedFiles>
357402 async fn did_change_watched_files ( & self , params : DidChangeWatchedFilesParams ) {
358403 let workers = self . workspace_workers . read ( ) . await ;
359404 // ToDo: what if an empty changes flag is passed?
@@ -393,6 +438,12 @@ impl LanguageServer for Backend {
393438 self . publish_all_diagnostics ( x) . await ;
394439 }
395440
441+ /// The server will start new [WorkspaceWorker]s for added workspace folders
442+ /// and stop and remove [WorkspaceWorker]s for removed workspace folders including:
443+ /// - clearing diagnostics
444+ /// - unregistering file watchers
445+ ///
446+ /// @link <https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_didChangeWorkspaceFolders>
396447 async fn did_change_workspace_folders ( & self , params : DidChangeWorkspaceFoldersParams ) {
397448 let mut workers = self . workspace_workers . write ( ) . await ;
398449 let mut cleared_diagnostics = vec ! [ ] ;
@@ -471,6 +522,10 @@ impl LanguageServer for Backend {
471522 }
472523 }
473524
525+ /// It will remove the in-memory file content, because the file is saved to disk.
526+ /// It will re-lint the file and send updated diagnostics, if necessary.
527+ ///
528+ /// @link <https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_didSave>
474529 async fn did_save ( & self , params : DidSaveTextDocumentParams ) {
475530 debug ! ( "oxc server did save" ) ;
476531 let uri = & params. text_document . uri ;
@@ -494,9 +549,10 @@ impl LanguageServer for Backend {
494549 . await ;
495550 }
496551 }
497-
498- /// When the document changed, it may not be written to disk, so we should
499- /// get the file context from the language client
552+ /// It will update the in-memory file content if the client supports dynamic formatting.
553+ /// It will re-lint the file and send updated diagnostics, if necessary.
554+ ///
555+ /// @link <https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_didChange>
500556 async fn did_change ( & self , params : DidChangeTextDocumentParams ) {
501557 let uri = & params. text_document . uri ;
502558 let workers = self . workspace_workers . read ( ) . await ;
@@ -522,6 +578,10 @@ impl LanguageServer for Backend {
522578 }
523579 }
524580
581+ /// It will add the in-memory file content if the client supports dynamic formatting.
582+ /// It will lint the file and send diagnostics, if necessary.
583+ ///
584+ /// @link <https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_didOpen>
525585 async fn did_open ( & self , params : DidOpenTextDocumentParams ) {
526586 let uri = & params. text_document . uri ;
527587 let workers = self . workspace_workers . read ( ) . await ;
@@ -548,6 +608,10 @@ impl LanguageServer for Backend {
548608 }
549609 }
550610
611+ /// It will remove the in-memory file content if the client supports dynamic formatting.
612+ /// It will clear the diagnostics (internally) for the closed file.
613+ ///
614+ /// @link <https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_didClose>
551615 async fn did_close ( & self , params : DidCloseTextDocumentParams ) {
552616 let uri = & params. text_document . uri ;
553617 let workers = self . workspace_workers . read ( ) . await ;
@@ -560,6 +624,10 @@ impl LanguageServer for Backend {
560624 worker. remove_diagnostics ( & params. text_document . uri ) . await ;
561625 }
562626
627+ /// It will return code actions or commands for the given range.
628+ /// The client can send `context.only` to `source.fixAll.oxc` to fix all diagnostics of the file.
629+ ///
630+ /// @link <https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_codeAction>
563631 async fn code_action ( & self , params : CodeActionParams ) -> Result < Option < CodeActionResponse > > {
564632 let uri = & params. text_document . uri ;
565633 let workers = self . workspace_workers . read ( ) . await ;
@@ -582,6 +650,10 @@ impl LanguageServer for Backend {
582650 Ok ( Some ( code_actions) )
583651 }
584652
653+ /// It will execute the given command with the provided arguments.
654+ /// Currently, only the `fixAll` command is supported.
655+ ///
656+ /// @link <https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_executeCommand>
585657 async fn execute_command (
586658 & self ,
587659 params : ExecuteCommandParams ,
@@ -618,6 +690,9 @@ impl LanguageServer for Backend {
618690 Err ( Error :: invalid_request ( ) )
619691 }
620692
693+ /// It will return text edits to format the document if formatting is enabled for the workspace.
694+ ///
695+ /// @link <https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting>
621696 async fn formatting ( & self , params : DocumentFormattingParams ) -> Result < Option < Vec < TextEdit > > > {
622697 let uri = & params. text_document . uri ;
623698 let workers = self . workspace_workers . read ( ) . await ;
@@ -629,6 +704,10 @@ impl LanguageServer for Backend {
629704}
630705
631706impl Backend {
707+ /// Create a new Backend with the given client.
708+ /// The Backend will manage multiple [WorkspaceWorker]s and their configurations.
709+ /// It also holds the capabilities of the language server and an in-memory file system.
710+ /// The client is used to communicate with the LSP client.
632711 pub fn new ( client : Client ) -> Self {
633712 Self {
634713 client,
@@ -670,7 +749,7 @@ impl Backend {
670749 options
671750 }
672751
673- // clears all diagnostics for workspace folders
752+ /// Clears all diagnostics for workspace folders
674753 async fn clear_all_diagnostics ( & self ) {
675754 let mut cleared_diagnostics = vec ! [ ] ;
676755 let workers = & * self . workspace_workers . read ( ) . await ;
@@ -680,6 +759,7 @@ impl Backend {
680759 self . publish_all_diagnostics ( & cleared_diagnostics) . await ;
681760 }
682761
762+ /// Publish diagnostics for all files.
683763 async fn publish_all_diagnostics ( & self , result : & [ ( String , Vec < Diagnostic > ) ] ) {
684764 join_all ( result. iter ( ) . map ( |( path, diagnostics) | {
685765 self . client . publish_diagnostics ( Uri :: from_str ( path) . unwrap ( ) , diagnostics. clone ( ) , None )
0 commit comments