Fork of daniellemaywood.uk/gleam — Wasm codegen work
4.1 kB
125 lines
1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: 2020 The Gleam contributors
3
4use crate::{
5 ast::SrcSpan,
6 build,
7 config::{PackageConfig, Repository},
8 line_numbers::LineNumbers,
9 paths::ProjectPaths,
10};
11
12use camino::{Utf8Component, Utf8Path, Utf8PathBuf};
13
14pub struct SourceLinker {
15 line_numbers: LineNumbers,
16 url_pattern: Option<(String, String)>,
17}
18
19impl SourceLinker {
20 pub fn new(
21 paths: &ProjectPaths,
22 project_config: &PackageConfig,
23 module: &build::Module,
24 ) -> Self {
25 let path = paths
26 .src_directory()
27 .join(module.name.as_str())
28 .strip_prefix(paths.root())
29 .expect("path is not in root")
30 .with_extension("gleam");
31
32 let path_in_repo = match project_config
33 .repository
34 .as_ref()
35 .map(|r| r.path())
36 .unwrap_or_default()
37 {
38 Some(repo_path) => to_url_path(&Utf8PathBuf::from(repo_path).join(path)),
39 _ => to_url_path(&path),
40 }
41 .unwrap_or_default();
42
43 let tag = project_config.tag_for_version(&project_config.version);
44
45 let url_pattern = project_config
46 .repository
47 .as_ref()
48 .map(|r| match r {
49 Repository::GitHub { user, repo, .. } => Some((
50 format!("https://github.com/{user}/{repo}/blob/{tag}/{path_in_repo}#L"),
51 "-L".into(),
52 )),
53 Repository::GitLab { user, repo, .. } => Some((
54 format!("https://gitlab.com/{user}/{repo}/-/blob/{tag}/{path_in_repo}#L"),
55 "-".into(),
56 )),
57 Repository::BitBucket { user, repo, .. } => Some((
58 format!("https://bitbucket.com/{user}/{repo}/src/{tag}/{path_in_repo}#lines-"),
59 ":".into(),
60 )),
61 Repository::Codeberg { user, repo, .. } => Some((
62 format!("https://codeberg.org/{user}/{repo}/src/tag/{tag}/{path_in_repo}#L"),
63 "-".into(),
64 )),
65 Repository::SourceHut { user, repo, .. } => Some((
66 format!("https://git.sr.ht/~{user}/{repo}/tree/{tag}/item/{path_in_repo}#L"),
67 "-".into(),
68 )),
69 Repository::Tangled { user, repo, .. } => Some((
70 format!("https://tangled.sh/{user}/{repo}/tree/{tag}/{path_in_repo}#L"),
71 "-".into(),
72 )),
73 Repository::Gitea {
74 user, repo, host, ..
75 }
76 | Repository::Forgejo {
77 user, repo, host, ..
78 } => {
79 let string_host = host.to_string();
80 let cleaned_host = string_host.trim_end_matches('/');
81 Some((
82 format!("{cleaned_host}/{user}/{repo}/src/tag/{tag}/{path_in_repo}#L",),
83 "-L".into(),
84 ))
85 }
86 Repository::Custom { .. } => None,
87 })
88 .unwrap_or_default();
89
90 SourceLinker {
91 line_numbers: LineNumbers::new(&module.code),
92 url_pattern,
93 }
94 }
95
96 pub fn url(&self, span: SrcSpan) -> String {
97 match &self.url_pattern {
98 Some((base, line_sep)) => {
99 let start_line = self.line_numbers.line_number(span.start);
100 let end_line = self.line_numbers.line_number(span.end);
101 if start_line == end_line {
102 format!("{base}{start_line}")
103 } else {
104 format!("{base}{start_line}{line_sep}{end_line}")
105 }
106 }
107
108 None => "".into(),
109 }
110 }
111}
112
113fn to_url_path(path: &Utf8Path) -> Option<String> {
114 let mut buf = String::new();
115 for c in path.components() {
116 if let Utf8Component::Normal(s) = c {
117 buf.push_str(s);
118 }
119 buf.push('/');
120 }
121
122 let _ = buf.pop();
123
124 Some(buf)
125}