Blockquotes style

This commit is contained in:
ef3d0c3e 2024-08-12 22:33:25 +02:00
parent 06fd73c9f9
commit d8fd2feefb
3 changed files with 122 additions and 31 deletions

21
Cargo.lock generated
View file

@ -59,6 +59,16 @@ dependencies = [
"syn 2.0.72", "syn 2.0.72",
] ]
[[package]]
name = "auto-registry"
version = "0.0.4"
dependencies = [
"lazy_static",
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]] [[package]]
name = "auto_impl" name = "auto_impl"
version = "1.2.0" version = "1.2.0"
@ -733,6 +743,7 @@ name = "nml"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"ariadne", "ariadne",
"auto-registry",
"dashmap 6.0.1", "dashmap 6.0.1",
"downcast-rs", "downcast-rs",
"getopts", "getopts",
@ -743,6 +754,7 @@ dependencies = [
"mlua", "mlua",
"rand 0.8.5", "rand 0.8.5",
"regex", "regex",
"runtime-format",
"rusqlite", "rusqlite",
"rust-crypto", "rust-crypto",
"serde", "serde",
@ -1094,6 +1106,15 @@ version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
[[package]]
name = "runtime-format"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09958d5b38bca768ede7928c767c89a08ba568144a7b61992aecae79b03c8c94"
dependencies = [
"tinyvec",
]
[[package]] [[package]]
name = "rusqlite" name = "rusqlite"
version = "0.31.0" version = "0.31.0"

View file

@ -17,6 +17,7 @@ inherits = "release"
debug = true debug = true
[dependencies] [dependencies]
auto-registry = { path = "crates/auto-registry" }
ariadne = "0.4.1" ariadne = "0.4.1"
dashmap = "6.0.1" dashmap = "6.0.1"
downcast-rs = "1.2.1" downcast-rs = "1.2.1"
@ -32,11 +33,16 @@ rust-crypto = "0.2.36"
serde = "1.0.204" serde = "1.0.204"
serde_json = "1.0.120" serde_json = "1.0.120"
syntect = "5.2.0" syntect = "5.2.0"
tokio = { version = "1.38.1", features = ["macros", "rt-multi-thread", "io-std"]} tokio = { version = "1.38.1", features = [
"macros",
"rt-multi-thread",
"io-std",
] }
tower-lsp = "0.20.0" tower-lsp = "0.20.0"
unicode-segmentation = "1.11.0" unicode-segmentation = "1.11.0"
walkdir = "2.5.0" walkdir = "2.5.0"
runtime-format = "0.1.3"
[dev-dependencies] [dev-dependencies]
rand = "0.8.5" rand = "0.8.5"

View file

@ -1,3 +1,4 @@
use core::fmt;
use std::any::Any; use std::any::Any;
use std::collections::HashMap; use std::collections::HashMap;
use std::ops::Range; use std::ops::Range;
@ -11,9 +12,13 @@ use blockquote_style::AuthorPos::Before;
use blockquote_style::BlockquoteStyle; use blockquote_style::BlockquoteStyle;
use regex::Match; use regex::Match;
use regex::Regex; use regex::Regex;
use runtime_fmt::rt_format; use runtime_format::FormatArgs;
use runtime_format::FormatError;
use runtime_format::FormatKey;
use runtime_format::FormatKeyError;
use crate::compiler::compiler::Compiler; use crate::compiler::compiler::Compiler;
use crate::compiler::compiler::Target;
use crate::compiler::compiler::Target::HTML; use crate::compiler::compiler::Target::HTML;
use crate::document::document::Document; use crate::document::document::Document;
use crate::document::element::ContainerElement; use crate::document::element::ContainerElement;
@ -42,6 +47,28 @@ pub struct Blockquote {
pub(self) style: Rc<blockquote_style::BlockquoteStyle>, pub(self) style: Rc<blockquote_style::BlockquoteStyle>,
} }
struct FmtPair<'a>(Target, &'a Blockquote);
impl FormatKey for FmtPair<'_> {
fn fmt(&self, key: &str, f: &mut fmt::Formatter<'_>) -> Result<(), FormatKeyError> {
match key {
"author" => write!(
f,
"{}",
Compiler::sanitize(self.0, self.1.author.as_ref().unwrap_or(&"".into()))
)
.map_err(FormatKeyError::Fmt),
"cite" => write!(
f,
"{}",
Compiler::sanitize(self.0, self.1.cite.as_ref().unwrap_or(&"".into()))
)
.map_err(FormatKeyError::Fmt),
_ => Err(FormatKeyError::UnknownKey),
}
}
}
impl Element for Blockquote { impl Element for Blockquote {
fn location(&self) -> &Token { &self.location } fn location(&self) -> &Token { &self.location }
@ -53,34 +80,32 @@ impl Element for Blockquote {
match compiler.target() { match compiler.target() {
HTML => { HTML => {
let mut result = r#"<div class="blockquote-content">"#.to_string(); let mut result = r#"<div class="blockquote-content">"#.to_string();
let format_author = || -> Result<String, runtime_fmt::Error> { let format_author = || -> Result<String, FormatError> {
let mut result = String::new(); let mut result = String::new();
if self.cite.is_some() || self.author.is_some() { if self.cite.is_some() || self.author.is_some() {
result += r#"<p class="blockquote-author">"#; result += r#"<p class="blockquote-author">"#;
match (&self.author, &self.cite) { let fmt_pair = FmtPair(compiler.target(), &self);
(Some(author), Some(cite)) => { match (self.author.is_some(), self.cite.is_some()) {
result += rt_format!( (true, true) => {
self.style.format[0].as_str(), let args =
author, FormatArgs::new(self.style.format[0].as_str(), &fmt_pair);
format!("<cite>{}</cite>", Compiler::sanitize(HTML, cite)), args.status()?;
)? result += args.to_string().as_str();
.as_str();
} }
(Some(author), None) => { (true, false) => {
result += rt_format!( let args =
self.style.format[1].as_str(), FormatArgs::new(self.style.format[1].as_str(), &fmt_pair);
Compiler::sanitize(HTML, author), args.status()?;
)? result += args.to_string().as_str();
.as_str()
} }
(None, Some(cite)) => { (false, false) => {
result += rt_format!( let args =
self.style.format[2].as_str(), FormatArgs::new(self.style.format[2].as_str(), &fmt_pair);
format!("<cite>{}</cite>", Compiler::sanitize(HTML, cite)), args.status()?;
)? result += args.to_string().as_str();
.as_str()
} }
(None, None) => panic!(""), _ => panic!(""),
} }
result += "</p>"; result += "</p>";
} }
@ -94,7 +119,7 @@ impl Element for Blockquote {
result += "<blockquote>"; result += "<blockquote>";
} }
if self.style.author_pos == Before { if self.style.author_pos == Before {
result += format_author().as_str(); result += format_author().map_err(|err| err.to_string())?.as_str();
} }
result += "<p>"; result += "<p>";
@ -103,7 +128,7 @@ impl Element for Blockquote {
} }
result += "</p></blockquote>"; result += "</p></blockquote>";
if self.style.author_pos == After { if self.style.author_pos == After {
result += format_author().as_str(); result += format_author().map_err(|err| err.to_string())?.as_str();
} }
result += "</div>"; result += "</div>";
@ -371,9 +396,9 @@ mod blockquote_style {
Self { Self {
author_pos: AuthorPos::After, author_pos: AuthorPos::After,
format: [ format: [
"A{author}, {cite}".into(), "{author}, {cite}".into(),
"B{author}".into(), "{author}".into(),
"C{cite}".into(), "{cite}".into(),
], ],
} }
} }
@ -409,8 +434,7 @@ AFTER
None, None,
)); ));
let parser = LangParser::default(); let parser = LangParser::default();
let state = ParserState::new(&parser, None); let (doc, _) = parser.parse(ParserState::new(&parser, None), source, None);
let (doc, _) = parser.parse(state, source, None);
validate_document!(doc.content().borrow(), 0, validate_document!(doc.content().borrow(), 0,
Paragraph { Text{ content == "BEFORE" }; }; Paragraph { Text{ content == "BEFORE" }; };
@ -427,4 +451,44 @@ AFTER
Paragraph { Text{ content == "AFTER" }; }; Paragraph { Text{ content == "AFTER" }; };
); );
} }
#[test]
pub fn style() {
let source = Rc::new(SourceFile::with_content(
"".to_string(),
r#"
@@style.blockquote = {
"author_pos": "Before",
"format": ["{cite} by {author}", "Author: {author}", "From: {cite}"]
}
PRE
>[author=A, cite=B, url=C] Some entry
> contin**ued here
> **
AFTER
"#
.to_string(),
None,
));
let parser = LangParser::default();
let (_, state) = parser.parse(ParserState::new(&parser, None), source, None);
let style = state
.shared
.styles
.borrow()
.current(blockquote_style::STYLE_KEY)
.downcast_rc::<BlockquoteStyle>()
.unwrap();
assert_eq!(style.author_pos, Before);
assert_eq!(
style.format,
[
"{cite} by {author}".to_string(),
"Author: {author}".to_string(),
"From: {cite}".to_string()
]
);
}
} }