|
1 | 1 | //! "Recursive" Syntax highlighting for code in doctests and fixtures.
|
2 | 2 |
|
| 3 | +use std::mem; |
| 4 | + |
3 | 5 | use either::Either;
|
4 | 6 | use hir::{HasAttrs, Semantics};
|
5 | 7 | use ide_db::call_info::ActiveParameter;
|
@@ -186,34 +188,44 @@ pub(super) fn doc_comment(hl: &mut Highlights, sema: &Semantics<RootDatabase>, n
|
186 | 188 | }
|
187 | 189 | };
|
188 | 190 |
|
189 |
| - match line.find(RUSTDOC_FENCE) { |
190 |
| - Some(idx) => { |
191 |
| - is_codeblock = !is_codeblock; |
192 |
| - // Check whether code is rust by inspecting fence guards |
193 |
| - let guards = &line[idx + RUSTDOC_FENCE.len()..]; |
194 |
| - let is_rust = |
195 |
| - guards.split(',').all(|sub| RUSTDOC_FENCE_TOKENS.contains(&sub.trim())); |
196 |
| - is_doctest = is_codeblock && is_rust; |
197 |
| - continue; |
| 191 | + let mut pos = TextSize::from(prefix.len() as u32); |
| 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); |
| 201 | + |
| 202 | + match line.find(RUSTDOC_FENCE) { |
| 203 | + Some(idx) => { |
| 204 | + is_codeblock = !is_codeblock; |
| 205 | + // Check whether code is rust by inspecting fence guards |
| 206 | + let guards = &line[idx + RUSTDOC_FENCE.len()..]; |
| 207 | + let is_rust = |
| 208 | + guards.split(',').all(|sub| RUSTDOC_FENCE_TOKENS.contains(&sub.trim())); |
| 209 | + is_doctest = is_codeblock && is_rust; |
| 210 | + continue; |
| 211 | + } |
| 212 | + None if !is_doctest => continue, |
| 213 | + None => (), |
198 | 214 | }
|
199 |
| - None if !is_doctest => continue, |
200 |
| - None => (), |
201 |
| - } |
202 |
| - |
203 |
| - let mut pos = TextSize::of(prefix); |
204 |
| - // whitespace after comment is ignored |
205 |
| - if let Some(ws) = line[pos.into()..].chars().next().filter(|c| c.is_whitespace()) { |
206 |
| - pos += TextSize::of(ws); |
207 |
| - } |
208 |
| - // lines marked with `#` should be ignored in output, we skip the `#` char |
209 |
| - if let Some(ws) = line[pos.into()..].chars().next().filter(|&c| c == '#') { |
210 |
| - pos += TextSize::of(ws); |
211 |
| - } |
212 | 215 |
|
213 |
| - new_comments.push(TextRange::at(range.start(), pos)); |
| 216 | + // whitespace after comment is ignored |
| 217 | + if let Some(ws) = line[pos.into()..].chars().next().filter(|c| c.is_whitespace()) { |
| 218 | + pos += TextSize::of(ws); |
| 219 | + } |
| 220 | + // lines marked with `#` should be ignored in output, we skip the `#` char |
| 221 | + if line[pos.into()..].starts_with('#') { |
| 222 | + pos += TextSize::of('#'); |
| 223 | + } |
214 | 224 |
|
215 |
| - inj.add(&line[pos.into()..], TextRange::new(range.start() + pos, range.end())); |
216 |
| - inj.add_unmapped("\n"); |
| 225 | + new_comments.push(TextRange::at(prev_range_start, pos)); |
| 226 | + inj.add(&line[pos.into()..], TextRange::new(pos, line_len) + prev_range_start); |
| 227 | + inj.add_unmapped("\n"); |
| 228 | + } |
217 | 229 | }
|
218 | 230 | inj.add_unmapped("\n}");
|
219 | 231 |
|
|
0 commit comments