From 6bf51b91f083a7833d0280c2bd45cfeb492444a5 Mon Sep 17 00:00:00 2001 From: trivernis Date: Thu, 4 Jun 2020 21:00:19 +0200 Subject: [PATCH] Add color formatting --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 +++- src/format/html.rs | 11 +++++++++++ src/parsing/elements.rs | 7 +++++++ src/parsing/inline.rs | 22 +++++++++++++++++++++- src/parsing/tokens.rs | 20 ++++++++++++++++++-- 7 files changed, 62 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5255230..5beaa2b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -404,7 +404,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "snekdown" -version = "0.11.0" +version = "0.12.0" dependencies = [ "chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "colored 1.9.3 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index e0933d3..b345029 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "snekdown" -version = "0.11.0" +version = "0.12.0" authors = ["trivernis "] edition = "2018" license-file = "LICENSE" diff --git a/README.md b/README.md index 6e84920..f5538f7 100644 --- a/README.md +++ b/README.md @@ -158,6 +158,7 @@ _Underlined_ ^Superscript^ `Monospace` :Emoji: +§[#0C0]Colored text§[] §[red] red §[] ``` ## Roadmap @@ -166,11 +167,12 @@ The end goal is to have a markup language with features similar to LaTeX. - [x] Checkboxes - [x] Emojis (\:emoji:) +- [x] Colors +- [ ] Watching and rendering on change - [ ] Metadata files - [ ] Bibliography - [ ] Math - [ ] Text sizes -- [ ] Colors - [ ] Title pages - [ ] Glossary - [ ] Cross References diff --git a/src/format/html.rs b/src/format/html.rs index 88811f3..910fcdc 100644 --- a/src/format/html.rs +++ b/src/format/html.rs @@ -59,6 +59,7 @@ impl ToHtml for Inline { Inline::Superscript(superscript) => superscript.to_html(), Inline::Checkbox(checkbox) => checkbox.to_html(), Inline::Emoji(emoji) => emoji.to_html(), + Inline::Colored(colored) => colored.to_html(), } } } @@ -498,3 +499,13 @@ impl ToHtml for Emoji { ) } } + +impl ToHtml for Colored { + fn to_html(&self) -> String { + format!( + "{}", + encode_attribute(self.color.as_str()), + self.value.to_html() + ) + } +} diff --git a/src/parsing/elements.rs b/src/parsing/elements.rs index 10c7f67..ec55e8b 100644 --- a/src/parsing/elements.rs +++ b/src/parsing/elements.rs @@ -158,6 +158,7 @@ pub enum Inline { Reference(Reference), Checkbox(Checkbox), Emoji(Emoji), + Colored(Colored), } #[derive(Clone, Debug)] @@ -259,6 +260,12 @@ pub struct Emoji { pub(crate) name: String, } +#[derive(Clone, Debug)] +pub struct Colored { + pub(crate) value: Box, + pub(crate) color: String, +} + // implementations impl Document { diff --git a/src/parsing/inline.rs b/src/parsing/inline.rs index 34a604c..0f3415a 100644 --- a/src/parsing/inline.rs +++ b/src/parsing/inline.rs @@ -17,6 +17,7 @@ pub(crate) trait ParseInline { fn parse_underlined(&mut self) -> ParseResult; fn parse_superscript(&mut self) -> ParseResult; fn parse_emoji(&mut self) -> ParseResult; + fn parse_colored(&mut self) -> ParseResult; fn parse_plain(&mut self) -> ParseResult; } @@ -47,6 +48,8 @@ impl ParseInline for Parser { Ok(Inline::Checkbox(checkbox)) } else if let Ok(emoji) = self.parse_emoji() { Ok(Inline::Emoji(emoji)) + } else if let Ok(colored) = self.parse_colored() { + Ok(Inline::Colored(colored)) } else { Ok(Inline::Plain(self.parse_plain()?)) } @@ -214,7 +217,7 @@ impl ParseInline for Parser { let start_index = self.index; self.assert_special(&EMOJI, start_index)?; self.skip_char(); - let name = self.get_string_until_or_revert(&[EMOJI], &[], start_index)?; + let name = self.get_string_until_or_revert(&[EMOJI], &[SPACE, LB], start_index)?; self.skip_char(); if let Some(emoji) = gh_emoji::get(name.as_str()) { let emoji_char = *emoji.chars().collect::<Vec<char>>().first().unwrap(); @@ -226,4 +229,21 @@ impl ParseInline for Parser { Err(self.revert_with_error(start_index)) } } + + /// parses colored text + fn parse_colored(&mut self) -> ParseResult<Colored> { + let start_index = self.index; + self.assert_special_sequence(&SQ_COLOR_START, start_index)?; + self.skip_char(); + let color = + self.get_string_until_or_revert(&[COLOR_CLOSE], &[SPACE, LB, SEMICOLON], start_index)?; + self.skip_char(); + if color.is_empty() { + return Err(ParseError::new(self.index)); + } + Ok(Colored { + value: Box::new(self.parse_inline()?), + color, + }) + } } diff --git a/src/parsing/tokens.rs b/src/parsing/tokens.rs index 479d6db..ffd1dc8 100644 --- a/src/parsing/tokens.rs +++ b/src/parsing/tokens.rs @@ -26,6 +26,8 @@ pub(crate) const SINGLE_QUOTE: char = '\''; pub(crate) const DOT: char = '.'; pub(crate) const UP: char = '^'; pub(crate) const COLON: char = ':'; +pub(crate) const PARAGRAPH: char = '§'; +pub(crate) const SEMICOLON: char = ';'; // aliases @@ -46,6 +48,9 @@ pub(crate) const PHOLDER_CLOSE: char = L_BRACKET; pub(crate) const CHECK_OPEN: char = R_BRACKET; pub(crate) const CHECK_CLOSE: char = L_BRACKET; pub(crate) const CHECK_CHECKED: char = X; +pub(crate) const COLOR_START: char = PARAGRAPH; +pub(crate) const COLOR_OPEN: char = R_BRACKET; +pub(crate) const COLOR_CLOSE: char = L_BRACKET; pub(crate) const ITALIC: char = ASTERISK; pub(crate) const MONOSPACE: char = BACKTICK; @@ -71,8 +76,18 @@ pub(crate) const BLOCK_SPECIAL_CHARS: [&[char]; 9] = [ &SQ_CENTERED_START, ]; -pub(crate) const INLINE_SPECIAL_CHARS: [char; 10] = [ - BACKTICK, TILDE, UNDERSCR, ASTERISK, DESC_OPEN, IMG_START, URL_OPEN, LB, SUPER, EMOJI, +pub(crate) const INLINE_SPECIAL_CHARS: [char; 11] = [ + BACKTICK, + TILDE, + UNDERSCR, + ASTERISK, + DESC_OPEN, + IMG_START, + URL_OPEN, + LB, + SUPER, + EMOJI, + COLOR_START, ]; pub(crate) const LIST_SPECIAL_CHARS: [char; 14] = [ @@ -86,6 +101,7 @@ pub(crate) const SQ_RULER: [char; 5] = [MINUS, SPACE, MINUS, SPACE, MINUS]; pub(crate) const SQ_PHOLDER_START: [char; 2] = [PHOLDER_OPEN, PHOLDER_OPEN]; pub(crate) const SQ_PHOLDER_STOP: [char; 2] = [PHOLDER_CLOSE, PHOLDER_CLOSE]; pub(crate) const SQ_CENTERED_START: [char; 2] = [PIPE, PIPE]; +pub(crate) const SQ_COLOR_START: [char; 2] = [COLOR_START, COLOR_OPEN]; // expressions