Skip to content
This repository has been archived by the owner on Aug 31, 2023. It is now read-only.

Commit

Permalink
feat(rome_lsp): send message to the client (#4730)
Browse files Browse the repository at this point in the history
  • Loading branch information
ematipico committed Jul 27, 2023
1 parent a3a13d7 commit 3370296
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 54 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ if no error diagnostics are emitted.
#### Other changes

- The Rome LSP is now able to show diagnostics that belong to JSON lint rules.
- Fix [#4564](https://github.com/rome/tools/issues/4564), now files too large don't emit errors.
- The Rome LSP now sends client messages when files are ignored or too big.

### Formatter

Expand Down
60 changes: 60 additions & 0 deletions crates/rome_lsp/src/diagnostics.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
use crate::utils::into_lsp_error;
use anyhow::Error;
use rome_service::WorkspaceError;
use std::fmt::{Display, Formatter};
use tower_lsp::lsp_types::MessageType;

#[derive(Debug)]
pub enum LspError {
WorkspaceError(WorkspaceError),
Anyhow(anyhow::Error),
}

impl From<WorkspaceError> for LspError {
fn from(value: WorkspaceError) -> Self {
Self::WorkspaceError(value)
}
}

impl From<anyhow::Error> for LspError {
fn from(value: Error) -> Self {
Self::Anyhow(value)
}
}

impl Display for LspError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
LspError::WorkspaceError(err) => {
write!(f, "{}", err)
}
LspError::Anyhow(err) => {
write!(f, "{}", err)
}
}
}
}

/// Receives an error coming from a LSP query, and converts it into a JSON-RPC error.
///
/// It accepts a `Client`, so contextual messages are sent to the user.
pub(crate) async fn handle_lsp_error<T>(
err: LspError,
client: &tower_lsp::Client,
) -> Result<Option<T>, tower_lsp::jsonrpc::Error> {
match err {
LspError::WorkspaceError(err) => match err {
// diagnostics that shouldn't raise an hard error, but send a message to the user
WorkspaceError::FormatWithErrorsDisabled(_)
| WorkspaceError::FileIgnored(_)
| WorkspaceError::FileTooLarge(_) => {
let message = format!("{}", err);
client.show_message(MessageType::WARNING, message).await;
Ok(None)
}

_ => Err(into_lsp_error(err)),
},
LspError::Anyhow(err) => Err(into_lsp_error(err)),
}
}
50 changes: 12 additions & 38 deletions crates/rome_lsp/src/handlers/formatting.rs
Original file line number Diff line number Diff line change
@@ -1,35 +1,25 @@
use crate::converters::{from_proto, to_proto};
use crate::diagnostics::LspError;
use crate::session::Session;
use anyhow::{Context, Error, Result};
use rome_service::{
workspace::{FormatFileParams, FormatOnTypeParams, FormatRangeParams},
WorkspaceError,
};
use anyhow::Context;
use rome_service::workspace::{FormatFileParams, FormatOnTypeParams, FormatRangeParams};
use tower_lsp::lsp_types::*;
use tracing::debug;

