mirror of
https://github.com/denoland/deno.git
synced 2025-09-26 20:29:11 +00:00
feat(lsp): provide registry details on hover if present (#13294)
Closes: #13272
This commit is contained in:
parent
2067820714
commit
57bfa87b2c
8 changed files with 111 additions and 6 deletions
|
@ -590,7 +590,8 @@ pub(crate) fn to_hover_text(
|
||||||
"{}​{}",
|
"{}​{}",
|
||||||
specifier[..url::Position::AfterScheme].to_string(),
|
specifier[..url::Position::AfterScheme].to_string(),
|
||||||
specifier[url::Position::AfterScheme..].to_string()
|
specifier[url::Position::AfterScheme..].to_string()
|
||||||
),
|
)
|
||||||
|
.replace('@', "​@"),
|
||||||
},
|
},
|
||||||
Err(_) => "_[errored]_".to_string(),
|
Err(_) => "_[errored]_".to_string(),
|
||||||
}
|
}
|
||||||
|
|
|
@ -1119,6 +1119,12 @@ impl Inner {
|
||||||
),
|
),
|
||||||
(None, None, _) => unreachable!("{}", json!(params)),
|
(None, None, _) => unreachable!("{}", json!(params)),
|
||||||
};
|
};
|
||||||
|
let value =
|
||||||
|
if let Some(docs) = self.module_registries.get_hover(&dep).await {
|
||||||
|
format!("{}\n\n---\n\n{}", value, docs)
|
||||||
|
} else {
|
||||||
|
value
|
||||||
|
};
|
||||||
Some(Hover {
|
Some(Hover {
|
||||||
contents: HoverContents::Markup(MarkupContent {
|
contents: HoverContents::Markup(MarkupContent {
|
||||||
kind: MarkupKind::Markdown,
|
kind: MarkupKind::Markdown,
|
||||||
|
|
|
@ -27,6 +27,7 @@ use deno_core::url::ParseError;
|
||||||
use deno_core::url::Position;
|
use deno_core::url::Position;
|
||||||
use deno_core::url::Url;
|
use deno_core::url::Url;
|
||||||
use deno_core::ModuleSpecifier;
|
use deno_core::ModuleSpecifier;
|
||||||
|
use deno_graph::Dependency;
|
||||||
use deno_runtime::deno_web::BlobStore;
|
use deno_runtime::deno_web::BlobStore;
|
||||||
use deno_runtime::permissions::Permissions;
|
use deno_runtime::permissions::Permissions;
|
||||||
use log::error;
|
use log::error;
|
||||||
|
@ -565,6 +566,60 @@ impl ModuleRegistry {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn get_hover(
|
||||||
|
&self,
|
||||||
|
dependency: &Dependency,
|
||||||
|
) -> Option<String> {
|
||||||
|
let maybe_code = dependency.get_code();
|
||||||
|
let maybe_type = dependency.get_type();
|
||||||
|
let specifier = match (maybe_code, maybe_type) {
|
||||||
|
(Some(specifier), _) => Some(specifier),
|
||||||
|
(_, Some(specifier)) => Some(specifier),
|
||||||
|
_ => None,
|
||||||
|
}?;
|
||||||
|
let origin = base_url(specifier);
|
||||||
|
let registries = self.origins.get(&origin)?;
|
||||||
|
let path = &specifier[Position::BeforePath..];
|
||||||
|
for registry in registries {
|
||||||
|
let tokens = parse(®istry.schema, None).ok()?;
|
||||||
|
let matcher = Matcher::new(&tokens, None).ok()?;
|
||||||
|
if let Some(match_result) = matcher.matches(path) {
|
||||||
|
let key = if let Some(Token::Key(key)) = tokens.iter().last() {
|
||||||
|
Some(key)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}?;
|
||||||
|
let url = registry.get_documentation_url_for_key(key)?;
|
||||||
|
let endpoint = get_endpoint_with_match(
|
||||||
|
key,
|
||||||
|
url,
|
||||||
|
specifier,
|
||||||
|
&tokens,
|
||||||
|
&match_result,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.ok()?;
|
||||||
|
let file = self
|
||||||
|
.file_fetcher
|
||||||
|
.fetch(&endpoint, &mut Permissions::allow_all())
|
||||||
|
.await
|
||||||
|
.ok()?;
|
||||||
|
let documentation: lsp::Documentation =
|
||||||
|
serde_json::from_str(&file.source).ok()?;
|
||||||
|
return match documentation {
|
||||||
|
lsp::Documentation::String(doc) => Some(doc),
|
||||||
|
lsp::Documentation::MarkupContent(lsp::MarkupContent {
|
||||||
|
value,
|
||||||
|
..
|
||||||
|
}) => Some(value),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
/// For a string specifier from the client, provide a set of completions, if
|
/// For a string specifier from the client, provide a set of completions, if
|
||||||
/// any, for the specifier.
|
/// any, for the specifier.
|
||||||
pub(crate) async fn get_completions(
|
pub(crate) async fn get_completions(
|
||||||
|
@ -858,7 +913,7 @@ impl ModuleRegistry {
|
||||||
self.get_origin_completions(current_specifier, range)
|
self.get_origin_completions(current_specifier, range)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_documentation(
|
pub(crate) async fn get_documentation(
|
||||||
&self,
|
&self,
|
||||||
url: &str,
|
url: &str,
|
||||||
) -> Option<lsp::Documentation> {
|
) -> Option<lsp::Documentation> {
|
||||||
|
|
|
@ -3044,7 +3044,8 @@ fn lsp_cache_location() {
|
||||||
let _g = http_server();
|
let _g = http_server();
|
||||||
let temp_dir = TempDir::new().expect("could not create temp dir");
|
let temp_dir = TempDir::new().expect("could not create temp dir");
|
||||||
let mut params: lsp::InitializeParams =
|
let mut params: lsp::InitializeParams =
|
||||||
serde_json::from_value(load_fixture("initialize_params.json")).unwrap();
|
serde_json::from_value(load_fixture("initialize_params_registry.json"))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
params.root_uri = Some(Url::from_file_path(temp_dir.path()).unwrap());
|
params.root_uri = Some(Url::from_file_path(temp_dir.path()).unwrap());
|
||||||
if let Some(Value::Object(mut map)) = params.initialization_options {
|
if let Some(Value::Object(mut map)) = params.initialization_options {
|
||||||
|
@ -3075,7 +3076,7 @@ fn lsp_cache_location() {
|
||||||
load_fixture("did_open_params_import_hover.json"),
|
load_fixture("did_open_params_import_hover.json"),
|
||||||
);
|
);
|
||||||
let diagnostics = diagnostics.into_iter().flat_map(|x| x.diagnostics);
|
let diagnostics = diagnostics.into_iter().flat_map(|x| x.diagnostics);
|
||||||
assert_eq!(diagnostics.count(), 12);
|
assert_eq!(diagnostics.count(), 14);
|
||||||
let (maybe_res, maybe_err) = client
|
let (maybe_res, maybe_err) = client
|
||||||
.write_request::<_, _, Value>(
|
.write_request::<_, _, Value>(
|
||||||
"deno/cache",
|
"deno/cache",
|
||||||
|
@ -3123,6 +3124,40 @@ fn lsp_cache_location() {
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
|
let (maybe_res, maybe_err) = client
|
||||||
|
.write_request::<_, _, Value>(
|
||||||
|
"textDocument/hover",
|
||||||
|
json!({
|
||||||
|
"textDocument": {
|
||||||
|
"uri": "file:///a/file.ts",
|
||||||
|
},
|
||||||
|
"position": {
|
||||||
|
"line": 7,
|
||||||
|
"character": 28
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert!(maybe_err.is_none());
|
||||||
|
assert_eq!(
|
||||||
|
maybe_res,
|
||||||
|
Some(json!({
|
||||||
|
"contents": {
|
||||||
|
"kind": "markdown",
|
||||||
|
"value": "**Resolved Dependency**\n\n**Code**: http​://localhost:4545/x/a/mod.ts\n\n\n---\n\n**a**\n\nmod.ts"
|
||||||
|
},
|
||||||
|
"range": {
|
||||||
|
"start": {
|
||||||
|
"line": 7,
|
||||||
|
"character": 19
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 7,
|
||||||
|
"character": 53
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
);
|
||||||
let cache_path = temp_dir.path().join(".cache");
|
let cache_path = temp_dir.path().join(".cache");
|
||||||
assert!(cache_path.is_dir());
|
assert!(cache_path.is_dir());
|
||||||
assert!(cache_path.join("gen").is_dir());
|
assert!(cache_path.join("gen").is_dir());
|
||||||
|
|
|
@ -3,6 +3,6 @@
|
||||||
"uri": "file:///a/file.ts",
|
"uri": "file:///a/file.ts",
|
||||||
"languageId": "typescript",
|
"languageId": "typescript",
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"text": "import * as a from \"http://127.0.0.1:4545/xTypeScriptTypes.js\";\n// @deno-types=\"http://127.0.0.1:4545/type_definitions/foo.d.ts\"\nimport * as b from \"http://127.0.0.1:4545/type_definitions/foo.js\";\nimport * as c from \"http://127.0.0.1:4545/subdir/type_reference.js\";\nimport * as d from \"http://127.0.0.1:4545/subdir/mod1.ts\";\nimport * as e from \"data:application/typescript;base64,ZXhwb3J0IGNvbnN0IGEgPSAiYSI7CgpleHBvcnQgZW51bSBBIHsKICBBLAogIEIsCiAgQywKfQo=\";\nimport * as f from \"./file_01.ts\";\n\nconsole.log(a, b, c, d, e, f);\n"
|
"text": "import * as a from \"http://127.0.0.1:4545/xTypeScriptTypes.js\";\n// @deno-types=\"http://127.0.0.1:4545/type_definitions/foo.d.ts\"\nimport * as b from \"http://127.0.0.1:4545/type_definitions/foo.js\";\nimport * as c from \"http://127.0.0.1:4545/subdir/type_reference.js\";\nimport * as d from \"http://127.0.0.1:4545/subdir/mod1.ts\";\nimport * as e from \"data:application/typescript;base64,ZXhwb3J0IGNvbnN0IGEgPSAiYSI7CgpleHBvcnQgZW51bSBBIHsKICBBLAogIEIsCiAgQywKfQo=\";\nimport * as f from \"./file_01.ts\";\nimport * as g from \"http://localhost:4545/x/a/mod.ts\";\n\nconsole.log(a, b, c, d, e, f, g);\n"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,10 @@
|
||||||
"cache": null,
|
"cache": null,
|
||||||
"codeLens": {
|
"codeLens": {
|
||||||
"implementations": true,
|
"implementations": true,
|
||||||
"references": true
|
"references": true,
|
||||||
|
"test": true
|
||||||
},
|
},
|
||||||
|
"config": "",
|
||||||
"importMap": null,
|
"importMap": null,
|
||||||
"lint": true,
|
"lint": true,
|
||||||
"suggest": {
|
"suggest": {
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key": "path",
|
"key": "path",
|
||||||
|
"documentation": "/lsp/registries/doc_${module}_${{version}}_${path}.json",
|
||||||
"url": "/lsp/registries/${module}_${{version}}_${path}.json"
|
"url": "/lsp/registries/${module}_${{version}}_${path}.json"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -30,6 +31,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key": "path",
|
"key": "path",
|
||||||
|
"documentation": "/lsp/registries/doc_${module}_latest_${path}.json",
|
||||||
"url": "/lsp/registries/${module}_latest_${path}.json"
|
"url": "/lsp/registries/${module}_latest_${path}.json"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
4
cli/tests/testdata/lsp/registries/doc_a_latest_mod.ts.json
vendored
Normal file
4
cli/tests/testdata/lsp/registries/doc_a_latest_mod.ts.json
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"kind": "markdown",
|
||||||
|
"value": "**a**\n\nmod.ts"
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue