Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide/src/syntax_highlighting/inject.rs')
| -rw-r--r-- | crates/ide/src/syntax_highlighting/inject.rs | 77 |
1 files changed, 41 insertions, 36 deletions
diff --git a/crates/ide/src/syntax_highlighting/inject.rs b/crates/ide/src/syntax_highlighting/inject.rs index ec1df6d1de..774934a249 100644 --- a/crates/ide/src/syntax_highlighting/inject.rs +++ b/crates/ide/src/syntax_highlighting/inject.rs @@ -9,7 +9,7 @@ use ide_db::{ SymbolKind, }; use syntax::{ - ast::{self, AstNode, IsString}, + ast::{self, AstNode, IsString, QuoteOffsets}, AstToken, NodeOrToken, SyntaxNode, TextRange, TextSize, }; @@ -61,7 +61,7 @@ pub(super) fn ra_fixture( } } - let (analysis, tmp_file_id) = Analysis::from_single_file(inj.text().to_string()); + let (analysis, tmp_file_id) = Analysis::from_single_file(inj.take_text()); for mut hl_range in analysis.highlight(tmp_file_id).unwrap() { for range in inj.map_range_up(hl_range.range) { @@ -85,31 +85,19 @@ const RUSTDOC_FENCE: &'static str = "```"; pub(super) fn doc_comment( hl: &mut Highlights, sema: &Semantics<RootDatabase>, - node: InFile<&SyntaxNode>, + InFile { file_id: src_file_id, value: node }: InFile<&SyntaxNode>, ) { - let (attributes, def) = match doc_attributes(sema, node.value) { + let (attributes, def) = match doc_attributes(sema, node) { Some(it) => it, None => return, }; - let mut inj = Injector::default(); - inj.add_unmapped("fn doctest() {\n"); - - let attrs_source_map = attributes.source_map(sema.db); - - let mut is_codeblock = false; - let mut is_doctest = false; - - // Replace the original, line-spanning comment ranges by new, only comment-prefix - // spanning comment ranges. - let mut new_comments = Vec::new(); - let mut string; - + // Extract intra-doc links and emit highlights for them. if let Some((docs, doc_mapping)) = attributes.docs_with_rangemap(sema.db) { extract_definitions_from_docs(&docs) .into_iter() .filter_map(|(range, link, ns)| { - doc_mapping.map(range).filter(|mapping| mapping.file_id == node.file_id).and_then( + doc_mapping.map(range).filter(|mapping| mapping.file_id == src_file_id).and_then( |InFile { value: mapped_range, .. }| { Some(mapped_range).zip(resolve_doc_path_for_def(sema.db, def, &link, ns)) }, @@ -127,31 +115,49 @@ pub(super) fn doc_comment( }); } + // Extract doc-test sources from the docs and calculate highlighting for them. + + let mut inj = Injector::default(); + inj.add_unmapped("fn doctest() {\n"); + + let attrs_source_map = attributes.source_map(sema.db); + + let mut is_codeblock = false; + let mut is_doctest = false; + + let mut new_comments = Vec::new(); + let mut string; + for attr in attributes.by_key("doc").attrs() { let InFile { file_id, value: src } = attrs_source_map.source_of(attr); - if file_id != node.file_id { + if file_id != src_file_id { continue; } - let (line, range, prefix) = match &src { + let (line, range) = match &src { Either::Left(it) => { string = match find_doc_string_in_attr(attr, it) { Some(it) => it, None => continue, }; - let text_range = string.syntax().text_range(); - let text_range = TextRange::new( - text_range.start() + TextSize::from(1), - text_range.end() - TextSize::from(1), - ); let text = string.text(); - (&text[1..text.len() - 1], text_range, "") + let text_range = string.syntax().text_range(); + match string.quote_offsets() { + Some(QuoteOffsets { contents, .. }) => { + (&text[contents - text_range.start()], contents) + } + None => (text, text_range), + } } Either::Right(comment) => { - (comment.text(), comment.syntax().text_range(), comment.prefix()) + let value = comment.prefix().len(); + let range = comment.syntax().text_range(); + ( + &comment.text()[value..], + TextRange::new(range.start() + TextSize::try_from(value).unwrap(), range.end()), + ) } }; - let mut pos = TextSize::from(prefix.len() as u32); let mut range_start = range.start(); for line in line.split('\n') { let line_len = TextSize::from(line.len() as u32); @@ -159,8 +165,7 @@ pub(super) fn doc_comment( let next_range_start = range_start + line_len + TextSize::from(1); mem::replace(&mut range_start, next_range_start) }; - // only first line has the prefix so take it away for future iterations - let mut pos = mem::take(&mut pos); + let mut pos = TextSize::from(0); match line.find(RUSTDOC_FENCE) { Some(idx) => { @@ -196,13 +201,13 @@ pub(super) fn doc_comment( inj.add_unmapped("\n}"); - let (analysis, tmp_file_id) = Analysis::from_single_file(inj.text().to_string()); + let (analysis, tmp_file_id) = Analysis::from_single_file(inj.take_text()); - for HlRange { range, highlight, binding_hash } in - analysis.with_db(|db| super::highlight(db, tmp_file_id, None, true)).unwrap() - { - for range in inj.map_range_up(range) { - hl.add(HlRange { range, highlight: highlight | HlMod::Injected, binding_hash }); + if let Ok(ranges) = analysis.with_db(|db| super::highlight(db, tmp_file_id, None, true)) { + for HlRange { range, highlight, binding_hash } in ranges { + for range in inj.map_range_up(range) { + hl.add(HlRange { range, highlight: highlight | HlMod::Injected, binding_hash }); + } } } |