Skip to content

Commit

Permalink
refactor(language_server): add capabilities struct (#7906)
Browse files Browse the repository at this point in the history
vscode test from local, 
intellij test from
#7445 (comment)
  • Loading branch information
Sysix authored Dec 16, 2024
1 parent 0867b40 commit e2b6233
Show file tree
Hide file tree
Showing 2 changed files with 140 additions and 45 deletions.
132 changes: 132 additions & 0 deletions crates/oxc_language_server/src/capabilities.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
use tower_lsp::lsp_types::{
ClientCapabilities, CodeActionKind, CodeActionOptions, CodeActionProviderCapability, OneOf,
ServerCapabilities, TextDocumentSyncCapability, TextDocumentSyncKind, WorkDoneProgressOptions,
WorkspaceFoldersServerCapabilities, WorkspaceServerCapabilities,
};

pub const CODE_ACTION_KIND_SOURCE_FIX_ALL_OXC: CodeActionKind =
CodeActionKind::new("source.fixAll.oxc");

pub struct Capabilities {
pub code_action_provider: bool,
}

impl From<ClientCapabilities> for Capabilities {
fn from(value: ClientCapabilities) -> Self {
// check if the client support some code action literal support
let code_action_provider = value.text_document.is_some_and(|capability| {
capability.code_action.is_some_and(|code_action| {
code_action.code_action_literal_support.is_some_and(|literal_support| {
!literal_support.code_action_kind.value_set.is_empty()
})
})
});

Self { code_action_provider }
}
}

impl From<Capabilities> for ServerCapabilities {
fn from(value: Capabilities) -> Self {
Self {
text_document_sync: Some(TextDocumentSyncCapability::Kind(TextDocumentSyncKind::FULL)),
workspace: Some(WorkspaceServerCapabilities {
workspace_folders: Some(WorkspaceFoldersServerCapabilities {
supported: Some(true),
change_notifications: Some(OneOf::Left(true)),
}),
file_operations: None,
}),
code_action_provider: if value.code_action_provider {
Some(CodeActionProviderCapability::Options(CodeActionOptions {
code_action_kinds: Some(vec![
CodeActionKind::QUICKFIX,
CODE_ACTION_KIND_SOURCE_FIX_ALL_OXC,
]),
work_done_progress_options: WorkDoneProgressOptions {
work_done_progress: None,
},
resolve_provider: None,
}))
} else {
None
},
..ServerCapabilities::default()
}
}
}

#[cfg(test)]
mod test {
use tower_lsp::lsp_types::{
ClientCapabilities, CodeActionClientCapabilities, CodeActionKindLiteralSupport,
CodeActionLiteralSupport, TextDocumentClientCapabilities,
};

use super::Capabilities;

#[test]
fn test_code_action_provider_vscode() {
let client_capabilities = ClientCapabilities {
text_document: Some(TextDocumentClientCapabilities {
code_action: Some(CodeActionClientCapabilities {
code_action_literal_support: Some(CodeActionLiteralSupport {
code_action_kind: CodeActionKindLiteralSupport {
// this is from build (see help, about):
// Version: 1.95.3 (user setup)
// Commit: f1a4fb101478ce6ec82fe9627c43efbf9e98c813
value_set: vec![
#[allow(clippy::manual_string_new)]
"".into(),
"quickfix".into(),
"refactor".into(),
"refactor.extract".into(),
"refactor.inline".into(),
"refactor.rewrite".into(),
"source".into(),
"source.organizeImports".into(),
],
},
}),
..CodeActionClientCapabilities::default()
}),
..TextDocumentClientCapabilities::default()
}),
..ClientCapabilities::default()
};

let capabilities = Capabilities::from(client_capabilities);

assert!(capabilities.code_action_provider);
}

#[test]
fn test_code_action_provider_intellij() {
let client_capabilities = ClientCapabilities {
text_document: Some(TextDocumentClientCapabilities {
code_action: Some(CodeActionClientCapabilities {
code_action_literal_support: Some(CodeActionLiteralSupport {
code_action_kind: CodeActionKindLiteralSupport {
// this is from build (see help, about):
// Build #IU-243.22562.145, built on December 8, 2024
value_set: vec![
"quickfix".into(),
#[allow(clippy::manual_string_new)]
"".into(),
"source".into(),
"refactor".into(),
],
},
}),
..CodeActionClientCapabilities::default()
}),
..TextDocumentClientCapabilities::default()
}),
..ClientCapabilities::default()
};

let capabilities = Capabilities::from(client_capabilities);

assert!(capabilities.code_action_provider);
}
}
53 changes: 8 additions & 45 deletions crates/oxc_language_server/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,21 @@ use tokio::sync::{Mutex, OnceCell, RwLock, SetError};
use tower_lsp::{
jsonrpc::{Error, ErrorCode, Result},
lsp_types::{
CodeAction, CodeActionKind, CodeActionOptions, CodeActionOrCommand, CodeActionParams,
CodeActionProviderCapability, CodeActionResponse, ConfigurationItem, Diagnostic,
DidChangeConfigurationParams, DidChangeTextDocumentParams, DidChangeWatchedFilesParams,
DidCloseTextDocumentParams, DidOpenTextDocumentParams, DidSaveTextDocumentParams,
InitializeParams, InitializeResult, InitializedParams, NumberOrString, OneOf, Position,
Range, ServerCapabilities, ServerInfo, TextDocumentSyncCapability, TextDocumentSyncKind,
TextEdit, Url, WorkDoneProgressOptions, WorkspaceEdit, WorkspaceFoldersServerCapabilities,
WorkspaceServerCapabilities,
CodeAction, CodeActionKind, CodeActionOrCommand, CodeActionParams, CodeActionResponse,
ConfigurationItem, Diagnostic, DidChangeConfigurationParams, DidChangeTextDocumentParams,
DidChangeWatchedFilesParams, DidCloseTextDocumentParams, DidOpenTextDocumentParams,
DidSaveTextDocumentParams, InitializeParams, InitializeResult, InitializedParams,
NumberOrString, Position, Range, ServerInfo, TextEdit, Url, WorkspaceEdit,
},
Client, LanguageServer, LspService, Server,
};

use oxc_linter::{FixKind, LinterBuilder, Oxlintrc};

use crate::capabilities::{Capabilities, CODE_ACTION_KIND_SOURCE_FIX_ALL_OXC};
use crate::linter::{DiagnosticReport, ServerLinter};

mod capabilities;
mod linter;

type FxDashMap<K, V> = DashMap<K, V, FxBuildHasher>;
Expand Down Expand Up @@ -88,9 +87,6 @@ enum SyntheticRunLevel {
OnType,
}

const CODE_ACTION_KIND_SOURCE_FIX_ALL_OXC: CodeActionKind =
CodeActionKind::new("source.fixAll.oxc");

#[tower_lsp::async_trait]
impl LanguageServer for Backend {
async fn initialize(&self, params: InitializeParams) -> Result<InitializeResult> {
Expand All @@ -106,45 +102,12 @@ impl LanguageServer for Backend {
*self.options.lock().await = value;
}

// check if the client support some code action literal support
let code_action_provider = if params.capabilities.text_document.is_some_and(|capability| {
capability.code_action.is_some_and(|code_action| {
code_action.code_action_literal_support.is_some_and(|literal_support| {
!literal_support.code_action_kind.value_set.is_empty()
})
})
}) {
Some(CodeActionProviderCapability::Options(CodeActionOptions {
code_action_kinds: Some(vec![
CodeActionKind::QUICKFIX,
CODE_ACTION_KIND_SOURCE_FIX_ALL_OXC,
]),
work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None },
resolve_provider: None,
}))
} else {
None
};

let oxlintrc = self.init_linter_config().await;
self.init_ignore_glob(oxlintrc).await;
Ok(InitializeResult {
server_info: Some(ServerInfo { name: "oxc".into(), version: None }),
offset_encoding: None,
capabilities: ServerCapabilities {
text_document_sync: Some(TextDocumentSyncCapability::Kind(
TextDocumentSyncKind::FULL,
)),
workspace: Some(WorkspaceServerCapabilities {
workspace_folders: Some(WorkspaceFoldersServerCapabilities {
supported: Some(true),
change_notifications: Some(OneOf::Left(true)),
}),
file_operations: None,
}),
code_action_provider,
..ServerCapabilities::default()
},
capabilities: Capabilities::from(params.capabilities).into(),
})
}

Expand Down

0 comments on commit e2b6233

Please sign in to comment.