diff options
author | Lukas Wirth <[email protected]> | 2021-03-17 19:57:30 +0000 |
---|---|---|
committer | Lukas Wirth <[email protected]> | 2021-03-17 20:00:01 +0000 |
commit | 9763f0a6bd0d576236ff126173d7df3462c22a52 (patch) | |
tree | 6bb31b0325e8a7b9bef577901575a048344e8eb5 /crates | |
parent | ec10835d604c534a0b0ad5fd3d8783e0bf123cbb (diff) |
Semantic highlight intradoclinks in documentation
Diffstat (limited to 'crates')
16 files changed, 132 insertions, 55 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/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 7a4f2645f..947cc974c 100644 --- a/crates/ide/src/syntax_highlighting/inject.rs +++ b/crates/ide/src/syntax_highlighting/inject.rs | |||
@@ -1,16 +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 std::mem; | 3 | use std::{mem, ops::Range}; |
4 | 4 | ||
5 | use either::Either; | 5 | use either::Either; |
6 | use hir::{HasAttrs, Semantics}; | 6 | use hir::{HasAttrs, Semantics}; |
7 | use ide_db::call_info::ActiveParameter; | 7 | use ide_db::{call_info::ActiveParameter, defs::Definition}; |
8 | use syntax::{ | 8 | use syntax::{ |
9 | ast::{self, AstNode, AttrsOwner, DocCommentsOwner}, | 9 | ast::{self, AstNode, AttrsOwner, DocCommentsOwner}, |
10 | match_ast, AstToken, NodeOrToken, SyntaxNode, SyntaxToken, TextRange, TextSize, | 10 | match_ast, AstToken, NodeOrToken, SyntaxNode, SyntaxToken, TextRange, TextSize, |
11 | }; | 11 | }; |
12 | 12 | ||
13 | use crate::{Analysis, HlMod, HlRange, HlTag, RootDatabase}; | 13 | use crate::{ |
14 | doc_links::extract_definitions_from_markdown, Analysis, HlMod, HlRange, HlTag, RootDatabase, | ||
15 | }; | ||
14 | 16 | ||
15 | use super::{highlights::Highlights, injector::Injector}; | 17 | use super::{highlights::Highlights, injector::Injector}; |
16 | 18 | ||
@@ -120,24 +122,24 @@ impl AstNode for AttrsOwnerNode { | |||
120 | fn doc_attributes<'node>( | 122 | fn doc_attributes<'node>( |
121 | sema: &Semantics<RootDatabase>, | 123 | sema: &Semantics<RootDatabase>, |
122 | node: &'node SyntaxNode, | 124 | node: &'node SyntaxNode, |
123 | ) -> Option<(AttrsOwnerNode, hir::Attrs)> { | 125 | ) -> Option<(AttrsOwnerNode, hir::Attrs, Definition)> { |
124 | match_ast! { | 126 | match_ast! { |
125 | match node { | 127 | match node { |
126 | ast::SourceFile(it) => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db))), | 128 | ast::SourceFile(it) => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Module(def)))), |
127 | ast::Fn(it) => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db))), | 129 | ast::Module(it) => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Module(def)))), |
128 | ast::Struct(it) => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db))), | 130 | ast::Fn(it) => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Function(def)))), |
129 | ast::Union(it) => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db))), | 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))))), |
130 | ast::RecordField(it) => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db))), | 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))))), |
131 | ast::TupleField(it) => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db))), | 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))))), |
132 | ast::Enum(it) => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db))), | 134 | ast::Variant(it) => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Variant(def)))), |
133 | ast::Variant(it) => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db))), | 135 | ast::Trait(it) => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Trait(def)))), |
134 | ast::Trait(it) => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db))), | 136 | ast::Static(it) => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Static(def)))), |
135 | ast::Module(it) => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db))), | 137 | ast::Const(it) => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Const(def)))), |
136 | ast::Static(it) => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db))), | 138 | ast::TypeAlias(it) => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::TypeAlias(def)))), |
137 | ast::Const(it) => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db))), | 139 | ast::Impl(it) => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db), Definition::SelfType(def))), |
138 | ast::TypeAlias(it) => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db))), | 140 | ast::RecordField(it) => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db), Definition::Field(def))), |
139 | ast::Impl(it) => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db))), | 141 | ast::TupleField(it) => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db), Definition::Field(def))), |
140 | ast::MacroRules(it) => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db))), | 142 | ast::MacroRules(it) => sema.to_def(&it).map(|def| (AttrsOwnerNode::new(it), def.attrs(sema.db), Definition::Macro(def))), |
141 | // ast::MacroDef(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))), | 143 | // ast::MacroDef(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))), |
142 | // ast::Use(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))), |
143 | _ => return None | 145 | _ => return None |
@@ -147,25 +149,23 @@ fn doc_attributes<'node>( | |||
147 | 149 | ||
148 | /// Injection of syntax highlighting of doctests. | 150 | /// Injection of syntax highlighting of doctests. |
149 | pub(super) fn doc_comment(hl: &mut Highlights, sema: &Semantics<RootDatabase>, node: &SyntaxNode) { | 151 | pub(super) fn doc_comment(hl: &mut Highlights, sema: &Semantics<RootDatabase>, node: &SyntaxNode) { |
150 | let (owner, attributes) = match doc_attributes(sema, node) { | 152 | let (owner, attributes, def) = match doc_attributes(sema, node) { |
151 | Some(it) => it, | 153 | Some(it) => it, |
152 | None => return, | 154 | None => return, |
153 | }; | 155 | }; |
154 | 156 | ||
155 | if attributes.docs().map_or(true, |docs| !String::from(docs).contains(RUSTDOC_FENCE)) { | ||
156 | return; | ||
157 | } | ||
158 | let attrs_source_map = attributes.source_map(&owner); | ||
159 | |||
160 | let mut inj = Injector::default(); | 157 | let mut inj = Injector::default(); |
161 | inj.add_unmapped("fn doctest() {\n"); | 158 | inj.add_unmapped("fn doctest() {\n"); |
162 | 159 | ||
160 | let attrs_source_map = attributes.source_map(&owner); | ||
161 | |||
163 | let mut is_codeblock = false; | 162 | let mut is_codeblock = false; |
164 | let mut is_doctest = false; | 163 | let mut is_doctest = false; |
165 | 164 | ||
166 | // 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 |
167 | // spanning comment ranges. | 166 | // spanning comment ranges. |
168 | let mut new_comments = Vec::new(); | 167 | let mut new_comments = Vec::new(); |
168 | let mut intra_doc_links = Vec::new(); | ||
169 | let mut string; | 169 | let mut string; |
170 | for attr in attributes.by_key("doc").attrs() { | 170 | for attr in attributes.by_key("doc").attrs() { |
171 | let src = attrs_source_map.source_of(&attr); | 171 | let src = attrs_source_map.source_of(&attr); |
@@ -209,7 +209,22 @@ pub(super) fn doc_comment(hl: &mut Highlights, sema: &Semantics<RootDatabase>, n | |||
209 | is_doctest = is_codeblock && is_rust; | 209 | is_doctest = is_codeblock && is_rust; |
210 | continue; | 210 | continue; |
211 | } | 211 | } |
212 | None if !is_doctest => continue, | 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 | } | ||
213 | None => (), | 228 | None => (), |
214 | } | 229 | } |
215 | 230 | ||
@@ -227,17 +242,28 @@ pub(super) fn doc_comment(hl: &mut Highlights, sema: &Semantics<RootDatabase>, n | |||
227 | inj.add_unmapped("\n"); | 242 | inj.add_unmapped("\n"); |
228 | } | 243 | } |
229 | } | 244 | } |
245 | |||
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 | } | ||
253 | |||
254 | if new_comments.is_empty() { | ||
255 | return; // no need to run an analysis on an empty file | ||
256 | } | ||
257 | |||
230 | inj.add_unmapped("\n}"); | 258 | inj.add_unmapped("\n}"); |
231 | 259 | ||
232 | 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()); |
233 | 261 | ||
234 | for h in analysis.with_db(|db| super::highlight(db, tmp_file_id, None, true)).unwrap() { | 262 | for HlRange { range, highlight, binding_hash } in |
235 | for r in inj.map_range_up(h.range) { | 263 | analysis.with_db(|db| super::highlight(db, tmp_file_id, None, true)).unwrap() |
236 | hl.add(HlRange { | 264 | { |
237 | range: r, | 265 | for range in inj.map_range_up(range) { |
238 | highlight: h.highlight | HlMod::Injected, | 266 | hl.add(HlRange { range, highlight: highlight | HlMod::Injected, binding_hash }); |
239 | binding_hash: h.binding_hash, | ||
240 | }); | ||
241 | } | 267 | } |
242 | } | 268 | } |
243 | 269 | ||
@@ -273,3 +299,31 @@ fn find_doc_string_in_attr(attr: &hir::Attr, it: &ast::Attr) -> Option<ast::Stri | |||
273 | } | 299 | } |
274 | } | 300 | } |
275 | } | 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 d792a23cf..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; } |
@@ -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> |
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 cf0b86ad0..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 | /// ``` |
@@ -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 | /// ``` |
diff --git a/crates/rust-analyzer/src/semantic_tokens.rs b/crates/rust-analyzer/src/semantic_tokens.rs index be0bea00b..0cb7d12a7 100644 --- a/crates/rust-analyzer/src/semantic_tokens.rs +++ b/crates/rust-analyzer/src/semantic_tokens.rs | |||
@@ -45,15 +45,16 @@ define_semantic_token_types![ | |||
45 | (BRACKET, "bracket"), | 45 | (BRACKET, "bracket"), |
46 | (BUILTIN_TYPE, "builtinType"), | 46 | (BUILTIN_TYPE, "builtinType"), |
47 | (CHAR_LITERAL, "characterLiteral"), | 47 | (CHAR_LITERAL, "characterLiteral"), |
48 | (COMMA, "comma"), | ||
49 | (COLON, "colon"), | 48 | (COLON, "colon"), |
49 | (COMMA, "comma"), | ||
50 | (CONST_PARAMETER, "constParameter"), | ||
50 | (DOT, "dot"), | 51 | (DOT, "dot"), |
51 | (ESCAPE_SEQUENCE, "escapeSequence"), | 52 | (ESCAPE_SEQUENCE, "escapeSequence"), |
52 | (FORMAT_SPECIFIER, "formatSpecifier"), | 53 | (FORMAT_SPECIFIER, "formatSpecifier"), |
53 | (GENERIC, "generic"), | 54 | (GENERIC, "generic"), |
54 | (CONST_PARAMETER, "constParameter"), | 55 | (INTRA_DOC_LINK, "intraDocLink"), |
55 | (LIFETIME, "lifetime"), | ||
56 | (LABEL, "label"), | 56 | (LABEL, "label"), |
57 | (LIFETIME, "lifetime"), | ||
57 | (PARENTHESIS, "parenthesis"), | 58 | (PARENTHESIS, "parenthesis"), |
58 | (PUNCTUATION, "punctuation"), | 59 | (PUNCTUATION, "punctuation"), |
59 | (SELF_KEYWORD, "selfKeyword"), | 60 | (SELF_KEYWORD, "selfKeyword"), |
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index c63fe2915..70501618e 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs | |||
@@ -435,19 +435,20 @@ fn semantic_token_type_and_modifiers( | |||
435 | SymbolKind::Trait => lsp_types::SemanticTokenType::INTERFACE, | 435 | SymbolKind::Trait => lsp_types::SemanticTokenType::INTERFACE, |
436 | SymbolKind::Macro => lsp_types::SemanticTokenType::MACRO, | 436 | SymbolKind::Macro => lsp_types::SemanticTokenType::MACRO, |
437 | }, | 437 | }, |
438 | HlTag::Attribute => semantic_tokens::ATTRIBUTE, | ||
439 | HlTag::BoolLiteral => semantic_tokens::BOOLEAN, | ||
438 | HlTag::BuiltinType => semantic_tokens::BUILTIN_TYPE, | 440 | HlTag::BuiltinType => semantic_tokens::BUILTIN_TYPE, |
439 | HlTag::None => semantic_tokens::GENERIC, | ||
440 | HlTag::ByteLiteral | HlTag::NumericLiteral => lsp_types::SemanticTokenType::NUMBER, | 441 | HlTag::ByteLiteral | HlTag::NumericLiteral => lsp_types::SemanticTokenType::NUMBER, |
441 | HlTag::BoolLiteral => semantic_tokens::BOOLEAN, | ||
442 | HlTag::StringLiteral => lsp_types::SemanticTokenType::STRING, | ||
443 | HlTag::CharLiteral => semantic_tokens::CHAR_LITERAL, | 442 | HlTag::CharLiteral => semantic_tokens::CHAR_LITERAL, |
444 | HlTag::Comment => lsp_types::SemanticTokenType::COMMENT, | 443 | HlTag::Comment => lsp_types::SemanticTokenType::COMMENT, |
445 | HlTag::Attribute => semantic_tokens::ATTRIBUTE, | 444 | HlTag::EscapeSequence => semantic_tokens::ESCAPE_SEQUENCE, |
446 | HlTag::Keyword => lsp_types::SemanticTokenType::KEYWORD, | ||
447 | HlTag::UnresolvedReference => semantic_tokens::UNRESOLVED_REFERENCE, | ||
448 | HlTag::FormatSpecifier => semantic_tokens::FORMAT_SPECIFIER, | 445 | HlTag::FormatSpecifier => semantic_tokens::FORMAT_SPECIFIER, |
446 | HlTag::IntraDocLink => semantic_tokens::INTRA_DOC_LINK, | ||
447 | HlTag::Keyword => lsp_types::SemanticTokenType::KEYWORD, | ||
448 | HlTag::None => semantic_tokens::GENERIC, | ||
449 | HlTag::Operator => lsp_types::SemanticTokenType::OPERATOR, | 449 | HlTag::Operator => lsp_types::SemanticTokenType::OPERATOR, |
450 | HlTag::EscapeSequence => semantic_tokens::ESCAPE_SEQUENCE, | 450 | HlTag::StringLiteral => lsp_types::SemanticTokenType::STRING, |
451 | HlTag::UnresolvedReference => semantic_tokens::UNRESOLVED_REFERENCE, | ||
451 | HlTag::Punctuation(punct) => match punct { | 452 | HlTag::Punctuation(punct) => match punct { |
452 | HlPunct::Bracket => semantic_tokens::BRACKET, | 453 | HlPunct::Bracket => semantic_tokens::BRACKET, |
453 | HlPunct::Brace => semantic_tokens::BRACE, | 454 | HlPunct::Brace => semantic_tokens::BRACE, |