From 2914e42ba102d517bafb242ceb1d11f3ac6b6ba6 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Thu, 21 Dec 2023 17:18:51 -0500 Subject: [PATCH] For plain list items with a single child that is a paragraph, do not wrap in paragraph html tags. This is mimicking the behavior from org-mode's HTML exporter. --- .../templates/html/element.dust | 1 + .../html/plain_list_simple_item.dust | 3 ++ src/context/element.rs | 5 +++ src/context/mod.rs | 1 + src/context/plain_list_simple_item.rs | 38 +++++++++++++++++++ src/intermediate/element.rs | 2 + src/intermediate/mod.rs | 2 + src/intermediate/plain_list_item.rs | 16 +++++++- src/intermediate/plain_list_simple_item.rs | 32 ++++++++++++++++ src/main.rs | 1 + 10 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 default_environment/templates/html/plain_list_simple_item.dust create mode 100644 src/context/plain_list_simple_item.rs create mode 100644 src/intermediate/plain_list_simple_item.rs diff --git a/default_environment/templates/html/element.dust b/default_environment/templates/html/element.dust index 81f0ca7..54f8359 100644 --- a/default_environment/templates/html/element.dust +++ b/default_environment/templates/html/element.dust @@ -1,6 +1,7 @@ {@select key=.type} {@eq value="paragraph"}{>paragraph/}{/eq} {@eq value="plain_list"}{>plain_list/}{/eq} + {@eq value="plain_list_simple_item"}{>plain_list_simple_item/}{/eq} {@eq value="center_block"}{>center_block/}{/eq} {@eq value="quote_block"}{>quote_block/}{/eq} {@eq value="special_block"}{>special_block/}{/eq} diff --git a/default_environment/templates/html/plain_list_simple_item.dust b/default_environment/templates/html/plain_list_simple_item.dust new file mode 100644 index 0000000..aa49c92 --- /dev/null +++ b/default_environment/templates/html/plain_list_simple_item.dust @@ -0,0 +1,3 @@ +{#.children} + {>object/} +{/.children} diff --git a/src/context/element.rs b/src/context/element.rs index f493919..dabc80c 100644 --- a/src/context/element.rs +++ b/src/context/element.rs @@ -1,5 +1,6 @@ use serde::Serialize; +use super::plain_list_simple_item::RenderPlainListSimpleItem; use super::render_context::RenderContext; use crate::error::CustomError; use crate::intermediate::IElement; @@ -35,6 +36,7 @@ use super::verse_block::RenderVerseBlock; pub(crate) enum RenderElement { Paragraph(RenderParagraph), PlainList(RenderPlainList), + PlainListSimpleItem(RenderPlainListSimpleItem), CenterBlock(RenderCenterBlock), QuoteBlock(RenderQuoteBlock), SpecialBlock(RenderSpecialBlock), @@ -69,6 +71,9 @@ render!(RenderElement, IElement, original, render_context, { render_context.clone(), inner, )?)), + IElement::PlainListSimpleItem(inner) => Ok(RenderElement::PlainListSimpleItem( + RenderPlainListSimpleItem::new(render_context.clone(), inner)?, + )), IElement::CenterBlock(inner) => Ok(RenderElement::CenterBlock(RenderCenterBlock::new( render_context.clone(), inner, diff --git a/src/context/mod.rs b/src/context/mod.rs index 99ff45c..adff5cf 100644 --- a/src/context/mod.rs +++ b/src/context/mod.rs @@ -41,6 +41,7 @@ mod paragraph; mod plain_link; mod plain_list; mod plain_list_item; +mod plain_list_simple_item; mod plain_text; mod planning; mod property_drawer; diff --git a/src/context/plain_list_simple_item.rs b/src/context/plain_list_simple_item.rs new file mode 100644 index 0000000..1b03208 --- /dev/null +++ b/src/context/plain_list_simple_item.rs @@ -0,0 +1,38 @@ +use serde::Serialize; + +use super::render_context::RenderContext; +use crate::error::CustomError; +use crate::intermediate::IPlainListSimpleItem; + +use super::macros::render; +use super::RenderObject; + +/// Special case for list items with only 1 child which is a paragraph. In those cases, the paragraph tags are omitted. This is equivalent to a Paragraph but in a different struct to have a different type tag. +#[derive(Debug, Serialize)] +#[serde(tag = "type")] +#[serde(rename = "plain_list_simple_item")] +pub(crate) struct RenderPlainListSimpleItem { + children: Vec, + post_blank: organic::types::PostBlank, +} + +render!( + RenderPlainListSimpleItem, + IPlainListSimpleItem, + original, + render_context, + { + let children = { + let mut ret = Vec::new(); + for obj in original.children.iter() { + ret.push(RenderObject::new(render_context.clone(), obj)?); + } + ret + }; + + Ok(RenderPlainListSimpleItem { + children, + post_blank: original.post_blank, + }) + } +); diff --git a/src/intermediate/element.rs b/src/intermediate/element.rs index 5072ea4..d07534b 100644 --- a/src/intermediate/element.rs +++ b/src/intermediate/element.rs @@ -1,6 +1,7 @@ use super::comment::IComment; use super::keyword::IKeyword; use super::macros::iselector; +use super::IPlainListSimpleItem; use super::IBabelCall; use super::ICenterBlock; @@ -32,6 +33,7 @@ use futures::future::{BoxFuture, FutureExt}; pub(crate) enum IElement { Paragraph(IParagraph), PlainList(IPlainList), + PlainListSimpleItem(IPlainListSimpleItem), CenterBlock(ICenterBlock), QuoteBlock(IQuoteBlock), SpecialBlock(ISpecialBlock), diff --git a/src/intermediate/mod.rs b/src/intermediate/mod.rs index ea61ba1..3516d15 100644 --- a/src/intermediate/mod.rs +++ b/src/intermediate/mod.rs @@ -41,6 +41,7 @@ mod paragraph; mod plain_link; mod plain_list; mod plain_list_item; +mod plain_list_simple_item; mod plain_text; mod planning; mod property_drawer; @@ -108,6 +109,7 @@ pub(crate) use paragraph::IParagraph; pub(crate) use plain_link::IPlainLink; pub(crate) use plain_list::IPlainList; pub(crate) use plain_list_item::IPlainListItem; +pub(crate) use plain_list_simple_item::IPlainListSimpleItem; pub(crate) use plain_text::IPlainText; pub(crate) use planning::IPlanning; pub(crate) use property_drawer::IPropertyDrawer; diff --git a/src/intermediate/plain_list_item.rs b/src/intermediate/plain_list_item.rs index 02f3241..64c7ae1 100644 --- a/src/intermediate/plain_list_item.rs +++ b/src/intermediate/plain_list_item.rs @@ -1,4 +1,5 @@ use super::macros::intermediate; +use super::IPlainListSimpleItem; use super::IElement; use super::IObject; @@ -26,8 +27,19 @@ intermediate!( let children = { let mut ret = Vec::new(); - for elem in original.children.iter() { - ret.push(IElement::new(intermediate_context.clone(), elem).await?); + + // Special case for list items with only 1 child which is a paragraph. In those cases, the paragraph tags are omitted. + if original.children.len() == 1 + && let Some(organic::types::Element::Paragraph(paragraph)) = + original.children.iter().next() + { + ret.push(IElement::PlainListSimpleItem( + IPlainListSimpleItem::new(intermediate_context.clone(), paragraph).await?, + )); + } else { + for elem in original.children.iter() { + ret.push(IElement::new(intermediate_context.clone(), elem).await?); + } } ret }; diff --git a/src/intermediate/plain_list_simple_item.rs b/src/intermediate/plain_list_simple_item.rs new file mode 100644 index 0000000..d247c47 --- /dev/null +++ b/src/intermediate/plain_list_simple_item.rs @@ -0,0 +1,32 @@ +use super::macros::intermediate; +use super::IObject; +use crate::error::CustomError; +use organic::types::StandardProperties; + +/// Special case for list items with only 1 child which is a paragraph. In those cases, the paragraph tags are omitted. This is equivalent to a Paragraph but in a different struct to have a different type tag. +#[derive(Debug, Clone)] +pub(crate) struct IPlainListSimpleItem { + pub(crate) children: Vec, + pub(crate) post_blank: organic::types::PostBlank, +} + +intermediate!( + IPlainListSimpleItem, + &'orig organic::types::Paragraph<'parse>, + original, + intermediate_context, + { + let children = { + let mut ret = Vec::new(); + for obj in original.children.iter() { + ret.push(IObject::new(intermediate_context.clone(), obj).await?); + } + ret + }; + + Ok(IPlainListSimpleItem { + children, + post_blank: original.get_post_blank(), + }) + } +); diff --git a/src/main.rs b/src/main.rs index d2d3edd..71c1ab3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,4 @@ +#![feature(let_chains)] use std::process::ExitCode; use clap::Parser;