From cf3491e5a7706979a8a9376fa4df7251a41cd279 Mon Sep 17 00:00:00 2001
From: ef3d0c3e <ef3d0c3e@pundalik.org>
Date: Mon, 5 Aug 2024 09:04:09 +0200
Subject: [PATCH] Update docs
---
docs/external/graphviz.nml | 6 +++-
docs/sections.nml | 56 ++++++++++++++++++++++++++++++++++++
docs/start.nml | 32 +++++++++++++++++++++
docs/styles/layout.nml | 8 +++---
docs/styles/user-defined.nml | 37 +++++++++++++++++++++++-
src/elements/comment.rs | 2 --
src/elements/customstyle.rs | 15 ++++++++--
src/elements/list.rs | 2 +-
src/elements/section.rs | 26 +++++++++++++++++
src/lua/kernel.rs | 16 -----------
src/parser/langparser.rs | 4 +++
src/parser/parser.rs | 16 +++++------
12 files changed, 184 insertions(+), 36 deletions(-)
create mode 100644 docs/sections.nml
create mode 100644 docs/start.nml
diff --git a/docs/external/graphviz.nml b/docs/external/graphviz.nml
index d0dabf0..778f50d 100644
--- a/docs/external/graphviz.nml
+++ b/docs/external/graphviz.nml
@@ -35,6 +35,10 @@ digraph {
[/graph]
#+LAYOUT_END
+The Graphviz functionnality requires the `dot` executable. More information on [Graphviz's website](file:///home/baraquiel/Programming/nml_rs/out/Graphviz.html).
+
+# Synopsis
+
Graphs blocks are delimited by `` [graph]...[/graph]``
# Properties
@@ -307,5 +311,5 @@ digraph UML_Class_diagram {
# Graphiz cache
-Rendered Graphviz graphs that have been rendered to **svg** are stored in the cache database, under table ``cached_dot``.
+Graphviz graphs that have been rendered to **svg** are stored in the cache database, under table ``cached_dot``.
Unless you modify the graph or it's properties, it won't be rendered again, instead it will be sourced from the database.
diff --git a/docs/sections.nml b/docs/sections.nml
new file mode 100644
index 0000000..d12c188
--- /dev/null
+++ b/docs/sections.nml
@@ -0,0 +1,56 @@
+@import template.nml
+@nav.previous = Getting Started
+%<make_doc({}, "Sections", "Sections")>%
+
+#{first} Sections
+
+To add a section to your document, put one or more ``Plain Text, #`` at the start of the line, followed a space and the name of your section.
+
+
+Which will render as:
+
+#+LAYOUT_BEGIN Split
+:: Make sure they don't pollute the ToC
+#+ Section name
+##+ Subsection
+##*+ Unnumbered section
+##+ Unnumbered section
+#+ This section is not in the ToC
+
+#+LAYOUT_NEXT
+
+Given by the following:
+``
+# Section name
+## Subsection
+#* Unnumbered section
+#+ This section is not in the ToC
+``
+#+LAYOUT_END
+
+# Sections references
+
+You can create a referenceable section by using ``Plain Text, #{refname}``, where `refname` is an internal reference name for use only within this document.
+You can then create a clickable reference to this section: ``§{refname}`` or ``§{refname}[caption=Click me!]``. Below is an example of this in action:
+
+###{refname}+* Section
+§{refname}[caption=Click me!] or §{first}[caption=First section]
+
+``
+###{refname}+* Section
+§{refname}[caption=Click me!] or §{first}[caption=First section]
+``
+
+# Section styling
+
+The styling for the section link is controlled by the style key ``style.section``
+
+ * ``link_pos``: `Before|After|None` Position of the section link.
+ * ``link``: `[Before, Link, After]` 3 strings-array
+
+```JSON, Default Style
+{
+ "link_pos": "Before",
+ "link": ["", "🔗", " "]
+}
+```
diff --git a/docs/start.nml b/docs/start.nml
new file mode 100644
index 0000000..bf54848
--- /dev/null
+++ b/docs/start.nml
@@ -0,0 +1,32 @@
+@import template.nml
+@nav.previous = Index
+%<make_doc({}, "Getting Started", "Getting Started")>%
+
+# Building NML
+
+You need at least the nightly version of rustc to compile NML.
+Instruction for your operating system can be found on [Rust's website](https://forge.rust-lang.org/infra/other-installation-methods.html).
+You'll also need liblua 5.4 installed. You can then move the `nml` executable in `target/release/nml` into your `\$PATH`
+
+``cargo build --bin nml`` or for release mode: ``cargo build --release --bin nml``
+
+# Building your first document
+
+ * ``nml -i input.nml -o output.html``
+
+# Using the cache
+
+NML relies on sqlite to keep a cache of precompiled elements that take a long time to process (e.g $|[kind=inline] \LaTeX|$).
+To enable caching, use option `-d` with a path: ``-d cache.db``. You can reuse the same cache for multiple documents and benefit from cached elements.
+Note that in directory-processing mode, a cache is required so that only modified ``.nml`` files get reprocessed.
+
+# Directory-Processing mode
+
+To use directory-processing mode, you need to pass an input directory and an output directory. Directory-processing mode requires that you use a database, so that it knows which documents have already been compiled. If the output directory doesn't exist, it will be automatically created.
+
+Compiling the docs:
+``Plain Text,
+nml -i docs -o docs_out -d cache.db
+``
+
+If you modify an ``Plain Text,@import``ed file, you will need to use the ``--force-rebuild`` option, as NML currently doesn't track which files are imported by other files.
diff --git a/docs/styles/layout.nml b/docs/styles/layout.nml
index 8104100..41eac58 100644
--- a/docs/styles/layout.nml
+++ b/docs/styles/layout.nml
@@ -46,17 +46,17 @@ First
Centered layout align text to the center of the current block.
-#### Style
+####+* Style
The ``Centered`` layout uses the `.centered` css class to center the text.
-#### Properties
+####+* Properties
* ``style`` Added css style to the div (defaults to none)
## Split
-#### Style
+####+* Style
The ``Split`` layout uses the `.split-container` and `.split` css class to create the desired layout.
If you wish to modify the relative width of the splits: add `style=flex: 0.5` in the properties, this makes the following split half the width of the other splits.
-#### Properties
+####+* Properties
* ``style`` Added css style to the div (defaults to none)
diff --git a/docs/styles/user-defined.nml b/docs/styles/user-defined.nml
index 4082253..bcd0216 100644
--- a/docs/styles/user-defined.nml
+++ b/docs/styles/user-defined.nml
@@ -1,4 +1,39 @@
@import ../template.nml
%<make_doc({"Styles"}, "User-Defined", "User-Defined Styles")>%
-# TODO
+# Defining a custom style
+```Lua
+%<[main]
+function undercustom_start(color)
+ nml.raw.push("inline", "<span style=\"border-bottom: 1px dashed " .. color .. "\">")
+end
+
+function undercustom_end()
+ nml.raw.push("inline", "</span>")
+end
+
+nml.custom_style.define_toggled("Undercustom Red", "~", "undercustom_start(\"red\")", "undercustom_end()")
+nml.custom_style.define_paired("Undercustom Green", "[|", "|]", "undercustom_start(\"Green\")", "undercustom_end()")
+>%
+```
+
+%<[main]
+function undercustom_start(color)
+ nml.raw.push("inline", "<span style=\"border-bottom: 1px dashed " .. color .. "\">")
+end
+
+function undercustom_end()
+ nml.raw.push("inline", "</span>")
+end
+
+nml.custom_style.define_toggled("Undercustom Red", "~", "undercustom_start(\"red\")", "undercustom_end()")
+nml.custom_style.define_paired("Undercustom Green", "[|", "|]", "undercustom_start(\"Green\")", "undercustom_end()")
+>%
+Results in the following:
+ * ``Plain Text,~Dashed underline~`` → ~Dashed underline~
+ * ``Plain Text,[|Dashed underline|]`` → [|Dashed underline|]
+
+# Limitations
+
+ * Custom styles cannot be removed and will be defined through the entire document
+ * Custom styles defined from lua must have their `start` and `end` functions in the `main` lua kernel.
diff --git a/src/elements/comment.rs b/src/elements/comment.rs
index 308ef10..2363243 100644
--- a/src/elements/comment.rs
+++ b/src/elements/comment.rs
@@ -92,8 +92,6 @@ impl RegexRule for CommentRule {
return reports;
}
-
- fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> { None }
}
#[cfg(test)]
diff --git a/src/elements/customstyle.rs b/src/elements/customstyle.rs
index 6a256a6..c235083 100644
--- a/src/elements/customstyle.rs
+++ b/src/elements/customstyle.rs
@@ -17,7 +17,6 @@ use crate::document::customstyle::CustomStyle;
use crate::document::customstyle::CustomStyleToken;
use crate::document::document::Document;
use crate::document::document::DocumentAccessors;
-use crate::lua::kernel::function_with_context;
use crate::lua::kernel::KernelContext;
use crate::lua::kernel::CTX;
use crate::parser::parser::Parser;
@@ -423,6 +422,18 @@ impl Rule for CustomStyleRule {
)| {
let mut result = Ok(());
+ if token_start == token_end
+ {
+ return Err(BadArgument {
+ to: Some("define_paired".to_string()),
+ pos: 3,
+ name: Some("token_end".to_string()),
+ cause: Arc::new(mlua::Error::external(format!(
+ "Custom style with name `{name}` cannot be defined: The start token must differ from the end token, use `define_toggled` insteda"
+ ))),
+ });
+ }
+
let style = LuaCustomStyle {
tokens: CustomStyleToken::Pair(token_start, token_end),
name: name.clone(),
@@ -434,7 +445,7 @@ impl Rule for CustomStyleRule {
ctx.as_ref().map(|ctx| {
if let Some(_) = ctx.parser.get_custom_style(name.as_str()) {
result = Err(BadArgument {
- to: Some("define_toggled".to_string()),
+ to: Some("define_paired".to_string()),
pos: 1,
name: Some("name".to_string()),
cause: Arc::new(mlua::Error::external(format!(
diff --git a/src/elements/list.rs b/src/elements/list.rs
index 889b16d..56d943f 100644
--- a/src/elements/list.rs
+++ b/src/elements/list.rs
@@ -373,7 +373,7 @@ impl Rule for ListRule {
}
// Parse entry content
- let token = Token::new(end_cursor.pos..end_cursor.pos, end_cursor.source.clone());
+ let token = Token::new(entry_start..end_cursor.pos, end_cursor.source.clone());
let entry_src = Rc::new(VirtualSource::new(
token.clone(),
"List Entry".to_string(),
diff --git a/src/elements/section.rs b/src/elements/section.rs
index e303674..0662084 100644
--- a/src/elements/section.rs
+++ b/src/elements/section.rs
@@ -409,6 +409,7 @@ mod section_style {
#[cfg(test)]
mod tests {
+ use crate::document::style::StyleHolder;
use crate::parser::langparser::LangParser;
use crate::parser::source::SourceFile;
use crate::validate_document;
@@ -472,4 +473,29 @@ nml.section.push("6", 6, "", "refname")
Section { depth == 6, title == "6", reference == Some("refname".to_string()) };
);
}
+
+ #[test]
+ fn style() {
+ let source = Rc::new(SourceFile::with_content(
+ "".to_string(),
+ r#"
+@@style.section = {
+ "link_pos": "None",
+ "link": ["a", "b", "c"]
+}
+ "#
+ .to_string(),
+ None,
+ ));
+ let parser = LangParser::default();
+ let _ = parser.parse(source, None);
+
+ let style = parser
+ .current_style(section_style::STYLE_KEY)
+ .downcast_rc::<SectionStyle>()
+ .unwrap();
+
+ assert_eq!(style.link_pos, SectionLinkPos::None);
+ assert_eq!(style.link, ["a".to_string(), "b".to_string(), "c".to_string()]);
+ }
}
diff --git a/src/lua/kernel.rs b/src/lua/kernel.rs
index 8503bfb..17798a2 100644
--- a/src/lua/kernel.rs
+++ b/src/lua/kernel.rs
@@ -76,19 +76,3 @@ pub trait KernelHolder {
fn insert_kernel(&self, name: String, kernel: Kernel) -> RefMut<'_, Kernel>;
}
-
-/// Runs a lua function with a context
-///
-/// This is the only way lua functions shoule be ran, because exported
-/// functions may require the context in order to operate
-pub fn function_with_context<'lua, A, R>(context: KernelContext, fun: &Function<'lua>, args: A) -> Result<R, Error>
-where
- A: IntoLuaMulti<'lua>,
- R: FromLuaMulti<'lua>,
-{
- CTX.set(Some(unsafe { std::mem::transmute(context) }));
- let ret = fun.call::<A, R>(args);
- CTX.set(None);
-
- ret
-}
diff --git a/src/parser/langparser.rs b/src/parser/langparser.rs
index f0bba36..0f66114 100644
--- a/src/parser/langparser.rs
+++ b/src/parser/langparser.rs
@@ -1,3 +1,4 @@
+use std::any::Any;
use std::cell::Ref;
use std::cell::RefCell;
use std::cell::RefMut;
@@ -48,6 +49,8 @@ pub struct LangParser {
// Parser state
pub err_flag: RefCell<bool>,
+ pub matches: RefCell<Vec<(usize, Option<Box<dyn Any>>)>>,
+
pub state: RefCell<StateHolder>,
pub kernels: RefCell<HashMap<String, Kernel>>,
pub styles: RefCell<HashMap<String, Rc<dyn ElementStyle>>>,
@@ -61,6 +64,7 @@ impl LangParser {
rules: vec![],
colors: ReportColors::with_colors(),
err_flag: RefCell::new(false),
+ matches: RefCell::new(Vec::new()),
state: RefCell::new(StateHolder::new()),
kernels: RefCell::new(HashMap::new()),
styles: RefCell::new(HashMap::new()),
diff --git a/src/parser/parser.rs b/src/parser/parser.rs
index a01ea16..43bf465 100644
--- a/src/parser/parser.rs
+++ b/src/parser/parser.rs
@@ -13,6 +13,7 @@ use crate::document::document::Document;
use crate::document::element::Element;
use crate::document::layout::LayoutHolder;
use crate::document::style::StyleHolder;
+use crate::elements::customstyle::CustomStyleRule;
use crate::lua::kernel::KernelHolder;
use ariadne::Color;
@@ -50,7 +51,9 @@ pub trait Parser: KernelHolder + StyleHolder + LayoutHolder + CustomStyleHolder
/// When colors are disabled, all colors should resolve to empty string
fn colors(&self) -> &ReportColors;
+ /// Gets a reference to all the [`Rule`]s defined for the parser
fn rules(&self) -> &Vec<Box<dyn Rule>>;
+ /// Gets a mutable reference to all the [`Rule`]s defined for the parser
fn rules_mut(&mut self) -> &mut Vec<Box<dyn Rule>>;
fn state(&self) -> Ref<'_, StateHolder>;
@@ -84,18 +87,13 @@ pub trait ParserStrategy {
impl<T: Parser> ParserStrategy for T {
fn add_rule(&mut self, rule: Box<dyn Rule>, after: Option<&'static str>) -> Result<(), String> {
- // Error on duplicate rule
let rule_name = (*rule).name();
- if let Err(e) = self.rules().iter().try_for_each(|rule| {
- if (*rule).name() != rule_name {
- return Ok(());
- }
-
+ // Error on duplicate rule
+ if let Some(_) = self.rules().iter().find(|rule| rule.name() == rule_name)
+ {
return Err(format!(
"Attempted to introduce duplicate rule: `{rule_name}`"
));
- }) {
- return Err(e);
}
match after {
@@ -134,7 +132,7 @@ impl<T: Parser> ParserStrategy for T {
.zip(matches.iter_mut())
.for_each(|(rule, (matched_at, match_data))| {
// Don't upate if not stepped over yet
- if *matched_at > cursor.pos && rule.downcast_ref::<crate::elements::customstyle::CustomStyleRule>().is_none() {
+ if *matched_at > cursor.pos && rule.downcast_ref::<CustomStyleRule>().is_none() {
// TODO: maybe we should expose matches() so it becomes possible to dynamically register a new rule
return;
}