use crate::proto;
#[derive(Clone, Debug, Default)]
pub struct Block {
children: Vec<proto::Block>,
}
impl Block {
pub fn new() -> Self {
Self {
children: Vec::new(),
}
}
pub fn append(mut self, block: impl Into<Block>) -> Self {
let block: Block = block.into();
self.children.extend(block.children);
self
}
pub fn prepend(mut self, block: impl Into<Block>) -> Self {
let block: Block = block.into();
let mut new_children = block.children;
new_children.extend(self.children);
self.children = new_children;
self
}
pub fn text(mut self, text: impl Into<String>) -> Self {
let text = text.into();
self.children.push(proto::Block {
plain: String::new(),
inner: Some(proto::block::Inner::Text(proto::TextBlock { text })),
});
self
}
pub fn bold(mut self, content: impl Into<Block>) -> Self {
let inner_block = content.into().into();
self.children.push(proto::Block {
plain: String::new(),
inner: Some(proto::block::Inner::Bold(Box::new(proto::BoldBlock {
inner: Some(Box::new(inner_block)),
}))),
});
self
}
pub fn italic(mut self, content: impl Into<Block>) -> Self {
let inner_block = content.into().into();
self.children.push(proto::Block {
plain: String::new(),
inner: Some(proto::block::Inner::Italics(Box::new(
proto::ItalicsBlock {
inner: Some(Box::new(inner_block)),
},
))),
});
self
}
pub fn underline(mut self, content: impl Into<Block>) -> Self {
let inner_block = content.into().into();
self.children.push(proto::Block {
plain: String::new(),
inner: Some(proto::block::Inner::Underline(Box::new(
proto::UnderlineBlock {
inner: Some(Box::new(inner_block)),
},
))),
});
self
}
pub fn strikethrough(mut self, content: impl Into<Block>) -> Self {
let inner_block = content.into().into();
self.children.push(proto::Block {
plain: String::new(),
inner: Some(proto::block::Inner::Strikethrough(Box::new(
proto::StrikethroughBlock {
inner: Some(Box::new(inner_block)),
},
))),
});
self
}
pub fn spoiler(mut self, content: impl Into<Block>) -> Self {
let inner_block = content.into().into();
self.children.push(proto::Block {
plain: String::new(),
inner: Some(proto::block::Inner::Spoiler(Box::new(
proto::SpoilerBlock {
inner: Some(Box::new(inner_block)),
},
))),
});
self
}
pub fn blockquote(mut self, content: impl Into<Block>) -> Self {
let inner_block = content.into().into();
self.children.push(proto::Block {
plain: String::new(),
inner: Some(proto::block::Inner::Blockquote(Box::new(
proto::BlockquoteBlock {
inner: Some(Box::new(inner_block)),
},
))),
});
self
}
pub fn inline_code(mut self, text: impl Into<String>) -> Self {
let text = text.into();
self.children.push(proto::Block {
plain: String::new(),
inner: Some(proto::block::Inner::InlineCode(proto::InlineCodeBlock {
text,
})),
});
self
}
pub fn fenced_code(mut self, info: impl Into<String>, text: impl Into<String>) -> Self {
let info = info.into();
let text = text.into();
self.children.push(proto::Block {
plain: String::new(),
inner: Some(proto::block::Inner::FencedCode(proto::FencedCodeBlock {
info,
text,
})),
});
self
}
pub fn link(mut self, url: impl Into<String>, content: impl Into<Block>) -> Self {
let url = url.into();
let inner_block = content.into().into();
self.children.push(proto::Block {
plain: String::new(),
inner: Some(proto::block::Inner::Link(Box::new(proto::LinkBlock {
url,
inner: Some(Box::new(inner_block)),
}))),
});
self
}
pub fn heading(mut self, level: i32, content: impl Into<Block>) -> Self {
let inner_block = content.into().into();
self.children.push(proto::Block {
plain: String::new(),
inner: Some(proto::block::Inner::Heading(Box::new(
proto::HeadingBlock {
level,
inner: Some(Box::new(inner_block)),
},
))),
});
self
}
pub fn list(mut self, items: impl IntoIterator<Item = impl Into<Block>>) -> Self {
let inner: Vec<proto::Block> = items.into_iter().map(|item| item.into().into()).collect();
self.children.push(proto::Block {
plain: String::new(),
inner: Some(proto::block::Inner::List(proto::ListBlock { inner })),
});
self
}
pub fn timestamp(mut self, time: std::time::SystemTime) -> Self {
let duration = time
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default();
let timestamp = prost_types::Timestamp {
seconds: duration.as_secs() as i64,
nanos: duration.subsec_nanos() as i32,
};
self.children.push(proto::Block {
plain: String::new(),
inner: Some(proto::block::Inner::Timestamp(proto::TimestampBlock {
inner: Some(timestamp),
})),
});
self
}
pub fn container(mut self, blocks: impl IntoIterator<Item = impl Into<Block>>) -> Self {
let inner: Vec<proto::Block> = blocks.into_iter().map(|b| b.into().into()).collect();
self.children.push(proto::Block {
plain: String::new(),
inner: Some(proto::block::Inner::Container(proto::ContainerBlock {
inner,
})),
});
self
}
}
impl From<Block> for proto::Block {
fn from(block: Block) -> Self {
if block.children.len() == 1 {
return block.children.into_iter().next().unwrap();
}
proto::Block {
plain: String::new(),
inner: Some(proto::block::Inner::Container(proto::ContainerBlock {
inner: block.children,
})),
}
}
}
impl From<proto::Block> for Block {
fn from(block: proto::Block) -> Self {
if let Some(proto::block::Inner::Container(container)) = block.inner {
Block {
children: container.inner,
}
} else {
Block {
children: vec![block],
}
}
}
}
impl From<&str> for Block {
fn from(text: &str) -> Self {
Block::new().text(text)
}
}
impl From<String> for Block {
fn from(text: String) -> Self {
Block::new().text(text)
}
}
impl From<Block> for crate::client::MessageContent {
fn from(block: Block) -> Self {
crate::client::MessageContent::Blocks(block.into())
}
}