Progress on the Gemtext parser

This commit is contained in:
Nathan Fisher 2023-06-02 00:26:19 -04:00
parent 60a8e74af3
commit 200dd8b451
3 changed files with 64 additions and 17 deletions

View file

@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize};
mod error; mod error;
mod link; mod link;
mod parser; mod parser;
pub use {error::Error, link::Link, parser::Parser}; pub use {error::Error, link::Link, parser::{GemtextNode, Parser}};
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct Recipients { pub struct Recipients {

View file

@ -17,13 +17,14 @@ enum State<'a> {
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum GemtextNode { pub enum GemtextNode {
Sender(Mailbox), Sender(Vec<Mailbox>),
Recipients(Recipients), Recipients(Recipients),
Timestamp(String), Timestamp(String),
Text(String), Text(String),
Heading1(String), Heading1(String),
Heading2(String), Heading2(String),
Heading3(String), Heading3(String),
ListItem(String),
Quote(String), Quote(String),
Preformatted(String), Preformatted(String),
Link(Link), Link(Link),
@ -32,13 +33,18 @@ pub enum GemtextNode {
impl fmt::Display for GemtextNode { impl fmt::Display for GemtextNode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
Self::Sender(m) => writeln!(f, "< {m}"), Self::Sender(m) => {
write!(f, "<")?;
m.iter().try_for_each(|m| write!(f, " {m}"))?;
writeln!(f)
},
Self::Recipients(r) => writeln!(f, "{r}"), Self::Recipients(r) => writeln!(f, "{r}"),
Self::Timestamp(t) => writeln!(f, "@ {t}"), Self::Timestamp(t) => writeln!(f, "@ {t}"),
Self::Text(t) => writeln!(f, "{t}"), Self::Text(t) => writeln!(f, "{t}"),
Self::Heading1(h) => writeln!(f, "# {h}"), Self::Heading1(h) => writeln!(f, "# {h}"),
Self::Heading2(h) => writeln!(f, "## {h}"), Self::Heading2(h) => writeln!(f, "## {h}"),
Self::Heading3(h) => writeln!(f, "### {h}"), Self::Heading3(h) => writeln!(f, "### {h}"),
Self::ListItem(l) => writeln!(f, "* {l}"),
Self::Quote(q) => writeln!(f, "> {q}"), Self::Quote(q) => writeln!(f, "> {q}"),
Self::Preformatted(p) => writeln!(f, "```\n{p}\n```"), Self::Preformatted(p) => writeln!(f, "```\n{p}\n```"),
Self::Link(l) => writeln!(f, "=> {l}"), Self::Link(l) => writeln!(f, "=> {l}"),
@ -48,27 +54,56 @@ impl fmt::Display for GemtextNode {
impl<'a> GemtextNode { impl<'a> GemtextNode {
fn parse_link(text: &'a str) -> Self { fn parse_link(text: &'a str) -> Self {
todo!() if let Ok(link) = text.parse() {
Self::Link(link)
} else {
Self::Text(text.to_string())
} }
fn parse_prompt(text: &'a str) -> Self {
todo!()
} }
fn parse_heading(text: &'a str) -> Self { fn parse_heading(text: &'a str) -> Self {
todo!() if let Some((h, s)) = text.split_once(char::is_whitespace) {
match h {
"#" => Self::Heading1(s.to_string()),
"##" => Self::Heading2(s.to_string()),
"###" => Self::Heading3(s.to_string()),
_ => Self::Text(text.to_string()),
}
} else {
Self::Text(text.to_string())
}
} }
fn parse_list_item(text: &'a str) -> Self { fn parse_list_item(text: &'a str) -> Self {
todo!() match text.split_once(char::is_whitespace) {
Some((pre, s)) if pre == "*" => GemtextNode::ListItem(s.to_string()),
_ => GemtextNode::Text(text.to_string()),
}
} }
fn parse_blockquote(text: &'a str) -> Self { fn parse_blockquote(text: &'a str) -> Self {
todo!() match text.split_once(char::is_whitespace) {
Some((prefix, suffix)) if prefix == ">" => GemtextNode::Quote(suffix.to_string()),
_ => GemtextNode::Text(text.to_string()),
}
} }
fn parse_senders(text: &'a str) -> Self { fn parse_senders(text: &'a str) -> Self {
todo!() let mut split = text.split_whitespace();
match split.next() {
Some(s) if s == "<" => {
let mut senders: Vec<Mailbox> = vec![];
for s in split {
if let Ok(m) = s.parse() {
senders.push(m);
} else {
return Self::Text(text.to_string());
}
}
Self::Sender(senders)
}
_ => Self::Text(text.to_string())
}
} }
fn parse_recipients(text: &'a str) -> Self { fn parse_recipients(text: &'a str) -> Self {
@ -94,7 +129,7 @@ impl<'a> Parser<'a> {
} }
} }
fn parse(mut self, raw: &'a str) -> Vec<GemtextNode> { pub fn parse(mut self, raw: &'a str) -> Vec<GemtextNode> {
for line in raw.lines() { for line in raw.lines() {
match self.state { match self.state {
State::Normal => self.parse_normal(line), State::Normal => self.parse_normal(line),
@ -105,11 +140,23 @@ impl<'a> Parser<'a> {
self.lines self.lines
} }
fn link(&mut self, line: &'a str) {
self.lines.push(GemtextNode::parse_link(line));
}
fn heading(&mut self, line: &'a str) {
self.lines.push(GemtextNode::parse_heading(line));
}
fn list_item(&mut self, line: &'a str) {
self.lines.push(GemtextNode::parse_list_item(line));
}
fn parse_normal(&mut self, line: &'a str) { fn parse_normal(&mut self, line: &'a str) {
match line { match line {
s if s.starts_with("=>") => {}, s if s.starts_with("=>") => self.link(s),
s if s.starts_with('#') => {}, s if s.starts_with('#') => self.heading(s),
s if s.starts_with('*') => {}, s if s.starts_with('*') => self.list_item(s),
s if s.starts_with('>') => {}, s if s.starts_with('>') => {},
s if s.starts_with("```") => {}, s if s.starts_with("```") => {},
s if s.starts_with('<') => {}, s if s.starts_with('<') => {},

View file

@ -4,7 +4,7 @@ pub use super::{
host::{Error as ParseHostError, Host}, host::{Error as ParseHostError, Host},
mailbox::{Error as ParseMailboxError, Mailbox}, mailbox::{Error as ParseMailboxError, Mailbox},
mailuser::Mailuser, mailuser::Mailuser,
message::{Error as ParseMessageError, Lines, Message, Recipients}, message::{Error as ParseMessageError, GemtextNode, Message, Recipients},
//receiver, //receiver,
request::{Error as ParseRequestError, Request}, request::{Error as ParseRequestError, Request},
response::{Error as ParseResponseError, Response}, response::{Error as ParseResponseError, Response},