diff options
Diffstat (limited to 'crates/ra_ide/src')
-rw-r--r-- | crates/ra_ide/src/hover.rs | 69 | ||||
-rw-r--r-- | crates/ra_ide/src/lib.rs | 5 |
2 files changed, 21 insertions, 53 deletions
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs index f4b10deac..0da10a08e 100644 --- a/crates/ra_ide/src/hover.rs +++ b/crates/ra_ide/src/hover.rs | |||
@@ -1,10 +1,8 @@ | |||
1 | use std::iter::once; | 1 | use std::iter::once; |
2 | use std::path::PathBuf; | ||
3 | use std::sync::Arc; | ||
4 | 2 | ||
5 | use hir::{ | 3 | use hir::{ |
6 | Adt, AsAssocItem, AssocItemContainer, FieldSource, HasSource, HirDisplay, ModuleDef, | 4 | Adt, AsAssocItem, AssocItemContainer, FieldSource, HasSource, HirDisplay, ModuleDef, |
7 | ModuleSource, Semantics, Documentation, AttrDef, Crate, GenericDef, ModPath, Hygiene | 5 | ModuleSource, Semantics, Documentation, AttrDef, Crate, ModPath, Hygiene |
8 | }; | 6 | }; |
9 | use itertools::Itertools; | 7 | use itertools::Itertools; |
10 | use ra_db::SourceDatabase; | 8 | use ra_db::SourceDatabase; |
@@ -13,11 +11,9 @@ use ra_ide_db::{ | |||
13 | RootDatabase, | 11 | RootDatabase, |
14 | }; | 12 | }; |
15 | use ra_syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, SyntaxNode, TokenAtOffset, ast::Path}; | 13 | use ra_syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, SyntaxNode, TokenAtOffset, ast::Path}; |
16 | use ra_project_model::ProjectWorkspace; | 14 | use ra_hir_def::{item_scope::ItemInNs, db::DefDatabase, resolver::HasResolver}; |
17 | use ra_hir_def::{item_scope::ItemInNs, db::DefDatabase, GenericDefId, ModuleId, resolver::HasResolver}; | ||
18 | use ra_tt::{Literal, Ident, Punct, TokenTree, Leaf}; | 15 | use ra_tt::{Literal, Ident, Punct, TokenTree, Leaf}; |
19 | use ra_hir_expand::name::AsName; | 16 | use ra_hir_expand::name::AsName; |
20 | use ra_parser::FragmentKind; | ||
21 | use maplit::{hashset, hashmap}; | 17 | use maplit::{hashset, hashmap}; |
22 | 18 | ||
23 | use comrak::{parse_document,format_commonmark, ComrakOptions, Arena}; | 19 | use comrak::{parse_document,format_commonmark, ComrakOptions, Arena}; |
@@ -130,7 +126,7 @@ impl HoverResult { | |||
130 | // | 126 | // |
131 | // Shows additional information, like type of an expression or documentation for definition when "focusing" code. | 127 | // Shows additional information, like type of an expression or documentation for definition when "focusing" code. |
132 | // Focusing is usually hovering with a mouse, but can also be triggered with a shortcut. | 128 | // Focusing is usually hovering with a mouse, but can also be triggered with a shortcut. |
133 | pub(crate) fn hover(db: &RootDatabase, position: FilePosition, workspaces: Arc<Vec<ProjectWorkspace>>) -> Option<RangeInfo<HoverResult>> { | 129 | pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeInfo<HoverResult>> { |
134 | let sema = Semantics::new(db); | 130 | let sema = Semantics::new(db); |
135 | let file = sema.parse(position.file_id).syntax().clone(); | 131 | let file = sema.parse(position.file_id).syntax().clone(); |
136 | let token = pick_best(file.token_at_offset(position.offset))?; | 132 | let token = pick_best(file.token_at_offset(position.offset))?; |
@@ -150,7 +146,7 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition, workspaces: Arc<V | |||
150 | } | 146 | } |
151 | } { | 147 | } { |
152 | let range = sema.original_range(&node).range; | 148 | let range = sema.original_range(&node).range; |
153 | let text = hover_text_from_name_kind(db, name_kind.clone()).map(|text| rewrite_links(db, &text, &name_kind, workspaces).unwrap_or(text)); | 149 | let text = hover_text_from_name_kind(db, name_kind.clone()).map(|text| rewrite_links(db, &text, &name_kind).unwrap_or(text)); |
154 | res.extend(text); | 150 | res.extend(text); |
155 | 151 | ||
156 | if !res.is_empty() { | 152 | if !res.is_empty() { |
@@ -393,15 +389,9 @@ fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option<Strin | |||
393 | } | 389 | } |
394 | 390 | ||
395 | /// Rewrite documentation links in markdown to point to local documentation/docs.rs | 391 | /// Rewrite documentation links in markdown to point to local documentation/docs.rs |
396 | fn rewrite_links(db: &RootDatabase, markdown: &str, definition: &Definition, workspaces: Arc<Vec<ProjectWorkspace>>) -> Option<String> { | 392 | fn rewrite_links(db: &RootDatabase, markdown: &str, definition: &Definition) -> Option<String> { |
397 | let arena = Arena::new(); | 393 | let arena = Arena::new(); |
398 | let doc = parse_document(&arena, markdown, &ComrakOptions::default()); | 394 | let doc = parse_document(&arena, markdown, &ComrakOptions::default()); |
399 | let doc_target_dirs = workspaces | ||
400 | .iter() | ||
401 | .filter_map(|workspace| if let ProjectWorkspace::Cargo{cargo: cargo_workspace, ..} = workspace {Some(cargo_workspace)} else {None}) | ||
402 | .map(|workspace| workspace.workspace_root()) | ||
403 | // TODO: `target` is configurable in cargo config, we should respect it | ||
404 | .map(|root| root.join("target/doc")); | ||
405 | 395 | ||
406 | iter_nodes(doc, &|node| { | 396 | iter_nodes(doc, &|node| { |
407 | match &mut node.data.borrow_mut().value { | 397 | match &mut node.data.borrow_mut().value { |
@@ -415,8 +405,8 @@ fn rewrite_links(db: &RootDatabase, markdown: &str, definition: &Definition, wor | |||
415 | Err(_) => { | 405 | Err(_) => { |
416 | let link_str = String::from_utf8(link.url.clone()).unwrap(); | 406 | let link_str = String::from_utf8(link.url.clone()).unwrap(); |
417 | let link_text = String::from_utf8(link.title.clone()).unwrap(); | 407 | let link_text = String::from_utf8(link.title.clone()).unwrap(); |
418 | let resolved = try_resolve_path(db, &mut doc_target_dirs.clone(), definition, &link_str, UrlMode::Url) | 408 | let resolved = try_resolve_path(db, definition, &link_str) |
419 | .or_else(|| try_resolve_intra(db, &mut doc_target_dirs.clone(), definition, &link_text, &link_str)); | 409 | .or_else(|| try_resolve_intra(db, definition, &link_text, &link_str)); |
420 | 410 | ||
421 | if let Some(resolved) = resolved { | 411 | if let Some(resolved) = resolved { |
422 | link.url = resolved.as_bytes().to_vec(); | 412 | link.url = resolved.as_bytes().to_vec(); |
@@ -451,7 +441,7 @@ impl Namespace { | |||
451 | 441 | ||
452 | ns_map | 442 | ns_map |
453 | .iter() | 443 | .iter() |
454 | .filter(|(ns, (prefixes, suffixes))| { | 444 | .filter(|(_ns, (prefixes, suffixes))| { |
455 | prefixes.iter().map(|prefix| s.starts_with(prefix) && s.chars().nth(prefix.len()+1).map(|c| c == '@' || c == ' ').unwrap_or(false)).any(|cond| cond) || | 445 | prefixes.iter().map(|prefix| s.starts_with(prefix) && s.chars().nth(prefix.len()+1).map(|c| c == '@' || c == ' ').unwrap_or(false)).any(|cond| cond) || |
456 | suffixes.iter().map(|suffix| s.starts_with(suffix) && s.chars().nth(suffix.len()+1).map(|c| c == '@' || c == ' ').unwrap_or(false)).any(|cond| cond) | 446 | suffixes.iter().map(|suffix| s.starts_with(suffix) && s.chars().nth(suffix.len()+1).map(|c| c == '@' || c == ' ').unwrap_or(false)).any(|cond| cond) |
457 | }) | 447 | }) |
@@ -463,7 +453,7 @@ impl Namespace { | |||
463 | /// Try to resolve path to local documentation via intra-doc-links (i.e. `super::gateway::Shard`). | 453 | /// Try to resolve path to local documentation via intra-doc-links (i.e. `super::gateway::Shard`). |
464 | /// | 454 | /// |
465 | /// See [RFC1946](https://github.com/rust-lang/rfcs/blob/master/text/1946-intra-rustdoc-links.md). | 455 | /// See [RFC1946](https://github.com/rust-lang/rfcs/blob/master/text/1946-intra-rustdoc-links.md). |
466 | fn try_resolve_intra(db: &RootDatabase, doc_target_dirs: impl Iterator<Item = PathBuf>, definition: &Definition, link_text: &str, link_target: &str) -> Option<String> { | 456 | fn try_resolve_intra(db: &RootDatabase, definition: &Definition, link_text: &str, link_target: &str) -> Option<String> { |
467 | eprintln!("try_resolve_intra"); | 457 | eprintln!("try_resolve_intra"); |
468 | 458 | ||
469 | // Set link_target for implied shortlinks | 459 | // Set link_target for implied shortlinks |
@@ -496,13 +486,13 @@ fn try_resolve_intra(db: &RootDatabase, doc_target_dirs: impl Iterator<Item = Pa | |||
496 | ModuleDef::Trait(t) => Into::<TraitId>::into(t.clone()).resolver(db), | 486 | ModuleDef::Trait(t) => Into::<TraitId>::into(t.clone()).resolver(db), |
497 | ModuleDef::TypeAlias(t) => Into::<ModuleId>::into(t.module(db)).resolver(db), | 487 | ModuleDef::TypeAlias(t) => Into::<ModuleId>::into(t.module(db)).resolver(db), |
498 | // TODO: This should be a resolver relative to `std` | 488 | // TODO: This should be a resolver relative to `std` |
499 | ModuleDef::BuiltinType(t) => Into::<ModuleId>::into(definition.module(db)?).resolver(db) | 489 | ModuleDef::BuiltinType(_t) => Into::<ModuleId>::into(definition.module(db)?).resolver(db) |
500 | }, | 490 | }, |
501 | Definition::Field(field) => Into::<VariantId>::into(Into::<VariantDef>::into(field.parent_def(db))).resolver(db), | 491 | Definition::Field(field) => Into::<VariantId>::into(Into::<VariantDef>::into(field.parent_def(db))).resolver(db), |
502 | Definition::Macro(m) => Into::<ModuleId>::into(m.module(db)?).resolver(db), | 492 | Definition::Macro(m) => Into::<ModuleId>::into(m.module(db)?).resolver(db), |
503 | Definition::SelfType(imp) => Into::<ImplId>::into(imp.clone()).resolver(db), | 493 | Definition::SelfType(imp) => Into::<ImplId>::into(imp.clone()).resolver(db), |
504 | // it's possible, read probable, that other arms of this are also unreachable | 494 | // it's possible, read probable, that other arms of this are also unreachable |
505 | Definition::Local(local) => unreachable!(), | 495 | Definition::Local(_local) => unreachable!(), |
506 | Definition::TypeParam(tp) => Into::<ModuleId>::into(tp.module(db)).resolver(db) | 496 | Definition::TypeParam(tp) => Into::<ModuleId>::into(tp.module(db)).resolver(db) |
507 | } | 497 | } |
508 | }; | 498 | }; |
@@ -542,13 +532,8 @@ fn try_resolve_intra(db: &RootDatabase, doc_target_dirs: impl Iterator<Item = Pa | |||
542 | ) | 532 | ) |
543 | } | 533 | } |
544 | 534 | ||
545 | enum UrlMode { | ||
546 | Url, | ||
547 | File | ||
548 | } | ||
549 | |||
550 | /// Try to resolve path to local documentation via path-based links (i.e. `../gateway/struct.Shard.html`). | 535 | /// Try to resolve path to local documentation via path-based links (i.e. `../gateway/struct.Shard.html`). |
551 | fn try_resolve_path(db: &RootDatabase, doc_target_dirs: impl Iterator<Item = PathBuf>, definition: &Definition, link: &str, mode: UrlMode) -> Option<String> { | 536 | fn try_resolve_path(db: &RootDatabase, definition: &Definition, link: &str) -> Option<String> { |
552 | eprintln!("try_resolve_path"); | 537 | eprintln!("try_resolve_path"); |
553 | let ns = if let Definition::ModuleDef(moddef) = definition { | 538 | let ns = if let Definition::ModuleDef(moddef) = definition { |
554 | ItemInNs::Types(moddef.clone().into()) | 539 | ItemInNs::Types(moddef.clone().into()) |
@@ -561,29 +546,13 @@ fn try_resolve_path(db: &RootDatabase, doc_target_dirs: impl Iterator<Item = Pat | |||
561 | // TODO: It should be possible to fall back to not-necessarilly-public paths if we can't find a public one, | 546 | // TODO: It should be possible to fall back to not-necessarilly-public paths if we can't find a public one, |
562 | // then hope rustdoc was run locally with `--document-private-items` | 547 | // then hope rustdoc was run locally with `--document-private-items` |
563 | let base = import_map.path_of(ns)?; | 548 | let base = import_map.path_of(ns)?; |
564 | let mut base = once(format!("{}", krate.display_name(db)?)).chain(base.segments.iter().map(|name| format!("{}", name))); | 549 | let base = once(format!("{}", krate.display_name(db)?)).chain(base.segments.iter().map(|name| format!("{}", name))).join("/"); |
565 | 550 | ||
566 | match mode { | 551 | get_doc_url(db, &krate) |
567 | UrlMode::Url => { | 552 | .and_then(|url| url.join(&base).ok()) |
568 | let mut base = base.join("/"); | 553 | .and_then(|url| get_symbol_filename(db, definition).as_deref().map(|f| url.join(f).ok()).flatten()) |
569 | get_doc_url(db, &krate) | 554 | .and_then(|url| url.join(link).ok()) |
570 | .and_then(|url| url.join(&base).ok()) | 555 | .map(|url| url.into_string()) |
571 | .and_then(|url| get_symbol_filename(db, definition).as_deref().map(|f| url.join(f).ok()).flatten()) | ||
572 | .and_then(|url| url.join(link).ok()) | ||
573 | .map(|url| url.into_string()) | ||
574 | }, | ||
575 | UrlMode::File => { | ||
576 | let base = base.collect::<PathBuf>(); | ||
577 | doc_target_dirs | ||
578 | .map(|dir| dir.join(format!("{}", krate.display_name(db).unwrap())).join(base.join("..").join(link))) | ||
579 | .inspect(|path| eprintln!("candidate {}", path.display())) | ||
580 | .filter(|path| path.exists()) | ||
581 | .map(|path| format!("file:///{}", path.display())) | ||
582 | // \. is treated as an escape in vscode's markdown hover rendering | ||
583 | .map(|path_str| path_str.replace("\\", "/")) | ||
584 | .next() | ||
585 | } | ||
586 | } | ||
587 | } | 556 | } |
588 | 557 | ||
589 | /// Try to get the root URL of the documentation of a crate. | 558 | /// Try to get the root URL of the documentation of a crate. |
diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs index d56d52d30..ecac5134e 100644 --- a/crates/ra_ide/src/lib.rs +++ b/crates/ra_ide/src/lib.rs | |||
@@ -54,7 +54,6 @@ use ra_ide_db::{ | |||
54 | LineIndexDatabase, | 54 | LineIndexDatabase, |
55 | }; | 55 | }; |
56 | use ra_syntax::{SourceFile, TextRange, TextSize}; | 56 | use ra_syntax::{SourceFile, TextRange, TextSize}; |
57 | use ra_project_model::ProjectWorkspace; | ||
58 | 57 | ||
59 | use crate::display::ToNav; | 58 | use crate::display::ToNav; |
60 | 59 | ||
@@ -390,8 +389,8 @@ impl Analysis { | |||
390 | } | 389 | } |
391 | 390 | ||
392 | /// Returns a short text describing element at position. | 391 | /// Returns a short text describing element at position. |
393 | pub fn hover(&self, position: FilePosition, workspaces: Arc<Vec<ProjectWorkspace>>) -> Cancelable<Option<RangeInfo<HoverResult>>> { | 392 | pub fn hover(&self, position: FilePosition) -> Cancelable<Option<RangeInfo<HoverResult>>> { |
394 | self.with_db(|db| hover::hover(db, position, workspaces)) | 393 | self.with_db(|db| hover::hover(db, position)) |
395 | } | 394 | } |
396 | 395 | ||
397 | /// Computes parameter information for the given call expression. | 396 | /// Computes parameter information for the given call expression. |