Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions crates/oxc_language_server/src/capabilities.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub struct Capabilities {
pub workspace_execute_command: bool,
pub workspace_configuration: bool,
pub dynamic_watchers: bool,
pub dynamic_formatting: bool,
}

impl From<ClientCapabilities> for Capabilities {
Expand All @@ -39,13 +40,20 @@ impl From<ClientCapabilities> for Capabilities {
watched_files.dynamic_registration.is_some_and(|dynamic| dynamic)
})
});
// TODO: enable it when we support formatting
// let formatting = value.text_document.as_ref().is_some_and(|text_document| {
// text_document.formatting.is_some_and(|formatting| {
// formatting.dynamic_registration.is_some_and(|dynamic| dynamic)
// })
// });

Self {
code_action_provider,
workspace_apply_edit,
workspace_execute_command,
workspace_configuration,
dynamic_watchers,
dynamic_formatting: false,
}
}
}
Expand Down
27 changes: 27 additions & 0 deletions crates/oxc_language_server/src/file_system.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use tower_lsp_server::lsp_types::Uri;

use crate::ConcurrentHashMap;

#[derive(Debug, Default)]
pub struct LSPFileSystem {
files: ConcurrentHashMap<Uri, String>,
}

impl LSPFileSystem {
pub fn clear(&self) {
self.files.pin().clear();
}

pub fn set(&self, uri: &Uri, content: String) {
self.files.pin().insert(uri.clone(), content);
}

#[expect(dead_code)] // used for the oxc_formatter in the future
pub fn get(&self, uri: &Uri) -> Option<String> {
self.files.pin().get(uri).cloned()
}

pub fn remove(&self, uri: &Uri) {
self.files.pin().remove(uri);
}
}
29 changes: 29 additions & 0 deletions crates/oxc_language_server/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use tower_lsp_server::{
mod capabilities;
mod code_actions;
mod commands;
mod file_system;
mod formatter;
mod linter;
mod options;
Expand All @@ -36,6 +37,8 @@ use linter::server_linter::ServerLinterRun;
use options::{Options, WorkspaceOption};
use worker::WorkspaceWorker;

use crate::file_system::LSPFileSystem;

type ConcurrentHashMap<K, V> = papaya::HashMap<K, V, FxBuildHasher>;

const OXC_CONFIG_FILE: &str = ".oxlintrc.json";
Expand All @@ -51,6 +54,7 @@ struct Backend {
// 2. `workspace/didChangeWorkspaceFolders` request
workspace_workers: Arc<RwLock<Vec<WorkspaceWorker>>>,
capabilities: OnceCell<Capabilities>,
file_system: Arc<RwLock<LSPFileSystem>>,
}

impl LanguageServer for Backend {
Expand Down Expand Up @@ -203,6 +207,9 @@ impl LanguageServer for Backend {

async fn shutdown(&self) -> Result<()> {
self.clear_all_diagnostics().await;
if self.capabilities.get().is_some_and(|option| option.dynamic_formatting) {
self.file_system.write().await.clear();
}
Ok(())
}

Expand Down Expand Up @@ -444,6 +451,12 @@ impl LanguageServer for Backend {
let Some(worker) = workers.iter().find(|worker| worker.is_responsible_for_uri(uri)) else {
return;
};

if self.capabilities.get().is_some_and(|option| option.dynamic_formatting) {
// saving the file means we can read again from the file system
self.file_system.write().await.remove(uri);
}

if let Some(diagnostics) = worker.lint_file(uri, None, ServerLinterRun::OnSave).await {
self.client
.publish_diagnostics(
Expand All @@ -464,6 +477,13 @@ impl LanguageServer for Backend {
return;
};
let content = params.content_changes.first().map(|c| c.text.clone());

if self.capabilities.get().is_some_and(|option| option.dynamic_formatting)
&& let Some(content) = &content
{
self.file_system.write().await.set(uri, content.to_string());
}

if let Some(diagnostics) = worker.lint_file(uri, content, ServerLinterRun::OnType).await {
self.client
.publish_diagnostics(
Expand All @@ -483,6 +503,11 @@ impl LanguageServer for Backend {
};

let content = params.text_document.text;

if self.capabilities.get().is_some_and(|option| option.dynamic_formatting) {
self.file_system.write().await.set(uri, content.to_string());
}

if let Some(diagnostics) =
worker.lint_file(uri, Some(content), ServerLinterRun::Always).await
{
Expand All @@ -502,6 +527,9 @@ impl LanguageServer for Backend {
let Some(worker) = workers.iter().find(|worker| worker.is_responsible_for_uri(uri)) else {
return;
};
if self.capabilities.get().is_some_and(|option| option.dynamic_formatting) {
self.file_system.write().await.remove(uri);
}
worker.remove_diagnostics(&params.text_document.uri).await;
}

Expand Down Expand Up @@ -626,6 +654,7 @@ async fn main() {
client,
workspace_workers: Arc::new(RwLock::new(vec![])),
capabilities: OnceCell::new(),
file_system: Arc::new(RwLock::new(LSPFileSystem::default())),
})
.finish();

Expand Down
Loading