aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock2
-rw-r--r--crates/ra_ide/Cargo.toml1
-rw-r--r--crates/ra_ide/src/hover.rs49
3 files changed, 42 insertions, 10 deletions
diff --git a/Cargo.lock b/Cargo.lock
index bc36f0fab..112c4210d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1276,12 +1276,14 @@ dependencies = [
1276 "ra_fmt", 1276 "ra_fmt",
1277 "ra_hir", 1277 "ra_hir",
1278 "ra_hir_def", 1278 "ra_hir_def",
1279 "ra_hir_expand",
1279 "ra_ide_db", 1280 "ra_ide_db",
1280 "ra_prof", 1281 "ra_prof",
1281 "ra_project_model", 1282 "ra_project_model",
1282 "ra_ssr", 1283 "ra_ssr",
1283 "ra_syntax", 1284 "ra_syntax",
1284 "ra_text_edit", 1285 "ra_text_edit",
1286 "ra_tt",
1285 "rand", 1287 "rand",
1286 "rustc-hash", 1288 "rustc-hash",
1287 "stdx", 1289 "stdx",
diff --git a/crates/ra_ide/Cargo.toml b/crates/ra_ide/Cargo.toml
index fa925fc5a..219ad33e6 100644
--- a/crates/ra_ide/Cargo.toml
+++ b/crates/ra_ide/Cargo.toml
@@ -35,6 +35,7 @@ ra_ssr = { path = "../ra_ssr" }
35ra_project_model = { path = "../ra_project_model" } 35ra_project_model = { path = "../ra_project_model" }
36ra_hir_def = { path = "../ra_hir_def" } 36ra_hir_def = { path = "../ra_hir_def" }
37ra_tt = { path = "../ra_tt" } 37ra_tt = { path = "../ra_tt" }
38ra_hir_expand = { path = "../ra_hir_expand" }
38 39
39# ra_ide should depend only on the top-level `hir` package. if you need 40# ra_ide should depend only on the top-level `hir` package. if you need
40# something from some `hir_xxx` subpackage, reexport the API via `hir`. 41# something from some `hir_xxx` subpackage, reexport the API via `hir`.
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs
index f703af434..760d7fe14 100644
--- a/crates/ra_ide/src/hover.rs
+++ b/crates/ra_ide/src/hover.rs
@@ -16,6 +16,7 @@ use ra_syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffs
16use ra_project_model::ProjectWorkspace; 16use ra_project_model::ProjectWorkspace;
17use ra_hir_def::{item_scope::ItemInNs, db::DefDatabase}; 17use ra_hir_def::{item_scope::ItemInNs, db::DefDatabase};
18use ra_tt::{Literal, Ident, Punct, TokenTree, Leaf}; 18use ra_tt::{Literal, Ident, Punct, TokenTree, Leaf};
19use ra_hir_expand::name::AsName;
19 20
20use comrak::{parse_document,format_commonmark, ComrakOptions, Arena}; 21use comrak::{parse_document,format_commonmark, ComrakOptions, Arena};
21use comrak::nodes::NodeValue; 22use comrak::nodes::NodeValue;
@@ -406,9 +407,9 @@ fn rewrite_links(db: &RootDatabase, markdown: &str, definition: &Definition, wor
406 match Url::parse(&String::from_utf8(link.url.clone()).unwrap()) { 407 match Url::parse(&String::from_utf8(link.url.clone()).unwrap()) {
407 // If this is a valid absolute URL don't touch it 408 // If this is a valid absolute URL don't touch it
408 Ok(_) => (), 409 Ok(_) => (),
409 // If contains .html file-based link to new page 410 // Otherwise there are two main possibilities
410 // If starts with #fragment file-based link to fragment on current page 411 // path-based links: `../../module/struct.MyStruct.html`
411 // If contains :: module-based link 412 // module-based links (AKA intra-doc links): `super::super::module::MyStruct`
412 Err(_) => { 413 Err(_) => {
413 let link_str = String::from_utf8(link.url.clone()).unwrap(); 414 let link_str = String::from_utf8(link.url.clone()).unwrap();
414 let resolved = try_resolve_path(db, &mut doc_target_dirs.clone(), definition, &link_str, UrlMode::Url) 415 let resolved = try_resolve_path(db, &mut doc_target_dirs.clone(), definition, &link_str, UrlMode::Url)
@@ -429,7 +430,9 @@ fn rewrite_links(db: &RootDatabase, markdown: &str, definition: &Definition, wor
429 Some(String::from_utf8(out).unwrap()) 430 Some(String::from_utf8(out).unwrap())
430} 431}
431 432
432/// Try to resolve path to local documentation via intra-doc-links (i.e. `super::gateway::Shard`) 433/// Try to resolve path to local documentation via intra-doc-links (i.e. `super::gateway::Shard`).
434///
435/// See [RFC1946](https://github.com/rust-lang/rfcs/blob/master/text/1946-intra-rustdoc-links.md).
433fn try_resolve_intra(db: &RootDatabase, doc_target_dirs: impl Iterator<Item = PathBuf>, definition: &Definition, link: &str) -> Option<String> { 436fn try_resolve_intra(db: &RootDatabase, doc_target_dirs: impl Iterator<Item = PathBuf>, definition: &Definition, link: &str) -> Option<String> {
434 None 437 None
435} 438}
@@ -439,7 +442,7 @@ enum UrlMode {
439 File 442 File
440} 443}
441 444
442/// Try to resolve path to local documentation via path-based links (i.e. `../gateway/struct.Shard.html`) 445/// Try to resolve path to local documentation via path-based links (i.e. `../gateway/struct.Shard.html`).
443fn try_resolve_path(db: &RootDatabase, doc_target_dirs: impl Iterator<Item = PathBuf>, definition: &Definition, link: &str, mode: UrlMode) -> Option<String> { 446fn try_resolve_path(db: &RootDatabase, doc_target_dirs: impl Iterator<Item = PathBuf>, definition: &Definition, link: &str, mode: UrlMode) -> Option<String> {
444 let ns = if let Definition::ModuleDef(moddef) = definition { 447 let ns = if let Definition::ModuleDef(moddef) = definition {
445 ItemInNs::Types(moddef.clone().into()) 448 ItemInNs::Types(moddef.clone().into())
@@ -456,12 +459,12 @@ fn try_resolve_path(db: &RootDatabase, doc_target_dirs: impl Iterator<Item = Pat
456 459
457 match mode { 460 match mode {
458 UrlMode::Url => { 461 UrlMode::Url => {
459 let root = get_doc_url(db, &krate);
460 let mut base = base.join("/"); 462 let mut base = base.join("/");
461 if link.starts_with("#") { 463 get_doc_url(db, &krate)
462 base = base + "/" 464 .and_then(|url| url.join(&base).ok())
463 }; 465 .and_then(|url| get_symbol_filename(db, definition).as_deref().map(|f| url.join(f).ok()).flatten())
464 root.and_then(|url| url.join(&base).ok()).and_then(|url| url.join(link).ok()).map(|url| url.into_string()) 466 .and_then(|url| url.join(link).ok())
467 .map(|url| url.into_string())
465 }, 468 },
466 UrlMode::File => { 469 UrlMode::File => {
467 let base = base.collect::<PathBuf>(); 470 let base = base.collect::<PathBuf>();
@@ -502,6 +505,32 @@ fn get_doc_url(db: &RootDatabase, krate: &Crate) -> Option<Url> {
502 doc_url.map(|s| s.trim_matches('"').to_owned() + "/").and_then(|s| Url::parse(&s).ok()) 505 doc_url.map(|s| s.trim_matches('"').to_owned() + "/").and_then(|s| Url::parse(&s).ok())
503} 506}
504 507
508/// Get the filename and extension generated for a symbol by rustdoc.
509///
510/// Example: `struct.Shard.html`
511fn get_symbol_filename(db: &RootDatabase, definition: &Definition) -> Option<String> {
512 Some(match definition {
513 Definition::ModuleDef(def) => match def {
514 ModuleDef::Adt(adt) => match adt {
515 Adt::Struct(s) => format!("struct.{}.html", s.name(db)),
516 Adt::Enum(e) => format!("enum.{}.html", e.name(db)),
517 Adt::Union(u) => format!("union.{}.html", u.name(db))
518 },
519 ModuleDef::Module(_) => "index.html".to_string(),
520 ModuleDef::Trait(t) => format!("trait.{}.html", t.name(db)),
521 ModuleDef::TypeAlias(t) => format!("type.{}.html", t.name(db)),
522 ModuleDef::BuiltinType(t) => format!("primitive.{}.html", t.as_name()),
523 ModuleDef::Function(f) => format!("fn.{}.html", f.name(db)),
524 ModuleDef::EnumVariant(ev) => format!("enum.{}.html#variant.{}", ev.parent_enum(db).name(db), ev.name(db)),
525 ModuleDef::Const(c) => format!("const.{}.html", c.name(db)?),
526 // TODO: Check this is the right prefix
527 ModuleDef::Static(s) => format!("static.{}.html", s.name(db)?)
528 },
529 Definition::Macro(m) => format!("macro.{}.html", m.name(db)?),
530 _ => None?
531 })
532}
533
505fn iter_nodes<'a, F>(node: &'a comrak::nodes::AstNode<'a>, f: &F) 534fn iter_nodes<'a, F>(node: &'a comrak::nodes::AstNode<'a>, f: &F)
506 where F : Fn(&'a comrak::nodes::AstNode<'a>) { 535 where F : Fn(&'a comrak::nodes::AstNode<'a>) {
507 f(node); 536 f(node);