Add SmartArrows

Signed-off-by: trivernis <trivernis@protonmail.com>
feature/epub-rendering
trivernis 4 years ago
parent 0db3c62c57
commit 1a4ec92aff
Signed by: Trivernis
GPG Key ID: DFFFCC2C7A02DB45

2
Cargo.lock generated

@ -1277,7 +1277,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "snekdown"
version = "0.28.0"
version = "0.29.0"
dependencies = [
"asciimath-rs 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)",
"base64 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",

@ -1,6 +1,6 @@
[package]
name = "snekdown"
version = "0.28.0"
version = "0.29.0"
authors = ["trivernis <trivernis@protonmail.com>"]
edition = "2018"
license-file = "LICENSE"

@ -148,17 +148,31 @@ Example:
```toml
# bibliography.bib.toml
[Meta]
author = "Snek"
published = "2020"
test-key = ["test value", "test value 2"]
[imports]
ignored-imports = ["style.css"] # those files won't get imported
included-stylesheets = ["style2.css"] # stylesheets that should be included
included-configs = [] # other metadata files that should be included
included-bibliography = ["mybib.toml"] # bibliography that should be included
included-glossary = ["myglossary.toml"] #glossary that sould be included
# those files won't get imported
ignored-imports = ["style.css"]
# stylesheets that should be included
included-stylesheets = ["style2.css"]
# other metadata files that should be included
included-configs = []
# bibliography that should be included
included-bibliography = ["mybib.toml"]
# glossary that sould be included
included-glossary = ["myglossary.toml"]
# if external sources (images, stylesheets, MathJax)
# should be embedded into the document (default true)
embed-external = true
# If SmartArrows should be used (default true)
smart-arrows = true
```
The `[Section]` keys are not relevant as the structure gets flattened before the values are read.
@ -287,6 +301,14 @@ $$$
The expression get's converted into MathML which is then converted by MathJax when loaded in
the browser.
## Smart Arrows
Snekdown automatically renders the sequences `-->`, `==>`, `<--`, `<==`, `<-->`, `<==>` as
their respective unicode arrows (similar to [markdown-it-smartarrows](https://github.com/adam-p/markdown-it-smartarrows)).
This behavior can be turned off by setting the config parameter `smart-arrows` to `false`
(the config needs to be imported before the arrows are used for that to work).
## Roadmap
The end goal is to have a markup language with features similar to LaTeX.

@ -183,6 +183,7 @@ pub enum Inline {
TemplateVar(Arc<RwLock<TemplateVariable>>),
CharacterCode(CharacterCode),
LineBreak,
Arrow(Arrow),
}
#[derive(Clone, Debug)]
@ -289,6 +290,16 @@ pub struct CharacterCode {
pub(crate) code: String,
}
#[derive(Clone, Debug)]
pub enum Arrow {
RightArrow,
LeftArrow,
LeftRightArrow,
BigRightArrow,
BigLeftArrow,
BigLeftRightArrow,
}
// implementations
impl Document {

@ -81,6 +81,15 @@ pub(crate) const CHARACTER_STOP: char = SEMICOLON;
pub(crate) const GLOSSARY_REF_START: char = TILDE;
// Arrows
pub(crate) const A_RIGHT_ARROW: &'static [char] = &['-', '-', '>'];
pub(crate) const A_LEFT_ARROW: &'static [char] = &['<', '-', '-'];
pub(crate) const A_LEFT_RIGHT_ARROW: &'static [char] = &['<', '-', '-', '>'];
pub(crate) const A_BIG_RIGHT_ARROW: &'static [char] = &['=', '=', '>'];
pub(crate) const A_BIG_LEFT_ARROW: &'static [char] = &['<', '=', '='];
pub(crate) const A_BIG_LEFT_RIGHT_ARROW: &'static [char] = &['<', '=', '=', '>'];
// groups
pub(crate) const QUOTES: [char; 2] = [SINGLE_QUOTE, DOUBLE_QUOTE];
@ -113,6 +122,15 @@ pub(crate) const INLINE_SPECIAL_CHARS: &'static [char] = &[
MATH,
];
pub(crate) const INLINE_SPECIAL_SEQUENCES: &'static [&'static [char]] = &[
A_BIG_LEFT_RIGHT_ARROW,
A_BIG_LEFT_ARROW,
A_BIG_RIGHT_ARROW,
A_RIGHT_ARROW,
A_LEFT_ARROW,
A_LEFT_RIGHT_ARROW,
];
pub(crate) const LIST_SPECIAL_CHARS: [char; 14] = [
MINUS, PLUS, ASTERISK, O, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
];

@ -49,7 +49,7 @@ code {
}
code pre {
font-family: "Fira Code", monospace;
font-family: "Fira Code", "Mono", monospace;
padding: 0.8em 0.2em;
background-color: #EEE !important;
border-radius: 0.25em;
@ -133,4 +133,8 @@ blockquote {
text-decoration: none;
color: inherit;
border-bottom: 1px dotted #000;
}
.arrow {
font-family: "Fira Code", "Mono", monospace;
}

@ -65,6 +65,7 @@ impl ToHtml for Inline {
Inline::LineBreak => writer.write("<br>".to_string()),
Inline::CharacterCode(code) => code.to_html(writer),
Inline::GlossaryReference(gloss) => gloss.lock().unwrap().to_html(writer),
Inline::Arrow(a) => a.to_html(writer),
}
}
}
@ -687,3 +688,19 @@ impl ToHtml for GlossaryReference {
Ok(())
}
}
impl ToHtml for Arrow {
fn to_html(&self, writer: &mut HTMLWriter) -> io::Result<()> {
writer.write("<span class=\"arrow\">".to_string())?;
match self {
Arrow::RightArrow => writer.write("&xrarr;".to_string()),
Arrow::LeftArrow => writer.write("&xlarr;".to_string()),
Arrow::LeftRightArrow => writer.write("&xharr;".to_string()),
Arrow::BigRightArrow => writer.write("&xrArr;".to_string()),
Arrow::BigLeftArrow => writer.write("&xlArr;".to_string()),
Arrow::BigLeftRightArrow => writer.write("&xhArr;".to_string()),
}?;
writer.write("</span>".to_string())
}
}

