You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

94 lines
1.7 KiB

package gemini
import (
"strings"
"unicode"
)
type LineType int
type Line interface {
Content() string
}
type LineParser struct {
inPreformatted bool
}
type PreformattingToggleLine struct{}
func (p PreformattingToggleLine) Content() string { return "" }
type PreformattedTextLine struct{ content string }
func (p PreformattedTextLine) Content() string { return p.content }
type LinkLine struct {
content string
href string
title string
}
func (l LinkLine) Content() string { return l.content }
func (l LinkLine) Href() string { return l.href }
func (l LinkLine) Title() string { return l.title }
const (
parsingURLStart int = 1
parsingURL = 2
parsingTitleStart = 3
parsingTitle = 4
)
func ParseLinkLine(line string) LinkLine {
l := LinkLine{content: line, href: "", title: ""}
state := parsingURL
for _, ch := range strings.TrimSpace(strings.TrimPrefix(line, "=>")) {
switch state {
case parsingURLStart:
if unicode.IsSpace(ch) {
continue
}
state = parsingURL
l.href += string(ch)
case parsingURL:
if unicode.IsSpace(ch) {
state = parsingTitleStart
continue
}
l.href += string(ch)
case parsingTitleStart:
if unicode.IsSpace(ch) {
continue
}
state = parsingTitle
l.title += string(ch)
case parsingTitle:
l.title += string(ch)
}
}
if len(l.title) == 0 {
l.title = l.href
}
return l
}
func (l *LineParser) ParseLine(lineStr string) Line {
switch {
case strings.HasPrefix(lineStr, "```"):
l.inPreformatted = !l.inPreformatted
return PreformattingToggleLine{}
case l.inPreformatted:
return PreformattedTextLine{lineStr}
case strings.HasPrefix(lineStr, "=>"):
return ParseLinkLine(lineStr)
}
return nil
}