aiken_project/docs/
source_links.rs1use crate::{
2 CheckedModule,
3 config::{Platform, ProjectConfig},
4};
5use aiken_lang::{ast::Span, line_numbers::LineNumbers};
6use camino::{Utf8Component, Utf8Path};
7use std::path::Path;
8
9pub struct SourceLinker {
10 line_numbers: LineNumbers,
11 url_pattern: Option<(String, String)>,
12}
13
14impl SourceLinker {
15 pub fn new(root: &Path, config: &ProjectConfig, module: &CheckedModule) -> Self {
16 let utf8_path = <&Utf8Path>::try_from(
17 module
18 .input_path
19 .as_path()
20 .strip_prefix(root)
21 .expect("root path isn't a prefix of project modules' paths!"),
22 )
23 .expect("module path contains non UTF-8 characters!");
24
25 let path_in_repo = to_url_path(utf8_path).unwrap_or_default();
26
27 let url_pattern = config
28 .repository
29 .as_ref()
30 .map(|repository| match repository.platform {
31 Platform::Github => (
32 format!(
33 "https://github.com/{}/{}/blob/{}/{}#L",
34 repository.user, repository.project, config.version, path_in_repo
35 ),
36 "-L".into(),
37 ),
38 Platform::Gitlab => (
39 format!(
40 "https://gitlab.com/{}/{}/-/blob/{}/{}#L",
41 repository.user, repository.project, config.version, path_in_repo
42 ),
43 "-".into(),
44 ),
45 Platform::Bitbucket => (
46 format!(
47 "https://bitbucket.com/{}/{}/src/{}/{}#lines-",
48 repository.user, repository.project, config.version, path_in_repo
49 ),
50 ":".into(),
51 ),
52 });
53
54 SourceLinker {
55 line_numbers: LineNumbers::new(&module.code),
56 url_pattern,
57 }
58 }
59
60 pub fn url(&self, span: Span) -> String {
61 match &self.url_pattern {
62 Some((base, line_sep)) => {
63 match (
64 self.line_numbers.line_number(span.start),
65 self.line_numbers.line_number(span.end),
66 ) {
67 (Some(start_line), Some(end_line)) => {
68 format!("{base}{start_line}{line_sep}{end_line}")
69 }
70 (Some(start_line), None) => format!("{base}{start_line}"),
71 _ => base.to_string(),
72 }
73 }
74 None => "".into(),
75 }
76 }
77}
78
79fn to_url_path(path: &Utf8Path) -> Option<String> {
80 let mut buf = String::new();
81 for c in path.components() {
82 if let Utf8Component::Normal(s) = c {
83 buf.push_str(s);
84 }
85 buf.push('/');
86 }
87
88 let _ = buf.pop();
89
90 Some(buf)
91}