Bindings for style

This commit is contained in:
ef3d0c3e 2024-08-03 11:53:59 +02:00
parent 8489796510
commit 90cf691737
5 changed files with 143 additions and 108 deletions

74
Cargo.lock generated
View file

@ -56,7 +56,7 @@ checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.53", "syn 2.0.72",
] ]
[[package]] [[package]]
@ -67,7 +67,7 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.53", "syn 2.0.72",
] ]
[[package]] [[package]]
@ -277,6 +277,16 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 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]] [[package]]
name = "errno" name = "errno"
version = "0.3.9" version = "0.3.9"
@ -389,7 +399,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.53", "syn 2.0.72",
] ]
[[package]] [[package]]
@ -696,10 +706,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d111deb18a9c9bd33e1541309f4742523bfab01d276bfa9a27519f6de9c11dc7" checksum = "d111deb18a9c9bd33e1541309f4742523bfab01d276bfa9a27519f6de9c11dc7"
dependencies = [ dependencies = [
"bstr", "bstr",
"erased-serde",
"mlua-sys", "mlua-sys",
"num-traits", "num-traits",
"once_cell", "once_cell",
"rustc-hash", "rustc-hash",
"serde",
"serde-value",
] ]
[[package]] [[package]]
@ -802,6 +815,15 @@ dependencies = [
"pkg-config", "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]] [[package]]
name = "parking_lot_core" name = "parking_lot_core"
version = "0.9.10" version = "0.9.10"
@ -852,7 +874,7 @@ dependencies = [
"pest_meta", "pest_meta",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.53", "syn 2.0.72",
] ]
[[package]] [[package]]
@ -883,7 +905,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.53", "syn 2.0.72",
] ]
[[package]] [[package]]
@ -931,9 +953,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.79" version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
@ -949,9 +971,9 @@ dependencies = [
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.35" version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
@ -1159,6 +1181,16 @@ dependencies = [
"serde_derive", "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]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.204" version = "1.0.204"
@ -1167,7 +1199,7 @@ checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.53", "syn 2.0.72",
] ]
[[package]] [[package]]
@ -1189,7 +1221,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.53", "syn 2.0.72",
] ]
[[package]] [[package]]
@ -1231,9 +1263,9 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.53" version = "2.0.72"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032" checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -1291,7 +1323,7 @@ checksum = "d20468752b09f49e909e55a5d338caa8bedf615594e9d80bc4c565d30faf798c"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.53", "syn 2.0.72",
] ]
[[package]] [[package]]
@ -1371,7 +1403,7 @@ checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.53", "syn 2.0.72",
] ]
[[package]] [[package]]
@ -1438,7 +1470,7 @@ checksum = "84fd902d4e0b9a4b27f2f440108dc034e1758628a9b702f8ec61ad66355422fa"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.53", "syn 2.0.72",
] ]
[[package]] [[package]]
@ -1466,7 +1498,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.53", "syn 2.0.72",
] ]
[[package]] [[package]]
@ -1478,6 +1510,12 @@ dependencies = [
"once_cell", "once_cell",
] ]
[[package]]
name = "typeid"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "059d83cc991e7a42fc37bd50941885db0888e34209f8cfd9aab07ddec03bc9cf"
[[package]] [[package]]
name = "typenum" name = "typenum"
version = "1.17.0" version = "1.17.0"
@ -1723,5 +1761,5 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.53", "syn 2.0.72",
] ]

View file

@ -25,7 +25,7 @@ graphviz-rust = "0.9.0"
lazy_static = "1.5.0" lazy_static = "1.5.0"
lsp-server = "0.7.6" lsp-server = "0.7.6"
lsp-types = "0.97.0" 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" regex = "1.10.3"
rusqlite = "0.31.0" rusqlite = "0.31.0"
rust-crypto = "0.2.36" rust-crypto = "0.2.36"

View file

@ -20,6 +20,13 @@ pub trait ElementStyle: Downcast + core::fmt::Debug {
/// Serializes sytle into json string /// Serializes sytle into json string
fn to_json(&self) -> 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<Rc<dyn ElementStyle>, mlua::Error>;
} }
impl_downcast!(ElementStyle); impl_downcast!(ElementStyle);
@ -31,7 +38,7 @@ pub trait StyleHolder {
fn styles_mut(&self) -> RefMut<'_, HashMap<String, Rc<dyn ElementStyle>>>; fn styles_mut(&self) -> RefMut<'_, HashMap<String, Rc<dyn ElementStyle>>>;
/// Checks if a given style key is registered /// 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 /// Gets the current active style for an element
/// NOTE: Will panic if a style is not defined for a given 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 to_json(&self) -> String { serde_json::to_string(self).unwrap() }
fn from_lua(
&self,
lua: &mlua::Lua,
value: mlua::Value,
) -> Result<std::rc::Rc<dyn ElementStyle>, mlua::Error> {
mlua::LuaSerdeExt::from_value::<$t>(lua, value)
.map(|obj| std::rc::Rc::new(obj) as std::rc::Rc<dyn ElementStyle>)
}
} }
}; };
} }

