diff --git a/Cargo.lock b/Cargo.lock index 04fa921..bfc1544 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -56,7 +56,7 @@ checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.72", ] [[package]] @@ -67,7 +67,7 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.72", ] [[package]] @@ -277,6 +277,16 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +[[package]] +name = "erased-serde" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24e2389d65ab4fab27dc2a5de7b191e1f6617d1f1c8855c0dc569c94a4cbb18d" +dependencies = [ + "serde", + "typeid", +] + [[package]] name = "errno" version = "0.3.9" @@ -389,7 +399,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.72", ] [[package]] @@ -696,10 +706,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d111deb18a9c9bd33e1541309f4742523bfab01d276bfa9a27519f6de9c11dc7" dependencies = [ "bstr", + "erased-serde", "mlua-sys", "num-traits", "once_cell", "rustc-hash", + "serde", + "serde-value", ] [[package]] @@ -802,6 +815,15 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "ordered-float" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" +dependencies = [ + "num-traits", +] + [[package]] name = "parking_lot_core" version = "0.9.10" @@ -852,7 +874,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.72", ] [[package]] @@ -883,7 +905,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.72", ] [[package]] @@ -931,9 +953,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.79" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] @@ -949,9 +971,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.35" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -1159,6 +1181,16 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" +dependencies = [ + "ordered-float", + "serde", +] + [[package]] name = "serde_derive" version = "1.0.204" @@ -1167,7 +1199,7 @@ checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.72", ] [[package]] @@ -1189,7 +1221,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.72", ] [[package]] @@ -1231,9 +1263,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.53" +version = "2.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032" +checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" dependencies = [ "proc-macro2", "quote", @@ -1291,7 +1323,7 @@ checksum = "d20468752b09f49e909e55a5d338caa8bedf615594e9d80bc4c565d30faf798c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.72", ] [[package]] @@ -1371,7 +1403,7 @@ checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.72", ] [[package]] @@ -1438,7 +1470,7 @@ checksum = "84fd902d4e0b9a4b27f2f440108dc034e1758628a9b702f8ec61ad66355422fa" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.72", ] [[package]] @@ -1466,7 +1498,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.72", ] [[package]] @@ -1478,6 +1510,12 @@ dependencies = [ "once_cell", ] +[[package]] +name = "typeid" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "059d83cc991e7a42fc37bd50941885db0888e34209f8cfd9aab07ddec03bc9cf" + [[package]] name = "typenum" version = "1.17.0" @@ -1723,5 +1761,5 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.72", ] diff --git a/Cargo.toml b/Cargo.toml index f6884a8..6838393 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,7 @@ graphviz-rust = "0.9.0" lazy_static = "1.5.0" lsp-server = "0.7.6" lsp-types = "0.97.0" -mlua = { version = "0.9.9", features = ["lua54", "vendored"] } +mlua = { version = "0.9.9", features = ["lua54", "vendored", "serialize"] } regex = "1.10.3" rusqlite = "0.31.0" rust-crypto = "0.2.36" diff --git a/src/document/style.rs b/src/document/style.rs index b7469a2..584f851 100644 --- a/src/document/style.rs +++ b/src/document/style.rs @@ -20,6 +20,13 @@ pub trait ElementStyle: Downcast + core::fmt::Debug { /// Serializes sytle into json string fn to_json(&self) -> String; + + /// Attempts to deserialize lua table into a new style + fn from_lua( + &self, + lua: &mlua::Lua, + value: mlua::Value, + ) -> Result, mlua::Error>; } impl_downcast!(ElementStyle); @@ -31,7 +38,7 @@ pub trait StyleHolder { fn styles_mut(&self) -> RefMut<'_, HashMap>>; /// Checks if a given style key is registered - fn is_registered(&self, style_key: &str) -> bool { self.styles().contains_key(style_key) } + fn is_style_registered(&self, style_key: &str) -> bool { self.styles().contains_key(style_key) } /// Gets the current active style for an element /// NOTE: Will panic if a style is not defined for a given element @@ -59,6 +66,15 @@ macro_rules! impl_elementstyle { } fn to_json(&self) -> String { serde_json::to_string(self).unwrap() } + + fn from_lua( + &self, + lua: &mlua::Lua, + value: mlua::Value, + ) -> Result, mlua::Error> { + mlua::LuaSerdeExt::from_value::<$t>(lua, value) + .map(|obj| std::rc::Rc::new(obj) as std::rc::Rc) + } } }; } diff --git a/src/elements/elemstyle.rs b/src/elements/elemstyle.rs index 47249e6..5386839 100644 --- a/src/elements/elemstyle.rs +++ b/src/elements/elemstyle.rs @@ -1,16 +1,24 @@ use std::any::Any; use std::ops::Range; use std::rc::Rc; +use std::sync::Arc; use ariadne::Fmt; use ariadne::Label; use ariadne::Report; use ariadne::ReportKind; +use mlua::Error::BadArgument; +use mlua::Function; +use mlua::Lua; +use mlua::LuaSerdeExt; +use mlua::Table; +use mlua::Value; use regex::Captures; use regex::Regex; use crate::document::document::Document; use crate::document::{self}; +use crate::lua::kernel::CTX; use crate::parser::parser::Parser; use crate::parser::rule::RegexRule; use crate::parser::rule::Rule; @@ -58,71 +66,6 @@ impl ElemStyleRule { impl Rule for ElemStyleRule { fn name(&self) -> &'static str { "Element Style" } - /* - fn on_regex_match<'a>( - &self, - _: usize, - parser: &dyn Parser, - _document: &'a dyn Document, - token: Token, - matches: Captures, - ) -> Vec, Range)>> { - let mut reports = vec![]; - - - // Get value - let new_style = if let Some(value) = matches.get(2) { - let value_str = match VariableRule::validate_value(value.as_str()) { - Err(err) => { - reports.push( - Report::build(ReportKind::Error, token.source(), value.start()) - .with_message("Invalid Style Value") - .with_label( - Label::new((token.source(), value.range())) - .with_message(format!( - "Value `{}` is not allowed: {err}", - value.as_str().fg(parser.colors().highlight) - )) - .with_color(parser.colors().error), - ) - .finish(), - ); - return reports; - } - Ok(value) => value, - }; - - // Attempt to serialize - match style.from_json(value_str.as_str()) { - Err(err) => { - reports.push( - Report::build(ReportKind::Error, token.source(), value.start()) - .with_message("Invalid Style Value") - .with_label( - Label::new((token.source(), value.range())) - .with_message(format!( - "Failed to serialize `{}` into style with key `{}`: {err}", - value_str.fg(parser.colors().highlight), - style.key().fg(parser.colors().info) - )) - .with_color(parser.colors().error), - ) - .finish(), - ); - return reports; - } - Ok(style) => style, - } - } else { - panic!("Unknown error") - }; - - parser.set_style(new_style); - - reports - } - */ - fn next_match(&self, cursor: &Cursor) -> Option<(usize, Box)> { self.start_re .find_at(cursor.source.content(), cursor.pos) @@ -164,7 +107,7 @@ impl Rule for ElemStyleRule { } // Check if key exists - if !parser.is_registered(trimmed) { + if !parser.is_style_registered(trimmed) { reports.push( Report::build(ReportKind::Error, cursor.source.clone(), key.start()) .with_message("Unknown Style Key") @@ -240,4 +183,46 @@ impl Rule for ElemStyleRule { (cursor, reports) } + + fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Option)>> { + let mut bindings = vec![]; + + bindings.push(( + "set".to_string(), + lua.create_function(|lua, (style_key, new_style): (String, Value)| { + let mut result = Ok(()); + CTX.with_borrow(|ctx| { + ctx.as_ref().map(|ctx| { + if !ctx.parser.is_style_registered(style_key.as_str()) { + result = Err(BadArgument { + to: Some("set".to_string()), + pos: 1, + name: Some("style_key".to_string()), + cause: Arc::new(mlua::Error::external(format!( + "Unable to find style with key: {style_key}" + ))), + }); + return; + } + + let style = ctx.parser.current_style(style_key.as_str()); + let new_style = match style.from_lua(lua, new_style) { + Err(err) => { + result = Err(err); + return; + } + Ok(new_style) => new_style, + }; + + ctx.parser.set_current_style(new_style); + }) + }); + + result + }) + .unwrap(), + )); + + Some(bindings) + } } diff --git a/src/lua/kernel.rs b/src/lua/kernel.rs index 470b3db..1a0bd30 100644 --- a/src/lua/kernel.rs +++ b/src/lua/kernel.rs @@ -1,11 +1,13 @@ -use std::cell::{RefCell, RefMut}; +use std::cell::RefCell; +use std::cell::RefMut; use mlua::Lua; -use crate::{document::document::Document, parser::{parser::Parser, source::Token}}; +use crate::document::document::Document; +use crate::parser::parser::Parser; +use crate::parser::source::Token; -pub struct KernelContext<'a, 'b> -{ +pub struct KernelContext<'a, 'b> { pub location: Token, pub parser: &'a dyn Parser, pub document: &'b dyn Document<'b>, @@ -13,34 +15,30 @@ pub struct KernelContext<'a, 'b> } thread_local! { - pub static CTX: RefCell>> = RefCell::new(None); + pub static CTX: RefCell>> = RefCell::new(None); } #[derive(Debug)] -pub struct Kernel -{ +pub struct Kernel { lua: Lua, } impl Kernel { - // TODO: Take parser as arg and + // TODO: Take parser as arg and // iterate over the rules // to find export the bindings (if some) - pub fn new(parser: &dyn Parser) -> Self { + pub fn new(parser: &dyn Parser) -> Self { let lua = Lua::new(); { let nml_table = lua.create_table().unwrap(); - for rule in parser.rules() - { - if let Some(bindings) = rule.lua_bindings(&lua) - { + for rule in parser.rules() { + if let Some(bindings) = rule.lua_bindings(&lua) { let table = lua.create_table().unwrap(); - let name = rule.name().to_lowercase(); + let name = rule.name().to_lowercase().replace(' ', "_"); - for (fun_name, fun) in bindings - { + for (fun_name, fun) in bindings { table.set(fun_name, fun).unwrap(); } @@ -51,16 +49,15 @@ impl Kernel { } Self { lua } - } + } /// Runs a procedure with a context /// /// This is the only way lua code shoule be ran, because exported /// functions may require the context in order to operate - pub fn run_with_context(&self, context: KernelContext, f: F) - -> T + pub fn run_with_context(&self, context: KernelContext, f: F) -> T where - F: FnOnce(&Lua) -> T + F: FnOnce(&Lua) -> T, { CTX.set(Some(unsafe { std::mem::transmute(context) })); let ret = f(&self.lua); @@ -70,8 +67,7 @@ impl Kernel { } } -pub trait KernelHolder -{ +pub trait KernelHolder { fn get_kernel(&self, name: &str) -> Option>; fn insert_kernel(&self, name: String, kernel: Kernel) -> RefMut<'_, Kernel>;