Update docs

This commit is contained in:
ef3d0c3e 2024-08-05 09:04:09 +02:00
parent b5c8fbbfea
commit cf3491e5a7
12 changed files with 184 additions and 36 deletions

View file

@ -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.

56
docs/sections.nml Normal file
View file

@ -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": ["", "🔗", " "]
}
```

32
docs/start.nml Normal file
View file

@ -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.

View file

@ -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)

View file

@ -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.

View file

@ -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)]

View file

@ -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!(

View file

@ -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(),

View file

@ -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()]);
}
}

View file

@ -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
}

View file

@ -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()),

View file

@ -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;
}