#[tracing::instrument(level = "debug", skip(session), err)]
pub(crate) fn format(
session: &Session,
params: DocumentFormattingParams,
) -> Result<Option<Vec<TextEdit>>> {
) -> Result<Option<Vec<TextEdit>>, LspError> {
let url = params.text_document.uri;
let rome_path = session.file_path(&url)?;

let doc = session.document(&url)?;

debug!("Formatting...");
let result = session
let printed = session
.workspace
.format_file(FormatFileParams { path: rome_path });

let printed = match result {
Ok(printed) => printed,
Err(WorkspaceError::FormatWithErrorsDisabled(_)) | Err(WorkspaceError::FileIgnored(_)) => {
return Ok(None)
}
Err(err) => return Err(Error::from(err)),
};
.format_file(FormatFileParams { path: rome_path })?;

let num_lines: u32 = doc.line_index.len();

Expand All @@ -53,7 +43,7 @@ pub(crate) fn format(
pub(crate) fn format_range(
session: &Session,
params: DocumentRangeFormattingParams,
) -> Result<Option<Vec<TextEdit>>> {
) -> Result<Option<Vec<TextEdit>>, LspError> {
let url = params.text_document.uri;
let rome_path = session.file_path(&url)?;
let doc = session.document(&url)?;
Expand All @@ -67,18 +57,10 @@ pub(crate) fn format_range(
)
})?;

let result = session.workspace.format_range(FormatRangeParams {
let formatted = session.workspace.format_range(FormatRangeParams {
path: rome_path,
range: format_range,
});

let formatted = match result {
Ok(formatted) => formatted,
Err(WorkspaceError::FormatWithErrorsDisabled(_)) | Err(WorkspaceError::FileIgnored(_)) => {
return Ok(None)
}
Err(err) => return Err(Error::from(err)),
};
})?;

// Recalculate the actual range that was reformatted from the formatter result
let formatted_range = match formatted.range() {
Expand All @@ -105,7 +87,7 @@ pub(crate) fn format_range(
pub(crate) fn format_on_type(
session: &Session,
params: DocumentOnTypeFormattingParams,
) -> Result<Option<Vec<TextEdit>>> {
) -> Result<Option<Vec<TextEdit>>, LspError> {
let url = params.text_document_position.text_document.uri;
let position = params.text_document_position.position;

Expand All @@ -116,18 +98,10 @@ pub(crate) fn format_on_type(
let offset = from_proto::offset(&doc.line_index, position, position_encoding)
.with_context(|| format!("failed to access position {position:?} in document {url}"))?;

let result = session.workspace.format_on_type(FormatOnTypeParams {
let formatted = session.workspace.format_on_type(FormatOnTypeParams {
path: rome_path,
offset,
});

let formatted = match result {
Ok(formatted) => formatted,
Err(WorkspaceError::FormatWithErrorsDisabled(_)) | Err(WorkspaceError::FileIgnored(_)) => {
return Ok(None)
}
Err(err) => return Err(Error::from(err)),
};
})?;

// Recalculate the actual range that was reformatted from the formatter result
let formatted_range = match formatted.range() {
Expand Down
1 change: 1 addition & 0 deletions crates/rome_lsp/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
mod capabilities;
mod converters;
mod diagnostics;
mod documents;
mod extension_settings;
mod handlers;
Expand Down
43 changes: 31 additions & 12 deletions crates/rome_lsp/src/server.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::capabilities::server_capabilities;
use crate::diagnostics::{handle_lsp_error, LspError};
use crate::requests::syntax_tree::{SyntaxTreePayload, SYNTAX_TREE_REQUEST};
use crate::session::{
CapabilitySet, CapabilityStatus, ClientInformation, Session, SessionHandle, SessionKey,
Expand All @@ -8,6 +9,7 @@ use crate::{handlers, requests};
use futures::future::ready;
use futures::FutureExt;
use rome_console::markup;
use rome_diagnostics::panic::PanicError;
use rome_fs::CONFIG_NAME;
use rome_service::workspace::{RageEntry, RageParams, RageResult};
use rome_service::{workspace, Workspace};
Expand Down Expand Up @@ -192,6 +194,20 @@ impl LSPServer {

self.session.register_capabilities(capabilities).await;
}

async fn map_op_error<T>(
&self,
result: Result<Result<Option<T>, LspError>, PanicError>,
) -> LspResult<Option<T>> {
match result {
Ok(result) => match result {
Ok(result) => Ok(result),
Err(err) => handle_lsp_error(err, &self.session.client).await,
},

Err(err) => Err(into_lsp_error(err)),
}
}
}

#[tower_lsp::async_trait]
Expand Down Expand Up @@ -340,30 +356,33 @@ impl LanguageServer for LSPServer {
&self,
params: DocumentFormattingParams,
) -> LspResult<Option<Vec<TextEdit>>> {
rome_diagnostics::panic::catch_unwind(move || {
handlers::formatting::format(&self.session, params).map_err(into_lsp_error)
})
.map_err(into_lsp_error)?
let result = rome_diagnostics::panic::catch_unwind(move || {
handlers::formatting::format(&self.session, params)
});

self.map_op_error(result).await
}

async fn range_formatting(
&self,
params: DocumentRangeFormattingParams,
) -> LspResult<Option<Vec<TextEdit>>> {
rome_diagnostics::panic::catch_unwind(move || {
handlers::formatting::format_range(&self.session, params).map_err(into_lsp_error)
})
.map_err(into_lsp_error)?
let result = rome_diagnostics::panic::catch_unwind(move || {
handlers::formatting::format_range(&self.session, params)
});

self.map_op_error(result).await
}

async fn on_type_formatting(
&self,
params: DocumentOnTypeFormattingParams,
) -> LspResult<Option<Vec<TextEdit>>> {
rome_diagnostics::panic::catch_unwind(move || {
handlers::formatting::format_on_type(&self.session, params).map_err(into_lsp_error)
})
.map_err(into_lsp_error)?
let result = rome_diagnostics::panic::catch_unwind(move || {
handlers::formatting::format_on_type(&self.session, params)
});

self.map_op_error(result).await
}

async fn rename(&self, params: RenameParams) -> LspResult<Option<WorkspaceEdit>> {
Expand Down
7 changes: 4 additions & 3 deletions crates/rome_service/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -386,9 +386,10 @@ pub struct CantReadFile {
#[diagnostic(
category = "internalError/fs",
message(
message("The file "{self.path}" was ignored"),
description = "The file {path} was ignored"
)
message("The file "{self.path}" was ignored."),
description = "The file {path} was ignored."
),
severity = Warning
)]
pub struct FileIgnored {
#[location(resource)]
Expand Down
2 changes: 1 addition & 1 deletion crates/rome_service/src/snapshots/file_ignored.snap
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ expression: content
---
example.js internalError/fs ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

× The file example.js was ignored
! The file example.js was ignored.



0 comments on commit 3370296

Please sign in to comment.