Update docs
This commit is contained in:
parent
b5c8fbbfea
commit
cf3491e5a7
12 changed files with 184 additions and 36 deletions
6
docs/external/graphviz.nml
vendored
6
docs/external/graphviz.nml
vendored
|
@ -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
56
docs/sections.nml
Normal 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
32
docs/start.nml
Normal 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.
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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!(
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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()]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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()),
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue