diff --git a/Cargo.lock b/Cargo.lock index d4ac12e43d11..d0cf89512c9f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1151,6 +1151,7 @@ dependencies = [ "log", "lsp-types", "parking_lot", + "percent-encoding", "serde", "serde_json", "thiserror", @@ -1202,6 +1203,7 @@ dependencies = [ "nucleo", "once_cell", "open", + "percent-encoding", "pulldown-cmark", "serde", "serde_json", diff --git a/helix-lsp/Cargo.toml b/helix-lsp/Cargo.toml index 8e9e3407c860..2b882aa57c9b 100644 --- a/helix-lsp/Cargo.toml +++ b/helix-lsp/Cargo.toml @@ -30,3 +30,4 @@ thiserror = "1.0" tokio = { version = "1.35", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot", "sync"] } tokio-stream = "0.1.14" parking_lot = "0.12.1" +percent-encoding = "2.3.1" diff --git a/helix-lsp/src/lib.rs b/helix-lsp/src/lib.rs index 4f2d47d42f26..091ba696a504 100644 --- a/helix-lsp/src/lib.rs +++ b/helix-lsp/src/lib.rs @@ -7,6 +7,7 @@ mod transport; pub use client::Client; pub mod copilot_types; +mod uri_deserializer; pub use futures_executor::block_on; pub use jsonrpc::Call; pub use lsp::{Position, Url}; @@ -28,6 +29,8 @@ use std::{ use thiserror::Error; use tokio_stream::wrappers::UnboundedReceiverStream; +use crate::uri_deserializer::to_percent_decode_url; + pub type Result = core::result::Result; pub type LanguageServerName = String; @@ -613,7 +616,8 @@ impl Notification { lsp::notification::Initialized::METHOD => Self::Initialized, lsp::notification::Exit::METHOD => Self::Exit, lsp::notification::PublishDiagnostics::METHOD => { - let params: lsp::PublishDiagnosticsParams = params.parse()?; + let mut params: lsp::PublishDiagnosticsParams = params.parse()?; + params.uri = to_percent_decode_url(¶ms.uri); Self::PublishDiagnostics(params) } diff --git a/helix-lsp/src/uri_deserializer.rs b/helix-lsp/src/uri_deserializer.rs new file mode 100644 index 000000000000..e6642f676fcc --- /dev/null +++ b/helix-lsp/src/uri_deserializer.rs @@ -0,0 +1,39 @@ +use lsp_types::Url; +use std::fmt; + +use serde::de::{self, Visitor}; + +pub struct LspUriVisitor; + +impl<'de> Visitor<'de> for LspUriVisitor { + type Value = lsp_types::Url; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("an uri") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + return lsp_types::Url::parse(&std::borrow::Cow::into_owned( + percent_encoding::percent_decode_str(v).decode_utf8_lossy(), + )) + .map_err(|e| E::custom(e)); + } + + // Similar for other methods: + // - visit_i16 + // - visit_u8 + // - visit_u16 + // - visit_u32 + // - visit_u64 +} + +// Stopgap until: https://github.com/gluon-lang/lsp-types/issues/276 +pub fn to_percent_decode_url(url: &Url) -> Url { + return Url::parse(&std::borrow::Cow::into_owned( + percent_encoding::percent_decode_str(url.as_str()).decode_utf8_lossy(), + )) + .expect("[Custom code]: failed to re-encode percent_decoded uri"); +} diff --git a/helix-term/Cargo.toml b/helix-term/Cargo.toml index 9a7162ac13ef..73171228d267 100644 --- a/helix-term/Cargo.toml +++ b/helix-term/Cargo.toml @@ -69,6 +69,7 @@ serde = { version = "1.0", features = ["derive"] } # ripgrep for global search grep-regex = "0.1.12" grep-searcher = "0.1.13" +percent-encoding = "2.3.1" [target.'cfg(not(windows))'.dependencies] # https://github.com/vorner/signal-hook/issues/100 signal-hook-tokio = { version = "0.3", features = ["futures-v0_3"] }