Skip to main content

interscript_rs/
locate.rs

1//! Map resolution over the load path — `Interscript.locate` parity:
2//! for every directory, try `.isc` (ISC maps), then `.iml`
3//! (character-set libraries), then `.imp` (legacy Ruby DSL; not
4//! supported here).
5
6use crate::error::{Error, Result};
7use std::path::{Path, PathBuf};
8
9pub fn locate(load_path: &[PathBuf], map_name: &str) -> Result<PathBuf> {
10    for dir in load_path {
11        for ext in ["isc", "iml", "imp"] {
12            let candidate = dir.join(format!("{map_name}.{ext}"));
13            if candidate.is_file() {
14                if ext == "imp" {
15                    return Err(Error::Unsupported(format!(
16                        "legacy .imp map {map_name:?} (Ruby DSL); only .isc/.iml run in slice 1"
17                    )));
18                }
19                return Ok(candidate);
20            }
21        }
22    }
23    Err(Error::MapNotFound(map_name.to_string()))
24}
25
26pub fn read_map(path: &Path) -> Result<String> {
27    std::fs::read_to_string(path).map_err(|e| Error::Io(format!("{}: {e}", path.display())))
28}
29
30/// Default load path: $ISCRS_MAPS (colon-separated), falling back to
31/// the sibling Interscript maps checkout (`../maps/maps` +
32/// `../maps/libs`, relative to the working directory).
33pub fn default_load_path() -> Vec<PathBuf> {
34    if let Ok(env) = std::env::var("ISCRS_MAPS") {
35        return std::env::split_paths(&env).collect();
36    }
37    let mut out = Vec::new();
38    for rel in ["maps/maps", "maps/libs"] {
39        for base in [".", "..", "../.."] {
40            let candidate = Path::new(base).join(rel);
41            if candidate.is_dir() {
42                out.push(candidate);
43                break;
44            }
45        }
46    }
47    out
48}