fancy_tree/lua/state/
mod.rs

1//! Module for creating a Lua state object for the application.
2use crate::git::Git;
3pub use builder::Builder;
4use mlua::Lua;
5use std::ffi::OsString;
6
7mod builder;
8
9/// Container for the Lua state.
10///
11/// This helps ensure proper lifetimes for any type that the state uses.
12pub struct State<'git> {
13    /// The actual Lua state.
14    inner: Lua,
15    /// An optional git state for interfacing with a repository.
16    git: Option<&'git Git>,
17}
18
19impl<'git> State<'git> {
20    /// The inner Lua state.
21    pub fn to_inner(&self) -> &Lua {
22        &self.inner
23    }
24
25    /// Gets the contained git instance.
26    pub fn git(&self) -> Option<&'git Git> {
27        self.git
28    }
29
30    /// Runs the function in a scope where git utilities are potentially available.
31    pub fn in_git_scope<T, F>(&self, f: F) -> mlua::Result<T>
32    where
33        F: FnOnce() -> mlua::Result<T>,
34    {
35        // HACK We can't build out the git API statically (like we can with the path
36        //      API) because of lifetimes.
37        // HACK Both git and git API must exist, so we can use a shortcut if neither exist.
38        let Some(git) = self.git else { return f() };
39        let Some(git_api) = self.git_api()? else {
40            return f();
41        };
42
43        self.inner.scope(|scope| {
44            let is_ignored = scope.create_function(|_lua, path: OsString| {
45                let is_ignored = git.is_ignored(path).unwrap_or(false);
46                Ok(is_ignored)
47            })?;
48            git_api.set("is_ignored", is_ignored)?;
49            f()
50        })
51    }
52
53    /// Gets a reference to the git table.
54    fn git_api(&self) -> mlua::Result<Option<mlua::Table>> {
55        let globals = self.inner.globals();
56        // TODO These hard-coded keys should be shared variables instead.
57        let api = globals.get::<mlua::Table>("fancytree")?;
58        api.get::<Option<mlua::Table>>("git")
59    }
60}