package main import ( "strings" ) type LineType uint8 const ( LineText LineType = iota LineLink LinePreformattingStart LinePreformattedText LinePreformattingEnd LineHeading1 LineHeading2 LineHeading3 LineListItem LineQuote ) // Line represents a line in a text document. type Line struct { Type LineType Text string URL string // only set for links Tabindex int // only set for links } // Parser is a Gemini text parser. type Parser struct { pre bool tabindex int } // NewParser returns a new Gemini text parser. func NewParser() *Parser { return &Parser{ tabindex: 1, } } // ParseLine parses a single Gemini text line. func (p *Parser) ParseLine(text string) Line { const spacetab = " \t" var line Line if strings.HasPrefix(text, "```") { p.pre = !p.pre text = text[3:] if p.pre { line.Type = LinePreformattingStart } else { line.Type = LinePreformattingEnd } line.Text = text } else if p.pre { line.Type = LinePreformattedText line.Text = text } else if strings.HasPrefix(text, "=>") { text = text[2:] text = strings.TrimLeft(text, spacetab) split := strings.IndexAny(text, spacetab) line.Type = LineLink if split == -1 { // text is a URL line.URL = text } else { url := text[:split] name := text[split:] name = strings.TrimLeft(name, spacetab) line.Text = name line.URL = url } // Set tabindex line.Tabindex = p.tabindex p.tabindex++ } else if strings.HasPrefix(text, "*") { text = text[1:] text = strings.TrimLeft(text, spacetab) line.Type = LineListItem line.Text = text } else if strings.HasPrefix(text, "###") { text = text[3:] text = strings.TrimLeft(text, spacetab) line.Type = LineHeading3 line.Text = text } else if strings.HasPrefix(text, "##") { text = text[2:] text = strings.TrimLeft(text, spacetab) line.Type = LineHeading2 line.Text = text } else if strings.HasPrefix(text, "#") { text = text[1:] text = strings.TrimLeft(text, spacetab) line.Type = LineHeading1 line.Text = text } else if strings.HasPrefix(text, ">") { text = text[1:] text = strings.TrimLeft(text, spacetab) line.Type = LineQuote line.Text = text } else { line.Type = LineText line.Text = text } return line }