Implement basic text/gemini
Dependencies
- [2]
ONQEIR5BWIP mime-type handling - [3]
AOJXTWBZRefactor read_until - [4]
AMTMTTJTUpgrade status parsing - [5]
3SPNKI46Improve parsing. Add modules that were missed - [6]
DBKKKHC2Initial commit
Change contents
- edit in src/main.rs at line 1
#![feature(pattern)] - edit in src/main.rs at line 5
use media::Media; - replacement in src/main.rs at line 63
let media = decode_media(mime, body);let media = decode_media(mime, &body); - replacement in src/main.rs at line 98
fn decode_media(mime: response::Mime, body: String) -> Media {fn decode_media(mime: response::Mime, body: &str) -> Media<'_> { - replacement in src/main.rs at line 101
"gemini" => Media::Gemini(body.as_str().into()),"gemini" => Media::Gemini(body.into()), - replacement in src/main.rs at line 109
enum Media {Gemini(Gemini),Text(String),}struct Gemini {}impl From<&str> for Gemini {fn from(value: &str) -> Self {todo!()mod media {use std::str::pattern::Pattern;use url::Url;#[derive(Clone, Debug)]pub enum Media<'a> {Gemini(Gemini<'a>),Text(&'a str),}impl<'a> Media<'a> {pub fn display(&self) {match self {Media::Gemini(g) => println!("{g:#?}"), // TODOMedia::Text(s) => println!("{s}"),}}}#[derive(Clone, Debug)]pub struct Gemini<'a> {// TODO include lang componentlines: Vec<Line<'a>>,}#[derive(Clone, Debug)]enum RawLine<'a> {Toggle { alt: TextLine<'a> },Line(Line<'a>),}#[derive(Clone, Debug)]pub enum Line<'a> {Heading {level: u8,title: TextLine<'a>,},Link {url: Url,description: Option<TextLine<'a>>,},Text(TextLine<'a>),Preformatted(TextLine<'a>),ListItem(TextLine<'a>),Quote(TextLine<'a>), - replacement in src/main.rs at line 151
}impl Media {fn display(&self) {match self {Media::Gemini(_) => todo!(), // TODOMedia::Text(s) => println!("{s}"),fn split_trim_maybe_once<'a, P: Pattern<'a> + Copy>(s: &'a str,p: P,) -> (&'a str, Option<&'a str>) {match s.split_once(p) {Some((s, rem)) => (s, Some(rem.trim_start_matches(p))),None => (s, None), - replacement in src/main.rs at line 159
todo!()}fn string_to_line(preformat: bool, string: TextLine<'_>) -> RawLine {let line = string.0;RawLine::Line({match line {// ignore anything after the lead chars on preformat lines"```" => {return RawLine::Toggle {alt: TextLine(&line[3..]),}}// ignore any other formatting between preformat toggle lines_ if preformat => Line::Preformatted(string),"=> " => {let line = &line[3..];match line.split_once(' ') {Some((url, desc)) => {let url = url.trim_start_matches(' ');Line::Link {url: url.parse().expect("invalid link url"),description: Some(TextLine(desc)),}}None => Line::Link {url: line.parse().expect("invalid link url"),description: None,},}}"* " => Line::ListItem(TextLine(&line[2..])),"# " => Line::Heading {level: 1,title: TextLine(&line[2..]),},"## " => Line::Heading {level: 2,title: TextLine(&line[3..]),},"### " => Line::Heading {level: 3,title: TextLine(&line[4..]),},"> " => Line::Quote(TextLine(&line[2..])),_ => Line::Text(string),}})}fn string_to_lines(value: &str) -> Vec<Line> {value.lines().map(TextLine)// start with preformatting set to off.scan(false, |preformat, line| {match string_to_line(*preformat, line) {// if we hit a toggle line, switch preformatting modeRawLine::Toggle { alt } => {*preformat = !*preformat;None}// otherwise, yield the lineRawLine::Line(l) => Some(l),}}).collect()}// guaranteed to be only a single line#[derive(Copy, Clone, Debug)]pub struct TextLine<'a>(&'a str);impl<'a> From<&'a str> for Gemini<'a> {fn from(value: &'a str) -> Self {Gemini {lines: string_to_lines(value),}}