Compare commits
No commits in common. "08ae603106743119c511d7be7a3e79f78b5de7c2" and "7a2c19af66c45911353133b096f08f094e308670" have entirely different histories.
08ae603106
...
7a2c19af66
28 changed files with 318 additions and 513 deletions
32
docs/external/graphviz.nml
vendored
32
docs/external/graphviz.nml
vendored
|
@ -1,32 +0,0 @@
|
||||||
@import ../template.nml
|
|
||||||
%<make_doc({"External Tools"}, "Graphviz", "Graphvis")>%
|
|
||||||
|
|
||||||
# Graphs from graphviz
|
|
||||||
|
|
||||||
[graph]
|
|
||||||
digraph {
|
|
||||||
bgcolor=transparent;
|
|
||||||
|
|
||||||
filelist [color=green, label="File List"];
|
|
||||||
doclist [color=green, label="Document List"];
|
|
||||||
iscached [shape=diamond, color=red, label="Cached?"];
|
|
||||||
parse [color=white, label=Parse];
|
|
||||||
compile [color=white, label=Compile];
|
|
||||||
cache [shape=box, color=blue, label=Cache];
|
|
||||||
|
|
||||||
edge [color=gray]
|
|
||||||
filelist -> iscached;
|
|
||||||
iscached -> cache[dir=both];
|
|
||||||
iscached -> doclist[label="+"];
|
|
||||||
|
|
||||||
iscached -> parse[label="No"];
|
|
||||||
parse -> compile;
|
|
||||||
compile -> cache[label="+"];
|
|
||||||
compile -> doclist[label="+"];
|
|
||||||
|
|
||||||
buildnav [color=white, label="Build Navigation"];
|
|
||||||
doclist -> buildnav;
|
|
||||||
output [color=white, label="Output"];
|
|
||||||
buildnav -> output;
|
|
||||||
}
|
|
||||||
[/graph]
|
|
5
docs/external/latex.nml
vendored
5
docs/external/latex.nml
vendored
|
@ -1,5 +1,8 @@
|
||||||
@import ../template.nml
|
@import ../template.nml
|
||||||
%<make_doc({"External Tools"}, "LaTeX", "LaTeX")>%
|
@compiler.output = latex.html
|
||||||
|
@nav.title = LaTeX
|
||||||
|
@nav.category = External Tools
|
||||||
|
@html.page_title = Documentation | LaTeX
|
||||||
|
|
||||||
@LaTeX = $|[kind=inline, caption=LaTeX]\LaTeX|$
|
@LaTeX = $|[kind=inline, caption=LaTeX]\LaTeX|$
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
@import template.nml
|
@import template.nml
|
||||||
%<make_doc({}, "Index", "Index")>%
|
@compiler.output = index.html
|
||||||
|
@nav.title = Documentation
|
||||||
|
@html.page_title = Documentation | Index
|
||||||
|
|
||||||
# Welcome to the NML documentation!
|
# Welcome to the NML documentation!
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
@import ../template.nml
|
@import ../template.nml
|
||||||
%<make_doc({"Lua"}, "Lua", "Lua Basics")>%
|
@compiler.output = lua.html
|
||||||
|
@nav.title = Lua
|
||||||
|
@nav.category = Lua
|
||||||
|
@html.page_title = Documentation | Lua
|
||||||
|
|
||||||
# Running lua code
|
# Running lua code
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
@import ../template.nml
|
@import ../template.nml
|
||||||
%<make_doc({"Styles"}, "Basic", "Basic Styles")>%
|
@compiler.output = basic.html
|
||||||
|
@nav.title = Basic
|
||||||
|
@nav.category = Styles
|
||||||
|
@html.page_title = Documentation | Basic Styles
|
||||||
|
|
||||||
# Basic styles
|
# Basic styles
|
||||||
## Bold
|
## Bold
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
@import ../template.nml
|
@import ../template.nml
|
||||||
%<make_doc({"Styles"}, "User-Defined", "User-Defined Styles")>%
|
@compiler.output = user-defined.html
|
||||||
|
@nav.title = User-Defined
|
||||||
|
@nav.category = Styles
|
||||||
|
@html.page_title = Documentation | User-Defined Styles
|
||||||
|
|
||||||
# TODO
|
# TODO
|
||||||
|
|
|
@ -6,22 +6,3 @@
|
||||||
\definecolor{__color1}{HTML}{d5d5d5} \\
|
\definecolor{__color1}{HTML}{d5d5d5} \\
|
||||||
\everymath{\color{__color1}\displaystyle}
|
\everymath{\color{__color1}\displaystyle}
|
||||||
@tex.main.block_prepend = \color{__color1}
|
@tex.main.block_prepend = \color{__color1}
|
||||||
|
|
||||||
@<
|
|
||||||
function make_doc(categories, title, page_title)
|
|
||||||
-- Navigation
|
|
||||||
nml.variable.insert("nav.title", title)
|
|
||||||
if categories[1] ~= nil
|
|
||||||
then
|
|
||||||
nml.variable.insert("nav.category", categories[1])
|
|
||||||
if categories[2] ~= nil
|
|
||||||
then
|
|
||||||
nml.variable.insert("nav.subcategory", categories[2])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- HTML
|
|
||||||
nml.variable.insert("html.page_title", "NML | " .. page_title)
|
|
||||||
nml.variable.insert("compiler.output", page_title .. ".html")
|
|
||||||
end
|
|
||||||
>@
|
|
||||||
|
|
|
@ -38,24 +38,6 @@ impl Compiler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sanitizes text for a [`Target`]
|
|
||||||
pub fn sanitize<S: AsRef<str>>(target: Target, str: S) -> String {
|
|
||||||
match target {
|
|
||||||
Target::HTML => str
|
|
||||||
.as_ref()
|
|
||||||
.replace("&", "&")
|
|
||||||
.replace("<", "<")
|
|
||||||
.replace(">", ">")
|
|
||||||
.replace("\"", """),
|
|
||||||
_ => todo!("Sanitize not implemented"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets a reference name
|
|
||||||
pub fn refname<S: AsRef<str>>(target: Target, str: S) -> String {
|
|
||||||
Self::sanitize(target, str).replace(' ', "_")
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Inserts or get a reference id for the compiled document
|
/// Inserts or get a reference id for the compiled document
|
||||||
///
|
///
|
||||||
/// # Parameters
|
/// # Parameters
|
||||||
|
@ -92,6 +74,18 @@ impl Compiler {
|
||||||
self.cache.as_ref().map(RefCell::borrow_mut)
|
self.cache.as_ref().map(RefCell::borrow_mut)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn sanitize<S: AsRef<str>>(target: Target, str: S) -> String {
|
||||||
|
match target {
|
||||||
|
Target::HTML => str
|
||||||
|
.as_ref()
|
||||||
|
.replace("&", "&")
|
||||||
|
.replace("<", "<")
|
||||||
|
.replace(">", ">")
|
||||||
|
.replace("\"", """),
|
||||||
|
_ => todo!("Sanitize not implemented"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn header(&self, document: &dyn Document) -> String {
|
pub fn header(&self, document: &dyn Document) -> String {
|
||||||
pub fn get_variable_or_error(
|
pub fn get_variable_or_error(
|
||||||
document: &dyn Document,
|
document: &dyn Document,
|
||||||
|
@ -115,11 +109,8 @@ impl Compiler {
|
||||||
result += "<!DOCTYPE HTML><html><head>";
|
result += "<!DOCTYPE HTML><html><head>";
|
||||||
result += "<meta charset=\"UTF-8\">";
|
result += "<meta charset=\"UTF-8\">";
|
||||||
if let Some(page_title) = get_variable_or_error(document, "html.page_title") {
|
if let Some(page_title) = get_variable_or_error(document, "html.page_title") {
|
||||||
result += format!(
|
result += format!("<title>{}</title>", Compiler::sanitize(self.target(), page_title.to_string()))
|
||||||
"<title>{}</title>",
|
.as_str();
|
||||||
Compiler::sanitize(self.target(), page_title.to_string())
|
|
||||||
)
|
|
||||||
.as_str();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(css) = document.get_variable("html.css") {
|
if let Some(css) = document.get_variable("html.css") {
|
||||||
|
@ -129,7 +120,7 @@ impl Compiler {
|
||||||
)
|
)
|
||||||
.as_str();
|
.as_str();
|
||||||
}
|
}
|
||||||
result += r#"</head><body><div class="layout">"#;
|
result += r#"</head><body><div id="layout">"#;
|
||||||
|
|
||||||
// TODO: TOC
|
// TODO: TOC
|
||||||
// TODO: Author, Date, Title, Div
|
// TODO: Author, Date, Title, Div
|
||||||
|
@ -157,7 +148,7 @@ impl Compiler {
|
||||||
let header = self.header(document);
|
let header = self.header(document);
|
||||||
|
|
||||||
// Body
|
// Body
|
||||||
let mut body = r#"<div class="content">"#.to_string();
|
let mut body = r#"<div id="content">"#.to_string();
|
||||||
for i in 0..borrow.len() {
|
for i in 0..borrow.len() {
|
||||||
let elem = &borrow[i];
|
let elem = &borrow[i];
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ impl NavEntry {
|
||||||
let mut result = String::new();
|
let mut result = String::new();
|
||||||
match target {
|
match target {
|
||||||
Target::HTML => {
|
Target::HTML => {
|
||||||
result += r#"<div class="navbar"><ul>"#;
|
result += r#"<div id="navbar"><ul>"#;
|
||||||
|
|
||||||
fn process(
|
fn process(
|
||||||
target: Target,
|
target: Target,
|
||||||
|
|
|
@ -544,7 +544,8 @@ impl RegexRule for CodeRule {
|
||||||
reports
|
reports
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> {
|
// TODO
|
||||||
|
fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Vec<(String, Function<'lua>)> {
|
||||||
let mut bindings = vec![];
|
let mut bindings = vec![];
|
||||||
bindings.push((
|
bindings.push((
|
||||||
"push_inline".to_string(),
|
"push_inline".to_string(),
|
||||||
|
@ -646,7 +647,7 @@ impl RegexRule for CodeRule {
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
));
|
));
|
||||||
|
|
||||||
Some(bindings)
|
bindings
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -80,5 +80,5 @@ impl RegexRule for CommentRule {
|
||||||
return reports;
|
return reports;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> { None }
|
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] }
|
||||||
}
|
}
|
||||||
|
|
|
@ -371,5 +371,5 @@ impl RegexRule for GraphRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> { None }
|
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] }
|
||||||
}
|
}
|
||||||
|
|
|
@ -178,5 +178,5 @@ impl RegexRule for ImportRule {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> { None }
|
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] }
|
||||||
}
|
}
|
||||||
|
|
|
@ -171,5 +171,5 @@ impl RegexRule for LinkRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> { None }
|
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] }
|
||||||
}
|
}
|
||||||
|
|
|
@ -337,5 +337,5 @@ impl Rule for ListRule
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> { None }
|
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] }
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,6 @@ use ariadne::Fmt;
|
||||||
use ariadne::Label;
|
use ariadne::Label;
|
||||||
use ariadne::Report;
|
use ariadne::Report;
|
||||||
use ariadne::ReportKind;
|
use ariadne::ReportKind;
|
||||||
use mlua::Function;
|
|
||||||
use mlua::Lua;
|
|
||||||
use regex::Captures;
|
use regex::Captures;
|
||||||
use regex::Match;
|
use regex::Match;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
@ -520,7 +518,9 @@ impl RegexRule for MediaRule {
|
||||||
reports
|
reports
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> { None }
|
fn lua_bindings<'lua>(&self, _lua: &'lua mlua::Lua) -> Vec<(String, mlua::Function<'lua>)> {
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -150,5 +150,5 @@ impl Rule for ParagraphRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> { None }
|
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] }
|
||||||
}
|
}
|
||||||
|
|
|
@ -231,7 +231,7 @@ impl RegexRule for RawRule {
|
||||||
reports
|
reports
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> {
|
fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Vec<(String, Function<'lua>)> {
|
||||||
let mut bindings = vec![];
|
let mut bindings = vec![];
|
||||||
|
|
||||||
bindings.push((
|
bindings.push((
|
||||||
|
@ -270,7 +270,7 @@ impl RegexRule for RawRule {
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
));
|
));
|
||||||
|
|
||||||
Some(bindings)
|
bindings
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,6 @@ use ariadne::Fmt;
|
||||||
use ariadne::Label;
|
use ariadne::Label;
|
||||||
use ariadne::Report;
|
use ariadne::Report;
|
||||||
use ariadne::ReportKind;
|
use ariadne::ReportKind;
|
||||||
use mlua::Function;
|
|
||||||
use mlua::Lua;
|
|
||||||
use regex::Captures;
|
use regex::Captures;
|
||||||
use regex::Match;
|
use regex::Match;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
@ -207,5 +205,7 @@ impl RegexRule for ReferenceRule {
|
||||||
reports
|
reports
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> { None }
|
fn lua_bindings<'lua>(&self, _lua: &'lua mlua::Lua) -> Vec<(String, mlua::Function<'lua>)> {
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -275,5 +275,5 @@ impl RegexRule for ScriptRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> { None }
|
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] }
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,14 +38,11 @@ impl Element for Section {
|
||||||
fn as_referenceable(&self) -> Option<&dyn ReferenceableElement> { Some(self) }
|
fn as_referenceable(&self) -> Option<&dyn ReferenceableElement> { Some(self) }
|
||||||
fn compile(&self, compiler: &Compiler, _document: &dyn Document) -> Result<String, String> {
|
fn compile(&self, compiler: &Compiler, _document: &dyn Document) -> Result<String, String> {
|
||||||
match compiler.target() {
|
match compiler.target() {
|
||||||
Target::HTML => {
|
Target::HTML => Ok(format!(
|
||||||
Ok(format!(
|
"<h{0}>{1}</h{0}>",
|
||||||
r#"<h{0} id="{1}">{2}</h{0}>"#,
|
|
||||||
self.depth,
|
self.depth,
|
||||||
Compiler::refname(compiler.target(), self.title.as_str()),
|
|
||||||
Compiler::sanitize(compiler.target(), self.title.as_str())
|
Compiler::sanitize(compiler.target(), self.title.as_str())
|
||||||
))
|
)),
|
||||||
},
|
|
||||||
Target::LATEX => Err("Unimplemented compiler".to_string()),
|
Target::LATEX => Err("Unimplemented compiler".to_string()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,27 +56,11 @@ impl ReferenceableElement for Section {
|
||||||
fn compile_reference(
|
fn compile_reference(
|
||||||
&self,
|
&self,
|
||||||
compiler: &Compiler,
|
compiler: &Compiler,
|
||||||
_document: &dyn Document,
|
document: &dyn Document,
|
||||||
reference: &super::reference::Reference,
|
reference: &super::reference::Reference,
|
||||||
_refid: usize,
|
refid: usize,
|
||||||
) -> Result<String, String> {
|
) -> Result<String, String> {
|
||||||
match compiler.target() {
|
todo!()
|
||||||
Target::HTML => {
|
|
||||||
let caption = reference.caption().map_or(
|
|
||||||
format!(
|
|
||||||
"({})",
|
|
||||||
Compiler::sanitize(compiler.target(), self.title.as_str())
|
|
||||||
),
|
|
||||||
|cap| cap.clone(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(format!(
|
|
||||||
"<a class=\"section-ref\" href=\"#{}\">{caption}</a>",
|
|
||||||
Compiler::refname(compiler.target(), self.title.as_str())
|
|
||||||
))
|
|
||||||
}
|
|
||||||
_ => todo!(""),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,7 +235,7 @@ impl RegexRule for SectionRule {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> {
|
fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Vec<(String, Function<'lua>)> {
|
||||||
let mut bindings = vec![];
|
let mut bindings = vec![];
|
||||||
|
|
||||||
bindings.push((
|
bindings.push((
|
||||||
|
@ -299,6 +280,6 @@ impl RegexRule for SectionRule {
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
));
|
));
|
||||||
|
|
||||||
Some(bindings)
|
bindings
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -183,5 +183,5 @@ impl RegexRule for StyleRule
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> { None }
|
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] }
|
||||||
}
|
}
|
||||||
|
|
|
@ -430,7 +430,7 @@ impl RegexRule for TexRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> { None }
|
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -61,7 +61,7 @@ impl Rule for TextRule {
|
||||||
panic!("Text cannot match");
|
panic!("Text cannot match");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> {
|
fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Vec<(String, Function<'lua>)> {
|
||||||
let mut bindings = vec![];
|
let mut bindings = vec![];
|
||||||
bindings.push((
|
bindings.push((
|
||||||
"push".to_string(),
|
"push".to_string(),
|
||||||
|
@ -83,6 +83,6 @@ impl Rule for TextRule {
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
));
|
));
|
||||||
|
|
||||||
Some(bindings)
|
bindings
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,109 +1,78 @@
|
||||||
use crate::document::document::Document;
|
use mlua::{Function, Lua};
|
||||||
use crate::document::variable::BaseVariable;
|
|
||||||
use crate::document::variable::PathVariable;
|
|
||||||
use crate::document::variable::Variable;
|
|
||||||
use crate::lua::kernel::CTX;
|
|
||||||
use crate::parser::parser::Parser;
|
|
||||||
use crate::parser::parser::ReportColors;
|
|
||||||
use crate::parser::rule::RegexRule;
|
|
||||||
use crate::parser::source::Source;
|
|
||||||
use crate::parser::source::Token;
|
|
||||||
use ariadne::Fmt;
|
|
||||||
use ariadne::Label;
|
|
||||||
use ariadne::Report;
|
|
||||||
use ariadne::ReportKind;
|
|
||||||
use mlua::Function;
|
|
||||||
use mlua::Lua;
|
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use std::ops::Range;
|
use crate::{document::document::Document, parser::{parser::{Parser, ReportColors}, rule::RegexRule, source::{Source, Token}}};
|
||||||
use std::rc::Rc;
|
use ariadne::{Report, Fmt, Label, ReportKind};
|
||||||
use std::str::FromStr;
|
use crate::document::variable::{BaseVariable, PathVariable, Variable};
|
||||||
|
use std::{ops::Range, rc::Rc};
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
||||||
enum VariableKind {
|
|
||||||
Regular,
|
|
||||||
Path,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromStr for VariableKind {
|
|
||||||
type Err = String;
|
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
||||||
match s {
|
|
||||||
"regular" | "" => Ok(VariableKind::Regular),
|
|
||||||
"path" | "'" => Ok(VariableKind::Path),
|
|
||||||
_ => Err(format!("Uknnown variable kind: `{s}`")),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct VariableRule {
|
pub struct VariableRule {
|
||||||
re: [Regex; 1],
|
re: [Regex; 1],
|
||||||
kinds: Vec<(String, String)>,
|
kinds: Vec<(String, String)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VariableRule {
|
impl VariableRule {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
re: [Regex::new(r"(?:^|\n)@([^[:alpha:]])?(.*?)=((?:\\\n|.)*)").unwrap()],
|
re: [Regex::new(r"(?:^|\n)@([^[:alpha:]])?(.*?)=((?:\\\n|.)*)").unwrap()],
|
||||||
kinds: vec![("".into(), "Regular".into()), ("'".into(), "Path".into())],
|
kinds: vec![
|
||||||
}
|
("".into(), "Regular".into()),
|
||||||
|
("'".into(), "Path".into())
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn make_variable(
|
pub fn make_variable(&self, colors: &ReportColors, location: Token, kind: usize, name: String, value: String) -> Result<Rc<dyn Variable>, String>
|
||||||
&self,
|
{
|
||||||
colors: &ReportColors,
|
match self.kinds[kind].0.as_str()
|
||||||
location: Token,
|
{
|
||||||
kind: usize,
|
"" => {
|
||||||
name: String,
|
Ok(Rc::new(BaseVariable::new(location, name, value)))
|
||||||
value: String,
|
}
|
||||||
) -> Result<Rc<dyn Variable>, String> {
|
"'" => {
|
||||||
match self.kinds[kind].0.as_str() {
|
match std::fs::canonicalize(value.as_str()) // TODO: not canonicalize
|
||||||
"" => Ok(Rc::new(BaseVariable::new(location, name, value))),
|
|
||||||
"'" => {
|
|
||||||
match std::fs::canonicalize(value.as_str()) // TODO: not canonicalize
|
|
||||||
{
|
{
|
||||||
Ok(path) => Ok(Rc::new(PathVariable::new(location, name, path))),
|
Ok(path) => Ok(Rc::new(PathVariable::new(location, name, path))),
|
||||||
Err(e) => Err(format!("Unable to canonicalize path `{}`: {}",
|
Err(e) => Err(format!("Unable to canonicalize path `{}`: {}",
|
||||||
value.fg(colors.highlight),
|
value.fg(colors.highlight),
|
||||||
e.to_string()))
|
e.to_string()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => panic!("Unhandled variable kind"),
|
_ => panic!("Unhandled variable kind")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trim and check variable name for validity
|
// Trim and check variable name for validity
|
||||||
pub fn validate_name<'a>(
|
pub fn validate_name<'a>(colors: &ReportColors, original_name: &'a str) -> Result<&'a str, String>
|
||||||
colors: &ReportColors,
|
{
|
||||||
original_name: &'a str,
|
let name = original_name.trim_start().trim_end();
|
||||||
) -> Result<&'a str, String> {
|
if name.contains("%")
|
||||||
let name = original_name.trim_start().trim_end();
|
{
|
||||||
if name.contains("%") {
|
return Err(format!("Name cannot contain '{}'",
|
||||||
return Err(format!("Name cannot contain '{}'", "%".fg(colors.info)));
|
"%".fg(colors.info)));
|
||||||
}
|
}
|
||||||
return Ok(name);
|
return Ok(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn validate_value(_colors: &ReportColors, original_value: &str) -> Result<String, String> {
|
pub fn validate_value(_colors: &ReportColors, original_value: &str) -> Result<String, String>
|
||||||
|
{
|
||||||
let mut escaped = 0usize;
|
let mut escaped = 0usize;
|
||||||
let mut result = String::new();
|
let mut result = String::new();
|
||||||
for c in original_value.trim_start().trim_end().chars() {
|
for c in original_value.trim_start().trim_end().chars() {
|
||||||
if c == '\\' {
|
if c == '\\' { escaped += 1 }
|
||||||
escaped += 1
|
else if c == '\n' {
|
||||||
} else if c == '\n' {
|
|
||||||
match escaped {
|
match escaped {
|
||||||
0 => return Err("Unknown error wile capturing variable".to_string()),
|
0 => return Err("Unknown error wile capturing variable".to_string()),
|
||||||
// Remove '\n'
|
// Remove '\n'
|
||||||
1 => {}
|
1 => {},
|
||||||
// Insert '\n'
|
// Insert '\n'
|
||||||
_ => {
|
_ => {
|
||||||
result.push(c);
|
result.push(c);
|
||||||
(0..escaped - 2).for_each(|_| result.push('\\'));
|
(0..escaped-2).for_each(|_| result.push('\\'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
escaped = 0;
|
escaped = 0;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
(0..escaped).for_each(|_| result.push('\\'));
|
(0..escaped).for_each(|_| result.push('\\'));
|
||||||
escaped = 0;
|
escaped = 0;
|
||||||
result.push(c);
|
result.push(c);
|
||||||
|
@ -112,7 +81,7 @@ impl VariableRule {
|
||||||
(0..escaped).for_each(|_| result.push('\\'));
|
(0..escaped).for_each(|_| result.push('\\'));
|
||||||
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RegexRule for VariableRule {
|
impl RegexRule for VariableRule {
|
||||||
|
@ -120,306 +89,233 @@ impl RegexRule for VariableRule {
|
||||||
|
|
||||||
fn regexes(&self) -> &[Regex] { &self.re }
|
fn regexes(&self) -> &[Regex] { &self.re }
|
||||||
|
|
||||||
fn on_regex_match<'a>(
|
fn on_regex_match<'a>(&self, _: usize, parser: &dyn Parser, document: &'a dyn Document, token: Token, matches: regex::Captures) -> Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>>
|
||||||
&self,
|
{
|
||||||
_: usize,
|
|
||||||
parser: &dyn Parser,
|
|
||||||
document: &'a dyn Document,
|
|
||||||
token: Token,
|
|
||||||
matches: regex::Captures,
|
|
||||||
) -> Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>> {
|
|
||||||
let mut result = vec![];
|
let mut result = vec![];
|
||||||
// [Optional] variable kind
|
// [Optional] variable kind
|
||||||
let var_kind = match matches.get(1) {
|
let var_kind = match matches.get(1)
|
||||||
|
{
|
||||||
Some(kind) => {
|
Some(kind) => {
|
||||||
// Find kind
|
// Find kind
|
||||||
let r = self
|
let r = self.kinds.iter().enumerate().find(|(_i, (ref char, ref _name))| {
|
||||||
.kinds
|
char == kind.as_str() });
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
.find(|(_i, (ref char, ref _name))| char == kind.as_str());
|
|
||||||
|
|
||||||
// Unknown kind specified
|
// Unknown kind specified
|
||||||
if r.is_none() {
|
if r.is_none()
|
||||||
result.push(
|
{
|
||||||
Report::build(ReportKind::Error, token.source(), kind.start())
|
result.push(
|
||||||
.with_message("Unknown variable kind")
|
Report::build(ReportKind::Error, token.source(), kind.start())
|
||||||
.with_label(
|
.with_message("Unknown variable kind")
|
||||||
Label::new((token.source(), kind.range()))
|
.with_label(
|
||||||
.with_message(format!(
|
Label::new((token.source(), kind.range()))
|
||||||
"Variable kind `{}` is unknown",
|
.with_message(format!("Variable kind `{}` is unknown",
|
||||||
kind.as_str().fg(parser.colors().highlight)
|
kind.as_str().fg(parser.colors().highlight)))
|
||||||
))
|
.with_color(parser.colors().error))
|
||||||
.with_color(parser.colors().error),
|
.with_help(format!("Leave empty for regular variables. Available variable kinds:{}",
|
||||||
)
|
self.kinds.iter().skip(1).fold("".to_string(), |acc, (char, name)| {
|
||||||
.with_help(format!(
|
acc + format!("\n - `{}` : {}",
|
||||||
"Leave empty for regular variables. Available variable kinds:{}",
|
char.fg(parser.colors().highlight),
|
||||||
self.kinds.iter().skip(1).fold(
|
name.fg(parser.colors().info)).as_str()
|
||||||
"".to_string(),
|
})))
|
||||||
|acc, (char, name)| {
|
.finish());
|
||||||
acc + format!(
|
|
||||||
"\n - `{}` : {}",
|
|
||||||
char.fg(parser.colors().highlight),
|
|
||||||
name.fg(parser.colors().info)
|
|
||||||
)
|
|
||||||
.as_str()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
))
|
|
||||||
.finish(),
|
|
||||||
);
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
r.unwrap().0
|
r.unwrap().0
|
||||||
}
|
}
|
||||||
None => 0,
|
None => 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
let var_name = match matches.get(2) {
|
let var_name = match matches.get(2)
|
||||||
Some(name) => match VariableRule::validate_name(&parser.colors(), name.as_str()) {
|
{
|
||||||
Ok(var_name) => var_name,
|
Some(name) => {
|
||||||
Err(msg) => {
|
match VariableRule::validate_name(&parser.colors(), name.as_str())
|
||||||
result.push(
|
{
|
||||||
Report::build(ReportKind::Error, token.source(), name.start())
|
Ok(var_name) => var_name,
|
||||||
.with_message("Invalid variable name")
|
Err(msg) => {
|
||||||
.with_label(
|
result.push(
|
||||||
Label::new((token.source(), name.range()))
|
Report::build(ReportKind::Error, token.source(), name.start())
|
||||||
.with_message(format!(
|
.with_message("Invalid variable name")
|
||||||
"Variable name `{}` is not allowed. {msg}",
|
.with_label(
|
||||||
name.as_str().fg(parser.colors().highlight)
|
Label::new((token.source(), name.range()))
|
||||||
))
|
.with_message(format!("Variable name `{}` is not allowed. {msg}",
|
||||||
.with_color(parser.colors().error),
|
name.as_str().fg(parser.colors().highlight)))
|
||||||
)
|
.with_color(parser.colors().error))
|
||||||
.finish(),
|
.finish());
|
||||||
);
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
},
|
||||||
},
|
}
|
||||||
_ => panic!("Unknown variable name"),
|
},
|
||||||
};
|
_ => panic!("Unknown variable name")
|
||||||
|
};
|
||||||
|
|
||||||
let var_value = match matches.get(3) {
|
let var_value = match matches.get(3)
|
||||||
Some(value) => match VariableRule::validate_value(&parser.colors(), value.as_str()) {
|
{
|
||||||
Ok(var_value) => var_value,
|
Some(value) => {
|
||||||
Err(msg) => {
|
match VariableRule::validate_value(&parser.colors(), value.as_str())
|
||||||
result.push(
|
{
|
||||||
Report::build(ReportKind::Error, token.source(), value.start())
|
Ok(var_value) => var_value,
|
||||||
.with_message("Invalid variable value")
|
Err(msg ) => {
|
||||||
.with_label(
|
result.push(
|
||||||
Label::new((token.source(), value.range()))
|
Report::build(ReportKind::Error, token.source(), value.start())
|
||||||
.with_message(format!(
|
.with_message("Invalid variable value")
|
||||||
"Variable value `{}` is not allowed. {msg}",
|
.with_label(
|
||||||
value.as_str().fg(parser.colors().highlight)
|
Label::new((token.source(), value.range()))
|
||||||
))
|
.with_message(format!("Variable value `{}` is not allowed. {msg}",
|
||||||
.with_color(parser.colors().error),
|
value.as_str().fg(parser.colors().highlight)))
|
||||||
)
|
.with_color(parser.colors().error))
|
||||||
.finish(),
|
.finish());
|
||||||
);
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
_ => panic!("Invalid variable value"),
|
}
|
||||||
};
|
_ => panic!("Invalid variable value")
|
||||||
|
};
|
||||||
|
|
||||||
match self.make_variable(
|
match self.make_variable(&parser.colors(), token.clone(), var_kind, var_name.to_string(), var_value)
|
||||||
&parser.colors(),
|
{
|
||||||
token.clone(),
|
Ok(variable) => document.add_variable(variable),
|
||||||
var_kind,
|
Err(msg) => {
|
||||||
var_name.to_string(),
|
let m = matches.get(0).unwrap();
|
||||||
var_value,
|
result.push(
|
||||||
) {
|
Report::build(ReportKind::Error, token.source(), m.start())
|
||||||
Ok(variable) => document.add_variable(variable),
|
.with_message("Unable to create variable")
|
||||||
Err(msg) => {
|
.with_label(
|
||||||
let m = matches.get(0).unwrap();
|
Label::new((token.source(), m.start()+1 .. m.end() ))
|
||||||
result.push(
|
.with_message(format!("Unable to create variable `{}`. {}",
|
||||||
Report::build(ReportKind::Error, token.source(), m.start())
|
var_name.fg(parser.colors().highlight),
|
||||||
.with_message("Unable to create variable")
|
msg))
|
||||||
.with_label(
|
.with_color(parser.colors().error))
|
||||||
Label::new((token.source(), m.start() + 1..m.end()))
|
.finish());
|
||||||
.with_message(format!(
|
|
||||||
"Unable to create variable `{}`. {}",
|
|
||||||
var_name.fg(parser.colors().highlight),
|
|
||||||
msg
|
|
||||||
))
|
|
||||||
.with_color(parser.colors().error),
|
|
||||||
)
|
|
||||||
.finish(),
|
|
||||||
);
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> {
|
// TODO
|
||||||
let mut bindings = vec![];
|
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] }
|
||||||
bindings.push((
|
|
||||||
"insert".to_string(),
|
|
||||||
lua.create_function(|_, (name, value): (String, String)| {
|
|
||||||
CTX.with_borrow(|ctx| {
|
|
||||||
ctx.as_ref().map(|ctx| {
|
|
||||||
let var = Rc::new(BaseVariable::new(ctx.location.clone(), name, value));
|
|
||||||
ctx.document.add_variable(var);
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
})
|
|
||||||
.unwrap(),
|
|
||||||
));
|
|
||||||
bindings.push((
|
|
||||||
"get".to_string(),
|
|
||||||
lua.create_function(|_, name: String| {
|
|
||||||
let mut value: Option<String> = None;
|
|
||||||
CTX.with_borrow(|ctx| {
|
|
||||||
ctx.as_ref().map(|ctx| {
|
|
||||||
if let Some(var) = ctx.document.get_variable(name.as_str())
|
|
||||||
{
|
|
||||||
value = Some(var.to_string());
|
|
||||||
}
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok(value)
|
|
||||||
})
|
|
||||||
.unwrap(),
|
|
||||||
));
|
|
||||||
|
|
||||||
Some(bindings)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct VariableSubstitutionRule {
|
pub struct VariableSubstitutionRule
|
||||||
|
{
|
||||||
re: [Regex; 1],
|
re: [Regex; 1],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VariableSubstitutionRule {
|
impl VariableSubstitutionRule {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
re: [Regex::new(r"%(.*?)%").unwrap()],
|
re: [Regex::new(r"%(.*?)%").unwrap()],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RegexRule for VariableSubstitutionRule {
|
impl RegexRule for VariableSubstitutionRule
|
||||||
fn name(&self) -> &'static str { "Variable Substitution" }
|
{
|
||||||
|
fn name(&self) -> &'static str { "Variable Substitution" }
|
||||||
|
|
||||||
fn regexes(&self) -> &[regex::Regex] { &self.re }
|
fn regexes(&self) -> &[regex::Regex] { &self.re }
|
||||||
|
|
||||||
fn on_regex_match<'a>(
|
fn on_regex_match<'a>(&self, _index: usize, parser: &dyn Parser, document: &'a dyn Document<'a>, token: Token, matches: regex::Captures) -> Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>> {
|
||||||
&self,
|
|
||||||
_index: usize,
|
|
||||||
parser: &dyn Parser,
|
|
||||||
document: &'a dyn Document<'a>,
|
|
||||||
token: Token,
|
|
||||||
matches: regex::Captures,
|
|
||||||
) -> Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>> {
|
|
||||||
let mut result = vec![];
|
let mut result = vec![];
|
||||||
|
|
||||||
let variable = match matches.get(1) {
|
let variable = match matches.get(1)
|
||||||
Some(name) => {
|
{
|
||||||
// Empty name
|
Some(name) => {
|
||||||
if name.as_str().is_empty() {
|
// Empty name
|
||||||
result.push(
|
if name.as_str().is_empty()
|
||||||
Report::build(ReportKind::Error, token.source(), name.start())
|
{
|
||||||
.with_message("Empty variable name")
|
result.push(
|
||||||
.with_label(
|
Report::build(ReportKind::Error, token.source(), name.start())
|
||||||
Label::new((token.source(), matches.get(0).unwrap().range()))
|
.with_message("Empty variable name")
|
||||||
.with_message(format!("Missing variable name for substitution"))
|
.with_label(
|
||||||
.with_color(parser.colors().error),
|
Label::new((token.source(), matches.get(0).unwrap().range()))
|
||||||
)
|
.with_message(format!("Missing variable name for substitution"))
|
||||||
.finish(),
|
.with_color(parser.colors().error))
|
||||||
);
|
.finish());
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
// Leading spaces
|
// Leading spaces
|
||||||
else if name.as_str().trim_start() != name.as_str() {
|
else if name.as_str().trim_start() != name.as_str()
|
||||||
result.push(
|
{
|
||||||
Report::build(ReportKind::Error, token.source(), name.start())
|
result.push(
|
||||||
.with_message("Invalid variable name")
|
Report::build(ReportKind::Error, token.source(), name.start())
|
||||||
.with_label(
|
.with_message("Invalid variable name")
|
||||||
Label::new((token.source(), name.range()))
|
.with_label(
|
||||||
.with_message(format!("Variable names contains leading spaces"))
|
Label::new((token.source(), name.range()))
|
||||||
.with_color(parser.colors().error),
|
.with_message(format!("Variable names contains leading spaces"))
|
||||||
)
|
.with_color(parser.colors().error))
|
||||||
.with_help("Remove leading spaces")
|
.with_help("Remove leading spaces")
|
||||||
.finish(),
|
.finish());
|
||||||
);
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
// Trailing spaces
|
// Trailing spaces
|
||||||
else if name.as_str().trim_end() != name.as_str() {
|
else if name.as_str().trim_end() != name.as_str()
|
||||||
result.push(
|
{
|
||||||
Report::build(ReportKind::Error, token.source(), name.start())
|
result.push(
|
||||||
.with_message("Invalid variable name")
|
Report::build(ReportKind::Error, token.source(), name.start())
|
||||||
.with_label(
|
.with_message("Invalid variable name")
|
||||||
Label::new((token.source(), name.range()))
|
.with_label(
|
||||||
.with_message(format!(
|
Label::new((token.source(), name.range()))
|
||||||
"Variable names contains trailing spaces"
|
.with_message(format!("Variable names contains trailing spaces"))
|
||||||
))
|
.with_color(parser.colors().error))
|
||||||
.with_color(parser.colors().error),
|
.with_help("Remove trailing spaces")
|
||||||
)
|
.finish());
|
||||||
.with_help("Remove trailing spaces")
|
|
||||||
.finish(),
|
|
||||||
);
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
// Invalid name
|
// Invalid name
|
||||||
match VariableRule::validate_name(&parser.colors(), name.as_str()) {
|
match VariableRule::validate_name(&parser.colors(), name.as_str())
|
||||||
Err(msg) => {
|
{
|
||||||
|
Err(msg) =>
|
||||||
|
{
|
||||||
result.push(
|
result.push(
|
||||||
Report::build(ReportKind::Error, token.source(), name.start())
|
Report::build(ReportKind::Error, token.source(), name.start())
|
||||||
.with_message("Invalid variable name")
|
.with_message("Invalid variable name")
|
||||||
.with_label(
|
.with_label(
|
||||||
Label::new((token.source(), name.range()))
|
Label::new((token.source(), name.range()))
|
||||||
.with_message(msg)
|
.with_message(msg)
|
||||||
.with_color(parser.colors().error),
|
.with_color(parser.colors().error))
|
||||||
)
|
.finish());
|
||||||
.finish(),
|
|
||||||
);
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get variable
|
// Get variable
|
||||||
match document.get_variable(name.as_str()) {
|
match document.get_variable(name.as_str())
|
||||||
None => {
|
{
|
||||||
result.push(
|
None => {
|
||||||
Report::build(ReportKind::Error, token.source(), name.start())
|
result.push(
|
||||||
.with_message("Unknown variable name")
|
Report::build(ReportKind::Error, token.source(), name.start())
|
||||||
.with_label(
|
.with_message("Unknown variable name")
|
||||||
Label::new((token.source(), name.range()))
|
.with_label(
|
||||||
.with_message(format!(
|
Label::new((token.source(), name.range()))
|
||||||
"Unable to find variable with name: `{}`",
|
.with_message(format!("Unable to find variable with name: `{}`",
|
||||||
name.as_str().fg(parser.colors().highlight)
|
name.as_str().fg(parser.colors().highlight)))
|
||||||
))
|
.with_color(parser.colors().error))
|
||||||
.with_color(parser.colors().error),
|
.finish());
|
||||||
)
|
return result;
|
||||||
.finish(),
|
}
|
||||||
);
|
Some(var) => var,
|
||||||
return result;
|
}
|
||||||
}
|
},
|
||||||
Some(var) => var,
|
_ => panic!("Unknown error")
|
||||||
}
|
};
|
||||||
}
|
|
||||||
_ => panic!("Unknown error"),
|
|
||||||
};
|
|
||||||
|
|
||||||
variable.parse(token, parser, document);
|
variable.parse(token, parser, document);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> { None }
|
// TODO
|
||||||
|
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] }
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,18 +34,15 @@ impl Kernel {
|
||||||
|
|
||||||
for rule in parser.rules()
|
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();
|
||||||
|
|
||||||
|
for (fun_name, fun) in rule.lua_bindings(&lua)
|
||||||
{
|
{
|
||||||
let table = lua.create_table().unwrap();
|
table.set(fun_name, fun).unwrap();
|
||||||
let name = rule.name().to_lowercase();
|
|
||||||
|
|
||||||
for (fun_name, fun) in bindings
|
|
||||||
{
|
|
||||||
table.set(fun_name, fun).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
nml_table.set(name, table).unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nml_table.set(name, table).unwrap();
|
||||||
}
|
}
|
||||||
lua.globals().set("nml", nml_table).unwrap();
|
lua.globals().set("nml", nml_table).unwrap();
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ pub trait Rule {
|
||||||
match_data: Option<Box<dyn Any>>,
|
match_data: Option<Box<dyn Any>>,
|
||||||
) -> (Cursor, Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>>);
|
) -> (Cursor, Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>>);
|
||||||
/// Export bindings to lua
|
/// Export bindings to lua
|
||||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>>;
|
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl core::fmt::Debug for dyn Rule {
|
impl core::fmt::Debug for dyn Rule {
|
||||||
|
@ -89,7 +89,7 @@ pub trait RegexRule {
|
||||||
matches: regex::Captures,
|
matches: regex::Captures,
|
||||||
) -> Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>>;
|
) -> Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>>;
|
||||||
|
|
||||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>>;
|
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: RegexRule> Rule for T {
|
impl<T: RegexRule> Rule for T {
|
||||||
|
@ -144,7 +144,7 @@ impl<T: RegexRule> Rule for T {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> {
|
fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Vec<(String, Function<'lua>)> {
|
||||||
self.lua_bindings(lua)
|
self.lua_bindings(lua)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
52
style.css
52
style.css
|
@ -2,19 +2,9 @@ body {
|
||||||
background-color: #1b1b1d;
|
background-color: #1b1b1d;
|
||||||
color: #c5c5c5;
|
color: #c5c5c5;
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.layout {
|
max-width: 90ch;
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
|
||||||
max-width: 99ch;
|
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
padding: 0;
|
|
||||||
width: 100%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Styles */
|
/* Styles */
|
||||||
|
@ -39,18 +29,13 @@ a.inline-code {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Navbar */
|
/* Navbar */
|
||||||
.navbar {
|
#navbar {
|
||||||
display: none;
|
|
||||||
|
|
||||||
left: 0;
|
left: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
width: max(calc((100vw - 99ch) / 2 - 15vw), 24ch);
|
width: max(16vw, 20ch);
|
||||||
height: 100vh;
|
|
||||||
position: fixed;
|
|
||||||
margin-right: 1em;
|
|
||||||
|
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
position: absolute;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
overscroll-behavior-y: contain;
|
overscroll-behavior-y: contain;
|
||||||
|
|
||||||
|
@ -61,53 +46,44 @@ a.inline-code {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 130ch) {
|
#navbar a {
|
||||||
.navbar {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
.container {
|
|
||||||
flex-direction: row;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.navbar a {
|
|
||||||
color: #ffb454;
|
color: #ffb454;
|
||||||
|
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar li {
|
#navbar li {
|
||||||
display: block;
|
display: block;
|
||||||
position: relative;
|
position: relative;
|
||||||
padding-left: 1em;
|
padding-left: 1em;
|
||||||
margin-left: 0em;
|
margin-left: 0em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar ul {
|
#navbar ul {
|
||||||
margin-left: 0em;
|
margin-left: 0em;
|
||||||
padding-left: 0;
|
padding-left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar summary{
|
#navbar summary{
|
||||||
display: block;
|
display: block;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar summary::marker,
|
#navbar summary::marker,
|
||||||
.navbar summary::-webkit-details-marker{
|
#navbar summary::-webkit-details-marker{
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar summary:focus{
|
#navbar summary:focus{
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar summary:focus-visible{
|
#navbar summary:focus-visible{
|
||||||
outline: 1px dotted #000;
|
outline: 1px dotted #000;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar summary:before {
|
#navbar summary:before {
|
||||||
content: "+";
|
content: "+";
|
||||||
color: #ffb454;
|
color: #ffb454;
|
||||||
float: left;
|
float: left;
|
||||||
|
@ -115,7 +91,7 @@ a.inline-code {
|
||||||
width: 1em;
|
width: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar details[open] > summary:before {
|
#navbar details[open] > summary:before {
|
||||||
content: "–";
|
content: "–";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue