aboutsummaryrefslogtreecommitdiff
path: root/crates/ide
diff options
context:
space:
mode:
authorLukas Wirth <[email protected]>2021-03-16 20:05:07 +0000
committerLukas Wirth <[email protected]>2021-03-16 20:15:26 +0000
commitc766492d2625dba65c3bd933841c71938f6dc747 (patch)
tree79fc22c7f6018bafa8856fa52494646ebf9781d3 /crates/ide
parent3daa302cd39c779cae0b096972f2fdc3e67e214c (diff)
Properly handle doc attributes in doc-comment highlight injection
Diffstat (limited to 'crates/ide')
-rw-r--r--crates/ide/src/syntax_highlighting/inject.rs48
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html18
-rw-r--r--crates/ide/src/syntax_highlighting/tests.rs16
3 files changed, 76 insertions, 6 deletions
diff --git a/crates/ide/src/syntax_highlighting/inject.rs b/crates/ide/src/syntax_highlighting/inject.rs
index 086db40e5..0f1de4fb8 100644
--- a/crates/ide/src/syntax_highlighting/inject.rs
+++ b/crates/ide/src/syntax_highlighting/inject.rs
@@ -5,7 +5,7 @@ use hir::{HasAttrs, Semantics};
5use ide_db::call_info::ActiveParameter; 5use ide_db::call_info::ActiveParameter;
6use syntax::{ 6use syntax::{
7 ast::{self, AstNode, AttrsOwner, DocCommentsOwner}, 7 ast::{self, AstNode, AttrsOwner, DocCommentsOwner},
8 match_ast, AstToken, SyntaxNode, SyntaxToken, TextRange, TextSize, 8 match_ast, AstToken, NodeOrToken, SyntaxNode, SyntaxToken, TextRange, TextSize,
9}; 9};
10 10
11use crate::{Analysis, HlMod, HlRange, HlTag, RootDatabase}; 11use crate::{Analysis, HlMod, HlRange, HlTag, RootDatabase};
@@ -153,7 +153,6 @@ pub(super) fn doc_comment(hl: &mut Highlights, sema: &Semantics<RootDatabase>, n
153 if attributes.docs().map_or(true, |docs| !String::from(docs).contains(RUSTDOC_FENCE)) { 153 if attributes.docs().map_or(true, |docs| !String::from(docs).contains(RUSTDOC_FENCE)) {
154 return; 154 return;
155 } 155 }
156 let doc_comments = attributes.by_key("doc").attrs().map(|attr| attr.to_src(&owner));
157 156
158 let mut inj = Injector::default(); 157 let mut inj = Injector::default();
159 inj.add_unmapped("fn doctest() {\n"); 158 inj.add_unmapped("fn doctest() {\n");
@@ -164,13 +163,28 @@ pub(super) fn doc_comment(hl: &mut Highlights, sema: &Semantics<RootDatabase>, n
164 // Replace the original, line-spanning comment ranges by new, only comment-prefix 163 // Replace the original, line-spanning comment ranges by new, only comment-prefix
165 // spanning comment ranges. 164 // spanning comment ranges.
166 let mut new_comments = Vec::new(); 165 let mut new_comments = Vec::new();
167 for comment in doc_comments { 166 let mut string;
168 let (line, range, prefix) = match &comment { 167 for attr in attributes.by_key("doc").attrs() {
169 Either::Left(_) => continue, // FIXME 168 let src = attr.to_src(&owner);
169 let (line, range, prefix) = match &src {
170 Either::Left(it) => {
171 string = match find_doc_string_in_attr(attr, it) {
172 Some(it) => it,
173 None => continue,
174 };
175 let text_range = string.syntax().text_range();
176 let text_range = TextRange::new(
177 text_range.start() + TextSize::from(1),
178 text_range.end() - TextSize::from(1),
179 );
180 let text = string.text();
181 (&text[1..text.len() - 1], text_range, "")
182 }
170 Either::Right(comment) => { 183 Either::Right(comment) => {
171 (comment.text(), comment.syntax().text_range(), comment.prefix()) 184 (comment.text(), comment.syntax().text_range(), comment.prefix())
172 } 185 }
173 }; 186 };
187
174 match line.find(RUSTDOC_FENCE) { 188 match line.find(RUSTDOC_FENCE) {
175 Some(idx) => { 189 Some(idx) => {
176 is_codeblock = !is_codeblock; 190 is_codeblock = !is_codeblock;
@@ -222,3 +236,27 @@ pub(super) fn doc_comment(hl: &mut Highlights, sema: &Semantics<RootDatabase>, n
222 }); 236 });
223 } 237 }
224} 238}
239
240fn find_doc_string_in_attr(attr: &hir::Attr, it: &ast::Attr) -> Option<ast::String> {
241 match it.literal() {
242 // #[doc = lit]
243 Some(lit) => match lit.kind() {
244 ast::LiteralKind::String(it) => Some(it),
245 _ => None,
246 },
247 // #[cfg_attr(..., doc = "", ...)]
248 None => {
249 // We gotta hunt the string token manually here
250 let text = attr.string_value()?;
251 // FIXME: We just pick the first string literal that has the same text as the doc attribute
252 // This means technically we might highlight the wrong one
253 it.syntax()
254 .descendants_with_tokens()
255 .filter_map(NodeOrToken::into_token)
256 .filter_map(ast::String::cast)
257 .find(|string| {
258 string.text().get(1..string.text().len() - 1).map_or(false, |it| it == text)
259 })
260 }
261 }
262}
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..45817faf9 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
@@ -105,4 +105,20 @@ 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">&gt;</span> <span class="brace">{</span> 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">&gt;</span> <span class="brace">{</span>
106 <span class="punctuation">$</span>expr 106 <span class="punctuation">$</span>expr
107 <span class="brace">}</span> 107 <span class="brace">}</span>
108<span class="brace">}</span></code></pre> \ No newline at end of file 108<span class="brace">}</span>
109
110<span class="comment documentation">/// ```rust</span>
111<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>
112<span class="comment documentation">/// ```</span>
113<span class="comment documentation">///</span>
114<span class="comment documentation">/// ```</span>
115<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>
116<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>
117<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>
118<span class="comment documentation">/// ```</span>
119<span class="comment documentation">///</span>
120<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>
121<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>
122<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>
123<span class="comment documentation">/// ```</span>
124<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></code></pre> \ No newline at end of file
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs
index 9d0cd1af5..a5ef2d29b 100644
--- a/crates/ide/src/syntax_highlighting/tests.rs
+++ b/crates/ide/src/syntax_highlighting/tests.rs
@@ -541,6 +541,22 @@ macro_rules! noop {
541 $expr 541 $expr
542 } 542 }
543} 543}
544
545/// ```rust
546/// let _ = example(&[1, 2, 3]);
547/// ```
548///
549/// ```
550/// loop {}
551#[cfg_attr(not(feature = "false"), doc = "loop {}")]
552#[doc = "loop {}"]
553/// ```
554///
555#[cfg_attr(feature = "alloc", doc = "```rust")]
556#[cfg_attr(not(feature = "alloc"), doc = "```ignore")]
557/// let _ = example(&alloc::vec![1, 2, 3]);
558/// ```
559pub fn mix_and_match() {}
544"# 560"#
545 .trim(), 561 .trim(),
546 expect_file!["./test_data/highlight_doctest.html"], 562 expect_file!["./test_data/highlight_doctest.html"],