View file

@ -1,16 +1,24 @@
use std::any::Any; use std::any::Any;
use std::ops::Range; use std::ops::Range;
use std::rc::Rc; use std::rc::Rc;
use std::sync::Arc;
use ariadne::Fmt; use ariadne::Fmt;
use ariadne::Label; use ariadne::Label;
use ariadne::Report; use ariadne::Report;
use ariadne::ReportKind; 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::Captures;
use regex::Regex; use regex::Regex;
use crate::document::document::Document; use crate::document::document::Document;
use crate::document::{self}; use crate::document::{self};
use crate::lua::kernel::CTX;
use crate::parser::parser::Parser; use crate::parser::parser::Parser;
use crate::parser::rule::RegexRule; use crate::parser::rule::RegexRule;
use crate::parser::rule::Rule; use crate::parser::rule::Rule;
@ -58,71 +66,6 @@ impl ElemStyleRule {
impl Rule for ElemStyleRule { impl Rule for ElemStyleRule {
fn name(&self) -> &'static str { "Element Style" } 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<Report<'_, (Rc<dyn Source>, Range<usize>)>> {
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<dyn Any>)> { fn next_match(&self, cursor: &Cursor) -> Option<(usize, Box<dyn Any>)> {
self.start_re self.start_re
.find_at(cursor.source.content(), cursor.pos) .find_at(cursor.source.content(), cursor.pos)
@ -164,7 +107,7 @@ impl Rule for ElemStyleRule {
} }
// Check if key exists // Check if key exists
if !parser.is_registered(trimmed) { if !parser.is_style_registered(trimmed) {
reports.push( reports.push(
Report::build(ReportKind::Error, cursor.source.clone(), key.start()) Report::build(ReportKind::Error, cursor.source.clone(), key.start())
.with_message("Unknown Style Key") .with_message("Unknown Style Key")
@ -240,4 +183,46 @@ impl Rule for ElemStyleRule {
(cursor, reports) (cursor, reports)
} }
fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> {
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)
}
} }

View file

@ -1,11 +1,13 @@
use std::cell::{RefCell, RefMut}; use std::cell::RefCell;
use std::cell::RefMut;
use mlua::Lua; 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 location: Token,
pub parser: &'a dyn Parser, pub parser: &'a dyn Parser,
pub document: &'b dyn Document<'b>, pub document: &'b dyn Document<'b>,
@ -13,34 +15,30 @@ pub struct KernelContext<'a, 'b>
} }
thread_local! { thread_local! {
pub static CTX: RefCell<Option<KernelContext<'static, 'static>>> = RefCell::new(None); pub static CTX: RefCell<Option<KernelContext<'static, 'static>>> = RefCell::new(None);
} }
#[derive(Debug)] #[derive(Debug)]
pub struct Kernel pub struct Kernel {
{
lua: Lua, lua: Lua,
} }
impl Kernel { impl Kernel {
// TODO: Take parser as arg and // TODO: Take parser as arg and
// iterate over the rules // iterate over the rules
// to find export the bindings (if some) // 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 lua = Lua::new();
{ {
let nml_table = lua.create_table().unwrap(); let nml_table = lua.create_table().unwrap();
for rule in parser.rules() for rule in parser.rules() {
{ if let Some(bindings) = rule.lua_bindings(&lua) {
if let Some(bindings) = rule.lua_bindings(&lua)
{
let table = lua.create_table().unwrap(); 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(); table.set(fun_name, fun).unwrap();
} }
@ -51,16 +49,15 @@ impl Kernel {
} }
Self { lua } Self { lua }
} }
/// Runs a procedure with a context /// Runs a procedure with a context
/// ///
/// This is the only way lua code shoule be ran, because exported /// This is the only way lua code shoule be ran, because exported
/// functions may require the context in order to operate /// functions may require the context in order to operate
pub fn run_with_context<T, F>(&self, context: KernelContext, f: F) pub fn run_with_context<T, F>(&self, context: KernelContext, f: F) -> T
-> T
where where
F: FnOnce(&Lua) -> T F: FnOnce(&Lua) -> T,
{ {
CTX.set(Some(unsafe { std::mem::transmute(context) })); CTX.set(Some(unsafe { std::mem::transmute(context) }));
let ret = f(&self.lua); let ret = f(&self.lua);
@ -70,8 +67,7 @@ impl Kernel {
} }
} }
pub trait KernelHolder pub trait KernelHolder {
{
fn get_kernel(&self, name: &str) -> Option<RefMut<'_, Kernel>>; fn get_kernel(&self, name: &str) -> Option<RefMut<'_, Kernel>>;
fn insert_kernel(&self, name: String, kernel: Kernel) -> RefMut<'_, Kernel>; fn insert_kernel(&self, name: String, kernel: Kernel) -> RefMut<'_, Kernel>;