diff options
-rw-r--r-- | crates/hir_def/src/attr.rs | 42 | ||||
-rw-r--r-- | crates/ide/src/doc_links.rs | 17 |
2 files changed, 27 insertions, 32 deletions
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs index 7791402c9..74bb6de35 100644 --- a/crates/hir_def/src/attr.rs +++ b/crates/hir_def/src/attr.rs | |||
@@ -1,8 +1,8 @@ | |||
1 | //! A higher level attributes based on TokenTree, with also some shortcuts. | 1 | //! A higher level attributes based on TokenTree, with also some shortcuts. |
2 | 2 | ||
3 | use std::{ | 3 | use std::{ |
4 | cmp::Ordering, | 4 | convert::{TryFrom, TryInto}, |
5 | ops::{self, Range}, | 5 | ops, |
6 | sync::Arc, | 6 | sync::Arc, |
7 | }; | 7 | }; |
8 | 8 | ||
@@ -479,6 +479,7 @@ impl AttrsWithOwner { | |||
479 | if !doc.is_empty() { | 479 | if !doc.is_empty() { |
480 | for line in doc.split('\n') { | 480 | for line in doc.split('\n') { |
481 | let line = line.trim_end(); | 481 | let line = line.trim_end(); |
482 | let line_len = line.len(); | ||
482 | let (offset, line) = match line.char_indices().nth(indent) { | 483 | let (offset, line) = match line.char_indices().nth(indent) { |
483 | Some((offset, _)) => (offset, &line[offset..]), | 484 | Some((offset, _)) => (offset, &line[offset..]), |
484 | None => (0, line), | 485 | None => (0, line), |
@@ -486,9 +487,9 @@ impl AttrsWithOwner { | |||
486 | let buf_offset = buf.len(); | 487 | let buf_offset = buf.len(); |
487 | buf.push_str(line); | 488 | buf.push_str(line); |
488 | mapping.push(( | 489 | mapping.push(( |
489 | Range { start: buf_offset, end: buf.len() }, | 490 | TextRange::new(buf_offset.try_into().ok()?, buf.len().try_into().ok()?), |
490 | idx, | 491 | idx, |
491 | Range { start: offset, end: line.len() }, | 492 | TextRange::new(offset.try_into().ok()?, line_len.try_into().ok()?), |
492 | )); | 493 | )); |
493 | buf.push('\n'); | 494 | buf.push('\n'); |
494 | } | 495 | } |
@@ -565,31 +566,18 @@ pub struct DocsRangeMap { | |||
565 | // (docstring-line-range, attr_index, attr-string-range) | 566 | // (docstring-line-range, attr_index, attr-string-range) |
566 | // a mapping from the text range of a line of the [`Documentation`] to the attribute index and | 567 | // a mapping from the text range of a line of the [`Documentation`] to the attribute index and |
567 | // the original (untrimmed) syntax doc line | 568 | // the original (untrimmed) syntax doc line |
568 | mapping: Vec<(Range<usize>, u32, Range<usize>)>, | 569 | mapping: Vec<(TextRange, u32, TextRange)>, |
569 | } | 570 | } |
570 | 571 | ||
571 | impl DocsRangeMap { | 572 | impl DocsRangeMap { |
572 | pub fn map(&self, range: Range<usize>) -> Option<InFile<TextRange>> { | 573 | pub fn map(&self, range: TextRange) -> Option<InFile<TextRange>> { |
573 | let found = self | 574 | let found = self.mapping.binary_search_by(|(probe, ..)| probe.ordering(range)).ok()?; |
574 | .mapping | ||
575 | .binary_search_by(|(probe, ..)| { | ||
576 | if probe.contains(&range.start) { | ||
577 | Ordering::Equal | ||
578 | } else { | ||
579 | probe.start.cmp(&range.end) | ||
580 | } | ||
581 | }) | ||
582 | .ok()?; | ||
583 | let (line_docs_range, idx, original_line_src_range) = self.mapping[found].clone(); | 575 | let (line_docs_range, idx, original_line_src_range) = self.mapping[found].clone(); |
584 | if range.end > line_docs_range.end { | 576 | if !line_docs_range.contains_range(range) { |
585 | return None; | 577 | return None; |
586 | } | 578 | } |
587 | 579 | ||
588 | let relative_range = Range { | 580 | let relative_range = range - line_docs_range.start(); |
589 | start: range.start - line_docs_range.start, | ||
590 | end: range.end - line_docs_range.start, | ||
591 | }; | ||
592 | let range_len = TextSize::from((range.end - range.start) as u32); | ||
593 | 581 | ||
594 | let &InFile { file_id, value: ref source } = &self.source[idx as usize]; | 582 | let &InFile { file_id, value: ref source } = &self.source[idx as usize]; |
595 | match source { | 583 | match source { |
@@ -599,12 +587,10 @@ impl DocsRangeMap { | |||
599 | let text_range = comment.syntax().text_range(); | 587 | let text_range = comment.syntax().text_range(); |
600 | let range = TextRange::at( | 588 | let range = TextRange::at( |
601 | text_range.start() | 589 | text_range.start() |
602 | + TextSize::from( | 590 | + TextSize::try_from(comment.prefix().len()).ok()? |
603 | (comment.prefix().len() | 591 | + original_line_src_range.start() |
604 | + original_line_src_range.start | 592 | + relative_range.start(), |
605 | + relative_range.start) as u32, | 593 | text_range.len().min(range.len()), |
606 | ), | ||
607 | text_range.len().min(range_len), | ||
608 | ); | 594 | ); |
609 | Some(InFile { file_id, value: range }) | 595 | Some(InFile { file_id, value: range }) |
610 | } | 596 | } |
diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs index 9a9a41113..2edd551cb 100644 --- a/crates/ide/src/doc_links.rs +++ b/crates/ide/src/doc_links.rs | |||
@@ -1,6 +1,9 @@ | |||
1 | //! Extracts, resolves and rewrites links and intra-doc links in markdown documentation. | 1 | //! Extracts, resolves and rewrites links and intra-doc links in markdown documentation. |
2 | 2 | ||
3 | use std::{convert::TryFrom, iter::once, ops::Range}; | 3 | use std::{ |
4 | convert::{TryFrom, TryInto}, | ||
5 | iter::once, | ||
6 | }; | ||
4 | 7 | ||
5 | use itertools::Itertools; | 8 | use itertools::Itertools; |
6 | use pulldown_cmark::{BrokenLink, CowStr, Event, InlineStr, LinkType, Options, Parser, Tag}; | 9 | use pulldown_cmark::{BrokenLink, CowStr, Event, InlineStr, LinkType, Options, Parser, Tag}; |
@@ -15,7 +18,9 @@ use ide_db::{ | |||
15 | defs::{Definition, NameClass, NameRefClass}, | 18 | defs::{Definition, NameClass, NameRefClass}, |
16 | RootDatabase, | 19 | RootDatabase, |
17 | }; | 20 | }; |
18 | use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxNode, SyntaxToken, TokenAtOffset, T}; | 21 | use syntax::{ |
22 | ast, match_ast, AstNode, SyntaxKind::*, SyntaxNode, SyntaxToken, TextRange, TokenAtOffset, T, | ||
23 | }; | ||
19 | 24 | ||
20 | use crate::{FilePosition, Semantics}; | 25 | use crate::{FilePosition, Semantics}; |
21 | 26 | ||
@@ -115,7 +120,7 @@ pub(crate) fn external_docs( | |||
115 | /// Extracts all links from a given markdown text. | 120 | /// Extracts all links from a given markdown text. |
116 | pub(crate) fn extract_definitions_from_markdown( | 121 | pub(crate) fn extract_definitions_from_markdown( |
117 | markdown: &str, | 122 | markdown: &str, |
118 | ) -> Vec<(Range<usize>, String, Option<hir::Namespace>)> { | 123 | ) -> Vec<(TextRange, String, Option<hir::Namespace>)> { |
119 | Parser::new_with_broken_link_callback( | 124 | Parser::new_with_broken_link_callback( |
120 | markdown, | 125 | markdown, |
121 | Options::empty(), | 126 | Options::empty(), |
@@ -126,7 +131,11 @@ pub(crate) fn extract_definitions_from_markdown( | |||
126 | if let Event::Start(Tag::Link(_, target, title)) = event { | 131 | if let Event::Start(Tag::Link(_, target, title)) = event { |
127 | let link = if target.is_empty() { title } else { target }; | 132 | let link = if target.is_empty() { title } else { target }; |
128 | let (link, ns) = parse_intra_doc_link(&link); | 133 | let (link, ns) = parse_intra_doc_link(&link); |
129 | Some((range, link.to_string(), ns)) | 134 | Some(( |
135 | TextRange::new(range.start.try_into().ok()?, range.end.try_into().ok()?), | ||
136 | link.to_string(), | ||
137 | ns, | ||
138 | )) | ||
130 | } else { | 139 | } else { |
131 | None | 140 | None |
132 | } | 141 | } |