Progress on the Gemtext parser
This commit is contained in:
parent
60a8e74af3
commit
200dd8b451
3 changed files with 64 additions and 17 deletions
|
@ -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 {
|
||||||
|
|
|
@ -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('<') => {},
|
||||||
|
|
|
@ -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},
|
||||||
|
|
Loading…
Add table
Reference in a new issue