diff options
Diffstat (limited to 'crates/ide/src')
18 files changed, 433 insertions, 77 deletions
diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs index 5ea9fc4fb..c7c1f4fee 100644 --- a/crates/ide/src/doc_links.rs +++ b/crates/ide/src/doc_links.rs | |||
@@ -65,6 +65,8 @@ pub(crate) fn extract_definitions_from_markdown( | |||
65 | ) -> Vec<(String, Option<hir::Namespace>, Range<usize>)> { | 65 | ) -> Vec<(String, Option<hir::Namespace>, Range<usize>)> { |
66 | let mut res = vec![]; | 66 | let mut res = vec![]; |
67 | let mut cb = |link: BrokenLink| { | 67 | let mut cb = |link: BrokenLink| { |
68 | // These allocations are actually unnecessary but the lifetimes on BrokenLinkCallback are wrong | ||
69 | // this is fixed in the repo but not on the crates.io release yet | ||
68 | Some(( | 70 | Some(( |
69 | /*url*/ link.reference.to_owned().into(), | 71 | /*url*/ link.reference.to_owned().into(), |
70 | /*title*/ link.reference.to_owned().into(), | 72 | /*title*/ link.reference.to_owned().into(), |
@@ -72,13 +74,10 @@ pub(crate) fn extract_definitions_from_markdown( | |||
72 | }; | 74 | }; |
73 | let doc = Parser::new_with_broken_link_callback(markdown, Options::empty(), Some(&mut cb)); | 75 | let doc = Parser::new_with_broken_link_callback(markdown, Options::empty(), Some(&mut cb)); |
74 | for (event, range) in doc.into_offset_iter() { | 76 | for (event, range) in doc.into_offset_iter() { |
75 | match event { | 77 | if let Event::Start(Tag::Link(_, target, title)) = event { |
76 | Event::Start(Tag::Link(_link_type, ref target, ref title)) => { | 78 | let link = if target.is_empty() { title } else { target }; |
77 | let link = if target.is_empty() { title } else { target }; | 79 | let (link, ns) = parse_link(&link); |
78 | let (link, ns) = parse_link(link); | 80 | res.push((link.to_string(), ns, range)); |
79 | res.push((link.to_string(), ns, range)); | ||
80 | } | ||
81 | _ => {} | ||
82 | } | 81 | } |
83 | } | 82 | } |
84 | res | 83 | res |
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs index b71f4917c..598b47e41 100644 --- a/crates/ide/src/goto_definition.rs +++ b/crates/ide/src/goto_definition.rs | |||
@@ -1,3 +1,5 @@ | |||
1 | use std::ops::Range; | ||
2 | |||
1 | use either::Either; | 3 | use either::Either; |
2 | use hir::{HasAttrs, ModuleDef, Semantics}; | 4 | use hir::{HasAttrs, ModuleDef, Semantics}; |
3 | use ide_db::{ | 5 | use ide_db::{ |
@@ -5,7 +7,8 @@ use ide_db::{ | |||
5 | RootDatabase, | 7 | RootDatabase, |
6 | }; | 8 | }; |
7 | use syntax::{ | 9 | use syntax::{ |
8 | ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxToken, TextSize, TokenAtOffset, T, | 10 | ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxToken, TextRange, TextSize, |
11 | TokenAtOffset, T, | ||
9 | }; | 12 | }; |
10 | 13 | ||
11 | use crate::{ | 14 | use crate::{ |
@@ -92,17 +95,18 @@ fn extract_positioned_link_from_comment( | |||
92 | position: FilePosition, | 95 | position: FilePosition, |
93 | comment: &ast::Comment, | 96 | comment: &ast::Comment, |
94 | ) -> Option<(String, Option<hir::Namespace>)> { | 97 | ) -> Option<(String, Option<hir::Namespace>)> { |
95 | let comment_range = comment.syntax().text_range(); | ||
96 | let doc_comment = comment.doc_comment()?; | 98 | let doc_comment = comment.doc_comment()?; |
99 | let comment_start = | ||
100 | comment.syntax().text_range().start() + TextSize::from(comment.prefix().len() as u32); | ||
97 | let def_links = extract_definitions_from_markdown(doc_comment); | 101 | let def_links = extract_definitions_from_markdown(doc_comment); |
98 | let (def_link, ns, _) = def_links.iter().min_by_key(|(_, _, def_link_range)| { | 102 | let (def_link, ns, _) = def_links.into_iter().find(|&(_, _, Range { start, end })| { |
99 | let matched_position = comment_range.start() + TextSize::from(def_link_range.start as u32); | 103 | TextRange::at( |
100 | match position.offset.checked_sub(matched_position) { | 104 | comment_start + TextSize::from(start as u32), |
101 | Some(distance) => distance, | 105 | TextSize::from((end - start) as u32), |
102 | None => comment_range.end(), | 106 | ) |
103 | } | 107 | .contains(position.offset) |
104 | })?; | 108 | })?; |
105 | Some((def_link.to_string(), *ns)) | 109 | Some((def_link, ns)) |
106 | } | 110 | } |
107 | 111 | ||
108 | fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> { | 112 | fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> { |
@@ -1136,7 +1140,7 @@ fn foo<'foo>(_: &'foo ()) { | |||
1136 | fn goto_def_for_intra_doc_link_same_file() { | 1140 | fn goto_def_for_intra_doc_link_same_file() { |
1137 | check( | 1141 | check( |
1138 | r#" | 1142 | r#" |
1139 | /// Blah, [`bar`](bar) .. [`foo`](foo)$0 has [`bar`](bar) | 1143 | /// Blah, [`bar`](bar) .. [`foo`](foo$0) has [`bar`](bar) |
1140 | pub fn bar() { } | 1144 | pub fn bar() { } |
1141 | 1145 | ||
1142 | /// You might want to see [`std::fs::read()`] too. | 1146 | /// You might want to see [`std::fs::read()`] too. |
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index 325014622..15d309d7d 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs | |||
@@ -1533,12 +1533,21 @@ fn my() {} | |||
1533 | fn test_hover_struct_doc_comment() { | 1533 | fn test_hover_struct_doc_comment() { |
1534 | check( | 1534 | check( |
1535 | r#" | 1535 | r#" |
1536 | /// bar docs | 1536 | /// This is an example |
1537 | /// multiline doc | ||
1538 | /// | ||
1539 | /// # Example | ||
1540 | /// | ||
1541 | /// ``` | ||
1542 | /// let five = 5; | ||
1543 | /// | ||
1544 | /// assert_eq!(6, my_crate::add_one(5)); | ||
1545 | /// ``` | ||
1537 | struct Bar; | 1546 | struct Bar; |
1538 | 1547 | ||
1539 | fn foo() { let bar = Ba$0r; } | 1548 | fn foo() { let bar = Ba$0r; } |
1540 | "#, | 1549 | "#, |
1541 | expect![[r#" | 1550 | expect![[r##" |
1542 | *Bar* | 1551 | *Bar* |
1543 | 1552 | ||
1544 | ```rust | 1553 | ```rust |
@@ -1551,8 +1560,17 @@ fn foo() { let bar = Ba$0r; } | |||
1551 | 1560 | ||
1552 | --- | 1561 | --- |
1553 | 1562 | ||
1554 | bar docs | 1563 | This is an example |
1555 | "#]], | 1564 | multiline doc |
1565 | |||
1566 | # Example | ||
1567 | |||
1568 | ``` | ||
1569 | let five = 5; | ||
1570 | |||
1571 | assert_eq!(6, my_crate::add_one(5)); | ||
1572 | ``` | ||
1573 | "##]], | ||
1556 | ); | 1574 | ); |
1557 | } | 1575 | } |
1558 | 1576 | ||
@@ -3424,6 +3442,40 @@ mod Foo$0 { | |||
3424 | } | 3442 | } |
3425 | 3443 | ||
3426 | #[test] | 3444 | #[test] |
3445 | fn hover_doc_block_style_indentend() { | ||
3446 | check( | ||
3447 | r#" | ||
3448 | /** | ||
3449 | foo | ||
3450 | ```rust | ||
3451 | let x = 3; | ||
3452 | ``` | ||
3453 | */ | ||
3454 | fn foo$0() {} | ||
3455 | "#, | ||
3456 | expect![[r#" | ||
3457 | *foo* | ||
3458 | |||
3459 | ```rust | ||
3460 | test | ||
3461 | ``` | ||
3462 | |||
3463 | ```rust | ||
3464 | fn foo() | ||
3465 | ``` | ||
3466 | |||
3467 | --- | ||
3468 | |||
3469 | foo | ||
3470 | |||
3471 | ```rust | ||
3472 | let x = 3; | ||
3473 | ``` | ||
3474 | "#]], | ||
3475 | ); | ||
3476 | } | ||
3477 | |||
3478 | #[test] | ||
3427 | fn hover_comments_dont_highlight_parent() { | 3479 | fn hover_comments_dont_highlight_parent() { |
3428 | check_hover_no_result( | 3480 | check_hover_no_result( |
3429 | r#" | 3481 | r#" |
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs index 397e2126b..bea020b06 100644 --- a/crates/ide/src/runnables.rs +++ b/crates/ide/src/runnables.rs | |||
@@ -576,6 +576,20 @@ fn should_have_runnable_1() {} | |||
576 | /// ``` | 576 | /// ``` |
577 | fn should_have_runnable_2() {} | 577 | fn should_have_runnable_2() {} |
578 | 578 | ||
579 | /** | ||
580 | ```rust | ||
581 | let z = 55; | ||
582 | ``` | ||
583 | */ | ||
584 | fn should_have_no_runnable_3() {} | ||
585 | |||
586 | /** | ||
587 | ```rust | ||
588 | let z = 55; | ||
589 | ``` | ||
590 | */ | ||
591 | fn should_have_no_runnable_4() {} | ||
592 | |||
579 | /// ```no_run | 593 | /// ```no_run |
580 | /// let z = 55; | 594 | /// let z = 55; |
581 | /// ``` | 595 | /// ``` |
@@ -616,7 +630,7 @@ fn should_have_no_runnable_6() {} | |||
616 | struct StructWithRunnable(String); | 630 | struct StructWithRunnable(String); |
617 | 631 | ||
618 | "#, | 632 | "#, |
619 | &[&BIN, &DOCTEST, &DOCTEST, &DOCTEST, &DOCTEST], | 633 | &[&BIN, &DOCTEST, &DOCTEST, &DOCTEST, &DOCTEST, &DOCTEST, &DOCTEST], |
620 | expect![[r#" | 634 | expect![[r#" |
621 | [ | 635 | [ |
622 | Runnable { | 636 | Runnable { |
@@ -682,7 +696,37 @@ struct StructWithRunnable(String); | |||
682 | file_id: FileId( | 696 | file_id: FileId( |
683 | 0, | 697 | 0, |
684 | ), | 698 | ), |
685 | full_range: 756..821, | 699 | full_range: 256..320, |
700 | name: "should_have_no_runnable_3", | ||
701 | }, | ||
702 | kind: DocTest { | ||
703 | test_id: Path( | ||
704 | "should_have_no_runnable_3", | ||
705 | ), | ||
706 | }, | ||
707 | cfg: None, | ||
708 | }, | ||
709 | Runnable { | ||
710 | nav: NavigationTarget { | ||
711 | file_id: FileId( | ||
712 | 0, | ||
713 | ), | ||
714 | full_range: 322..398, | ||
715 | name: "should_have_no_runnable_4", | ||
716 | }, | ||
717 | kind: DocTest { | ||
718 | test_id: Path( | ||
719 | "should_have_no_runnable_4", | ||
720 | ), | ||
721 | }, | ||
722 | cfg: None, | ||
723 | }, | ||
724 | Runnable { | ||
725 | nav: NavigationTarget { | ||
726 | file_id: FileId( | ||
727 | 0, | ||
728 | ), | ||
729 | full_range: 900..965, | ||
686 | name: "StructWithRunnable", | 730 | name: "StructWithRunnable", |
687 | }, | 731 | }, |
688 | kind: DocTest { | 732 | kind: DocTest { |
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs index 870146d24..ba3447b3a 100644 --- a/crates/ide/src/syntax_highlighting.rs +++ b/crates/ide/src/syntax_highlighting.rs | |||
@@ -150,7 +150,7 @@ fn traverse( | |||
150 | WalkEvent::Enter(it) => it, | 150 | WalkEvent::Enter(it) => it, |
151 | WalkEvent::Leave(it) => { | 151 | WalkEvent::Leave(it) => { |
152 | if let Some(node) = it.as_node() { | 152 | if let Some(node) = it.as_node() { |
153 | inject::doc_comment(hl, node); | 153 | inject::doc_comment(hl, sema, node); |
154 | } | 154 | } |
155 | continue; | 155 | continue; |
156 | } | 156 | } |
diff --git a/crates/ide/src/syntax_highlighting/html.rs b/crates/ide/src/syntax_highlighting/html.rs index 0ee7bc96e..1d34731ab 100644 --- a/crates/ide/src/syntax_highlighting/html.rs +++ b/crates/ide/src/syntax_highlighting/html.rs | |||
@@ -59,6 +59,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
59 | .label { color: #DFAF8F; font-style: italic; } | 59 | .label { color: #DFAF8F; font-style: italic; } |
60 | .comment { color: #7F9F7F; } | 60 | .comment { color: #7F9F7F; } |
61 | .documentation { color: #629755; } | 61 | .documentation { color: #629755; } |
62 | .intra_doc_link { color: #A9C577; } | ||
62 | .injected { opacity: 0.65 ; } | 63 | .injected { opacity: 0.65 ; } |
63 | .struct, .enum { color: #7CB8BB; } | 64 | .struct, .enum { color: #7CB8BB; } |
64 | .enum_variant { color: #BDE0F3; } | 65 | .enum_variant { color: #BDE0F3; } |
diff --git a/crates/ide/src/syntax_highlighting/inject.rs b/crates/ide/src/syntax_highlighting/inject.rs index 4f825523c..947cc974c 100644 --- a/crates/ide/src/syntax_highlighting/inject.rs +++ b/crates/ide/src/syntax_highlighting/inject.rs | |||
@@ -1,10 +1,18 @@ | |||
1 | //! "Recursive" Syntax highlighting for code in doctests and fixtures. | 1 | //! "Recursive" Syntax highlighting for code in doctests and fixtures. |
2 | 2 | ||
3 | use hir::Semantics; | 3 | use std::{mem, ops::Range}; |
4 | use ide_db::call_info::ActiveParameter; | ||
5 | use syntax::{ast, AstToken, SyntaxNode, SyntaxToken, TextRange, TextSize}; | ||
6 | 4 | ||
7 | use crate::{Analysis, HlMod, HlRange, HlTag, RootDatabase}; | 5 | use either::Either; |
6 | use hir::{HasAttrs, Semantics}; | ||
7 | use ide_db::{call_info::ActiveParameter, defs::Definition}; | ||
8 | use syntax::{ | ||
9 | ast::{self, AstNode, AttrsOwner, DocCommentsOwner}, | ||
10 | match_ast, AstToken, NodeOrToken, SyntaxNode, SyntaxToken, TextRange, TextSize, | ||
11 | }; | ||
12 | |||
13 | use crate::{ | ||
14 | doc_links::extract_definitions_from_markdown, Analysis, HlMod, HlRange, HlTag, RootDatabase, | ||
15 | }; | ||
8 | 16 | ||
9 | use super::{highlights::Highlights, injector::Injector}; | 17 | use super::{highlights::Highlights, injector::Injector}; |
10 | 18 | ||
@@ -81,70 +89,181 @@ const RUSTDOC_FENCE_TOKENS: &[&'static str] = &[ | |||
81 | "edition2021", | 89 | "edition2021", |
82 | ]; | 90 | ]; |
83 | 91 | ||
84 | /// Injection of syntax highlighting of doctests. | 92 | // Basically an owned dyn AttrsOwner without extra Boxing |
85 | pub(super) fn doc_comment(hl: &mut Highlights, node: &SyntaxNode) { | 93 | struct AttrsOwnerNode { |
86 | let doc_comments = node | 94 | node: SyntaxNode, |
87 | .children_with_tokens() | 95 | } |
88 | .filter_map(|it| it.into_token().and_then(ast::Comment::cast)) | 96 | |
89 | .filter(|it| it.kind().doc.is_some()); | 97 | impl AttrsOwnerNode { |
98 | fn new<N: DocCommentsOwner>(node: N) -> Self { | ||
99 | AttrsOwnerNode { node: node.syntax().clone() } | ||
100 | } | ||
101 | } | ||
102 | |||
103 | impl AttrsOwner for AttrsOwnerNode {} | ||
104 | impl AstNode for AttrsOwnerNode { | ||
105 | fn can_cast(_: syntax::SyntaxKind) -> bool | ||
106 | where | ||
107 | Self: Sized, | ||
108 | { | ||
109 | false | ||
110 | } | ||
111 | fn cast(_: SyntaxNode) -> Option<Self> | ||
112 | where | ||
113 | Self: Sized, | ||
114 | { | ||
115 | None | ||
116 | } | ||
117 | fn syntax(&self) -> &SyntaxNode { | ||
118 | &self.node | ||
119 | } | ||
120 | } | ||
90 | 121 | ||
91 | if !doc_comments.clone().any(|it| it.text().contains(RUSTDOC_FENCE)) { | 122 | fn doc_attributes<'node>( |
92 | return; | 123 | sema: &Semantics<RootDatabase>, |
124 | node: &'node SyntaxNode, | ||
125 | ) -> Option<(AttrsOwnerNode, hir::Attrs, Definition)> { | ||
126 | match_ast! { | ||
127 | match node { | ||
128 | ast::SourceFile(it) => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Module(def)))), | ||
129 | ast::Module(it) => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Module(def)))), | ||
130 | ast::Fn(it) => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Function(def)))), | ||
131 | ast::Struct(it) => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Struct(def))))), | ||
132 | ast::Union(it) => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Union(def))))), | ||
133 | ast::Enum(it) => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Enum(def))))), | ||
134 | ast::Variant(it) => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Variant(def)))), | ||
135 | ast::Trait(it) => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Trait(def)))), | ||
136 | ast::Static(it) => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Static(def)))), | ||
137 | ast::Const(it) => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Const(def)))), | ||
138 | ast::TypeAlias(it) => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::TypeAlias(def)))), | ||
139 | ast::Impl(it) => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db), Definition::SelfType(def))), | ||
140 | ast::RecordField(it) => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db), Definition::Field(def))), | ||
141 | ast::TupleField(it) => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db), Definition::Field(def))), | ||
142 | ast::MacroRules(it) => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db), Definition::Macro(def))), | ||
143 | // ast::MacroDef(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))), | ||
144 | // ast::Use(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))), | ||
145 | _ => return None | ||
146 | } | ||
93 | } | 147 | } |
148 | } | ||
149 | |||
150 | /// Injection of syntax highlighting of doctests. | ||
151 | pub(super) fn doc_comment(hl: &mut Highlights, sema: &Semantics<RootDatabase>, node: &SyntaxNode) { | ||
152 | let (owner, attributes, def) = match doc_attributes(sema, node) { | ||
153 | Some(it) => it, | ||
154 | None => return, | ||
155 | }; | ||
94 | 156 | ||
95 | let mut inj = Injector::default(); | 157 | let mut inj = Injector::default(); |
96 | inj.add_unmapped("fn doctest() {\n"); | 158 | inj.add_unmapped("fn doctest() {\n"); |
97 | 159 | ||
160 | let attrs_source_map = attributes.source_map(&owner); | ||
161 | |||
98 | let mut is_codeblock = false; | 162 | let mut is_codeblock = false; |
99 | let mut is_doctest = false; | 163 | let mut is_doctest = false; |
100 | 164 | ||
101 | // Replace the original, line-spanning comment ranges by new, only comment-prefix | 165 | // Replace the original, line-spanning comment ranges by new, only comment-prefix |
102 | // spanning comment ranges. | 166 | // spanning comment ranges. |
103 | let mut new_comments = Vec::new(); | 167 | let mut new_comments = Vec::new(); |
104 | for comment in doc_comments { | 168 | let mut intra_doc_links = Vec::new(); |
105 | match comment.text().find(RUSTDOC_FENCE) { | 169 | let mut string; |
106 | Some(idx) => { | 170 | for attr in attributes.by_key("doc").attrs() { |
107 | is_codeblock = !is_codeblock; | 171 | let src = attrs_source_map.source_of(&attr); |
108 | // Check whether code is rust by inspecting fence guards | 172 | let (line, range, prefix) = match &src { |
109 | let guards = &comment.text()[idx + RUSTDOC_FENCE.len()..]; | 173 | Either::Left(it) => { |
110 | let is_rust = | 174 | string = match find_doc_string_in_attr(attr, it) { |
111 | guards.split(',').all(|sub| RUSTDOC_FENCE_TOKENS.contains(&sub.trim())); | 175 | Some(it) => it, |
112 | is_doctest = is_codeblock && is_rust; | 176 | None => continue, |
113 | continue; | 177 | }; |
178 | let text_range = string.syntax().text_range(); | ||
179 | let text_range = TextRange::new( | ||
180 | text_range.start() + TextSize::from(1), | ||
181 | text_range.end() - TextSize::from(1), | ||
182 | ); | ||
183 | let text = string.text(); | ||
184 | (&text[1..text.len() - 1], text_range, "") | ||
114 | } | 185 | } |
115 | None if !is_doctest => continue, | 186 | Either::Right(comment) => { |
116 | None => (), | 187 | (comment.text(), comment.syntax().text_range(), comment.prefix()) |
117 | } | 188 | } |
189 | }; | ||
118 | 190 | ||
119 | let line: &str = comment.text(); | 191 | let mut pos = TextSize::from(prefix.len() as u32); |
120 | let range = comment.syntax().text_range(); | 192 | let mut range_start = range.start(); |
193 | for line in line.split('\n') { | ||
194 | let line_len = TextSize::from(line.len() as u32); | ||
195 | let prev_range_start = { | ||
196 | let next_range_start = range_start + line_len + TextSize::from(1); | ||
197 | mem::replace(&mut range_start, next_range_start) | ||
198 | }; | ||
199 | // only first line has the prefix so take it away for future iterations | ||
200 | let mut pos = mem::take(&mut pos); | ||
121 | 201 | ||
122 | let mut pos = TextSize::of(comment.prefix()); | 202 | match line.find(RUSTDOC_FENCE) { |
123 | // whitespace after comment is ignored | 203 | Some(idx) => { |
124 | if let Some(ws) = line[pos.into()..].chars().next().filter(|c| c.is_whitespace()) { | 204 | is_codeblock = !is_codeblock; |
125 | pos += TextSize::of(ws); | 205 | // Check whether code is rust by inspecting fence guards |
126 | } | 206 | let guards = &line[idx + RUSTDOC_FENCE.len()..]; |
127 | // lines marked with `#` should be ignored in output, we skip the `#` char | 207 | let is_rust = |
128 | if let Some(ws) = line[pos.into()..].chars().next().filter(|&c| c == '#') { | 208 | guards.split(',').all(|sub| RUSTDOC_FENCE_TOKENS.contains(&sub.trim())); |
129 | pos += TextSize::of(ws); | 209 | is_doctest = is_codeblock && is_rust; |
210 | continue; | ||
211 | } | ||
212 | None if !is_doctest => { | ||
213 | intra_doc_links.extend( | ||
214 | extract_definitions_from_markdown(line) | ||
215 | .into_iter() | ||
216 | .filter(|(link, ns, _)| { | ||
217 | validate_intra_doc_link(sema.db, &def, link, *ns) | ||
218 | }) | ||
219 | .map(|(.., Range { start, end })| { | ||
220 | TextRange::at( | ||
221 | prev_range_start + TextSize::from(start as u32), | ||
222 | TextSize::from((end - start) as u32), | ||
223 | ) | ||
224 | }), | ||
225 | ); | ||
226 | continue; | ||
227 | } | ||
228 | None => (), | ||
229 | } | ||
230 | |||
231 | // whitespace after comment is ignored | ||
232 | if let Some(ws) = line[pos.into()..].chars().next().filter(|c| c.is_whitespace()) { | ||
233 | pos += TextSize::of(ws); | ||
234 | } | ||
235 | // lines marked with `#` should be ignored in output, we skip the `#` char | ||
236 | if line[pos.into()..].starts_with('#') { | ||
237 | pos += TextSize::of('#'); | ||
238 | } | ||
239 | |||
240 | new_comments.push(TextRange::at(prev_range_start, pos)); | ||
241 | inj.add(&line[pos.into()..], TextRange::new(pos, line_len) + prev_range_start); | ||
242 | inj.add_unmapped("\n"); | ||
130 | } | 243 | } |
244 | } | ||
131 | 245 | ||
132 | new_comments.push(TextRange::at(range.start(), pos)); | 246 | for range in intra_doc_links { |
247 | hl.add(HlRange { | ||
248 | range, | ||
249 | highlight: HlTag::IntraDocLink | HlMod::Documentation, | ||
250 | binding_hash: None, | ||
251 | }); | ||
252 | } | ||
133 | 253 | ||
134 | inj.add(&line[pos.into()..], TextRange::new(range.start() + pos, range.end())); | 254 | if new_comments.is_empty() { |
135 | inj.add_unmapped("\n"); | 255 | return; // no need to run an analysis on an empty file |
136 | } | 256 | } |
257 | |||
137 | inj.add_unmapped("\n}"); | 258 | inj.add_unmapped("\n}"); |
138 | 259 | ||
139 | let (analysis, tmp_file_id) = Analysis::from_single_file(inj.text().to_string()); | 260 | let (analysis, tmp_file_id) = Analysis::from_single_file(inj.text().to_string()); |
140 | 261 | ||
141 | for h in analysis.with_db(|db| super::highlight(db, tmp_file_id, None, true)).unwrap() { | 262 | for HlRange { range, highlight, binding_hash } in |
142 | for r in inj.map_range_up(h.range) { | 263 | analysis.with_db(|db| super::highlight(db, tmp_file_id, None, true)).unwrap() |
143 | hl.add(HlRange { | 264 | { |
144 | range: r, | 265 | for range in inj.map_range_up(range) { |
145 | highlight: h.highlight | HlMod::Injected, | 266 | hl.add(HlRange { range, highlight: highlight | HlMod::Injected, binding_hash }); |
146 | binding_hash: h.binding_hash, | ||
147 | }); | ||
148 | } | 267 | } |
149 | } | 268 | } |
150 | 269 | ||
@@ -156,3 +275,55 @@ pub(super) fn doc_comment(hl: &mut Highlights, node: &SyntaxNode) { | |||
156 | }); | 275 | }); |
157 | } | 276 | } |
158 | } | 277 | } |
278 | |||
279 | fn find_doc_string_in_attr(attr: &hir::Attr, it: &ast::Attr) -> Option<ast::String> { | ||
280 | match it.literal() { | ||
281 | // #[doc = lit] | ||
282 | Some(lit) => match lit.kind() { | ||
283 | ast::LiteralKind::String(it) => Some(it), | ||
284 | _ => None, | ||
285 | }, | ||
286 | // #[cfg_attr(..., doc = "", ...)] | ||
287 | None => { | ||
288 | // We gotta hunt the string token manually here | ||
289 | let text = attr.string_value()?; | ||
290 | // FIXME: We just pick the first string literal that has the same text as the doc attribute | ||
291 | // This means technically we might highlight the wrong one | ||
292 | it.syntax() | ||
293 | .descendants_with_tokens() | ||
294 | .filter_map(NodeOrToken::into_token) | ||
295 | .filter_map(ast::String::cast) | ||
296 | .find(|string| { | ||
297 | string.text().get(1..string.text().len() - 1).map_or(false, |it| it == text) | ||
298 | }) | ||
299 | } | ||
300 | } | ||
301 | } | ||
302 | |||
303 | fn validate_intra_doc_link( | ||
304 | db: &RootDatabase, | ||
305 | def: &Definition, | ||
306 | link: &str, | ||
307 | ns: Option<hir::Namespace>, | ||
308 | ) -> bool { | ||
309 | match def { | ||
310 | Definition::ModuleDef(def) => match def { | ||
311 | hir::ModuleDef::Module(it) => it.resolve_doc_path(db, &link, ns), | ||
312 | hir::ModuleDef::Function(it) => it.resolve_doc_path(db, &link, ns), | ||
313 | hir::ModuleDef::Adt(it) => it.resolve_doc_path(db, &link, ns), | ||
314 | hir::ModuleDef::Variant(it) => it.resolve_doc_path(db, &link, ns), | ||
315 | hir::ModuleDef::Const(it) => it.resolve_doc_path(db, &link, ns), | ||
316 | hir::ModuleDef::Static(it) => it.resolve_doc_path(db, &link, ns), | ||
317 | hir::ModuleDef::Trait(it) => it.resolve_doc_path(db, &link, ns), | ||
318 | hir::ModuleDef::TypeAlias(it) => it.resolve_doc_path(db, &link, ns), | ||
319 | hir::ModuleDef::BuiltinType(_) => None, | ||
320 | }, | ||
321 | Definition::Macro(it) => it.resolve_doc_path(db, &link, ns), | ||
322 | Definition::Field(it) => it.resolve_doc_path(db, &link, ns), | ||
323 | Definition::SelfType(_) | ||
324 | | Definition::Local(_) | ||
325 | | Definition::GenericParam(_) | ||
326 | | Definition::Label(_) => None, | ||
327 | } | ||
328 | .is_some() | ||
329 | } | ||
diff --git a/crates/ide/src/syntax_highlighting/tags.rs b/crates/ide/src/syntax_highlighting/tags.rs index 3c02fdb11..ce46e5127 100644 --- a/crates/ide/src/syntax_highlighting/tags.rs +++ b/crates/ide/src/syntax_highlighting/tags.rs | |||
@@ -18,19 +18,20 @@ pub struct HlMods(u32); | |||
18 | pub enum HlTag { | 18 | pub enum HlTag { |
19 | Symbol(SymbolKind), | 19 | Symbol(SymbolKind), |
20 | 20 | ||
21 | Attribute, | ||
21 | BoolLiteral, | 22 | BoolLiteral, |
22 | BuiltinType, | 23 | BuiltinType, |
23 | ByteLiteral, | 24 | ByteLiteral, |
24 | CharLiteral, | 25 | CharLiteral, |
25 | NumericLiteral, | ||
26 | StringLiteral, | ||
27 | Attribute, | ||
28 | Comment, | 26 | Comment, |
29 | EscapeSequence, | 27 | EscapeSequence, |
30 | FormatSpecifier, | 28 | FormatSpecifier, |
29 | IntraDocLink, | ||
31 | Keyword, | 30 | Keyword, |
32 | Punctuation(HlPunct), | 31 | NumericLiteral, |
33 | Operator, | 32 | Operator, |
33 | Punctuation(HlPunct), | ||
34 | StringLiteral, | ||
34 | UnresolvedReference, | 35 | UnresolvedReference, |
35 | 36 | ||
36 | // For things which don't have a specific highlight. | 37 | // For things which don't have a specific highlight. |
@@ -116,6 +117,7 @@ impl HlTag { | |||
116 | HlTag::Comment => "comment", | 117 | HlTag::Comment => "comment", |
117 | HlTag::EscapeSequence => "escape_sequence", | 118 | HlTag::EscapeSequence => "escape_sequence", |
118 | HlTag::FormatSpecifier => "format_specifier", | 119 | HlTag::FormatSpecifier => "format_specifier", |
120 | HlTag::IntraDocLink => "intra_doc_link", | ||
119 | HlTag::Keyword => "keyword", | 121 | HlTag::Keyword => "keyword", |
120 | HlTag::Punctuation(punct) => match punct { | 122 | HlTag::Punctuation(punct) => match punct { |
121 | HlPunct::Bracket => "bracket", | 123 | HlPunct::Bracket => "bracket", |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html b/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html index d421a7803..60c7518af 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html | |||
@@ -7,6 +7,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
7 | .label { color: #DFAF8F; font-style: italic; } | 7 | .label { color: #DFAF8F; font-style: italic; } |
8 | .comment { color: #7F9F7F; } | 8 | .comment { color: #7F9F7F; } |
9 | .documentation { color: #629755; } | 9 | .documentation { color: #629755; } |
10 | .intra_doc_link { color: #A9C577; } | ||
10 | .injected { opacity: 0.65 ; } | 11 | .injected { opacity: 0.65 ; } |
11 | .struct, .enum { color: #7CB8BB; } | 12 | .struct, .enum { color: #7CB8BB; } |
12 | .enum_variant { color: #BDE0F3; } | 13 | .enum_variant { color: #BDE0F3; } |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html index 5e877df88..5d802a647 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html | |||
@@ -7,6 +7,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
7 | .label { color: #DFAF8F; font-style: italic; } | 7 | .label { color: #DFAF8F; font-style: italic; } |
8 | .comment { color: #7F9F7F; } | 8 | .comment { color: #7F9F7F; } |
9 | .documentation { color: #629755; } | 9 | .documentation { color: #629755; } |
10 | .intra_doc_link { color: #A9C577; } | ||
10 | .injected { opacity: 0.65 ; } | 11 | .injected { opacity: 0.65 ; } |
11 | .struct, .enum { color: #7CB8BB; } | 12 | .struct, .enum { color: #7CB8BB; } |
12 | .enum_variant { color: #BDE0F3; } | 13 | .enum_variant { color: #BDE0F3; } |
@@ -81,7 +82,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
81 | <span class="comment documentation">/// </span><span class="comment injected"> comment */</span> | 82 | <span class="comment documentation">/// </span><span class="comment injected"> comment */</span> |
82 | <span class="comment documentation">///</span> | 83 | <span class="comment documentation">///</span> |
83 | <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="variable declaration injected">multi_line_string</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="string_literal injected">"Foo</span> | 84 | <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="variable declaration injected">multi_line_string</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="string_literal injected">"Foo</span> |
84 | <span class="comment documentation">/// </span><span class="string_literal injected"> bar</span> | 85 | <span class="comment documentation">/// </span><span class="string_literal injected"> bar</span><span class="escape_sequence injected">\n</span> |
85 | <span class="comment documentation">/// </span><span class="string_literal injected"> "</span><span class="semicolon injected">;</span> | 86 | <span class="comment documentation">/// </span><span class="string_literal injected"> "</span><span class="semicolon injected">;</span> |
86 | <span class="comment documentation">///</span> | 87 | <span class="comment documentation">///</span> |
87 | <span class="comment documentation">/// ```</span> | 88 | <span class="comment documentation">/// ```</span> |
@@ -98,6 +99,11 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
98 | <span class="brace">}</span> | 99 | <span class="brace">}</span> |
99 | <span class="brace">}</span> | 100 | <span class="brace">}</span> |
100 | 101 | ||
102 | <span class="comment documentation">/// </span><span class="intra_doc_link documentation">[`Foo`](Foo)</span><span class="comment documentation"> is a struct</span> | ||
103 | <span class="comment documentation">/// </span><span class="intra_doc_link documentation">[`all_the_links`](all_the_links)</span><span class="comment documentation"> is this function</span> | ||
104 | <span class="comment documentation">/// [`noop`](noop) is a macro below</span> | ||
105 | <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration">all_the_links</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> | ||
106 | |||
101 | <span class="comment documentation">/// ```</span> | 107 | <span class="comment documentation">/// ```</span> |
102 | <span class="comment documentation">/// </span><span class="macro injected">noop!</span><span class="parenthesis injected">(</span><span class="numeric_literal injected">1</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span> | 108 | <span class="comment documentation">/// </span><span class="macro injected">noop!</span><span class="parenthesis injected">(</span><span class="numeric_literal injected">1</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span> |
103 | <span class="comment documentation">/// ```</span> | 109 | <span class="comment documentation">/// ```</span> |
@@ -105,4 +111,36 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
105 | <span class="parenthesis">(</span><span class="punctuation">$</span>expr<span class="colon">:</span>expr<span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="brace">{</span> | 111 | <span class="parenthesis">(</span><span class="punctuation">$</span>expr<span class="colon">:</span>expr<span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="brace">{</span> |
106 | <span class="punctuation">$</span>expr | 112 | <span class="punctuation">$</span>expr |
107 | <span class="brace">}</span> | 113 | <span class="brace">}</span> |
108 | <span class="brace">}</span></code></pre> \ No newline at end of file | 114 | <span class="brace">}</span> |
115 | |||
116 | <span class="comment documentation">/// ```rust</span> | ||
117 | <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="punctuation injected">_</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="function injected">example</span><span class="parenthesis injected">(</span><span class="operator injected">&</span><span class="bracket injected">[</span><span class="numeric_literal injected">1</span><span class="comma injected">,</span><span class="none injected"> </span><span class="numeric_literal injected">2</span><span class="comma injected">,</span><span class="none injected"> </span><span class="numeric_literal injected">3</span><span class="bracket injected">]</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span> | ||
118 | <span class="comment documentation">/// ```</span> | ||
119 | <span class="comment documentation">///</span> | ||
120 | <span class="comment documentation">/// ```</span> | ||
121 | <span class="comment documentation">/// </span><span class="keyword control injected">loop</span><span class="none injected"> </span><span class="brace injected">{</span><span class="brace injected">}</span> | ||
122 | <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">cfg_attr</span><span class="parenthesis attribute">(</span><span class="attribute attribute">not</span><span class="parenthesis attribute">(</span><span class="attribute attribute">feature </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"false"</span><span class="parenthesis attribute">)</span><span class="comma attribute">,</span><span class="attribute attribute"> doc </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"</span><span class="keyword control injected">loop</span><span class="none injected"> </span><span class="brace injected">{</span><span class="brace injected">}</span><span class="string_literal attribute">"</span><span class="parenthesis attribute">)</span><span class="attribute attribute">]</span> | ||
123 | <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">doc</span><span class="attribute attribute"> </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"</span><span class="keyword control injected">loop</span><span class="none injected"> </span><span class="brace injected">{</span><span class="brace injected">}</span><span class="string_literal attribute">"</span><span class="attribute attribute">]</span> | ||
124 | <span class="comment documentation">/// ```</span> | ||
125 | <span class="comment documentation">///</span> | ||
126 | <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">cfg_attr</span><span class="parenthesis attribute">(</span><span class="attribute attribute">feature </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"alloc"</span><span class="comma attribute">,</span><span class="attribute attribute"> doc </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"```rust"</span><span class="parenthesis attribute">)</span><span class="attribute attribute">]</span> | ||
127 | <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">cfg_attr</span><span class="parenthesis attribute">(</span><span class="attribute attribute">not</span><span class="parenthesis attribute">(</span><span class="attribute attribute">feature </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"alloc"</span><span class="parenthesis attribute">)</span><span class="comma attribute">,</span><span class="attribute attribute"> doc </span><span class="operator attribute">=</span><span class="attribute attribute"> </span><span class="string_literal attribute">"```ignore"</span><span class="parenthesis attribute">)</span><span class="attribute attribute">]</span> | ||
128 | <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="punctuation injected">_</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="function injected">example</span><span class="parenthesis injected">(</span><span class="operator injected">&</span><span class="none injected">alloc::</span><span class="macro injected">vec!</span><span class="bracket injected">[</span><span class="numeric_literal injected">1</span><span class="comma injected">,</span><span class="none injected"> </span><span class="numeric_literal injected">2</span><span class="comma injected">,</span><span class="none injected"> </span><span class="numeric_literal injected">3</span><span class="bracket injected">]</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span> | ||
129 | <span class="comment documentation">/// ```</span> | ||
130 | <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration">mix_and_match</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> | ||
131 | |||
132 | <span class="comment documentation">/** | ||
133 | It is beyond me why you'd use these when you got /// | ||
134 | ```rust | ||
135 | </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="punctuation injected">_</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="function injected">example</span><span class="parenthesis injected">(</span><span class="operator injected">&</span><span class="bracket injected">[</span><span class="numeric_literal injected">1</span><span class="comma injected">,</span><span class="none injected"> </span><span class="numeric_literal injected">2</span><span class="comma injected">,</span><span class="none injected"> </span><span class="numeric_literal injected">3</span><span class="bracket injected">]</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span><span class="comment documentation"> | ||
136 | ``` | ||
137 | */</span> | ||
138 | <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration">block_comments</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> | ||
139 | |||
140 | <span class="comment documentation">/** | ||
141 | Really, I don't get it | ||
142 | ```rust | ||
143 | </span><span class="comment documentation"> </span><span class="none injected"> </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="punctuation injected">_</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="function injected">example</span><span class="parenthesis injected">(</span><span class="operator injected">&</span><span class="bracket injected">[</span><span class="numeric_literal injected">1</span><span class="comma injected">,</span><span class="none injected"> </span><span class="numeric_literal injected">2</span><span class="comma injected">,</span><span class="none injected"> </span><span class="numeric_literal injected">3</span><span class="bracket injected">]</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span><span class="comment documentation"> | ||
144 | ``` | ||
145 | */</span> | ||
146 | <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration">block_comments2</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span></code></pre> \ No newline at end of file | ||
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html b/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html index 6f7a7ffff..4e312765c 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html | |||
@@ -7,6 +7,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
7 | .label { color: #DFAF8F; font-style: italic; } | 7 | .label { color: #DFAF8F; font-style: italic; } |
8 | .comment { color: #7F9F7F; } | 8 | .comment { color: #7F9F7F; } |
9 | .documentation { color: #629755; } | 9 | .documentation { color: #629755; } |
10 | .intra_doc_link { color: #A9C577; } | ||
10 | .injected { opacity: 0.65 ; } | 11 | .injected { opacity: 0.65 ; } |
11 | .struct, .enum { color: #7CB8BB; } | 12 | .struct, .enum { color: #7CB8BB; } |
12 | .enum_variant { color: #BDE0F3; } | 13 | .enum_variant { color: #BDE0F3; } |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html index 753b535b5..57dfe7509 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html | |||
@@ -7,6 +7,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
7 | .label { color: #DFAF8F; font-style: italic; } | 7 | .label { color: #DFAF8F; font-style: italic; } |
8 | .comment { color: #7F9F7F; } | 8 | .comment { color: #7F9F7F; } |
9 | .documentation { color: #629755; } | 9 | .documentation { color: #629755; } |
10 | .intra_doc_link { color: #A9C577; } | ||
10 | .injected { opacity: 0.65 ; } | 11 | .injected { opacity: 0.65 ; } |
11 | .struct, .enum { color: #7CB8BB; } | 12 | .struct, .enum { color: #7CB8BB; } |
12 | .enum_variant { color: #BDE0F3; } | 13 | .enum_variant { color: #BDE0F3; } |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html index 66d80c4b6..75dbd0f14 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html | |||
@@ -7,6 +7,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
7 | .label { color: #DFAF8F; font-style: italic; } | 7 | .label { color: #DFAF8F; font-style: italic; } |
8 | .comment { color: #7F9F7F; } | 8 | .comment { color: #7F9F7F; } |
9 | .documentation { color: #629755; } | 9 | .documentation { color: #629755; } |
10 | .intra_doc_link { color: #A9C577; } | ||
10 | .injected { opacity: 0.65 ; } | 11 | .injected { opacity: 0.65 ; } |
11 | .struct, .enum { color: #7CB8BB; } | 12 | .struct, .enum { color: #7CB8BB; } |
12 | .enum_variant { color: #BDE0F3; } | 13 | .enum_variant { color: #BDE0F3; } |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html index 036cb6c11..423256a20 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html | |||
@@ -7,6 +7,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
7 | .label { color: #DFAF8F; font-style: italic; } | 7 | .label { color: #DFAF8F; font-style: italic; } |
8 | .comment { color: #7F9F7F; } | 8 | .comment { color: #7F9F7F; } |
9 | .documentation { color: #629755; } | 9 | .documentation { color: #629755; } |
10 | .intra_doc_link { color: #A9C577; } | ||
10 | .injected { opacity: 0.65 ; } | 11 | .injected { opacity: 0.65 ; } |
11 | .struct, .enum { color: #7CB8BB; } | 12 | .struct, .enum { color: #7CB8BB; } |
12 | .enum_variant { color: #BDE0F3; } | 13 | .enum_variant { color: #BDE0F3; } |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlighting.html b/crates/ide/src/syntax_highlighting/test_data/highlighting.html index 2f983c0b8..fffe8c0f5 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlighting.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlighting.html | |||
@@ -7,6 +7,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
7 | .label { color: #DFAF8F; font-style: italic; } | 7 | .label { color: #DFAF8F; font-style: italic; } |
8 | .comment { color: #7F9F7F; } | 8 | .comment { color: #7F9F7F; } |
9 | .documentation { color: #629755; } | 9 | .documentation { color: #629755; } |
10 | .intra_doc_link { color: #A9C577; } | ||
10 | .injected { opacity: 0.65 ; } | 11 | .injected { opacity: 0.65 ; } |
11 | .struct, .enum { color: #7CB8BB; } | 12 | .struct, .enum { color: #7CB8BB; } |
12 | .enum_variant { color: #BDE0F3; } | 13 | .enum_variant { color: #BDE0F3; } |
diff --git a/crates/ide/src/syntax_highlighting/test_data/injection.html b/crates/ide/src/syntax_highlighting/test_data/injection.html index 78dfec951..34d8deb68 100644 --- a/crates/ide/src/syntax_highlighting/test_data/injection.html +++ b/crates/ide/src/syntax_highlighting/test_data/injection.html | |||
@@ -7,6 +7,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
7 | .label { color: #DFAF8F; font-style: italic; } | 7 | .label { color: #DFAF8F; font-style: italic; } |
8 | .comment { color: #7F9F7F; } | 8 | .comment { color: #7F9F7F; } |
9 | .documentation { color: #629755; } | 9 | .documentation { color: #629755; } |
10 | .intra_doc_link { color: #A9C577; } | ||
10 | .injected { opacity: 0.65 ; } | 11 | .injected { opacity: 0.65 ; } |
11 | .struct, .enum { color: #7CB8BB; } | 12 | .struct, .enum { color: #7CB8BB; } |
12 | .enum_variant { color: #BDE0F3; } | 13 | .enum_variant { color: #BDE0F3; } |
diff --git a/crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html b/crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html index e64f2e5e9..d9ca3a4c4 100644 --- a/crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html +++ b/crates/ide/src/syntax_highlighting/test_data/rainbow_highlighting.html | |||
@@ -7,6 +7,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
7 | .label { color: #DFAF8F; font-style: italic; } | 7 | .label { color: #DFAF8F; font-style: italic; } |
8 | .comment { color: #7F9F7F; } | 8 | .comment { color: #7F9F7F; } |
9 | .documentation { color: #629755; } | 9 | .documentation { color: #629755; } |
10 | .intra_doc_link { color: #A9C577; } | ||
10 | .injected { opacity: 0.65 ; } | 11 | .injected { opacity: 0.65 ; } |
11 | .struct, .enum { color: #7CB8BB; } | 12 | .struct, .enum { color: #7CB8BB; } |
12 | .enum_variant { color: #BDE0F3; } | 13 | .enum_variant { color: #BDE0F3; } |
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs index 9d0cd1af5..7b2922b0d 100644 --- a/crates/ide/src/syntax_highlighting/tests.rs +++ b/crates/ide/src/syntax_highlighting/tests.rs | |||
@@ -468,7 +468,7 @@ fn main() { | |||
468 | } | 468 | } |
469 | 469 | ||
470 | #[test] | 470 | #[test] |
471 | fn test_highlight_doctest() { | 471 | fn test_highlight_doc_comment() { |
472 | check_highlighting( | 472 | check_highlighting( |
473 | r#" | 473 | r#" |
474 | /// ``` | 474 | /// ``` |
@@ -516,7 +516,7 @@ impl Foo { | |||
516 | /// comment */ | 516 | /// comment */ |
517 | /// | 517 | /// |
518 | /// let multi_line_string = "Foo | 518 | /// let multi_line_string = "Foo |
519 | /// bar | 519 | /// bar\n |
520 | /// "; | 520 | /// "; |
521 | /// | 521 | /// |
522 | /// ``` | 522 | /// ``` |
@@ -533,6 +533,11 @@ impl Foo { | |||
533 | } | 533 | } |
534 | } | 534 | } |
535 | 535 | ||
536 | /// [`Foo`](Foo) is a struct | ||
537 | /// [`all_the_links`](all_the_links) is this function | ||
538 | /// [`noop`](noop) is a macro below | ||
539 | pub fn all_the_links() {} | ||
540 | |||
536 | /// ``` | 541 | /// ``` |
537 | /// noop!(1); | 542 | /// noop!(1); |
538 | /// ``` | 543 | /// ``` |
@@ -541,6 +546,38 @@ macro_rules! noop { | |||
541 | $expr | 546 | $expr |
542 | } | 547 | } |
543 | } | 548 | } |
549 | |||
550 | /// ```rust | ||
551 | /// let _ = example(&[1, 2, 3]); | ||
552 | /// ``` | ||
553 | /// | ||
554 | /// ``` | ||
555 | /// loop {} | ||
556 | #[cfg_attr(not(feature = "false"), doc = "loop {}")] | ||
557 | #[doc = "loop {}"] | ||
558 | /// ``` | ||
559 | /// | ||
560 | #[cfg_attr(feature = "alloc", doc = "```rust")] | ||
561 | #[cfg_attr(not(feature = "alloc"), doc = "```ignore")] | ||
562 | /// let _ = example(&alloc::vec![1, 2, 3]); | ||
563 | /// ``` | ||
564 | pub fn mix_and_match() {} | ||
565 | |||
566 | /** | ||
567 | It is beyond me why you'd use these when you got /// | ||
568 | ```rust | ||
569 | let _ = example(&[1, 2, 3]); | ||
570 | ``` | ||
571 | */ | ||
572 | pub fn block_comments() {} | ||
573 | |||
574 | /** | ||
575 | Really, I don't get it | ||
576 | ```rust | ||
577 | let _ = example(&[1, 2, 3]); | ||
578 | ``` | ||
579 | */ | ||
580 | pub fn block_comments2() {} | ||
544 | "# | 581 | "# |
545 | .trim(), | 582 | .trim(), |
546 | expect_file!["./test_data/highlight_doctest.html"], | 583 | expect_file!["./test_data/highlight_doctest.html"], |