Skip to content

Commit 63b9d59

Browse files
committed
docs(language_server): docs for Backend struct
1 parent ee9ecbe commit 63b9d59

File tree

1 file changed

+84
-4
lines changed

1 file changed

+84
-4
lines changed

crates/oxc_language_server/src/backend.rs

Lines changed: 84 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
3247
pub 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

4667
impl 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

631706
impl 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

Comments
 (0)