summaryrefslogtreecommitdiff
path: root/gemini/gemtext/parse_line.go
diff options
context:
space:
mode:
authortjpcc <tjp@ctrl-c.club>2023-01-17 16:41:04 -0700
committertjpcc <tjp@ctrl-c.club>2023-01-17 16:41:04 -0700
commit6586db782ea6dcb5f2eb191a690ec7e7df51161f (patch)
tree36158a53a6d8aad9f5a873c6c43d598ce5647b97 /gemini/gemtext/parse_line.go
parent2ef530daa47b301a40c1ee93cd43b8f36fc68c0b (diff)
Updates
* update README * move "gemtext" to within "gemini"
Diffstat (limited to 'gemini/gemtext/parse_line.go')
-rw-r--r--gemini/gemtext/parse_line.go107
1 files changed, 107 insertions, 0 deletions
diff --git a/gemini/gemtext/parse_line.go b/gemini/gemtext/parse_line.go
new file mode 100644
index 0000000..39187a8
--- /dev/null
+++ b/gemini/gemtext/parse_line.go
@@ -0,0 +1,107 @@
+package gemtext
+
+import "bytes"
+
+// ParseLine parses a single line (including the trailing \n) into a gemtext.Line.
+func ParseLine(line []byte) Line {
+ if len(line) == 0 {
+ return nil
+ }
+
+ switch line[0] {
+ case '=':
+ if len(line) == 1 || line[1] != '>' {
+ break
+ }
+ return parseLinkLine(line)
+ case '`':
+ if len(line) < 3 || line[1] != '`' || line[2] != '`' {
+ break
+ }
+ return parsePreformatToggleLine(line)
+ case '#':
+ level := 1
+ if len(line) > 1 && line[1] == '#' {
+ level += 1
+ if len(line) > 2 && line[2] == '#' {
+ level += 1
+ }
+ }
+ return parseHeadingLine(level, line)
+ case '*':
+ if len(line) == 1 || line[1] != ' ' {
+ break
+ }
+ return parseListItemLine(line)
+ case '>':
+ return parseQuoteLine(line)
+ }
+
+ return TextLine{raw: line}
+}
+
+func parseLinkLine(raw []byte) LinkLine {
+ line := LinkLine{raw: raw}
+
+ // move past =>[<whitespace>]
+ raw = bytes.TrimLeft(raw[2:], " \t")
+
+ // find the next space or tab
+ spIdx := bytes.IndexByte(raw, ' ')
+ tbIdx := bytes.IndexByte(raw, '\t')
+ idx := spIdx
+ if idx == -1 {
+ idx = tbIdx
+ }
+ if tbIdx >= 0 && tbIdx < idx {
+ idx = tbIdx
+ }
+
+ if idx < 0 {
+ line.url = bytes.TrimRight(raw, "\r\n")
+ return line
+ }
+
+ line.url = raw[:idx]
+ raw = raw[idx+1:]
+
+ label := bytes.TrimRight(bytes.TrimLeft(raw, " \t"), "\r\n")
+ if len(label) > 0 {
+ line.label = label
+ }
+
+ return line
+}
+
+func parsePreformatToggleLine(raw []byte) PreformatToggleLine {
+ line := PreformatToggleLine{raw: raw}
+
+ raw = bytes.TrimRight(raw[3:], "\r\n")
+ if len(raw) > 0 {
+ line.altText = raw
+ }
+
+ return line
+}
+
+func parseHeadingLine(level int, raw []byte) HeadingLine {
+ return HeadingLine{
+ raw: raw,
+ lineType: LineTypeHeading1 - 1 + LineType(level),
+ body: bytes.TrimRight(bytes.TrimLeft(raw[level:], " \t"), "\r\n"),
+ }
+}
+
+func parseListItemLine(raw []byte) ListItemLine {
+ return ListItemLine{
+ raw: raw,
+ body: bytes.TrimRight(raw[2:], "\r\n"),
+ }
+}
+
+func parseQuoteLine(raw []byte) QuoteLine {
+ return QuoteLine{
+ raw: raw,
+ body: bytes.TrimRight(raw[1:], "\r\n"),
+ }
+}