Resolve conflict between glossary and striked text parsing

Signed-off-by: trivernis <trivernis@protonmail.com>
pull/2/head
trivernis 4 years ago
parent 04e1e30fef
commit 72d0e0a215
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]] [[package]]
name = "snekdown" name = "snekdown"
version = "0.29.1" version = "0.29.2"
dependencies = [ dependencies = [
"asciimath-rs 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "base64 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",

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

@ -34,6 +34,7 @@ pub(crate) const PERCENT: char = '%';
pub(crate) const COMMA: char = ','; pub(crate) const COMMA: char = ',';
pub(crate) const MATH: char = '$'; pub(crate) const MATH: char = '$';
pub(crate) const AMPERSAND: char = '&'; pub(crate) const AMPERSAND: char = '&';
pub(crate) const QUESTION_MARK: char = '?';
// aliases // aliases
@ -135,7 +136,7 @@ pub(crate) const LIST_SPECIAL_CHARS: [char; 14] = [
MINUS, PLUS, ASTERISK, O, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', MINUS, PLUS, ASTERISK, O, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
]; ];
pub(crate) const WHITESPACE: [char; 4] = [' ', '\t', '\r', '\n']; pub(crate) const WHITESPACE: &[char] = &[' ', '\t', '\r', '\n'];
pub(crate) const INLINE_WHITESPACE: [char; 3] = [' ', '\t', '\r']; pub(crate) const INLINE_WHITESPACE: [char; 3] = [' ', '\t', '\r'];
// sequences // sequences

@ -0,0 +1,136 @@
body {
overflow-x: hidden;
color: #000;
word-break: break-word;
}
.content {
font-family: "Fira Sans", "Noto Sans", SansSerif, sans-serif;
margin: auto;
background-color: #FFF;
}
h1 {
font-size: 2.2rem;
}
h2 {
font-size: 1.8rem;
}
h3 {
font-size: 1.4rem;
}
h4 {
font-size: 1rem;
}
h5 {
font-size: 0.8rem;
}
h6 {
font-size: 0.4rem;
}
img {
max-width: 100%;
max-height: 100vh;
height: auto;
}
code {
color: #000;
}
code pre {
font-family: "Fira Code", "Mono", monospace;
padding: 0.8em 0.2em;
background-color: #EEE !important;
border-radius: 0.25em;
}
code.inlineCode {
font-family: "Fira Code", monospace;
border-radius: 0.1em;
background-color: #EEE;
padding: 0 0.1em
}
.tableWrapper {
overflow-x: auto;
width: 100%;
}
.tableWrapper > table {
margin: auto;
}
table {
border-collapse: collapse;
}
table tr:nth-child(odd) {
background-color: #DDD;
}
table tr:nth-child(1) {
background-color: white;
font-weight: bold;
border-bottom: 1px solid black;
}
table td, table th {
border-left: 1px solid black;
padding: 0.2em 0.5em
}
table tr td:first-child, table tr th:first-child {
border-left: none;
}
blockquote {
margin-left: 0;
background-color: rgba(0, 0, 0, 0);
}
.quote {
border-left: 0.3em solid gray;
border-radius: 0.2em;
padding-left: 1em;
margin-left: 0;
background-color: #EEE;
}
.quote .metadata {
font-style: italic;
padding-left: 0.5em;
color: #444
}
.figure {
width: 100%;
display: block;
text-align: center;
}
.figure .imageDescription {
display: block;
color: #444;
font-style: italic;
}
.centered {
text-align: center;
}
.glossaryReference {
text-decoration: none;
color: inherit;
border-bottom: 1px dotted #000;
}
.arrow {
font-family: "Fira Code", "Mono", monospace;
}

@ -0,0 +1,154 @@
use crate::elements::{
Block, Document, Element, Header, Inline, Line, List, ListItem, Paragraph, Section,
};
use crate::format::epub::epub_writer::EpubWriter;
use std::io::Result;
use std::mem;
pub trait ToEpub {
fn to_epub(&self, writer: &mut EpubWriter) -> Result<()>;
}
impl ToEpub for Element {
fn to_epub(&self, writer: &mut EpubWriter) -> Result<()> {
match self {
Element::Inline(inline) => inline.to_epub(writer),
Element::Block(block) => block.to_epub(writer),
Element::Line(line) => line.to_epub(writer),
}
}
}
impl ToEpub for Block {
fn to_epub(&self, writer: &mut EpubWriter) -> Result<()> {
match self {
Block::Null => Ok(()),
Block::Section(s) => s.to_epub(writer),
Block::List(l) => l.to_epub(writer),
Block::Paragraph(p) => p.to_epub(writer),
}
}
}
impl ToEpub for Line {
fn to_epub(&self, writer: &mut EpubWriter) -> Result<()> {
unimplemented!()
}
}
impl ToEpub for Inline {
fn to_epub(&self, writer: &mut EpubWriter) -> Result<()> {
unimplemented!()
}
}
impl ToEpub for Document {
fn to_epub(&self, writer: &mut EpubWriter) -> Result<()> {
self.downloads.lock().unwrap().download_all();
let style = minify(std::include_str!("assets/style.css"));
writer.stylesheet(style)?;
for mut stylesheet in self.stylesheets {
let mut sheet = stylesheet.lock().unwrap();
let data = mem::take(&mut sheet.data);
if let Some(data) = data {
let sheet_data = String::from_utf8(data)?;
writer.stylesheet(&sheet_data);
}
}
Ok(())
}
}
impl ToEpub for Section {
fn to_epub(&self, writer: &mut EpubWriter) -> Result<()> {
writer.section(self.header.size, self.header.plain.clone())?;
writer.content("<!DOCTYPE html>".to_string());
writer.content("<html xmlns=\"http://www.w3.org/1999/xhtml\"><body>".to_string());
self.header.to_epub(writer)?;
for element in &self.elements {
element.to_epub(writer)?;
}
writer.content("</body></html>".to_string());
Ok(())
}
}
impl ToEpub for Header {
fn to_epub(&self, writer: &mut EpubWriter) -> Result<()> {
writer.content(format!("<h{} id=\"", self.size));
writer.escaped_attribute_content(self.anchor.clone());
writer.content("\">".to_string());
self.line.to_epub(writer);
writer.content("</h1>".to_string());
Ok(())
}
}
impl ToEpub for List {
fn to_epub(&self, writer: &mut EpubWriter) -> Result<()> {
if self.ordered {
writer.content("<ol>".to_string());
for item in self.items {
item.to_epub(writer);
}
writer.content("</ol>".to_string());
} else {
writer.content("<ul>".to_string());
for item in self.items {
item.to_epub(writer);
}
writer.content("</ul>".to_string());
}
Ok(())
}
}
impl ToEpub for ListItem {
fn to_epub(&self, writer: &mut EpubWriter) -> Result<()> {
writer.content("<li>".to_string());
self.text.to_epub(writer)?;
if let Some(first) = self.children.first() {
if first.ordered {
writer.content("<ol>".to_string());
for item in &self.children {
item.to_epub(writer)?;
}
writer.content("</ol>".to_string());
} else {
writer.content("<ul>".to_string());
for item in &self.children {
item.to_epub(writer)?;
}
writer.content("</ul>".to_string());
}
}
writer.content("</li>".to_string());
Ok(())
}
}
impl ToEpub for Paragraph {
fn to_epub(&self, writer: &mut EpubWriter) -> Result<()> {
writer.content("<div class=\"paragraph\"".to_string());
if let Some(first) = self.elements.first() {
first.to_epub(writer)?;
}
if self.elements.len() > 1 {
for element in &self.elements[1..] {
writer.content("<br/>".to_string());
element.to_epub(writer)?;
}
}
Ok(())
}
}

@ -94,12 +94,12 @@ impl ParseInline for Parser {
} else if let Ok(mono) = self.parse_monospace() { } else if let Ok(mono) = self.parse_monospace() {
log::trace!("Inline::Monospace {}", mono.value); log::trace!("Inline::Monospace {}", mono.value);
Ok(Inline::Monospace(mono)) Ok(Inline::Monospace(mono))
} else if let Ok(gloss) = self.parse_glossary_reference() {
log::trace!("Inline::GlossaryReference {}", gloss.lock().unwrap().short);
Ok(Inline::GlossaryReference(gloss))
} else if let Ok(striked) = self.parse_striked() { } else if let Ok(striked) = self.parse_striked() {
log::trace!("Inline::Striked"); log::trace!("Inline::Striked");
Ok(Inline::Striked(striked)) Ok(Inline::Striked(striked))
} else if let Ok(gloss) = self.parse_glossary_reference() {
log::trace!("Inline::GlossaryReference {}", gloss.lock().unwrap().short);
Ok(Inline::GlossaryReference(gloss))
} else if let Ok(superscript) = self.parse_superscript() { } else if let Ok(superscript) = self.parse_superscript() {
log::trace!("Inline::Superscript"); log::trace!("Inline::Superscript");
Ok(Inline::Superscript(superscript)) Ok(Inline::Superscript(superscript))
@ -252,6 +252,7 @@ impl ParseInline for Parser {
self.ctm.assert_sequence(&STRIKED, Some(start_index))?; self.ctm.assert_sequence(&STRIKED, Some(start_index))?;
self.ctm.seek_one()?; self.ctm.seek_one()?;
let mut inline = vec![self.parse_inline()?]; let mut inline = vec![self.parse_inline()?];
while !self.ctm.check_sequence(&STRIKED) { while !self.ctm.check_sequence(&STRIKED) {
if let Ok(result) = self.parse_inline() { if let Ok(result) = self.parse_inline() {
inline.push(result); inline.push(result);
@ -259,7 +260,14 @@ impl ParseInline for Parser {
return Err(self.ctm.rewind_with_error(start_index)); return Err(self.ctm.rewind_with_error(start_index));
} }
} }
self.ctm.seek_one()?; self.ctm.rewind(self.ctm.get_index() - STRIKED.len());
if self.ctm.check_any(WHITESPACE) {
return Err(self.ctm.rewind_with_error(start_index));
}
for _ in 0..(STRIKED.len() + 1) {
self.ctm.seek_one()?;
}
Ok(StrikedText { value: inline }) Ok(StrikedText { value: inline })
} }
@ -396,8 +404,9 @@ impl ParseInline for Parser {
/// Parses a reference to a glossary entry /// Parses a reference to a glossary entry
fn parse_glossary_reference(&mut self) -> ParseResult<Arc<Mutex<GlossaryReference>>> { fn parse_glossary_reference(&mut self) -> ParseResult<Arc<Mutex<GlossaryReference>>> {
self.ctm.assert_char(&GLOSSARY_REF_START, None)?;
let start_index = self.ctm.get_index(); let start_index = self.ctm.get_index();
self.ctm
.assert_char(&GLOSSARY_REF_START, Some(start_index))?;
self.ctm.seek_one()?; self.ctm.seek_one()?;
let display = if self.ctm.check_char(&GLOSSARY_REF_START) { let display = if self.ctm.check_char(&GLOSSARY_REF_START) {
@ -409,10 +418,10 @@ impl ParseInline for Parser {
let mut key = let mut key =
self.ctm self.ctm
.get_string_until_any_or_rewind(&WHITESPACE, &[TILDE], start_index)?; .get_string_until_any_or_rewind(&WHITESPACE, &[TILDE], start_index)?;
if key.len() == 0 { if key.is_empty() {
return Err(self.ctm.rewind_with_error(start_index)); return Err(self.ctm.rewind_with_error(start_index));
} }
if !key.chars().last().unwrap().is_alphabetic() { while !key.is_empty() && !key.chars().last().unwrap().is_alphabetic() {
self.ctm.rewind(self.ctm.get_index() - 1); self.ctm.rewind(self.ctm.get_index() - 1);
key = key[..key.len() - 1].to_string(); key = key[..key.len() - 1].to_string();
} }

Loading…
Cancel
Save