@ -3,7 +3,7 @@ use crate::elements::tokens::*;
use crate::elements::BibReference;
use crate::elements::*;
use crate::parser::block::ParseBlock;
use crate::references::configuration::keys::BIB_REF_DISPLAY;
use crate::references::configuration::keys::{BIB_REF_DISPLAY, SMART_ARROWS};
use crate::references::glossary::GlossaryDisplay;
use crate::references::glossary::GlossaryReference;
use crate::references::templates::{GetTemplateVariables, Template, TemplateVariable};
@ -36,6 +36,7 @@ pub(crate) trait ParseInline {
fn parse_placeholder(&mut self) -> ParseResult<Arc<RwLock<Placeholder>>>;
fn parse_template(&mut self) -> ParseResult<Template>;
fn parse_character_code(&mut self) -> ParseResult<CharacterCode>;
fn parse_arrow(&mut self) -> ParseResult<Arrow>;
}
impl ParseInline for Parser {
@ -120,6 +121,9 @@ impl ParseInline for Parser {
} else if let Ok(char_code) = self.parse_character_code() {
log::trace!("Inline::CharacterCode {}", char_code.code);
Ok(Inline::CharacterCode(char_code))
} else if let Ok(arrow) = self.parse_arrow() {
log::trace!("Inline::Arrow {:?}", arrow);
Ok(Inline::Arrow(arrow))
} else {
let plain = self.parse_plain()?;
log::trace!("Inline::Plain {}", plain.value);
@ -434,10 +438,13 @@ impl ParseInline for Parser {
}
while let Some(ch) = self.ctm.next_char() {
let index = self.ctm.get_index();
if self.ctm.check_any(&INLINE_SPECIAL_CHARS)
|| self.ctm.check_any(&self.inline_break_at)
|| self.ctm.check_any_sequence(&INLINE_SPECIAL_SEQUENCES)
|| (self.parse_variables && self.ctm.check_char(&TEMP_VAR_OPEN))
{
self.ctm.rewind(index);
break;
}
if !self.ctm.check_char(&SPECIAL_ESCAPE) {
@ -623,4 +630,38 @@ impl ParseInline for Parser {
Ok(CharacterCode { code })
}
/// Parses an arrow
fn parse_arrow(&mut self) -> ParseResult<Arrow> {
if !self
.options
.document
.config
.get_entry(SMART_ARROWS)
.and_then(|e| e.get().as_bool())
.unwrap_or(true)
{
Err(self.ctm.err())
} else if self.ctm.check_sequence(A_LEFT_RIGHT_ARROW) {
self.ctm.seek_one()?;
Ok(Arrow::LeftRightArrow)
} else if self.ctm.check_sequence(A_RIGHT_ARROW) {
self.ctm.seek_one()?;
Ok(Arrow::RightArrow)
} else if self.ctm.check_sequence(A_LEFT_ARROW) {
self.ctm.seek_one()?;
Ok(Arrow::LeftArrow)
} else if self.ctm.check_sequence(A_BIG_LEFT_RIGHT_ARROW) {
self.ctm.seek_one()?;
Ok(Arrow::BigLeftRightArrow)
} else if self.ctm.check_sequence(A_BIG_RIGHT_ARROW) {
self.ctm.seek_one()?;
Ok(Arrow::BigRightArrow)
} else if self.ctm.check_sequence(A_BIG_LEFT_ARROW) {
self.ctm.seek_one()?;
Ok(Arrow::BigLeftArrow)
} else {
Err(self.ctm.err())
}
}
}

@ -7,3 +7,4 @@ pub const IMP_CONFIGS: &str = "included-configs";
pub const IMP_BIBLIOGRAPHY: &str = "included-bibliography";
pub const IMP_GLOSSARY: &str = "included-glossary";
pub const EMBED_EXTERNAL: &str = "embed-external";
pub const SMART_ARROWS: &str = "smart-arrows";

@ -42,6 +42,14 @@ impl Value {
_ => "".to_string(),
}
}
/// Returns the bool value if the value is a boolean
pub fn as_bool(&self) -> Option<bool> {
match self {
Value::Bool(b) => Some(*b),
_ => None,
}
}
}
impl ConfigEntry {

Loading…
Cancel
Save