Added bindings & tests
This commit is contained in:
parent
35408f03b1
commit
b3b99c4069
10 changed files with 321 additions and 52 deletions
4
src/cache/cache.rs
vendored
4
src/cache/cache.rs
vendored
|
@ -23,7 +23,7 @@ pub trait Cached {
|
||||||
|
|
||||||
fn key(&self) -> <Self as Cached>::Key;
|
fn key(&self) -> <Self as Cached>::Key;
|
||||||
|
|
||||||
fn init(con: &mut Connection) -> Result<(), rusqlite::Error> {
|
fn init(con: &Connection) -> Result<(), rusqlite::Error> {
|
||||||
con.execute(<Self as Cached>::sql_table(), ()).map(|_| ())
|
con.execute(<Self as Cached>::sql_table(), ()).map(|_| ())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ pub trait Cached {
|
||||||
/// Note that on error, [`f`] may still have been called
|
/// Note that on error, [`f`] may still have been called
|
||||||
fn cached<E, F>(
|
fn cached<E, F>(
|
||||||
&self,
|
&self,
|
||||||
con: &mut Connection,
|
con: &Connection,
|
||||||
f: F,
|
f: F,
|
||||||
) -> Result<<Self as Cached>::Value, CachedError<E>>
|
) -> Result<<Self as Cached>::Value, CachedError<E>>
|
||||||
where
|
where
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use std::cell::Ref;
|
use std::cell::Ref;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::cell::RefMut;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
@ -20,27 +19,20 @@ pub enum Target {
|
||||||
LATEX,
|
LATEX,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Compiler {
|
pub struct Compiler<'a> {
|
||||||
target: Target,
|
target: Target,
|
||||||
cache: Option<RefCell<Connection>>,
|
cache: Option<&'a Connection>,
|
||||||
reference_count: RefCell<HashMap<String, HashMap<String, usize>>>,
|
reference_count: RefCell<HashMap<String, HashMap<String, usize>>>,
|
||||||
sections_counter: RefCell<Vec<usize>>,
|
sections_counter: RefCell<Vec<usize>>,
|
||||||
|
|
||||||
unresolved_references: RefCell<Vec<(usize, CrossReference)>>,
|
unresolved_references: RefCell<Vec<(usize, CrossReference)>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Compiler {
|
impl<'a> Compiler<'a> {
|
||||||
pub fn new(target: Target, db_path: Option<String>) -> Self {
|
pub fn new(target: Target, con: Option<&'a Connection>) -> Self {
|
||||||
let cache = match db_path {
|
|
||||||
None => None,
|
|
||||||
Some(path) => match Connection::open(path) {
|
|
||||||
Err(e) => panic!("Cannot connect to database: {e}"),
|
|
||||||
Ok(con) => Some(con),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
Self {
|
Self {
|
||||||
target,
|
target,
|
||||||
cache: cache.map(|con| RefCell::new(con)),
|
cache: con,
|
||||||
reference_count: RefCell::new(HashMap::new()),
|
reference_count: RefCell::new(HashMap::new()),
|
||||||
sections_counter: RefCell::new(vec![]),
|
sections_counter: RefCell::new(vec![]),
|
||||||
unresolved_references: RefCell::new(vec![]),
|
unresolved_references: RefCell::new(vec![]),
|
||||||
|
@ -94,7 +86,7 @@ impl Compiler {
|
||||||
///
|
///
|
||||||
/// # Parameters
|
/// # Parameters
|
||||||
/// - [`reference`] The reference to get or insert
|
/// - [`reference`] The reference to get or insert
|
||||||
pub fn reference_id<'a>(&self, document: &'a dyn Document, reference: ElemReference) -> usize {
|
pub fn reference_id<'b>(&self, document: &'b dyn Document, reference: ElemReference) -> usize {
|
||||||
let mut borrow = self.reference_count.borrow_mut();
|
let mut borrow = self.reference_count.borrow_mut();
|
||||||
let reference = document.get_from_reference(&reference).unwrap();
|
let reference = document.get_from_reference(&reference).unwrap();
|
||||||
let refkey = reference.refcount_key();
|
let refkey = reference.refcount_key();
|
||||||
|
@ -129,8 +121,9 @@ impl Compiler {
|
||||||
|
|
||||||
pub fn target(&self) -> Target { self.target }
|
pub fn target(&self) -> Target { self.target }
|
||||||
|
|
||||||
pub fn cache(&self) -> Option<RefMut<'_, Connection>> {
|
pub fn cache(&self) -> Option<&'a Connection> {
|
||||||
self.cache.as_ref().map(RefCell::borrow_mut)
|
self.cache
|
||||||
|
//self.cache.as_ref().map(RefCell::borrow_mut)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn header(&self, document: &dyn Document) -> String {
|
pub fn header(&self, document: &dyn Document) -> String {
|
||||||
|
|
|
@ -221,7 +221,9 @@ mod tests {
|
||||||
use rand::rngs::OsRng;
|
use rand::rngs::OsRng;
|
||||||
use rand::RngCore;
|
use rand::RngCore;
|
||||||
|
|
||||||
use super::*;
|
use crate::compiler::process::process_from_memory;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn sort() {
|
fn sort() {
|
||||||
|
@ -244,4 +246,54 @@ mod tests {
|
||||||
assert_eq!(shuffled, entries);
|
assert_eq!(shuffled, entries);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn batch() {
|
||||||
|
let result = process_from_memory(
|
||||||
|
Target::HTML,
|
||||||
|
vec![
|
||||||
|
r#"
|
||||||
|
@html.page_title = 0
|
||||||
|
@compiler.output = 0.html
|
||||||
|
@nav.title = C
|
||||||
|
@nav.category = First
|
||||||
|
"#
|
||||||
|
.into(),
|
||||||
|
r#"
|
||||||
|
@html.page_title = 1
|
||||||
|
@compiler.output = 1.html
|
||||||
|
@nav.title = A
|
||||||
|
@nav.category = First
|
||||||
|
"#
|
||||||
|
.into(),
|
||||||
|
r#"
|
||||||
|
@html.page_title = 2
|
||||||
|
@compiler.output = 2.html
|
||||||
|
@nav.title = B
|
||||||
|
@nav.category = First
|
||||||
|
"#
|
||||||
|
.into(),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let nav = create_navigation(&result).unwrap();
|
||||||
|
assert_eq!(nav.children.get("First").unwrap().entries, vec![
|
||||||
|
(
|
||||||
|
"A".to_string(),
|
||||||
|
"1.html".to_string(),
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"B".to_string(),
|
||||||
|
"2.html".to_string(),
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"C".to_string(),
|
||||||
|
"0.html".to_string(),
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,7 +102,7 @@ pub fn process(
|
||||||
let doc = parse(&parser, Rc::new(source), debug_opts)?;
|
let doc = parse(&parser, Rc::new(source), debug_opts)?;
|
||||||
|
|
||||||
// Compile
|
// Compile
|
||||||
let compiler = Compiler::new(target, db_path.clone());
|
let compiler = Compiler::new(target, Some(&con));
|
||||||
let (mut compiled, postprocess) = compiler.compile(&*doc);
|
let (mut compiled, postprocess) = compiler.compile(&*doc);
|
||||||
|
|
||||||
compiled.mtime = modified.duration_since(UNIX_EPOCH).unwrap().as_secs();
|
compiled.mtime = modified.duration_since(UNIX_EPOCH).unwrap().as_secs();
|
||||||
|
|
|
@ -268,15 +268,15 @@ impl Element for Code {
|
||||||
Target::HTML => {
|
Target::HTML => {
|
||||||
static CACHE_INIT: Once = Once::new();
|
static CACHE_INIT: Once = Once::new();
|
||||||
CACHE_INIT.call_once(|| {
|
CACHE_INIT.call_once(|| {
|
||||||
if let Some(mut con) = compiler.cache() {
|
if let Some(con) = compiler.cache() {
|
||||||
if let Err(e) = Code::init(&mut con) {
|
if let Err(e) = Code::init(con) {
|
||||||
eprintln!("Unable to create cache table: {e}");
|
eprintln!("Unable to create cache table: {e}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Some(mut con) = compiler.cache() {
|
if let Some(con) = compiler.cache() {
|
||||||
match self.cached(&mut con, |s| s.highlight_html(compiler)) {
|
match self.cached(con, |s| s.highlight_html(compiler)) {
|
||||||
Ok(s) => Ok(s),
|
Ok(s) => Ok(s),
|
||||||
Err(e) => match e {
|
Err(e) => match e {
|
||||||
CachedError::SqlErr(e) => {
|
CachedError::SqlErr(e) => {
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
use std::sync::Arc;
|
||||||
use std::sync::Once;
|
use std::sync::Once;
|
||||||
|
|
||||||
|
use crate::lua::kernel::CTX;
|
||||||
use crate::parser::parser::ParserState;
|
use crate::parser::parser::ParserState;
|
||||||
use crate::parser::util::Property;
|
use crate::parser::util::Property;
|
||||||
use crate::parser::util::PropertyMapError;
|
use crate::parser::util::PropertyMapError;
|
||||||
|
@ -16,6 +18,9 @@ use crypto::sha2::Sha512;
|
||||||
use graphviz_rust::cmd::Format;
|
use graphviz_rust::cmd::Format;
|
||||||
use graphviz_rust::cmd::Layout;
|
use graphviz_rust::cmd::Layout;
|
||||||
use graphviz_rust::exec_dot;
|
use graphviz_rust::exec_dot;
|
||||||
|
use mlua::Error::BadArgument;
|
||||||
|
use mlua::Function;
|
||||||
|
use mlua::Lua;
|
||||||
use regex::Captures;
|
use regex::Captures;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
|
||||||
|
@ -111,21 +116,26 @@ impl Element for Graphviz {
|
||||||
|
|
||||||
fn element_name(&self) -> &'static str { "Graphviz" }
|
fn element_name(&self) -> &'static str { "Graphviz" }
|
||||||
|
|
||||||
fn compile(&self, compiler: &Compiler, _document: &dyn Document, _cursor: usize) -> Result<String, String> {
|
fn compile(
|
||||||
|
&self,
|
||||||
|
compiler: &Compiler,
|
||||||
|
_document: &dyn Document,
|
||||||
|
_cursor: usize,
|
||||||
|
) -> Result<String, String> {
|
||||||
match compiler.target() {
|
match compiler.target() {
|
||||||
Target::HTML => {
|
Target::HTML => {
|
||||||
static CACHE_INIT: Once = Once::new();
|
static CACHE_INIT: Once = Once::new();
|
||||||
CACHE_INIT.call_once(|| {
|
CACHE_INIT.call_once(|| {
|
||||||
if let Some(mut con) = compiler.cache() {
|
if let Some(con) = compiler.cache() {
|
||||||
if let Err(e) = Graphviz::init(&mut con) {
|
if let Err(e) = Graphviz::init(con) {
|
||||||
eprintln!("Unable to create cache table: {e}");
|
eprintln!("Unable to create cache table: {e}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// TODO: Format svg in a div
|
// TODO: Format svg in a div
|
||||||
|
|
||||||
if let Some(mut con) = compiler.cache() {
|
if let Some(con) = compiler.cache() {
|
||||||
match self.cached(&mut con, |s| s.dot_to_svg()) {
|
match self.cached(con, |s| s.dot_to_svg()) {
|
||||||
Ok(s) => Ok(s),
|
Ok(s) => Ok(s),
|
||||||
Err(e) => match e {
|
Err(e) => match e {
|
||||||
CachedError::SqlErr(e) => {
|
CachedError::SqlErr(e) => {
|
||||||
|
@ -178,7 +188,7 @@ impl GraphRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RegexRule for GraphRule {
|
impl RegexRule for GraphRule {
|
||||||
fn name(&self) -> &'static str { "Graph" }
|
fn name(&self) -> &'static str { "Graphviz" }
|
||||||
fn previous(&self) -> Option<&'static str> { Some("Tex") }
|
fn previous(&self) -> Option<&'static str> { Some("Tex") }
|
||||||
|
|
||||||
fn regexes(&self) -> &[regex::Regex] { &self.re }
|
fn regexes(&self) -> &[regex::Regex] { &self.re }
|
||||||
|
@ -360,4 +370,102 @@ impl RegexRule for GraphRule {
|
||||||
|
|
||||||
reports
|
reports
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn register_bindings<'lua>(&self, lua: &'lua Lua) -> Vec<(String, Function<'lua>)> {
|
||||||
|
let mut bindings = vec![];
|
||||||
|
bindings.push((
|
||||||
|
"push".to_string(),
|
||||||
|
lua.create_function(|_, (layout, width, dot): (String, String, String)| {
|
||||||
|
let mut result = Ok(());
|
||||||
|
|
||||||
|
CTX.with_borrow(|ctx| {
|
||||||
|
ctx.as_ref().map(|ctx| {
|
||||||
|
let layout = match layout_from_str(layout.as_str()) {
|
||||||
|
Err(err) => {
|
||||||
|
result = Err(BadArgument {
|
||||||
|
to: Some("push".to_string()),
|
||||||
|
pos: 1,
|
||||||
|
name: Some("layout".to_string()),
|
||||||
|
cause: Arc::new(mlua::Error::external(format!(
|
||||||
|
"Unable to get layout type: {err}"
|
||||||
|
))),
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Ok(layout) => layout,
|
||||||
|
};
|
||||||
|
|
||||||
|
ctx.state.push(
|
||||||
|
ctx.document,
|
||||||
|
Box::new(Graphviz {
|
||||||
|
location: ctx.location.clone(),
|
||||||
|
dot,
|
||||||
|
layout,
|
||||||
|
width,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
result
|
||||||
|
})
|
||||||
|
.unwrap(),
|
||||||
|
));
|
||||||
|
|
||||||
|
bindings
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::parser::langparser::LangParser;
|
||||||
|
use crate::parser::parser::Parser;
|
||||||
|
use crate::parser::source::SourceFile;
|
||||||
|
use crate::validate_document;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn parse() {
|
||||||
|
let source = Rc::new(SourceFile::with_content(
|
||||||
|
"".to_string(),
|
||||||
|
r#"
|
||||||
|
[graph][width=200px, layout=neato]
|
||||||
|
Some graph...
|
||||||
|
[/graph]
|
||||||
|
[graph]
|
||||||
|
Another graph
|
||||||
|
[/graph]
|
||||||
|
"#
|
||||||
|
.to_string(),
|
||||||
|
None,
|
||||||
|
));
|
||||||
|
let parser = LangParser::default();
|
||||||
|
let (doc, _) = parser.parse(ParserState::new(&parser, None), source, None);
|
||||||
|
|
||||||
|
validate_document!(doc.content().borrow(), 0,
|
||||||
|
Graphviz { width == "200px", dot == "Some graph..." };
|
||||||
|
Graphviz { dot == "Another graph" };
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn lua() {
|
||||||
|
let source = Rc::new(SourceFile::with_content(
|
||||||
|
"".to_string(),
|
||||||
|
r#"
|
||||||
|
%<nml.graphviz.push("neato", "200px", "Some graph...")>%
|
||||||
|
%<nml.graphviz.push("dot", "", "Another graph")>%
|
||||||
|
"#
|
||||||
|
.to_string(),
|
||||||
|
None,
|
||||||
|
));
|
||||||
|
let parser = LangParser::default();
|
||||||
|
let (doc, _) = parser.parse(ParserState::new(&parser, None), source, None);
|
||||||
|
|
||||||
|
validate_document!(doc.content().borrow(), 0,
|
||||||
|
Graphviz { width == "200px", dot == "Some graph..." };
|
||||||
|
Graphviz { dot == "Another graph" };
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -325,7 +325,7 @@ impl MediaRule {
|
||||||
|
|
||||||
impl RegexRule for MediaRule {
|
impl RegexRule for MediaRule {
|
||||||
fn name(&self) -> &'static str { "Media" }
|
fn name(&self) -> &'static str { "Media" }
|
||||||
fn previous(&self) -> Option<&'static str> { Some("Graph") }
|
fn previous(&self) -> Option<&'static str> { Some("Graphviz") }
|
||||||
|
|
||||||
fn regexes(&self) -> &[regex::Regex] { &self.re }
|
fn regexes(&self) -> &[regex::Regex] { &self.re }
|
||||||
|
|
||||||
|
|
|
@ -307,11 +307,11 @@ impl RegexRule for ReferenceRule {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::compiler::process::process_from_memory;
|
use crate::compiler::process::process_from_memory;
|
||||||
use crate::elements::paragraph::Paragraph;
|
use crate::elements::paragraph::Paragraph;
|
||||||
use crate::elements::section::Section;
|
use crate::elements::section::Section;
|
||||||
use crate::parser::langparser::LangParser;
|
use crate::parser::langparser::LangParser;
|
||||||
use crate::parser::parser::Parser;
|
use crate::parser::parser::Parser;
|
||||||
use crate::parser::source::SourceFile;
|
use crate::parser::source::SourceFile;
|
||||||
use crate::validate_document;
|
use crate::validate_document;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -366,30 +366,36 @@ use crate::parser::source::SourceFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn test_external()
|
pub fn test_external() {
|
||||||
{
|
let result = process_from_memory(
|
||||||
let result = process_from_memory(Target::HTML, vec![
|
Target::HTML,
|
||||||
r#"
|
vec![
|
||||||
|
r#"
|
||||||
@html.page_title = 0
|
@html.page_title = 0
|
||||||
@compiler.output = a.html
|
@compiler.output = a.html
|
||||||
|
|
||||||
#{ref} Referenceable section
|
#{ref} Referenceable section
|
||||||
"#.into(),
|
"#
|
||||||
r#"
|
.into(),
|
||||||
|
r#"
|
||||||
@html.page_title = 1
|
@html.page_title = 1
|
||||||
@compiler.output = b.html
|
@compiler.output = b.html
|
||||||
|
|
||||||
§{#ref}
|
§{#ref}
|
||||||
§{a#ref}
|
§{a#ref}
|
||||||
#{ref2} Another Referenceable section
|
#{ref2} Another Referenceable section
|
||||||
"#.into(),
|
"#
|
||||||
r#"
|
.into(),
|
||||||
|
r#"
|
||||||
@html.page_title = 2
|
@html.page_title = 2
|
||||||
|
|
||||||
§{#ref}[caption=from 0]
|
§{#ref}[caption=from 0]
|
||||||
§{#ref2}[caption=from 1]
|
§{#ref2}[caption=from 1]
|
||||||
"#.into(),
|
"#
|
||||||
]).unwrap();
|
.into(),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert!(result[1].0.borrow().body.starts_with("<div class=\"content\"><p><a href=\"a.html#Referenceable_section\">#ref</a><a href=\"a.html#Referenceable_section\">a#ref</a></p>"));
|
assert!(result[1].0.borrow().body.starts_with("<div class=\"content\"><p><a href=\"a.html#Referenceable_section\">#ref</a><a href=\"a.html#Referenceable_section\">a#ref</a></p>"));
|
||||||
assert!(result[2].0.borrow().body.starts_with("<div class=\"content\"><p><a href=\"a.html#Referenceable_section\">from 0</a><a href=\"b.html#Another_Referenceable_section\">from 1</a></p>"));
|
assert!(result[2].0.borrow().body.starts_with("<div class=\"content\"><p><a href=\"a.html#Referenceable_section\">from 0</a><a href=\"b.html#Another_Referenceable_section\">from 1</a></p>"));
|
||||||
|
|
|
@ -6,6 +6,7 @@ use std::process::Command;
|
||||||
use std::process::Stdio;
|
use std::process::Stdio;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
use std::sync::Arc;
|
||||||
use std::sync::Once;
|
use std::sync::Once;
|
||||||
|
|
||||||
use ariadne::Fmt;
|
use ariadne::Fmt;
|
||||||
|
@ -14,6 +15,8 @@ use ariadne::Report;
|
||||||
use ariadne::ReportKind;
|
use ariadne::ReportKind;
|
||||||
use crypto::digest::Digest;
|
use crypto::digest::Digest;
|
||||||
use crypto::sha2::Sha512;
|
use crypto::sha2::Sha512;
|
||||||
|
use mlua::Function;
|
||||||
|
use mlua::Lua;
|
||||||
use regex::Captures;
|
use regex::Captures;
|
||||||
use regex::Match;
|
use regex::Match;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
@ -25,6 +28,7 @@ use crate::compiler::compiler::Target;
|
||||||
use crate::document::document::Document;
|
use crate::document::document::Document;
|
||||||
use crate::document::element::ElemKind;
|
use crate::document::element::ElemKind;
|
||||||
use crate::document::element::Element;
|
use crate::document::element::Element;
|
||||||
|
use crate::lua::kernel::CTX;
|
||||||
use crate::parser::parser::ParserState;
|
use crate::parser::parser::ParserState;
|
||||||
use crate::parser::parser::ReportColors;
|
use crate::parser::parser::ReportColors;
|
||||||
use crate::parser::rule::RegexRule;
|
use crate::parser::rule::RegexRule;
|
||||||
|
@ -149,13 +153,18 @@ impl Element for Tex {
|
||||||
|
|
||||||
fn element_name(&self) -> &'static str { "LaTeX" }
|
fn element_name(&self) -> &'static str { "LaTeX" }
|
||||||
|
|
||||||
fn compile(&self, compiler: &Compiler, document: &dyn Document, _cursor: usize) -> Result<String, String> {
|
fn compile(
|
||||||
|
&self,
|
||||||
|
compiler: &Compiler,
|
||||||
|
document: &dyn Document,
|
||||||
|
_cursor: usize,
|
||||||
|
) -> Result<String, String> {
|
||||||
match compiler.target() {
|
match compiler.target() {
|
||||||
Target::HTML => {
|
Target::HTML => {
|
||||||
static CACHE_INIT: Once = Once::new();
|
static CACHE_INIT: Once = Once::new();
|
||||||
CACHE_INIT.call_once(|| {
|
CACHE_INIT.call_once(|| {
|
||||||
if let Some(mut con) = compiler.cache() {
|
if let Some(con) = compiler.cache() {
|
||||||
if let Err(e) = FormattedTex::init(&mut con) {
|
if let Err(e) = FormattedTex::init(con) {
|
||||||
eprintln!("Unable to create cache table: {e}");
|
eprintln!("Unable to create cache table: {e}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -185,8 +194,8 @@ impl Element for Tex {
|
||||||
Tex::format_latex(&fontsize, &preamble, &format!("{prepend}{}", self.tex))
|
Tex::format_latex(&fontsize, &preamble, &format!("{prepend}{}", self.tex))
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = if let Some(mut con) = compiler.cache() {
|
let result = if let Some(con) = compiler.cache() {
|
||||||
match latex.cached(&mut con, |s| s.latex_to_svg(&exec, &fontsize)) {
|
match latex.cached(con, |s| s.latex_to_svg(&exec, &fontsize)) {
|
||||||
Ok(s) => Ok(s),
|
Ok(s) => Ok(s),
|
||||||
Err(e) => match e {
|
Err(e) => match e {
|
||||||
CachedError::SqlErr(e) => {
|
CachedError::SqlErr(e) => {
|
||||||
|
@ -427,6 +436,95 @@ impl RegexRule for TexRule {
|
||||||
|
|
||||||
reports
|
reports
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn register_bindings<'lua>(&self, lua: &'lua Lua) -> Vec<(String, Function<'lua>)> {
|
||||||
|
let mut bindings = vec![];
|
||||||
|
bindings.push((
|
||||||
|
"push_math".to_string(),
|
||||||
|
lua.create_function(
|
||||||
|
|_, (env, kind, tex, caption): (Option<String>, String, String, Option<String>)| {
|
||||||
|
let mut result = Ok(());
|
||||||
|
CTX.with_borrow(|ctx| {
|
||||||
|
ctx.as_ref().map(|ctx| {
|
||||||
|
let kind = match TexKind::from_str(kind.as_str()) {
|
||||||
|
Ok(kind) => kind,
|
||||||
|
Err(err) => {
|
||||||
|
result = Err(mlua::Error::BadArgument {
|
||||||
|
to: Some("push".to_string()),
|
||||||
|
pos: 2,
|
||||||
|
name: Some("kind".to_string()),
|
||||||
|
cause: Arc::new(mlua::Error::external(format!(
|
||||||
|
"Unable to get tex kind: {err}"
|
||||||
|
))),
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ctx.state.push(
|
||||||
|
ctx.document,
|
||||||
|
Box::new(Tex {
|
||||||
|
location: ctx.location.clone(),
|
||||||
|
mathmode: true,
|
||||||
|
kind,
|
||||||
|
env: env.unwrap_or("main".to_string()),
|
||||||
|
tex,
|
||||||
|
caption,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
result
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
));
|
||||||
|
|
||||||
|
bindings.push((
|
||||||
|
"push".to_string(),
|
||||||
|
lua.create_function(
|
||||||
|
|_, (env, kind, tex, caption): (Option<String>, String, String, Option<String>)| {
|
||||||
|
let mut result = Ok(());
|
||||||
|
CTX.with_borrow(|ctx| {
|
||||||
|
ctx.as_ref().map(|ctx| {
|
||||||
|
let kind = match TexKind::from_str(kind.as_str()) {
|
||||||
|
Ok(kind) => kind,
|
||||||
|
Err(err) => {
|
||||||
|
result = Err(mlua::Error::BadArgument {
|
||||||
|
to: Some("push".to_string()),
|
||||||
|
pos: 2,
|
||||||
|
name: Some("kind".to_string()),
|
||||||
|
cause: Arc::new(mlua::Error::external(format!(
|
||||||
|
"Unable to get tex kind: {err}"
|
||||||
|
))),
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ctx.state.push(
|
||||||
|
ctx.document,
|
||||||
|
Box::new(Tex {
|
||||||
|
location: ctx.location.clone(),
|
||||||
|
mathmode: false,
|
||||||
|
kind,
|
||||||
|
env: env.unwrap_or("main".to_string()),
|
||||||
|
tex,
|
||||||
|
caption,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
result
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
));
|
||||||
|
|
||||||
|
bindings
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -447,6 +545,9 @@ mod tests {
|
||||||
$[kind=block, caption=Some\, text\\] 1+1=2 $
|
$[kind=block, caption=Some\, text\\] 1+1=2 $
|
||||||
$|[env=another] Non Math \LaTeX |$
|
$|[env=another] Non Math \LaTeX |$
|
||||||
$[kind=block,env=another] e^{i\pi}=-1$
|
$[kind=block,env=another] e^{i\pi}=-1$
|
||||||
|
%<nml.tex.push_math(nil, "block", "1+1=2", "Some, text\\")>%
|
||||||
|
%<nml.tex.push("another", "block", "Non Math \\LaTeX", nil)>%
|
||||||
|
%<nml.tex.push_math("another", "block", "e^{i\\pi}=-1", nil)>%
|
||||||
"#
|
"#
|
||||||
.to_string(),
|
.to_string(),
|
||||||
None,
|
None,
|
||||||
|
@ -458,6 +559,9 @@ $[kind=block,env=another] e^{i\pi}=-1$
|
||||||
Tex { mathmode == true, tex == "1+1=2", env == "main", caption == Some("Some, text\\".to_string()) };
|
Tex { mathmode == true, tex == "1+1=2", env == "main", caption == Some("Some, text\\".to_string()) };
|
||||||
Tex { mathmode == false, tex == "Non Math \\LaTeX", env == "another" };
|
Tex { mathmode == false, tex == "Non Math \\LaTeX", env == "another" };
|
||||||
Tex { mathmode == true, tex == "e^{i\\pi}=-1", env == "another" };
|
Tex { mathmode == true, tex == "e^{i\\pi}=-1", env == "another" };
|
||||||
|
Tex { mathmode == true, tex == "1+1=2", env == "main", caption == Some("Some, text\\".to_string()) };
|
||||||
|
Tex { mathmode == false, tex == "Non Math \\LaTeX", env == "another" };
|
||||||
|
Tex { mathmode == true, tex == "e^{i\\pi}=-1", env == "another" };
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -469,6 +573,9 @@ $[kind=block,env=another] e^{i\pi}=-1$
|
||||||
$[ caption=Some\, text\\] 1+1=2 $
|
$[ caption=Some\, text\\] 1+1=2 $
|
||||||
$|[env=another, kind=inline , caption = Enclosed \]. ] Non Math \LaTeX|$
|
$|[env=another, kind=inline , caption = Enclosed \]. ] Non Math \LaTeX|$
|
||||||
$[env=another] e^{i\pi}=-1$
|
$[env=another] e^{i\pi}=-1$
|
||||||
|
%<nml.tex.push_math("main", "inline", "1+1=2", "Some, text\\")>%
|
||||||
|
%<nml.tex.push("another", "inline", "Non Math \\LaTeX", "Enclosed ].")>%
|
||||||
|
%<nml.tex.push_math("another", "inline", "e^{i\\pi}=-1", nil)>%
|
||||||
"#
|
"#
|
||||||
.to_string(),
|
.to_string(),
|
||||||
None,
|
None,
|
||||||
|
@ -479,7 +586,10 @@ $[env=another] e^{i\pi}=-1$
|
||||||
validate_document!(doc.content().borrow(), 0,
|
validate_document!(doc.content().borrow(), 0,
|
||||||
Paragraph {
|
Paragraph {
|
||||||
Tex { mathmode == true, tex == "1+1=2", env == "main", caption == Some("Some, text\\".to_string()) };
|
Tex { mathmode == true, tex == "1+1=2", env == "main", caption == Some("Some, text\\".to_string()) };
|
||||||
Tex { mathmode == false, tex == "Non Math \\LaTeX", env == "another" };
|
Tex { mathmode == false, tex == "Non Math \\LaTeX", env == "another", caption == Some("Enclosed ].".to_string()) };
|
||||||
|
Tex { mathmode == true, tex == "e^{i\\pi}=-1", env == "another" };
|
||||||
|
Tex { mathmode == true, tex == "1+1=2", env == "main", caption == Some("Some, text\\".to_string()) };
|
||||||
|
Tex { mathmode == false, tex == "Non Math \\LaTeX", env == "another", caption == Some("Enclosed ].".to_string()) };
|
||||||
Tex { mathmode == true, tex == "e^{i\\pi}=-1", env == "another" };
|
Tex { mathmode == true, tex == "e^{i\\pi}=-1", env == "another" };
|
||||||
};
|
};
|
||||||
);
|
);
|
||||||
|
|
|
@ -205,7 +205,7 @@ mod tests {
|
||||||
"Blockquote",
|
"Blockquote",
|
||||||
"Code",
|
"Code",
|
||||||
"Tex",
|
"Tex",
|
||||||
"Graph",
|
"Graphviz",
|
||||||
"Media",
|
"Media",
|
||||||
"Layout",
|
"Layout",
|
||||||
"Style",
|
"Style",
|
||||||
|
|
Loading…
Reference in a new issue