Skip to content

Commit 0218aeb

Browse files
committed
Auto merge of rust-lang#12150 - rainy-me:feat/fix-doc-url-links, r=rainy-me
fix: doc url link type fix: rust-lang#12033 I did some debugging and found the cause looks like to be some doc links' `LinkType` are kept as `Shortcut` which don't make sense for url links. This PR should resolve both problems in the origin issue, but aside this PR, more work are needed for doc_links. about `LinkType`: https://github.com/raphlinus/pulldown-cmark/blob/f29bd1e228913690e5092c9594e4e607423ff0aa/src/lib.rs#L191-L210
2 parents 1f709d5 + ddff1b2 commit 0218aeb

File tree

4 files changed

+84
-33
lines changed

4 files changed

+84
-33
lines changed

crates/hir-def/src/attr.rs

+19
Original file line numberDiff line numberDiff line change
@@ -853,6 +853,25 @@ impl<'attr> AttrQuery<'attr> {
853853
.iter()
854854
.filter(move |attr| attr.path.as_ident().map_or(false, |s| s.to_smol_str() == key))
855855
}
856+
857+
/// Find string value for a specific key inside token tree
858+
///
859+
/// ```ignore
860+
/// #[doc(html_root_url = "url")]
861+
/// ^^^^^^^^^^^^^ key
862+
/// ```
863+
pub fn find_string_value_in_tt(self, key: &'attr str) -> Option<&SmolStr> {
864+
self.tt_values().find_map(|tt| {
865+
let name = tt.token_trees.iter()
866+
.skip_while(|tt| !matches!(tt, tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { text, ..} )) if text == key))
867+
.nth(2);
868+
869+
match name {
870+
Some(tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal{ref text, ..}))) => Some(text),
871+
_ => None
872+
}
873+
})
874+
}
856875
}
857876

858877
fn attrs_from_item_tree<N: ItemTreeNode>(id: ItemTreeId<N>, db: &dyn DefDatabase) -> RawAttrs {

crates/hir/src/lib.rs

+1-18
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,6 @@ use syntax::{
7575
ast::{self, HasAttrs as _, HasDocComments, HasName},
7676
AstNode, AstPtr, SmolStr, SyntaxNodePtr, T,
7777
};
78-
use tt::{Ident, Leaf, Literal, TokenTree};
7978

8079
use crate::db::{DefDatabase, HirDatabase};
8180

@@ -230,23 +229,7 @@ impl Crate {
230229
pub fn get_html_root_url(self: &Crate, db: &dyn HirDatabase) -> Option<String> {
231230
// Look for #![doc(html_root_url = "...")]
232231
let attrs = db.attrs(AttrDefId::ModuleId(self.root_module(db).into()));
233-
let doc_attr_q = attrs.by_key("doc");
234-
235-
if !doc_attr_q.exists() {
236-
return None;
237-
}
238-
239-
let doc_url = doc_attr_q.tt_values().filter_map(|tt| {
240-
let name = tt.token_trees.iter()
241-
.skip_while(|tt| !matches!(tt, TokenTree::Leaf(Leaf::Ident(Ident { text, ..} )) if text == "html_root_url"))
242-
.nth(2);
243-
244-
match name {
245-
Some(TokenTree::Leaf(Leaf::Literal(Literal{ref text, ..}))) => Some(text),
246-
_ => None
247-
}
248-
}).next();
249-
232+
let doc_url = attrs.by_key("doc").find_string_value_in_tt("html_root_url");
250233
doc_url.map(|s| s.trim_matches('"').trim_end_matches('/').to_owned() + "/")
251234
}
252235

crates/ide/src/doc_links.rs

+30-15
Original file line numberDiff line numberDiff line change
@@ -45,19 +45,19 @@ pub(crate) fn rewrite_links(db: &RootDatabase, markdown: &str, definition: Defin
4545
// and valid URLs so we choose to be too eager to try to resolve what might be
4646
// a URL.
4747
if target.contains("://") {
48-
(target.to_string(), title.to_string())
48+
(Some(LinkType::Inline), target.to_string(), title.to_string())
4949
} else {
5050
// Two possibilities:
5151
// * path-based links: `../../module/struct.MyStruct.html`
5252
// * module-based links (AKA intra-doc links): `super::super::module::MyStruct`
53-
if let Some(rewritten) = rewrite_intra_doc_link(db, definition, target, title) {
54-
return rewritten;
53+
if let Some((target, title)) = rewrite_intra_doc_link(db, definition, target, title) {
54+
return (None, target, title);
5555
}
5656
if let Some(target) = rewrite_url_link(db, definition, target) {
57-
return (target, title.to_string());
57+
return (Some(LinkType::Inline), target, title.to_string());
5858
}
5959

60-
(target.to_string(), title.to_string())
60+
(None, target.to_string(), title.to_string())
6161
}
6262
});
6363
let mut out = String::new();
@@ -368,33 +368,42 @@ fn mod_path_of_def(db: &RootDatabase, def: Definition) -> Option<String> {
368368
/// Rewrites a markdown document, applying 'callback' to each link.
369369
fn map_links<'e>(
370370
events: impl Iterator<Item = Event<'e>>,
371-
callback: impl Fn(&str, &str) -> (String, String),
371+
callback: impl Fn(&str, &str) -> (Option<LinkType>, String, String),
372372
) -> impl Iterator<Item = Event<'e>> {
373373
let mut in_link = false;
374-
let mut link_target: Option<CowStr> = None;
374+
// holds the origin link target on start event and the rewritten one on end event
375+
let mut end_link_target: Option<CowStr> = None;
376+
// normally link's type is determined by the type of link tag in the end event,
377+
// however in same cases we want to change the link type, for example,
378+
// `Shortcut` type doesn't make sense for url links
379+
let mut end_link_type: Option<LinkType> = None;
375380

376381
events.map(move |evt| match evt {
377382
Event::Start(Tag::Link(_, ref target, _)) => {
378383
in_link = true;
379-
link_target = Some(target.clone());
384+
end_link_target = Some(target.clone());
380385
evt
381386
}
382387
Event::End(Tag::Link(link_type, target, _)) => {
383388
in_link = false;
384389
Event::End(Tag::Link(
385-
link_type,
386-
link_target.take().unwrap_or(target),
390+
end_link_type.unwrap_or(link_type),
391+
end_link_target.take().unwrap_or(target),
387392
CowStr::Borrowed(""),
388393
))
389394
}
390395
Event::Text(s) if in_link => {
391-
let (link_target_s, link_name) = callback(&link_target.take().unwrap(), &s);
392-
link_target = Some(CowStr::Boxed(link_target_s.into()));
396+
let (link_type, link_target_s, link_name) =
397+
callback(&end_link_target.take().unwrap(), &s);
398+
end_link_target = Some(CowStr::Boxed(link_target_s.into()));
399+
end_link_type = link_type;
393400
Event::Text(CowStr::Boxed(link_name.into()))
394401
}
395402
Event::Code(s) if in_link => {
396-
let (link_target_s, link_name) = callback(&link_target.take().unwrap(), &s);
397-
link_target = Some(CowStr::Boxed(link_target_s.into()));
403+
let (link_type, link_target_s, link_name) =
404+
callback(&end_link_target.take().unwrap(), &s);
405+
end_link_target = Some(CowStr::Boxed(link_target_s.into()));
406+
end_link_type = link_type;
398407
Event::Code(CowStr::Boxed(link_name.into()))
399408
}
400409
_ => evt,
@@ -468,7 +477,13 @@ fn filename_and_frag_for_def(
468477
Adt::Union(u) => format!("union.{}.html", u.name(db)),
469478
},
470479
Definition::Module(m) => match m.name(db) {
471-
Some(name) => format!("{}/index.html", name),
480+
// `#[doc(keyword = "...")]` is internal used only by rust compiler
481+
Some(name) => match m.attrs(db).by_key("doc").find_string_value_in_tt("keyword") {
482+
Some(kw) => {
483+
format!("keyword.{}.html", kw.trim_matches('"'))
484+
}
485+
None => format!("{}/index.html", name),
486+
},
472487
None => String::from("index.html"),
473488
},
474489
Definition::Trait(t) => format!("trait.{}.html", t.name(db)),

crates/ide/src/hover/tests.rs

+34
Original file line numberDiff line numberDiff line change
@@ -3641,6 +3641,40 @@ mod return_keyword {}
36413641
);
36423642
}
36433643

3644+
#[test]
3645+
fn hover_keyword_doc() {
3646+
check(
3647+
r#"
3648+
//- /main.rs crate:main deps:std
3649+
fn foo() {
3650+
let bar = mov$0e || {};
3651+
}
3652+
//- /libstd.rs crate:std
3653+
#[doc(keyword = "move")]
3654+
/// [closure]
3655+
/// [closures][closure]
3656+
/// [threads]
3657+
///
3658+
/// [closure]: ../book/ch13-01-closures.html
3659+
/// [threads]: ../book/ch16-01-threads.html#using-move-closures-with-threads
3660+
mod move_keyword {}
3661+
"#,
3662+
expect![[r##"
3663+
*move*
3664+
3665+
```rust
3666+
move
3667+
```
3668+
3669+
---
3670+
3671+
[closure](https://doc.rust-lang.org/nightly/book/ch13-01-closures.html)
3672+
[closures](https://doc.rust-lang.org/nightly/book/ch13-01-closures.html)
3673+
[threads](https://doc.rust-lang.org/nightly/book/ch16-01-threads.html#using-move-closures-with-threads)
3674+
"##]],
3675+
);
3676+
}
3677+
36443678
#[test]
36453679
fn hover_keyword_as_primitive() {
36463680
check(

0 commit comments

Comments
 (0)