Implement basic text/gemini

CandyCorvid
Jul 13, 2023, 10:32 AM
HVFBGX2A2LBL6HSFKPNIG5KGQPVMZ5GFYJ4ZPDAM4POSRTQSKN7QC

Dependencies

Change contents

  • edit in src/main.rs at line 1
    [4.3665]
    [4.0]
    #![feature(pattern)]
  • edit in src/main.rs at line 5
    [3.31]
    [4.6831]
    use media::Media;
  • replacement in src/main.rs at line 63
    [4.7856][2.118:168]()
    let media = decode_media(mime, body);
    [4.7856]
    [2.168]
    let media = decode_media(mime, &body);
  • replacement in src/main.rs at line 98
    [2.201][2.201:264]()
    fn decode_media(mime: response::Mime, body: String) -> Media {
    [2.201]
    [2.264]
    fn decode_media(mime: response::Mime, body: &str) -> Media<'_> {
  • replacement in src/main.rs at line 101
    [2.355][2.355:416]()
    "gemini" => Media::Gemini(body.as_str().into()),
    [2.355]
    [2.416]
    "gemini" => Media::Gemini(body.into()),
  • replacement in src/main.rs at line 109
    [4.4504][2.513:663]()
    enum Media {
    Gemini(Gemini),
    Text(String),
    }
    struct Gemini {}
    impl From<&str> for Gemini {
    fn from(value: &str) -> Self {
    todo!()
    [4.4504]
    [2.663]
    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:#?}"), // TODO
    Media::Text(s) => println!("{s}"),
    }
    }
    }
    #[derive(Clone, Debug)]
    pub struct Gemini<'a> {
    // TODO include lang component
    lines: 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
    [2.669][2.669:825]()
    }
    impl Media {
    fn display(&self) {
    match self {
    Media::Gemini(_) => todo!(), // TODO
    Media::Text(s) => println!("{s}"),
    [2.669]
    [2.825]
    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
    [2.835][2.835:851]()
    todo!()
    [2.835]
    [2.851]
    }
    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 mode
    RawLine::Toggle { alt } => {
    *preformat = !*preformat;
    None
    }
    // otherwise, yield the line
    RawLine::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),
    }
    }