Compare commits
2 commits
8489796510
...
0982527944
Author | SHA1 | Date | |
---|---|---|---|
0982527944 | |||
90cf691737 |
10 changed files with 274 additions and 128 deletions
74
Cargo.lock
generated
74
Cargo.lock
generated
|
@ -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",
|
||||||
]
|
]
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -25,3 +25,8 @@ function make_doc(categories, title, page_title)
|
||||||
nml.variable.insert("compiler.output", page_title .. ".html")
|
nml.variable.insert("compiler.output", page_title .. ".html")
|
||||||
end
|
end
|
||||||
>@
|
>@
|
||||||
|
|
||||||
|
@@style.section = {
|
||||||
|
"link_pos": "Before",
|
||||||
|
"link": ["", "🔗 ", " "]
|
||||||
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ use super::compiler::Target;
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct NavEntry {
|
pub struct NavEntry {
|
||||||
pub(self) entries: Vec<(String, String)>,
|
pub(self) entries: Vec<(String, String, Option<String>)>,
|
||||||
pub(self) children: HashMap<String, NavEntry>,
|
pub(self) children: HashMap<String, NavEntry>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ impl NavEntry {
|
||||||
depth: usize,
|
depth: usize,
|
||||||
) {
|
) {
|
||||||
// Orphans = Links
|
// Orphans = Links
|
||||||
for (title, path) in &entry.entries {
|
for (title, path, _) in &entry.entries {
|
||||||
result.push_str(
|
result.push_str(
|
||||||
format!(
|
format!(
|
||||||
r#"<li><a href="{}">{}</a></li>"#,
|
r#"<li><a href="{}">{}</a></li>"#,
|
||||||
|
@ -75,6 +75,36 @@ impl NavEntry {
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets the insert index of the entry inside an already sorted entry list
|
||||||
|
fn sort_entry(
|
||||||
|
title: &String,
|
||||||
|
previous: &Option<String>,
|
||||||
|
entries: &Vec<(String, String, Option<String>)>,
|
||||||
|
) -> usize {
|
||||||
|
let mut insert_at = 0;
|
||||||
|
if let Some(previous) = &previous
|
||||||
|
// Using sort key
|
||||||
|
{
|
||||||
|
for (i, (ent_title, _, _)) in entries.iter().enumerate() {
|
||||||
|
if ent_title == previous {
|
||||||
|
insert_at = i + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then sort alphabetically
|
||||||
|
for (ent_title, _, ent_previous) in entries.iter().skip(insert_at) {
|
||||||
|
if (previous.is_some() && ent_previous != previous) || ent_title > title {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
insert_at += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
insert_at
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_navigation(docs: &Vec<CompiledDocument>) -> Result<NavEntry, String> {
|
pub fn create_navigation(docs: &Vec<CompiledDocument>) -> Result<NavEntry, String> {
|
||||||
|
@ -83,12 +113,16 @@ pub fn create_navigation(docs: &Vec<CompiledDocument>) -> Result<NavEntry, Strin
|
||||||
children: HashMap::new(),
|
children: HashMap::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// All paths (for duplicate checking)
|
||||||
|
let mut all_paths = HashMap::new();
|
||||||
|
|
||||||
for doc in docs {
|
for doc in docs {
|
||||||
let cat = doc.get_variable("nav.category");
|
let cat = doc.get_variable("nav.category");
|
||||||
let subcat = doc.get_variable("nav.subcategory");
|
let subcat = doc.get_variable("nav.subcategory");
|
||||||
let title = doc
|
let title = doc
|
||||||
.get_variable("nav.title")
|
.get_variable("nav.title")
|
||||||
.or(doc.get_variable("doc.title"));
|
.or(doc.get_variable("doc.title"));
|
||||||
|
let previous = doc.get_variable("nav.previous").map(|s| s.clone());
|
||||||
let path = doc.get_variable("compiler.output");
|
let path = doc.get_variable("compiler.output");
|
||||||
|
|
||||||
let (title, path) = match (title, path) {
|
let (title, path) = match (title, path) {
|
||||||
|
@ -142,8 +176,67 @@ pub fn create_navigation(docs: &Vec<CompiledDocument>) -> Result<NavEntry, Strin
|
||||||
&mut nav
|
&mut nav
|
||||||
};
|
};
|
||||||
|
|
||||||
pent.entries.push((title.clone(), path.clone()))
|
// Find duplicates titles in current parent
|
||||||
|
for (ent_title, _, _) in &pent.entries {
|
||||||
|
if ent_title == title {
|
||||||
|
return Err(format!(
|
||||||
|
"Conflicting entry title `{title}` for entries with the same parent: ({})",
|
||||||
|
pent.entries
|
||||||
|
.iter()
|
||||||
|
.map(|(title, _, _)| title.clone())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(", ")
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find duplicate paths
|
||||||
|
if let Some(dup_title) = all_paths.get(path) {
|
||||||
|
return Err(format!("Conflicting paths: `{path}`. Previously used for entry: `{dup_title}`, conflicting use in `{title}`"));
|
||||||
|
}
|
||||||
|
all_paths.insert(path.clone(), title.clone());
|
||||||
|
|
||||||
|
pent.entries.insert(
|
||||||
|
NavEntry::sort_entry(title, &previous, &pent.entries),
|
||||||
|
(title.clone(), path.clone(), previous),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(nav)
|
Ok(nav)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sort() {
|
||||||
|
let entries: Vec<(String, String, Option<String>)> = vec![
|
||||||
|
("Root".into(), "".into(), None),
|
||||||
|
("First".into(), "".into(), Some("Root".into())),
|
||||||
|
("1".into(), "".into(), Some("First".into())),
|
||||||
|
("2".into(), "".into(), Some("First".into())),
|
||||||
|
];
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
NavEntry::sort_entry(&"E".into(), &Some("Root".into()), &entries),
|
||||||
|
1
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
NavEntry::sort_entry(&"G".into(), &Some("Root".into()), &entries),
|
||||||
|
2
|
||||||
|
);
|
||||||
|
// Orphans
|
||||||
|
assert_eq!(NavEntry::sort_entry(&"Q".into(), &None, &entries), 0);
|
||||||
|
assert_eq!(NavEntry::sort_entry(&"S".into(), &None, &entries), 4);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
NavEntry::sort_entry(&"1.1".into(), &Some("First".into()), &entries),
|
||||||
|
3
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
NavEntry::sort_entry(&"2.1".into(), &Some("First".into()), &entries),
|
||||||
|
4
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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>)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,7 +81,7 @@ impl ReferenceRule {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
Self {
|
Self {
|
||||||
re: [Regex::new(r"§\{(.*)\}(\[((?:\\.|[^\\\\])*?)\])?").unwrap()],
|
re: [Regex::new(r"§\{(.*?)\}(\[((?:\\.|[^\\\\])*?)\])?").unwrap()],
|
||||||
properties: PropertyParser{ properties: props },
|
properties: PropertyParser{ properties: props },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,16 +46,17 @@ impl Element for Section {
|
||||||
match compiler.target() {
|
match compiler.target() {
|
||||||
Target::HTML => {
|
Target::HTML => {
|
||||||
// Section numbering
|
// Section numbering
|
||||||
let number = if (self.kind & section_kind::NO_NUMBER) == section_kind::NO_NUMBER {
|
let number = if (self.kind & section_kind::NO_NUMBER) != section_kind::NO_NUMBER {
|
||||||
let numbering = compiler.section_counter(self.depth);
|
let numbering = compiler.section_counter(self.depth);
|
||||||
let number = " ".to_string()
|
|
||||||
+ numbering
|
let mut result = String::new();
|
||||||
.iter()
|
for num in numbering.iter()
|
||||||
.map(|n| n.to_string())
|
{
|
||||||
.collect::<Vec<_>>()
|
result = result + num.to_string().as_str() + ".";
|
||||||
.join(".")
|
}
|
||||||
.as_str();
|
result += " ";
|
||||||
number
|
|
||||||
|
result
|
||||||
} else {
|
} else {
|
||||||
String::new()
|
String::new()
|
||||||
};
|
};
|
||||||
|
@ -71,8 +72,10 @@ impl Element for Section {
|
||||||
|
|
||||||
let refname = Compiler::refname(compiler.target(), self.title.as_str());
|
let refname = Compiler::refname(compiler.target(), self.title.as_str());
|
||||||
let link = format!(
|
let link = format!(
|
||||||
"<a class=\"section-link\" href=\"#{refname}\">{}</a>",
|
"{}<a class=\"section-link\" href=\"#{refname}\">{}</a>{}",
|
||||||
Compiler::sanitize(compiler.target(), self.style.link.as_str())
|
Compiler::sanitize(compiler.target(), self.style.link[0].as_str()),
|
||||||
|
Compiler::sanitize(compiler.target(), self.style.link[1].as_str()),
|
||||||
|
Compiler::sanitize(compiler.target(), self.style.link[2].as_str())
|
||||||
);
|
);
|
||||||
|
|
||||||
if self.style.link_pos == SectionLinkPos::After {
|
if self.style.link_pos == SectionLinkPos::After {
|
||||||
|
@ -123,7 +126,7 @@ impl ReferenceableElement for Section {
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(format!(
|
Ok(format!(
|
||||||
"<a class=\"section-ref\" href=\"#{}\">{caption}</a>",
|
"<a class=\"section-reference\" href=\"#{}\">{caption}</a>",
|
||||||
Compiler::refname(compiler.target(), self.title.as_str())
|
Compiler::refname(compiler.target(), self.title.as_str())
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -390,14 +393,14 @@ mod section_style {
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct SectionStyle {
|
pub struct SectionStyle {
|
||||||
pub link_pos: SectionLinkPos,
|
pub link_pos: SectionLinkPos,
|
||||||
pub link: String,
|
pub link: [String; 3],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for SectionStyle {
|
impl Default for SectionStyle {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
link_pos: SectionLinkPos::After,
|
link_pos: SectionLinkPos::Before,
|
||||||
link: "🔗".to_string(),
|
link: ["".into(), "🔗".into(), " ".into()],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::{cell::{RefCell, RefMut}, collections::HashMap, rc::Rc};
|
use std::{cell::{RefCell, RefMut}, collections::HashMap, rc::Rc};
|
||||||
|
|
||||||
use crate::{document::{document::Document, element::Element}, lua::kernel::{Kernel, KernelHolder}, parser::{parser::{Parser, ReportColors}, rule::Rule, source::{Cursor, Source}, state::StateHolder}};
|
use crate::{document::{document::Document, element::Element, style::{ElementStyle, StyleHolder}}, lua::kernel::{Kernel, KernelHolder}, parser::{parser::{Parser, ReportColors}, rule::Rule, source::{Cursor, Source}, state::StateHolder}};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct LineCursor
|
pub struct LineCursor
|
||||||
|
@ -146,3 +146,13 @@ impl KernelHolder for LsParser
|
||||||
self.get_kernel(name.as_str()).unwrap()
|
self.get_kernel(name.as_str()).unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl StyleHolder for LsParser {
|
||||||
|
fn styles(&self) -> std::cell::Ref<'_, HashMap<String, Rc<dyn ElementStyle>>> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn styles_mut(&self) -> RefMut<'_, HashMap<String, Rc<dyn ElementStyle>>> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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>,
|
||||||
|
@ -17,8 +19,7 @@ thread_local! {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Kernel
|
pub struct Kernel {
|
||||||
{
|
|
||||||
lua: Lua,
|
lua: Lua,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,15 +33,12 @@ impl Kernel {
|
||||||
{
|
{
|
||||||
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,10 +55,9 @@ impl Kernel {
|
||||||
///
|
///
|
||||||
/// 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>;
|
||||||
|
|
Loading…
Reference in a new issue