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
19 changes: 13 additions & 6 deletions crates/oxc_language_server/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use tower_lsp_server::{
use tracing::{debug, error, info, warn};

use crate::{
ConcurrentHashMap, ToolBuilder,
ConcurrentHashMap, LanguageId, ToolBuilder,
capabilities::{Capabilities, DiagnosticMode, server_capabilities},
file_system::LSPFileSystem,
options::WorkspaceOption,
Expand Down Expand Up @@ -242,7 +242,8 @@ impl LanguageServer for Backend {
if responsible_worker.is_none_or(|w| !std::ptr::eq(w, worker)) {
continue;
}
let content = self.file_system.read().await.get(uri);
let content =
self.file_system.read().await.get(uri).map(|(_, content)| content);
let diagnostics = worker.run_diagnostic(uri, content.as_deref()).await;
match diagnostics {
Err(err) => {
Expand Down Expand Up @@ -659,7 +660,11 @@ impl LanguageServer for Backend {

let content = params.text_document.text;

self.file_system.write().await.set(uri.clone(), content.clone());
self.file_system.write().await.set_with_language(
uri.clone(),
LanguageId::new(params.text_document.language_id),
content.clone(),
);

if self.capabilities.get().is_some_and(|cap| cap.diagnostic_mode == DiagnosticMode::Push) {
match worker.run_diagnostic(&uri, Some(&content)).await {
Expand Down Expand Up @@ -757,8 +762,9 @@ impl LanguageServer for Backend {
RelatedFullDocumentDiagnosticReport::default(),
)));
};
let diagnostics =
worker.run_diagnostic(uri, self.file_system.read().await.get(uri).as_deref()).await;

let content = self.file_system.read().await.get(uri).map(|(_, content)| content);
let diagnostics = worker.run_diagnostic(uri, content.as_deref()).await;

let diagnostics = match diagnostics {
Err(err) => {
Expand Down Expand Up @@ -820,7 +826,8 @@ impl LanguageServer for Backend {
let Some(worker) = Self::find_worker_for_uri(&workers, uri) else {
return Ok(None);
};
match worker.format_file(uri, self.file_system.read().await.get(uri).as_deref()).await {
let content = self.file_system.read().await.get(uri).map(|(_, content)| content);
match worker.format_file(uri, content.as_deref()).await {
Ok(edits) => {
if edits.is_empty() {
return Ok(None);
Expand Down
17 changes: 13 additions & 4 deletions crates/oxc_language_server/src/file_system.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use tower_lsp_server::ls_types::Uri;

use crate::ConcurrentHashMap;
use crate::{ConcurrentHashMap, LanguageId};

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

impl LSPFileSystem {
Expand All @@ -13,10 +13,19 @@ impl LSPFileSystem {
}

pub fn set(&self, uri: Uri, content: String) {
self.files.pin().insert(uri, content);
let language_id = self.get_language_id(&uri).unwrap_or_default();
self.files.pin().insert(uri, (language_id, content));
}

pub fn get(&self, uri: &Uri) -> Option<String> {
pub fn set_with_language(&self, uri: Uri, language_id: LanguageId, content: String) {
self.files.pin().insert(uri, (language_id, content));
}

pub fn get_language_id(&self, uri: &Uri) -> Option<LanguageId> {
self.files.pin().get(uri).map(|(lang, _)| lang.clone())
}

pub fn get(&self, uri: &Uri) -> Option<(LanguageId, String)> {
self.files.pin().get(uri).cloned()
}

Expand Down
17 changes: 17 additions & 0 deletions crates/oxc_language_server/src/language_id.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/// Represents language IDs passed from the client in `textDocument/didOpen` notifications.
///
/// These are used to select the appropriate parser strategy for a given file.
/// It is the tool's responsibility to use the correct parser strategy for a file
/// based on its file extension, but newly created files may not have an extension,
/// so we rely on the language ID to determine which parser strategy to use.
///
/// For a more complete list of known language identifiers, see:
/// <https://code.visualstudio.com/docs/languages/identifiers#_known-language-identifiers>
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct LanguageId(String);

impl LanguageId {
pub fn new(id: String) -> Self {
Self(id)
}
}
2 changes: 2 additions & 0 deletions crates/oxc_language_server/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ use tower_lsp_server::{LspService, Server, ls_types::ServerInfo};
mod backend;
mod capabilities;
mod file_system;
mod language_id;
mod options;
#[cfg(test)]
mod tests;
mod tool;
mod worker;

pub use crate::capabilities::{Capabilities, DiagnosticMode};
pub use crate::language_id::LanguageId;
pub use crate::tool::{DiagnosticResult, Tool, ToolBuilder, ToolRestartChanges};

pub type ConcurrentHashMap<K, V> = papaya::HashMap<K, V, FxBuildHasher>;
Expand Down
5 changes: 2 additions & 3 deletions crates/oxc_language_server/src/worker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -373,9 +373,8 @@ impl WorkspaceWorker {
};

for uri in file_system.keys() {
let Ok(mut reports) =
tool.run_diagnostic(&uri, file_system.get(&uri).as_deref())
else {
let content = file_system.get(&uri).map(|(_, content)| content);
let Ok(mut reports) = tool.run_diagnostic(&uri, content.as_deref()) else {
// If diagnostics could not be run, skip this URI, but continue with others
// TODO: Should we aggregate errors instead? One by one, or all together?
continue;
Expand Down
Loading