valis_core/modules/script/
engine.rs1use std::env;
2use std::path::PathBuf;
3
4use rlua::{Context, Lua, Result, ToLua, UserData, Value};
5use rlua::Error as LuaError;
6use rlua::FromLua;
7use rlua::Table;
8use termion::color;
9use tokio::runtime::Runtime;
10use uuid::Uuid;
11
12use crate::modules::{core, db};
13use crate::modules::db::DatabaseOperations;
14use crate::modules::db::serializers::SerializableDateTime;
15use crate::modules::formats::text;
16use crate::modules::formats::yaml::{get_yaml_value, update_yaml_value};
17use crate::modules::log::ack;
18use crate::modules::notes::markdown;
19use crate::modules::notes::markdown::Page;
20use crate::modules::projects::{agile, git};
21use crate::modules::projects::git::core::{GitOperations, SimpleRepo};
22use crate::modules::tasks::todoist;
23
24fn remove_comment_lines(s: &str) -> String {
26 s.lines()
27 .filter(|line| !line.trim().starts_with("#"))
28 .collect::<Vec<&str>>()
29 .join("\n")
30}
31
32fn pretty_print_table(table: &Table, indent: usize) -> Result<()> {
33 let pairs = table.clone().pairs::<Value, Value>();
34 for pair in pairs {
35 let (key, value) = pair?;
36 print!("{}{}", " ".repeat(indent), color::Fg(color::Cyan)); match key {
38 Value::String(s) => print!("{}", s.to_str()?),
39 Value::Integer(i) => print!("{}", i),
40 Value::Number(n) => print!("{}", n),
41 _ => print!("(non-string/number key)"),
42 }
43 print!(": {}", color::Fg(color::Reset));
44 match value {
45 Value::Table(t) => {
46 println!();
47 pretty_print_table(&t, indent + 2)?; }
49 Value::String(s) => println!("{}{}", color::Fg(color::White), s.to_str()?), Value::Integer(i) => println!("{}{}", color::Fg(color::Magenta), i), Value::Number(n) => println!("{}{}", color::Fg(color::Magenta), n), _ => println!("(non-table/string/number value)"),
53 }
54 print!("{}", color::Fg(color::Reset));
55 }
56 Ok(())
57}
58
59pub fn prepare_context(ctx: &Context) {
64 let globals = ctx.globals();
65 let git_clone = ctx
66 .create_function(|_, (url, destination): (String, String)| {
67 let repo = SimpleRepo {
68 url: url.to_owned(),
69 branch: None,
70 destination: destination.to_owned(),
71 };
72 ack(&format!(
73 "cloning {} into {}",
74 &url.to_owned(),
75 &destination.to_owned()
76 ));
77 repo.clone();
78 return Ok(());
79 })
80 .unwrap();
81 globals.set("git_clone", git_clone).unwrap();
82 let run = ctx
83 .create_function(|_, command: String| {
84 return Ok(core::run_buffered(&command));
85 })
86 .unwrap();
87 globals.set("run", run).unwrap();
88 let get_yaml_value = ctx
89 .create_function(|_, (file_path, yaml_key_path): (String, String)| {
90 return Ok(get_yaml_value(&file_path, &yaml_key_path).ok().unwrap());
91 })
92 .unwrap();
93 globals.set("yaml_get_value", get_yaml_value).unwrap();
94 let update_yaml_value = ctx
95 .create_function(
96 |_, (file_path, yaml_key_path, new_value): (String, String, String)| {
97 let v = update_yaml_value(&file_path, &yaml_key_path, &new_value)
99 .ok()
100 .unwrap();
101 return Ok(());
102 },
103 )
104 .unwrap();
105 globals.set("yaml_set_value", update_yaml_value).unwrap();
106 let replace_matching_line = ctx
107 .create_function(
108 |_, (file_path, regex, new_value): (String, String, String)| {
109 match text::replace_matching_line(&file_path, ®ex, &new_value) {
110 Ok(()) => Ok(()),
111 Err(e) => Err(LuaError::RuntimeError(
112 "Could not replace matching line".to_string(),
113 )),
114 }
115 },
116 )
117 .unwrap();
118 globals.set("replace_line", replace_matching_line).unwrap();
119 let set_dir = ctx
120 .create_function(|_, dir: String| match core::set_dir(&dir) {
121 Ok(()) => Ok(()),
122 Err(e) => Err(LuaError::RuntimeError(
123 "Could not set current directory".to_string(),
124 )),
125 })
126 .unwrap();
127 globals.set("set_dir", set_dir).unwrap();
128 let get_dir = ctx
129 .create_function(|_, ()| match core::get_dir() {
130 Ok(dir) => Ok(dir),
131 Err(e) => Err(LuaError::RuntimeError(
132 "Could not get current directory".to_string(),
133 )),
134 })
135 .unwrap();
136 globals.set("get_dir", get_dir).unwrap();
137 let from_home = ctx
138 .create_function(|_, path: String| {
139 return core::from_home(&path)
140 .ok_or_else(|| LuaError::RuntimeError("Could not get path from home".to_string()));
141 })
142 .unwrap();
143 globals.set("from_home", from_home).unwrap();
144 let git_from_root = ctx
145 .create_function(|_, path: String| {
146 return git::core::from_root(&path).ok_or_else(|| {
147 LuaError::RuntimeError("Could not get path from git root".to_string())
148 });
149 })
150 .unwrap();
151 globals.set("git_from_root", git_from_root).unwrap();
152 let md_load = ctx
153 .create_function(|ctx, path: String| {
154 let mut pb = PathBuf::new();
155 pb.push(path);
156 let page: Page = markdown::PageLoader::from_path(&pb);
157 let table = ctx.create_table()?;
158 table.set("title", page.title.to_string())?;
159 table.set("path", page.path.to_str().unwrap_or(""))?;
160 table.set("contents", page.contents.to_string())?;
161 let wikilinks = page
162 .wikilinks
163 .into_iter()
164 .map(|wikilink| {
165 let table = ctx.create_table().ok().unwrap();
166 table.set("name", wikilink.name).ok().unwrap();
167 table.set("link", wikilink.link).ok().unwrap();
168 table.set("anchor", wikilink.anchor).ok().unwrap();
169 table
170 .set("link_type", wikilink.link_type as u8)
171 .ok()
172 .unwrap();
173 table
174 })
175 .collect::<Vec<Table>>();
176 table.set("wikilinks", wikilinks).ok().unwrap();
177
178 Ok(table)
179 })
180 .unwrap();
181 globals.set("md_load", md_load).unwrap();
182 let pprint = ctx
183 .create_function(|_, table: Table| {
184 pretty_print_table(&table, 2)
185 })
186 .unwrap();
187 globals.set("pprint", pprint).unwrap();
188 todoist::lua::todoist_sync(ctx);
189 todoist::lua::todoist_add_task_to_sprint(ctx);
190 agile::lua::agile_create_project(ctx);
191 agile::lua::agile_create_sprint(ctx);
192 agile::lua::agile_show_sprint(ctx);
193 git::lua::_get_git_project_root_path(ctx);
194 git::lua::_get_git_project_branches(ctx);
195}
196
197pub fn execute(script: &str) -> Result<()> {
201 let lua = Lua::new();
202
203 lua.context(|lua_ctx| {
204 prepare_context(&lua_ctx);
205 let prelude = include_str!("prelude.lua");
206 lua_ctx.load(prelude).exec().unwrap();
207 lua_ctx.load(&remove_comment_lines(script)).exec().unwrap();
208 Ok(())
209 })
210}