Skip to main content

imp_lua/
loader.rs

1use std::path::{Path, PathBuf};
2
3use crate::sandbox::{LuaError, LuaRuntime};
4
5/// Discovered Lua extension.
6#[derive(Debug, Clone)]
7pub struct LuaExtension {
8    pub name: String,
9    pub path: PathBuf,
10}
11
12/// Discover Lua extensions from user and project directories.
13pub fn discover_extensions(
14    user_config_dir: &Path,
15    project_dir: Option<&Path>,
16) -> Vec<LuaExtension> {
17    let mut extensions = Vec::new();
18
19    let mut dirs = vec![user_config_dir.join("lua")];
20    if let Some(project) = project_dir {
21        dirs.push(project.join(".imp").join("lua"));
22    }
23
24    for dir in &dirs {
25        if let Ok(entries) = std::fs::read_dir(dir) {
26            for entry in entries.flatten() {
27                let path = entry.path();
28
29                // Direct .lua file
30                if path.extension().is_some_and(|e| e == "lua") {
31                    let name = path
32                        .file_stem()
33                        .map(|s| s.to_string_lossy().to_string())
34                        .unwrap_or_default();
35                    extensions.push(LuaExtension { name, path });
36                    continue;
37                }
38
39                // Directory with init.lua
40                if path.is_dir() {
41                    let init = path.join("init.lua");
42                    if init.exists() {
43                        let name = path
44                            .file_name()
45                            .map(|s| s.to_string_lossy().to_string())
46                            .unwrap_or_default();
47                        extensions.push(LuaExtension { name, path: init });
48                    }
49                }
50            }
51        }
52    }
53
54    extensions
55}
56
57/// Load all discovered extensions into a Lua runtime.
58pub fn load_extensions(
59    runtime: &LuaRuntime,
60    extensions: &[LuaExtension],
61) -> Vec<(String, Result<(), LuaError>)> {
62    extensions
63        .iter()
64        .map(|ext| {
65            let result = runtime.exec_file(&ext.path);
66            (ext.name.clone(), result)
67        })
68        .collect()
69}
70
71/// Hot reload: drop old state, create new runtime, re-load extensions.
72pub fn reload(
73    user_config_dir: &Path,
74    project_dir: Option<&Path>,
75) -> Result<(LuaRuntime, Vec<LuaExtension>), LuaError> {
76    let extensions = discover_extensions(user_config_dir, project_dir);
77    let runtime = LuaRuntime::new()?;
78    crate::bridge::setup_host_api(&runtime)?;
79    load_extensions(&runtime, &extensions);
80    Ok((runtime, extensions))
81}