Skip to content
Draft
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
7 changes: 6 additions & 1 deletion apps/oxfmt/src/lsp/server_formatter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,12 @@ impl Tool for ServerFormatter {
}
}

fn run_format(&self, uri: &Uri, content: Option<&str>) -> Result<Vec<TextEdit>, String> {
fn run_format(
&self,
uri: &Uri,
content: Option<&str>,
_range: Option<&Range>,
) -> Result<Vec<TextEdit>, String> {
let Some(path) = uri.to_file_path() else { return Err("Invalid file URI".to_string()) };

if self.is_ignored(&path) {
Expand Down
4 changes: 4 additions & 0 deletions crates/oxc_language_server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,10 @@ The server will lint the file and report the diagnostics back to the client.

Returns a list of [TextEdit](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textEdit)

#### [textDocument/rangeFormatting](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_rangeFormatting)

Returns a list of [TextEdit](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textEdit) only specific for the provided range.

## Optional LSP Specifications from Client

### Client
Expand Down
41 changes: 37 additions & 4 deletions crates/oxc_language_server/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ use tower_lsp_server::{
DidChangeWorkspaceFoldersParams, DidCloseTextDocumentParams, DidOpenTextDocumentParams,
DidSaveTextDocumentParams, DocumentDiagnosticParams, DocumentDiagnosticReport,
DocumentDiagnosticReportKind, DocumentDiagnosticReportResult, DocumentFormattingParams,
ExecuteCommandParams, FullDocumentDiagnosticReport, InitializeParams, InitializeResult,
InitializedParams, MessageType, RelatedFullDocumentDiagnosticReport, ServerInfo, TextEdit,
Uri,
DocumentRangeFormattingParams, ExecuteCommandParams, FullDocumentDiagnosticReport,
InitializeParams, InitializeResult, InitializedParams, MessageType,
RelatedFullDocumentDiagnosticReport, ServerInfo, TextEdit, Uri,
},
};
use tracing::{debug, error, info, warn};
Expand Down Expand Up @@ -800,7 +800,40 @@ 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 {
match worker.format_file(uri, self.file_system.read().await.get(uri).as_deref(), None).await
{
Ok(edits) => {
if edits.is_empty() {
return Ok(None);
}
Ok(Some(edits))
}
Err(err) => {
Err(Error { code: ErrorCode::ServerError(1), message: Cow::Owned(err), data: None })
}
}
}

/// It will return text edits to format the document if formatting is enabled for the workspace.
///
/// See: <https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_rangeFormatting>
async fn range_formatting(
&self,
params: DocumentRangeFormattingParams,
) -> Result<Option<Vec<TextEdit>>> {
let uri = &params.text_document.uri;
let workers = self.workspace_workers.read().await;
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(),
Some(&params.range),
)
.await
{
Ok(edits) => {
if edits.is_empty() {
return Ok(None);
Expand Down
8 changes: 7 additions & 1 deletion crates/oxc_language_server/src/tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,19 @@ pub trait Tool: Send + Sync {

/// Format the content of the given URI.
/// If `content` is `None`, the tool should read the content from the file system.
/// If `range` is `Some`, the tool should format only the specified range.
/// Returns a vector of `TextEdit` representing the formatting changes.
///
/// Not all tools will implement formatting, so the default implementation returns empty vector.
///
/// # Errors
/// Return [`Err`] when an error occurs, ignoring formatting should return [`Ok`] with an empty vector.
fn run_format(&self, _uri: &Uri, _content: Option<&str>) -> Result<Vec<TextEdit>, String> {
fn run_format(
&self,
_uri: &Uri,
_content: Option<&str>,
_range: Option<&Range>,
) -> Result<Vec<TextEdit>, String> {
Ok(Vec::new())
}

Expand Down
3 changes: 2 additions & 1 deletion crates/oxc_language_server/src/worker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,9 +192,10 @@ impl WorkspaceWorker {
&self,
uri: &Uri,
content: Option<&str>,
range: Option<&Range>,
) -> Result<Vec<TextEdit>, String> {
for tool in self.tools.read().await.iter() {
let edits = tool.run_format(uri, content)?;
let edits = tool.run_format(uri, content, range)?;
// If no edits are made, continue to the next tool
if edits.is_empty() {
continue;
Expand Down
Loading