An elegant, extensible typesetter with a friendly interface and decent output.
This repo is currently transitioning from a C implementation to a Rust one. Some features may be broken or not-yet reimplemented. The Emblem file format will remain largely identical, however.
- Overview
- Usage
- How to Obtain
- How it Works
- Syntax Overview
- Styling Overview
- Extensions Overview
- License and Author
- Contributions
Emblem takes input of a file written in the format it recognises, typesets it and then outputs it in some format. Whilst typesetting, the document is styled using CSS and can be operated upon by extensions written in Lua. The resulting document is then passed to some output driver which is responsible for translating it into some format and outputting it.
As there can be relations between some parts of a document, the running of Lua extensions, styling by CSS and typesetting is run repeatedly until either the document settles to an acceptable state, or a maximum number of iterations is reached.
As this iteration is done internally, the executable em
need only be run once to fully typeset a document from a given input.
Emblem operates as below.
Emblem can be used through command-line using the em
binary.
For example to compile a document hello.em
into HTML, the following can be run.
em example
Note the ‘.em’ file extension is optional, this will be true of most file extensions used.
The output format can be changed by passing the -T
option.
By default, html
is used, but other formats are also available.
For example, the output could be changed to bbcode:
em example -Tbb
Emblem also supports extensions which can be added to the document-environment by the -x[ext]
option.
Extensions can also be passed text values using the -a[ext].[param]=[val]
option.
For example, example.em
could be compiled into bbcode using the asdf
extension with its argument fdsa
being set to qwer
:
em example -Tbb -xasdf -aasdf.fdsa=qwer
The order of options passed is not significant, except in the case that the same parameter to the same extension is set multiple times, in which case the rightmost value is taken. Documentation for the entire command-line interface are available in the releases.
To use Emblem, you will need the em
binary, which can be obtained through one of two methods.
Binaries for Linux, macOS and Windows can be found on the releases page. Coming soonish
For Arch Linux users, Emblem is available via the AUR: Also coming soonish
yay -S emblem
Programs you will need:
git
yq
- GNU Autotools
- Standard UNIX tools
- gcc
To compile and run the em
, you will need to install the following libraries:
- criterion
- glibc (Comes with all good GNU/Linux distributions)
- libcss
- libsass
- lua 5.4
- lua-argparse
- lua-htmlparser
- lua-lpeg
- lua-lyaml
- moonscript
- ncurses
Now to compile, clone the git repository, cd
into it, and then issue the following commands.
./scripts/autogen
./configure
make
This should result in a binary called em
being created.
Maintainers: When adding new source files, the above commands will need to be re-run as the autogen
script generates a list of files which will be linked into the binary.
To execute tests, run make check_em
and then ./check_em
.
Here we discuss how Emblem works and how it may be used.
To start, Emblem takes input of a single file—either given explicitly at the command-line or otherwise implicitly taken to be read from its standard input stream. Emblem expects this file to conform to the rules of its syntax as specified a later section. From this file may be referenced others which Emblem will then read and parse as it did the first. This process completes once there are no required files which have not been read and parsed.
Extensions are then loaded and initialised.
Next, the typesetting loop starts. This begins with a run through the document evaluating calls to functions defined in extensions, these extensions may indicate that they require another typesetting run. The result is then analysed to ascertain the styles which must be applied to each element in the document. The document is then typeset. If another typesetting run has been requested and the number of iterations has not exceeded the maximum specified by the user, the loop reiterates.
Extensions are then de-initialised.
Finally, the typeset document is passed to the output driver which is responsible for translating the structure into an external document format.
The Emblem syntax is based on two core concepts: directives and pragmas, the former being a more expressive cousin of the latter. These are both commands issued by the user which can affect the style and content of a document but are processed at different stages in the processing of a document.
Pragmas, or preprocessor directives, are commands which are executed as the document is being parsed. They are used to change the state of the parser or force it to insert the contents of a new file at a particular point in a containing file.
Directives are used to both style content and to generate it by interacting with extensions. All other concepts in the Emblem syntax such as markdown-like syntax or the scripting language are translated down to directive-calls for evaluation.
Each of these things shall be explained in further detail over the coming subsections.
As one might expect, in Emblem, words are words.
If a line contains a double forward-slash, the rest of the line is interpreted as a comment and will not appear in the output.
Multi-line comments are delimited by /*
and */
.
// This is a comment.
/* This is a multi-line comment.
Like the name implies, it can exist over multiple lines. */
/* These comments can also be nested /* like so, without risk of the comment being */ prematurely closed when it is interpreted. */
Elements of a document can be styled by using directives.
These are words which start with a dot, such as .example
and are the link to the more advanced features of Emblem.
A directive is both a styling instruction and also—if it has been declared by an extension—a call to a function which takes some parameters and outputs document content. These arguments can be specified in a few different ways. All of the following will centre a piece of text.
.centre{This text will be centred}
.centre{As 'centre' is not a command,}{the different arguments will just be concatenated in the output}
.centre{It’s possible to use the curly braces to hold multi-line arguments.}{
Just so long as the contents in the curly braces is indented.
This will continue until the matching closing-brace.
Paragraph breaks are allowed and are applied if the context permits.
}
.centre:
A single colon can be used to start an indented block as an argument.
This is exactly the same as the curly-braces and indents above.
Just with a little-less visual clutter.
.centre{Curly brace arguments}:
and those with a colon and indent can be combined, the only constraint is that the curly-brace arguments (if any) must come first.
.centre:
If there are multiple long arguments to a function, it can be useful to use a _continuation_ argument.
These are delimited by a dedented double colon,
::
like so. These continuation arguments follow the same rules as those above except that they can only appear after a single-colon argument block.
The ability to delimit multiple sections of a document can be useful when the directive is a recognised function call.
.if{true}:
Something to show when the condition is true
::
Something to show when the condition is false
Conditions are interpreted by the following rules: if the condition is empty or equal to either 0
or false
(case-insensitive), then it is interpreted as ‘false.’ otherwise it is ‘true.’
This is an example of the scripting module, std.lingo
.
More information is seen in the scripting reference.
Emblem interprets some characters as special (for example the underscore which can be used to make italics), however in some cases their literal value is desired instead.
In this case, a backslash can be used to force Emblem to ignore special meanings (e.g. \_
will always output an underscore, instead of possibly affecting styling).
The basic syntax can be used to express all concepts which Emblem can understand, however for convenience, some more brief forms are defined. Some of the following should be familiar to markdown users.
_Single underscores denote italic._
*So do single asterisks.*
__Double underscores denote bold.__
**So do double asterisks.**
_**Styles can be nested, nested**_
__And *nested* some more__
`backticks can be used use monospace`
`These too _can_ be **nested**`
=Single equals-delimiters make the included text _small caps_=
==Double equals-delimiters use an _alternative_ font face, such as sans-serif in an otherise serif document==
The above syntax simply expands to directive calls:
- Italic delimiters expand to
.it
- Bold delimiters expand to
.bf
- Mono-space delimiters expand to
.tt
- Small-cap delimiters expand to
.sc
- Alternative face delimiters expand to
.af
It should be noted that these delimiters are only recognised at the beginning and ends of words and as such do not need to be escaped when they appear strictly within them. The only exception to this is when trailing punctuation is used, in which case closing delimiters can be placed before these. This can be used for example to end a non-bold sentence with a bold word but not a bold full-stop.
Headers can be specified in a line starting with one to six hashes.
# This is a level 1 header
## This is a level 2 header, a little smaller probably
### This is a level 3 header
#### Guess what this is
##### This is a level 5 header
###### This is a level 6 header
These respectively expand to calls to .h1
to .h6
.
In Emblem, these represent numbered headings which appear in a table of contents. If this is not desired, there are starred versions of the functions available.
#* This is a level 1 unnumbered heading
##* This is a level 2 unnumbered heading
###* This is a level 3 unnumbered heading
####* Now guess what this is
#####* This is a level 5 unnumbered heading
######* This is a level 6 unnumbered heading
These expand to calls to .h1*
to .h6*
respectively.
Syntactic sugar is also available for the cross-referencing and bibliography systems.
An anchor can be set down with @name, and makes not of the current label value at this location
This can then be referenced with #name.
Headers and other items may set the current label, allowing the user to mark the location of a cross-reference they want, safe in the knowledge that their cross-references handled for them.
The call @name
expands to .anchor{name}
and #name
responds to .ref{name}
.
Citations can be marked down in a similar manner, as text inside square brackets without any spaces.
This is a sentence I’d like to atrribute to someone else by citing [that_someone]
So their name will also appear later in the
.bib
Sometimes to can be convenient to affect the structure of the document in a small way without needing to write extension code. This can be achieved by using the scripting directives define in Emblem’s standard library, which create a small shell-like language. The scripting language contains a minimal set of directives to perform common programming language functionality.
The .set-var
function sets a variable to a given value.
For example, .set-var{x}{asdf}
will set variable x
to the string asdf
.
The value of a variable can be retrieved with the .get-var
function.
After the above, .get-var{x}
will now return asdf
.
Emblem is quite accepting of the number of arguments passed to a function, following the standard behaviour of Lua.
If an emblem directive expects a n arguments and receives too many, the rest are ignored.
Similarly, if fewer than n are received, then the remaining ones are treated as Lua’s nil
, which if seen by Emblem’s core is expanded to the empty string.
Below, where ‘string representation’ is seen, this should be interpreted as Emblem evaluating the value it is given before concatenating together all text-elements contained within it.
The following functions are provided as standard.
.streq
This takes two inputs, checks their string representations and returns1
if they are the same, otherwise0
.echo
This takes any number of inputs and prints them on the command-line, separated by spaces. Useful for debugging..echo-on-pass
This takes a number and then any number of inputs and if the current pass index is equal to the given number, executes.echo
..defined
This takes one input and if its string representation is the name of a variable which has previously been set returns1
, otherwise0
.exists
This takes one input and if its string representation is the name of a known function returns1
, otherwise0
The content of a document can be conditionally-modified using Emblem script directives.
The .if
directive takes two inputs.
The first input is evaluated as a condition and if it is true, then the second input is returned, otherwise nil
.
The .ifelse
directive is similar to .if
except that it takes three inputs.
If the condition in the first input is evaluated to true the second input is returned, otherwise the third.
The .case
directive takes a number, n, and cases cs (the rest of its inputs), and returns the n-th entry in cs if it exists, otherwise the last.
The .while
directive represents an unbounded loop.
It takes two inputs: a condition and a body.
The .while
loop evaluates the condition, and if it is true it evaluates the body.
This is repeated until the condition becomes false.
What is returned is the sequence of values that where returned when evaluating the body during iteration.
The .foreach
directive represents a bounded loop.
It takes three inputs: the name of a variable, a sequence of values (such as a sentence) and a body.
The loop iterates once for each value in the sequence, assigning the named variable that value before evaluating the body.
Like the .while
loop, what is returned is the sequence of values which were returned when evaluating the body during iteration.
If the iteration variable was already defined before the start of the loop, it retakes its previous value once the loop has ended.
Directive | Description |
---|---|
.anchor |
Set down a cross-reference anchor, subsequent references to this anchor will return the label value here. |
.bib |
Output a bibliography here, optionally specify the source file of the references. |
.case |
Control flow directive, see above. |
.cite |
Place a citation marker down and have a corresponding entry appear in the bibliography. |
.def |
Define a custom directive. |
.defined |
Returns whether a given variable has been defined in the current scope. |
.echo |
Write a string representation of its inputs stdout . |
.echo-on |
Same as .echo , but its first input is a number n, and output is only performed on the n-th typesetting pass. |
.error |
Output an error and quit. |
.error-on |
Same as .error but its first input is a number n, and output is only performed on the n-th typesetting pass |
.exists |
Returns whether a directive would execute extension code. |
.foreach |
Control flow directive, see above. |
.get-var |
Returns the value of a given variable in the current context. |
.h1 |
Constructs a level 1 header. |
.h2 |
Constructs a level 2 header. |
.h3 |
Constructs a level 3 header. |
.h4 |
Constructs a level 4 header. |
.h5 |
Constructs a level 5 header. |
.h6 |
Constructs a level 6 header. |
.if |
Control flow directive, see above. |
.ifelse |
Control flow directive, see above. |
.include |
Read and include a given file here. Can optionally specify a language to use, or rely on emblem’s detection of the file extension. Caches result by file-name to avoid re-running parsers. |
.include* |
Read and include a given file here. Can optionally specify a language to use, or rely on emblem’s detection of the file extension. Always runs the relevant parser. |
.known_directives |
Output a list of known directives. |
.ref |
Takes a key and returns the label value where an anchor with the same the same key was set down. |
.set-var |
Set a variable with a given string value in the current context. |
.streq |
Returns whether the text extracted from two inputs is the same. |
.toc |
Outputs a table of contents. |
.undef |
Undefines a directive. |
.warn |
Same as .error but outputs a warning instead. |
.warn-on |
Same as .error-on but outputs a warning instead. |
.while |
Control flow directive, see above. |
Some document-functions of Emblem do not interact with extensions. These are preprocessed-out before the document begins its typesetting and extension-execution run. The following statements are only valid as the first and only element of a line. Any white-space to the left of a pragma is ignored, hence they do not need to follow the indentation rules of the rest of the document.
The :include
pragma takes input of a file name surrounded by double-quotes, reads it and substitutes it into the document in the current position, hence allowing for multi-file documents.
As this is handled before any execution of extension code, it is possible for external tools to interpret the file-structure of a given document without needing to execute its code.
The line:
:include "some-file-to-include"
Will include a file “some-file-to-include.em”.
The .em
file extension is optional.
The :line
pragma updates the parser’s reference for its current position in the document for when errors are reported.
This is useful when an Emblem document is the output of another program and the user wishes for error messages to refer to another source location.
The pragma takes a filename in double-quotes, a number which represents the new current line index and a number which represents the new current column index.
The line:
:line "some-other-file.md" 32 54
Will make Emblem believe that it is currently in “some-other-file.md” at line 32 and column 54 once the next line starts.
File extensions are not optional here as the filename is copied verbatim.
Line pragmas are local the file which is currently being parsed and so are unaffected by :include
-ing files.
Directives can not only control the content of a document, they can style it too.
Whenever a directive is used, it automatically applies the style of the same name to its output.
For example, the .h1
directive for defining titles also applies the .h1
style to its output.
But where do these styles come from?
Emblem takes input of a stylesheet written in either plain CSS, SASS or SCSS. So for example, the following snippet would make the entire document use the Bodoni* 11 font and use light grey text on a dark-grey background.
.body {
font-family: 'Bodoni* 11', serif;
background-color: #2d2d2d;
color: #dddddd;
}
When writing styles, care should be taken to ensure that the names of rules always start with a ‘.’, just like the directives which call them.
So for example, although using a styling rule for body
will function as intended for HTML output, however if another format were used, the styling associated with body
(no prefixed dot) would be missing.
To style the entire document, a .body
style should be used instead.
Extensions can also help style their own results by importing their own stylesheets. As these are imported before the user’s one, default styles can be overridden as desired.
Emblem is hackable, that is, arbitrary functionality may be added by its users. This is done in one of three ways:
- In code executed as the document goes through its typesetting cycle (‘extensions’)
- In code executed to convert a given input format to Emblem’s internal structures (‘input drivers’)
- In code executed to convert to a given output format (‘output drivers’).
Typesetting-time extensions, hereafter referred to simply as ‘extensions,’ are snippets of Lua code which are imported after the document has been parsed and are executed as it undergoes its typesetting run.
Extensions can define functions to be accessed in the document by editing the Emblem Public Table stored in the em
variable.
For example, we may wish create a document which includes a note of how long it took to compile.
To do this, we must create a function which creates the desired string, and place it into some field in the em
table, say cpu_time_used
em.cpu_time_used = function()
return 'This document was typeset in ' .. os.clock() .. ' seconds of CPU time'
end
If this code is written in a file called cpu-time.lua
, it can be imported by adding the flag -xcpu-time
when em
is run (note the file extension is optional).
Now, when the directive .cpu_time_used
is seen in the document, the above code will be executed, it will be replaced with the message.
Emblem is lazy, that is, it tries to do no more work than is necessary to typeset a document. So for example, if a directive takes three inputs and just outputs the first one, emblem will not bother to evaluate the others. This is because by default, Emblem will only evaluate a node if it can guarantee that it will appear in the output.
Sometimes, however, it can be useful to force Emblem to use a different evaluation order, such as to inspect the results which would not otherwise appear directly in the output.
This can be done using the eval
function, which takes a node and evaluates it, or the eval_string
function which
Evaluation order is manipulated in the definition of the .if
directive, which looks something like the following:
em.if = function(c, b)
cs = eval_string(c)
if cs == '' or cs == '0' or string.lower(cs) == 'false' then
return nil
else
return b
end
end
Here, although input c
is never present in what is returned, by calling eval_string
upon it we can reason about it.
The following functions are defined in Emblem’s standard library and are likely useful to extension writers.
Package | Function | Description |
---|---|---|
std.ast |
mkcall |
Takes a name of a directive, returns a function which constructs a Call node with that name and the rest of its arguments |
std.base |
copy_loc |
Copy a location pointer into a table, allows storage of a location after it has been destroyed. |
std.base |
em_loc |
Return the location in the source which corresponds to the directive which is currently being evaluated. |
std.base |
eval_string |
Evaluate a node tree and extract a |
std.base |
eval |
Evaluates a node in the document tree and returns a table which represents the result, used to force (early) evaluation |
std.base |
get_var |
Get the value of a given variable in the current context. |
std.base |
include_file |
Runs the core emblem file parser on a given location and returns the result |
std.base |
iter_num |
Return the current iteration number. |
std.base |
node_string |
Extract the text represented by a document tree (must have been evaluated) |
std.base |
requires_reiter |
Set a flag which marks the document as in-need of another typesetting pass |
std.base |
set_var_string |
Set the value of a variable in the current scope, calling eval_string to obtain the value. |
std.base |
set_var |
Set the value of a variable in the current scope to a given value. |
std.bib |
cite_styles |
Table of known citation styles, values are functions which take a reference and outputs the text to go in a citation’s square brackets |
std.bib |
get_cite_style |
Returns the name of the current citation style |
std.bib |
set_cite_style |
Sets the current citation style |
std.func |
co_to_list |
Evaluates a coroutine’s yielded values to a list. |
std.func |
co_to_map |
Evaluates a coroutine’s returned {key,value} pairs to a table. |
std.func |
do_nothing |
A function which does nothing. |
std.func |
filter_list |
Takes a predicate and a list, returns a list of inputted elements which satisfy the predicate. |
std.func |
filter |
Takes a predicate and a coroutine, yielding yielded values which satisfy the predicate. |
std.func |
id |
A function which returns its input. |
std.func |
int |
A coroutine which yields integers in a non-repeating sequence. |
std.func |
key_list |
Returns a list of keys in a given table. |
std.func |
keys |
Yields keys yielded by a given coroutine. |
std.func |
kv_pairs |
Yields the key-value pairs of a table. |
std.func |
map |
Takes a function and a coroutine, yields the value of the function applied to yielded elements of the coroutine. |
std.func |
nat |
Yields the natural numbers in a non-repeating sequence. |
std.func |
seq |
Yields the integers in a sequence, takes input of first , last and step exactly as a Lua for-loop does (for i=first,last,step do ... end ) |
std.func |
take |
Takes a predicate and a coroutine, yields from the coroutine until the predicate no longer holds. |
std.func |
value_list |
Returns a list of values in a given table |
std.func |
whole |
Yields the whole numbers in a non-repeating sequence |
std.lingo |
cond |
Evaluates its input, returns false if the input if nil , false , ‘’ , 0 or ‘false’ (case-insensitive), otherwise returns true |
std.lingo |
toint |
Returns a concise representation of a condition. |
std.log |
log_debug_on |
Take an input n and call the rest of the inputs ... , calls std.log.log_debug(...) only on typesetting iteration n. |
std.log |
log_debug |
Output a given debugging message if the output verbosity is great enough. |
std.log |
log_err_at_loc |
Output a given error message at a specified location. |
std.log |
log_err_at_on |
Call std.log.log_err_at_loc but only on a specified typesetting iteration. |
std.log |
log_err_here |
Output an error message which includes the location of the current directive being evaluated. |
std.log |
log_err_on |
Take an input n and call the rest of the inputs ... , calls std.log.log_err(...) only on typesetting iteration n. |
std.log |
log_err |
Output a given error message if the output verbosity is great enough. Then, unconditionally exit. |
std.log |
log_info_on |
Take an input n and call the rest of the inputs ... , calls std.log.log_info(...) only on typesetting iteration n. |
std.log |
log_info |
Output a given informational message if the output verbosity is great enough. |
std.log |
log_warn_at_loc |
Output a given warning message at a specified location. |
std.log |
log_warn_at_on |
Call std.log.log_warn_at_loc but only on a specified typesetting iteration. |
std.log |
log_warn_here |
Output a warning message which includes the location of the current directive being evaluated. |
std.log |
log_warn_on |
Take an input n and call the rest of the inputs ... , calls std.log.log_warn(...) only on typesetting iteration n. |
std.log |
log_warn |
Output a given warning message if the output verbosity is great enough. |
std.ref |
get_label |
Return the current label value. |
std.ref |
set_label |
Set the current label value (the value returned by a ref to an anchor which was set down after the current call to get_label but before the next one, or the end of the current scope). |
std.util |
elem |
Takes a value v and a list of values vs , returns true iff v is a value in vs . |
std.util |
eq |
Compare the equality of two values (recursively if necessary, respecting the __eq metamethod) |
std.util |
extend |
Takes input of two lists and returns their concatenation (pure) |
std.util |
is_list |
Returns whether a given value represents a list, that is, it is a table whose indices are all numeric and which range from one to the length of the table. |
std.util |
non_nil |
Returns whether its input is not nil . |
std.util |
on_iter_wrap |
Takes a function f and returns a function which takes input of a value n and a list of arguments ... , and only calls f(...) if the current iteration is equal to the number evaluated from n . |
std.util |
sorted |
Sorts a list in-place and returns it. |
The Emblem standard library is written in Moonscript, which compiles to Lua. The following concepts are easily described in terms of classes and objects.
Package | Function | Subclass of | Description |
---|---|---|---|
std.ast |
Call |
Node |
Represents a document directive-call node. |
std.ast |
Content |
Node |
Represents a document content node. |
std.ast |
Word |
Node |
Represents a document word node |
std.bib |
Bib |
SyncSet |
Constructs a bibliography object, optionally takes the name of the header to use. |
std.events |
Component |
N/A | Represents an object which responds to the events: on_start , on_iter_start , on_iter_end and on_end . |
std.events |
Counter |
Component |
Represents an integer which is incremented with each use and is reset at the start of each iteration, or when another counter which lists it as a sub-counter is incremented. |
std.events |
SyncBox |
Component |
A container for a single value, requests a typesetting loop re-run if value at the end of the current iteration is different from that at the end of the previous. Can be passed an initial value, default 0 . |
std.events |
SyncContainer |
Component |
A container for a compound value, requests a typesetting loop re-run if value at the end of the current iteration is different from that at the end of the previous. Can be passed an initial value, default {} . |
std.events |
SyncList |
Component |
A SyncContainer which represents a list (ordered elements) |
std.events |
SyncMap |
Component |
A SyncContainer which represents a mapping (indexable key-value pairs). |
std.events |
SyncSet |
Component |
A SyncContainer which represents a set (unique elements). |
std.hdr |
Toc |
SyncList |
Constructs a table of contents object |
The following variables are created by Emblem’s core and are likely useful to extension writers.
Package | Variable | Description |
---|---|---|
std.base |
em |
Emblem public table, a map of callables used when evaluating a directive. Checked every time a directive is evaluated to determine whether any extension code must be run. |
std.base |
vars |
List of contexts containing the values of variables. |
std.constants |
node_flags |
Flags which may be bitwise-or’d together, and are accepted by the core. |
std.constants |
node_types |
IDs of the types of nodes recognised when the core unpacks table-representations of syntax trees. The classes in std.ast construct the such objects. |
std.lingo |
known_languages |
Map of languages to their respective interpreters for use with .include directives. |
std.lingo |
known_file_extensions |
Map of file extensions to their respective languages for use with .include directives. |
std.style |
stylers |
A map of common styling functions such as italic and bold |
To help extensions react to how the document is being processed, there are several events which are triggered.
These are triggered on objects which extend the Component
class defined in the std.base
module and are as follows.
on_start
, executed once after all extensions are loadedon_iter_start
, executed at the start of each iterationon_iter_end
, executed at the end of each iterationon_end
, executed once, after the final iteration but before output
There are a number of classes which may be imported from the std.std
module which provide frameworks for storing data whilst reacting to these events.
For example, the table of contents is a subclass of Component
which stores the names and numbers of headings as the document is processed, requesting another run if the table of contents at the end of the previous run is different to that at the end of the current (e.g. a page-number has been updated by some other change).
A re-iteration can be requested by calling the requires_reiter
function in Lua.
This will cause the typesetting loop to be run again, unless the (user-configurable) number of maximum iterations has been reached.
The number of the current iteration (starting from 1) is accessible through the em_iter
variable.
Emblem can take input of any format for which it has an input driver.
When Emblem inputs a file through the .include
directive, a language can optionally be specified in the second parameter to determine the parser to use.
This language is used to look up the parser to use in the std.in.drivers.known_languages
table.
An input driver is simply a module which adds at least one parser function into this table.
Emblem is capable of outputting to any format for which it has an output driver.
The binary itself contains some output drivers, but it is also possible to import ones from other sources as desired.
In analogy with input drivers, there exists a table, std.out.drivers.output_drivers
, which is used when looking up the language into which the document will be output.
An output driver is simply module which adds at least one outputting function into this table.
This project is maintained by Ed Jones and is licensed under the GNU General Public License version 3.
Contributions are welcome!
Some notes on the build process.
- The file
em.yml
is used to document the command-line interface and dependencies of the project - When a new file is added which must be included in the binary (either C or Lua/Moonscript source),
scripts/autogen && ./configure
must be rerun make
will by default compile theem
binarymake check_em
can be used to compile the unit test binarycheck_em
make dist
will generate an archive containing all things present in a distributable version of the projectmake format
can be used to format the codemake lint
can be used to run the linter