# There are two types of elements in Mau, inline and block ones
# (the nomenclature is borrowed from HTML).
# Block elements are always on a new line, so they correspond to
# main items in the document, while inline elements can only appear
# inside a paragraph.
[docs]class Node:
node_type = "node"
[docs] def asdict(self):
return {"type": self.node_type} # pragma: no cover
def __eq__(self, other):
return self.asdict() == other.asdict()
# Inline elements
[docs]class ValueNode(Node):
node_type = "value_node"
def __init__(self, value):
self.value = value
[docs] def asdict(self):
return {"type": self.node_type, "value": self.value}
[docs]class ContainerNode(Node):
node_type = "container_node"
def __init__(self, content):
self.content = content
[docs] def asdict(self):
return {"type": self.node_type, "content": [i.asdict() for i in self.content]}
[docs]class WrapperNode(ValueNode):
node_type = "wrapper_node"
def __init__(self, value, content):
super().__init__(value)
self.content = content
[docs] def asdict(self):
return {
"type": self.node_type,
"value": self.value,
"content": self.content.asdict(),
}
[docs]class WordNode(ValueNode):
"""This is a single word, it's used internally
and eventually packed together with others into
a TextNode
"""
node_type = "word"
[docs]class TextNode(ValueNode):
"""This contains plain text and is created
as a collation of multiple WordNode objects
Attributes:
value: the text contained in the node
"""
node_type = "text"
[docs]class SentenceNode(ContainerNode):
"""A recursive container node.
This node represents the content of a paragraph, but it is recursive,
while :obj:`ParagraphNode` is not. It can contain other :obj:`SentenceNode`
objects, or other types of nodes like :obj:`TextNode`,
:obj:`StyleNode` or :obj:`MacroNode`.
Attributes:
content (:obj:`list`): a list of nodes contained in this node
"""
node_type = "sentence"
[docs]class StyleNode(WrapperNode):
"""Describes the style applied to a node.
It contains a single node that is styled with the given value.
Currently Mau supports 2 styles represented by `*` and `_`
but this node is agnostic.
Attributes:
value (:obj:`str`): the name of the style
content (:obj:`SentenceNode`): a single node
"""
node_type = "style"
[docs]class VerbatimNode(ValueNode):
"""Verbatim text.
This node contains verbatim text.
Attributes:
value: the text contained in the node
"""
node_type = "verbatim"
[docs]class ClassNode(Node):
"""Text with one or more class.
This node contains text that has been assigned
one or more classes.
Attributes:
value: the text contained in the node
classes (:obj:`list`): the classes assigned to the text
"""
node_type = "class"
def __init__(self, classes, content):
self.classes = classes
self.content = content
[docs] def asdict(self):
return {
"type": self.node_type,
"classes": self.classes,
"content": self.content.asdict(),
}
[docs]class MacroNode(Node):
"""Base node for macros.
This node contains a macro, with a name and arguments.
Attributes:
value: the name of the macro
arguments: the string of arguments
"""
node_type = "macro"
def __init__(self, name, args=None, kwargs=None):
self.name = name
self.args = args or []
self.kwargs = kwargs or {}
try:
self.value = self.args[0]
except IndexError:
self.value = None
[docs] def asdict(self):
return {
"type": self.node_type,
"name": self.name,
"value": self.value,
"args": self.args,
"kwargs": self.kwargs,
}
[docs]class LinkNode(Node):
"""Link macro.
This node contains a link.
Attributes:
target: the target of the link
text: the text of the link
"""
node_type = "link"
def __init__(self, target, text):
self.target = target
self.text = text
[docs] def asdict(self):
return {
"type": self.node_type,
"target": self.target,
"text": self.text,
}
[docs]class ImageNode(Node):
"""Inline image.
This node contains an inline image.
Attributes:
uri: the URI of the image
alt_text: alternative text if the image is not available
width: width of the image
height: height fo the image
"""
node_type = "image"
def __init__(self, uri, alt_text=None, width=None, height=None):
self.uri = uri
self.alt_text = alt_text
self.width = width
self.height = height
[docs] def asdict(self):
return {
"type": self.node_type,
"uri": self.uri,
"alt_text": self.alt_text,
"width": self.width,
"height": self.height,
}
# Block elements
[docs]class HorizontalRuleNode(Node):
"""A horizontal rule."""
[docs] def asdict(self):
return {"type": "horizontal_rule"}
[docs]class ContentNode(Node):
"""Content included in the page.
This represents generic content included in the page.
Arguments:
uri: the URI of the image
title: caption of the image
args: unnamed arguments
kwargs: named arguments
"""
node_type = "content"
def __init__(self, uri, title=None, args=None, kwargs=None):
self.uri = uri
self.title = title
self.kwargs = kwargs or {}
self.args = args or []
[docs] def asdict(self):
return {
"type": self.node_type,
"uri": self.uri,
"title": self.title.asdict() if self.title else None,
"args": self.args,
"kwargs": self.kwargs,
}
[docs]class ContentImageNode(Node):
"""An image included in the page.
This represents an image included in the page.
Arguments:
uri: the URI of the image
alt_text: alternative text if the image is not available
classes (:obj:`list`): list of classes added to the image
title: caption of the image
kwargs: named arguments
"""
node_type = "content_image"
def __init__(self, uri, alt_text, classes=None, title=None, kwargs=None):
self.uri = uri
self.alt_text = alt_text
self.classes = classes
self.title = title
self.kwargs = kwargs or {}
[docs] def asdict(self):
return {
"type": self.node_type,
"alt_text": self.alt_text,
"uri": self.uri,
"title": self.title.asdict() if self.title else None,
"classes": self.classes,
"kwargs": self.kwargs,
}
[docs]class ParagraphNode(Node):
"""A paragraph.
This is a wrapper around a single :obj:`SentenceNode`. This node
is not recursive.
Arguments:
content (:obj:`SentenceNode`): the text of the paragraph
args: unnamed arguments
kwargs: named arguments
"""
node_type = "paragraph"
def __init__(self, content, args=None, kwargs=None):
self.args = args or []
self.kwargs = kwargs or {}
self.content = content
[docs] def asdict(self):
return {
"type": self.node_type,
"content": self.content.asdict(),
"args": self.args,
"kwargs": self.kwargs,
}
[docs]class BlockNode(Node):
"""A block.
This node contains a generic block.
Arguments:
blocktype: the type of this block
content: content of the block
secondary_content: secondary content of this block
title: title of this block
classes: a comma-separated list of classes
engine: the engine used to render this block
preprocessor: the preprocessor used for this block
args: unnamed arguments
kwargs: named arguments
"""
node_type = "block"
def __init__(
self,
blocktype,
content,
secondary_content,
title=None,
classes=None,
engine=None,
preprocessor=None,
args=None,
kwargs=None,
):
self.blocktype = blocktype
self.content = content
self.secondary_content = secondary_content
self.title = title
self.classes = classes or []
self.engine = engine
self.preprocessor = preprocessor
self.args = args or []
self.kwargs = kwargs or {}
[docs] def asdict(self):
return {
"type": self.node_type,
"blocktype": self.blocktype,
"content": [i.asdict() for i in self.content],
"secondary_content": [i.asdict() for i in self.secondary_content],
"classes": self.classes,
"engine": self.engine,
"preprocessor": self.preprocessor,
"args": self.args,
"kwargs": self.kwargs,
"title": self.title.asdict() if self.title else None,
}
[docs]class SourceNode(Node):
"""A block of verbatim text or source code.
This node contains verbatim text or source code.
Arguments:
language: the language of the code contained in this block
callouts: callouts for this source code
{"markers": [(linenum, name)], "contents": {name:text}}
highlights: list of lines that have to be highlighted
delimiter: callouts delimiter
code: content of the block
title: title of this block
kwargs: named arguments
"""
node_type = "source"
def __init__(
self, language, callouts, highlights, delimiter, code, title=None, kwargs=None
):
self.language = language
self.callouts = callouts
self.highlights = highlights
self.delimiter = delimiter
self.code = code
self.title = title
self.kwargs = kwargs or {}
[docs] def asdict(self):
return {
"type": self.node_type,
"language": self.language,
"callouts": self.callouts,
"highlights": self.highlights,
"delimiter": self.delimiter,
"code": [i.asdict() for i in self.code],
"title": self.title.asdict() if self.title else None,
"kwargs": self.kwargs,
}
[docs]class CommandNode(Node):
"""A Mau command.
This represents a command issued in a Mau document.
Arguments:
name: the name of the command
args: unnamed arguments
kwargs: named arguments
"""
node_type = "command"
def __init__(self, name, args=None, kwargs=None):
self.args = args or []
self.kwargs = kwargs or {}
self.name = name
[docs] def asdict(self):
return {
"type": self.node_type,
"name": self.name,
"args": self.args,
"kwargs": self.kwargs,
}
[docs]class TocNode(Node):
"""A Table of Contents.
This node contains the entries of the Table of Contents.
Arguments:
entries: a list of TocEntryNode objects
"""
node_type = "toc"
def __init__(self, entries=None):
self.entries = entries or []
[docs] def asdict(self):
return {"type": self.node_type, "entries": [i.asdict() for i in self.entries]}
[docs]class TocEntryNode(Node):
"""An entry of the Table of Contents.
This node contains an entry of the Table of Contents.
Arguments:
level: level of this entry (level of the header)
text: the text of the entry
anchor: the ID of the header
children: child entries
"""
node_type = "toc_entry"
def __init__(self, header_node, children=None):
self.header = header_node
self.children = children or []
[docs] def asdict(self):
return {
"type": self.node_type,
"header": self.header.asdict(),
"children": [i.asdict() for i in self.children],
}
[docs]class ListNode(Node):
"""A list.
This node contains an ordered or unordered list.
Arguments:
ordered (:obj:`bool`): whether the list is ordered or not
items (:obj:`list`): entries contained in this entry
main_node (:obj:`bool`): whether this is the main node of the list
"""
node_type = "list"
def __init__(self, ordered, items, main_node=False):
self.ordered = ordered
self.items = items
self.main_node = main_node
[docs] def asdict(self):
return {
"type": self.node_type,
"ordered": self.ordered,
"items": [i.asdict() for i in self.items],
"main_node": self.main_node,
}
[docs]class ListItemNode(Node):
"""An entry in a list.
This node contains an entry of an ordered or unordered list.
Arguments:
level: the level of depth of this entry in the list
content: the content of the entry
"""
node_type = "list_item"
def __init__(self, level, content):
self.level = level
self.content = content
[docs] def asdict(self):
return {
"type": self.node_type,
"level": self.level,
"content": self.content.asdict(),
}
[docs]class DocumentNode(ContainerNode):
"""A document.
This node represents the full document.
Arguments:
content: the content of the document
"""
node_type = "document"