//! A higher level attributes based on TokenTree, with also some shortcuts.
use std::{
- cmp::Ordering,
- ops::{self, Range},
+ convert::{TryFrom, TryInto},
+ ops,
sync::Arc,
};
if !doc.is_empty() {
for line in doc.split('\n') {
let line = line.trim_end();
+ let line_len = line.len();
let (offset, line) = match line.char_indices().nth(indent) {
Some((offset, _)) => (offset, &line[offset..]),
None => (0, line),
let buf_offset = buf.len();
buf.push_str(line);
mapping.push((
- Range { start: buf_offset, end: buf.len() },
+ TextRange::new(buf_offset.try_into().ok()?, buf.len().try_into().ok()?),
idx,
- Range { start: offset, end: line.len() },
+ TextRange::new(offset.try_into().ok()?, line_len.try_into().ok()?),
));
buf.push('\n');
}
// (docstring-line-range, attr_index, attr-string-range)
// a mapping from the text range of a line of the [`Documentation`] to the attribute index and
// the original (untrimmed) syntax doc line
- mapping: Vec<(Range<usize>, u32, Range<usize>)>,
+ mapping: Vec<(TextRange, u32, TextRange)>,
}
impl DocsRangeMap {
- pub fn map(&self, range: Range<usize>) -> Option<InFile<TextRange>> {
- let found = self
- .mapping
- .binary_search_by(|(probe, ..)| {
- if probe.contains(&range.start) {
- Ordering::Equal
- } else {
- probe.start.cmp(&range.end)
- }
- })
- .ok()?;
+ pub fn map(&self, range: TextRange) -> Option<InFile<TextRange>> {
+ let found = self.mapping.binary_search_by(|(probe, ..)| probe.ordering(range)).ok()?;
let (line_docs_range, idx, original_line_src_range) = self.mapping[found].clone();
- if range.end > line_docs_range.end {
+ if !line_docs_range.contains_range(range) {
return None;
}
- let relative_range = Range {
- start: range.start - line_docs_range.start,
- end: range.end - line_docs_range.start,
- };
- let range_len = TextSize::from((range.end - range.start) as u32);
+ let relative_range = range - line_docs_range.start();
let &InFile { file_id, value: ref source } = &self.source[idx as usize];
match source {
let text_range = comment.syntax().text_range();
let range = TextRange::at(
text_range.start()
- + TextSize::from(
- (comment.prefix().len()
- + original_line_src_range.start
- + relative_range.start) as u32,
- ),
- text_range.len().min(range_len),
+ + TextSize::try_from(comment.prefix().len()).ok()?
+ + original_line_src_range.start()
+ + relative_range.start(),
+ text_range.len().min(range.len()),
);
Some(InFile { file_id, value: range })
}
//! Extracts, resolves and rewrites links and intra-doc links in markdown documentation.
-use std::{convert::TryFrom, iter::once, ops::Range};
+use std::{
+ convert::{TryFrom, TryInto},
+ iter::once,
+};
use itertools::Itertools;
use pulldown_cmark::{BrokenLink, CowStr, Event, InlineStr, LinkType, Options, Parser, Tag};
defs::{Definition, NameClass, NameRefClass},
RootDatabase,
};
-use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxNode, SyntaxToken, TokenAtOffset, T};
+use syntax::{
+ ast, match_ast, AstNode, SyntaxKind::*, SyntaxNode, SyntaxToken, TextRange, TokenAtOffset, T,
+};
use crate::{FilePosition, Semantics};
/// Extracts all links from a given markdown text.
pub(crate) fn extract_definitions_from_markdown(
markdown: &str,
-) -> Vec<(Range<usize>, String, Option<hir::Namespace>)> {
+) -> Vec<(TextRange, String, Option<hir::Namespace>)> {
Parser::new_with_broken_link_callback(
markdown,
Options::empty(),
if let Event::Start(Tag::Link(_, target, title)) = event {
let link = if target.is_empty() { title } else { target };
let (link, ns) = parse_intra_doc_link(&link);
- Some((range, link.to_string(), ns))
+ Some((
+ TextRange::new(range.start.try_into().ok()?, range.end.try_into().ok()?),
+ link.to_string(),
+ ns,
+ ))
} else {
None
}