1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
use super::*;
use crate::project::collect_link_literals;
/// The clickable file links in `text`: every string literal that resolves to an
/// existing regular file. Relative spellings resolve against `base_dir` (the
/// document's own directory), matching arity's `source()` resolution; absolute
/// spellings (and any when `base_dir` is `None`) are taken verbatim. A pure CST
/// walk plus one `stat` per literal — no semantic model, no workspace snapshot.
///
/// Documents larger than `file_size_limit` bytes are skipped wholesale so link
/// discovery never walks a pathological generated file. Targets are resolved
/// eagerly (no `documentLink/resolve` round-trip); a resolve provider could be
/// added later if the per-literal `stat` ever shows up in a profile.
pub fn compute_document_links(
text: &str,
base_dir: Option<&Path>,
file_size_limit: u64,
) -> Vec<DocumentLink> {
if text.len() as u64 > file_size_limit {
return Vec::new();
}
let root = parse(text).cst;
let line_index = LineIndex::new(text);
collect_link_literals(&root)
.into_iter()
.filter_map(|literal| {
// Resolve exactly as `source_literal_edge` does: join relative
// spellings onto the base dir, take absolute ones verbatim.
let target_path = match base_dir {
Some(dir) if literal.was_relative => dir.join(&literal.spelling),
_ => PathBuf::from(&literal.spelling),
};
// Only existing regular files become links (skip dirs and misses).
if !target_path.is_file() {
return None;
}
let target = uri::from_path(&target_path)?;
Some(DocumentLink {
range: text_range_to_lsp_range(&line_index, literal.literal_range),
target: Some(target),
tooltip: None,
data: None,
})
})
.collect()
}