1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-16 16:53:20 -05:00
denoland-deno/cli/lsp/utils.rs
2020-12-07 21:46:39 +11:00

114 lines
2.8 KiB
Rust

// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
use deno_core::error::custom_error;
use deno_core::error::AnyError;
use deno_core::serde_json::Value;
use deno_core::url::Position;
use deno_core::url::Url;
use deno_core::ModuleSpecifier;
use lsp_server::Notification;
use serde::de::DeserializeOwned;
use std::error::Error;
use std::fmt;
// TODO(@kitsonk) support actually supporting cancellation requests from the
// client.
pub struct Canceled {
_private: (),
}
impl Canceled {
#[allow(unused)]
pub fn new() -> Self {
Self { _private: () }
}
#[allow(unused)]
pub fn throw() -> ! {
std::panic::resume_unwind(Box::new(Canceled::new()))
}
}
impl fmt::Display for Canceled {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "cancelled")
}
}
impl fmt::Debug for Canceled {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Canceled")
}
}
impl Error for Canceled {}
pub fn from_json<T: DeserializeOwned>(
what: &'static str,
json: Value,
) -> Result<T, AnyError> {
let response = T::deserialize(&json).map_err(|err| {
custom_error(
"DeserializeFailed",
format!("Failed to deserialize {}: {}; {}", what, err, json),
)
})?;
Ok(response)
}
pub fn is_canceled(e: &(dyn Error + 'static)) -> bool {
e.downcast_ref::<Canceled>().is_some()
}
pub fn notification_is<N: lsp_types::notification::Notification>(
notification: &Notification,
) -> bool {
notification.method == N::METHOD
}
/// Normalizes a file name returned from the TypeScript compiler into a URI that
/// should be sent by the language server to the client.
pub fn normalize_file_name(file_name: &str) -> Result<Url, AnyError> {
let specifier_str = if file_name.starts_with("file://") {
file_name.to_string()
} else {
format!("deno:///{}", file_name.replacen("://", "/", 1))
};
Url::parse(&specifier_str).map_err(|err| err.into())
}
/// Normalize URLs from the client, where "virtual" `deno:///` URLs are
/// converted into proper module specifiers.
pub fn normalize_url(url: Url) -> ModuleSpecifier {
if url.scheme() == "deno"
&& (url.path().starts_with("/http") || url.path().starts_with("/asset"))
{
let specifier_str = url[Position::BeforePath..]
.replacen("/", "", 1)
.replacen("/", "://", 1);
if let Ok(specifier) =
percent_encoding::percent_decode_str(&specifier_str).decode_utf8()
{
if let Ok(specifier) = ModuleSpecifier::resolve_url(&specifier) {
return specifier;
}
}
}
ModuleSpecifier::from(url)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_normalize_url() {
let fixture = Url::parse("deno:///https/deno.land/x/mod.ts").unwrap();
let actual = normalize_url(fixture);
assert_eq!(
actual,
ModuleSpecifier::resolve_url("https://deno.land/x/mod.ts").unwrap()
);
}
}