aiken/crates/aiken-project/src/docs/source_links.rs

92 lines
2.8 KiB
Rust

use crate::{
CheckedModule,
config::{Platform, ProjectConfig},
};
use aiken_lang::{ast::Span, line_numbers::LineNumbers};
use camino::{Utf8Component, Utf8Path};
use std::path::Path;
pub struct SourceLinker {
line_numbers: LineNumbers,
url_pattern: Option<(String, String)>,
}
impl SourceLinker {
pub fn new(root: &Path, config: &ProjectConfig, module: &CheckedModule) -> Self {
let utf8_path = <&Utf8Path>::try_from(
module
.input_path
.as_path()
.strip_prefix(root)
.expect("root path isn't a prefix of project modules' paths!"),
)
.expect("module path contains non UTF-8 characters!");
let path_in_repo = to_url_path(utf8_path).unwrap_or_default();
let url_pattern = config
.repository
.as_ref()
.map(|repository| match repository.platform {
Platform::Github => (
format!(
"https://github.com/{}/{}/blob/{}/{}#L",
repository.user, repository.project, config.version, path_in_repo
),
"-L".into(),
),
Platform::Gitlab => (
format!(
"https://gitlab.com/{}/{}/-/blob/{}/{}#L",
repository.user, repository.project, config.version, path_in_repo
),
"-".into(),
),
Platform::Bitbucket => (
format!(
"https://bitbucket.com/{}/{}/src/{}/{}#lines-",
repository.user, repository.project, config.version, path_in_repo
),
":".into(),
),
});
SourceLinker {
line_numbers: LineNumbers::new(&module.code),
url_pattern,
}
}
pub fn url(&self, span: Span) -> String {
match &self.url_pattern {
Some((base, line_sep)) => {
match (
self.line_numbers.line_number(span.start),
self.line_numbers.line_number(span.end),
) {
(Some(start_line), Some(end_line)) => {
format!("{base}{start_line}{line_sep}{end_line}")
}
(Some(start_line), None) => format!("{base}{start_line}"),
_ => base.to_string(),
}
}
None => "".into(),
}
}
}
fn to_url_path(path: &Utf8Path) -> Option<String> {
let mut buf = String::new();
for c in path.components() {
if let Utf8Component::Normal(s) = c {
buf.push_str(s);
}
buf.push('/');
}
let _ = buf.pop();
Some(buf)
}