code_moniker_workspace/
environment.rs1use std::path::{Path, PathBuf};
2
3use code_moniker_core::core::code_graph::CodeGraph;
4use code_moniker_core::core::moniker::Moniker;
5use code_moniker_core::core::uri::{UriConfig, to_uri};
6use code_moniker_core::lang::Lang;
7
8pub type ExtractContext = crate::extract::Context;
9pub type IdentityResolver = crate::source::LocalIdentityResolver;
10pub type IndexedSourceMaterial = crate::source::CodeIndexMaterial;
11pub type ResourceCache = crate::source::LocalResourceCache;
12pub type SourceFile = crate::sources::SourceFile;
13pub type SourceFileSet = crate::sources::SourceSet;
14pub type SourceRoot = crate::sources::SourceRoot;
15
16pub fn discover_sources(
17 paths: &[PathBuf],
18 project: Option<String>,
19) -> anyhow::Result<SourceFileSet> {
20 crate::sources::discover(paths, project)
21}
22
23pub fn discover_source_files(
24 root: &Path,
25 files: &[PathBuf],
26 project: Option<String>,
27) -> anyhow::Result<SourceFileSet> {
28 crate::sources::discover_files(root, files, project)
29}
30
31pub fn language_for_path(path: &Path) -> anyhow::Result<Lang> {
32 Ok(crate::lang::path_to_lang(path)?)
33}
34
35pub fn load_or_extract_source(
36 path: &Path,
37 anchor: &Path,
38 lang: Lang,
39 cache_dir: Option<&Path>,
40 ctx: &ExtractContext,
41) -> anyhow::Result<(CodeGraph, Option<String>)> {
42 Ok(crate::cache::load_or_extract_result(
43 path, anchor, lang, cache_dir, ctx,
44 )?)
45}
46
47pub fn cached_index_material(
48 cache: &ResourceCache,
49 generation: crate::snapshot::ResourceGeneration,
50) -> Option<std::sync::Arc<IndexedSourceMaterial>> {
51 cache.index_material(generation)
52}
53
54pub fn next_resource_generation(cache: &ResourceCache) -> crate::snapshot::ResourceGeneration {
55 cache.next_generation()
56}
57
58#[cfg(test)]
59pub fn extract_source(lang: Lang, source: &str, path: &Path) -> CodeGraph {
60 crate::extract::extract(lang, source, path)
61}
62
63pub fn extract_source_with(
64 lang: Lang,
65 source: &str,
66 path: &Path,
67 ctx: &ExtractContext,
68) -> CodeGraph {
69 crate::extract::extract_with(lang, source, path, ctx)
70}
71
72pub fn line_range(source: &str, start: u32, end: u32) -> (u32, u32) {
73 crate::lines::line_range(source, start, end)
74}
75
76pub fn compact_moniker(moniker: &Moniker, scheme: &str) -> String {
77 render_compact_moniker(moniker).unwrap_or_else(|| to_uri(moniker, &UriConfig { scheme }))
78}
79
80fn render_compact_moniker(moniker: &Moniker) -> Option<String> {
81 let view = moniker.as_view();
82 let mut lang: Option<String> = None;
83 let mut packages: Vec<String> = Vec::new();
84 let mut dirs: Vec<String> = Vec::new();
85 let mut modules: Vec<String> = Vec::new();
86 let mut rest: Vec<(String, String)> = Vec::new();
87 for segment in view.segments() {
88 let kind = std::str::from_utf8(segment.kind).ok()?.to_string();
89 let name = std::str::from_utf8(segment.name).ok()?.to_string();
90 match kind.as_str() {
91 "lang" => lang = Some(name),
92 "package" => packages.push(name),
93 "dir" => dirs.push(name),
94 "module" => modules.push(name),
95 _ => rest.push((kind, name)),
96 }
97 }
98 let head = lang.unwrap_or_else(|| {
99 std::str::from_utf8(view.project())
100 .unwrap_or(".")
101 .to_string()
102 });
103 if packages.is_empty() && dirs.is_empty() && modules.is_empty() && rest.is_empty() {
104 return Some(head);
105 }
106 let mut out = String::new();
107 out.push_str(&head);
108 out.push(':');
109 let mut wrote_scope = false;
110 if !packages.is_empty() {
111 out.push_str(&packages.join("."));
112 wrote_scope = true;
113 } else if !dirs.is_empty() {
114 out.push_str(&dirs.join("/"));
115 wrote_scope = true;
116 }
117 let has_module = !modules.is_empty();
118 if has_module {
119 if wrote_scope {
120 out.push('/');
121 }
122 out.push_str(&modules.join("."));
123 }
124 for (idx, (kind, name)) in rest.iter().enumerate() {
125 if idx == 0 && has_module {
126 out.push('.');
127 } else if wrote_scope || has_module || idx > 0 {
128 out.push('/');
129 }
130 out.push_str(kind);
131 out.push(':');
132 out.push_str(name);
133 }
134 Some(out)
135}