diff --git a/parser.go b/parser.go index 33bf205..b88dd00 100644 --- a/parser.go +++ b/parser.go @@ -46,13 +46,13 @@ func addPrefix(pref string, link string) string { // ParseLink takes a gemini link as a string and returns a GemtextObject and an error. func ParseLink(l string) (GemtextObject, error) { - f := strings.Fields(l) - if f[0] != "=>" { + if !strings.HasPrefix(l, "=>") { return GemtextObject{}, fmt.Errorf("Not a gemtext link!") } else { + f := strings.Fields(l[2:]) link := GemtextObject{Type: LINK, Literal: l} - link.Path = f[1] - link.Text = strings.Join(f[2:]," ") + link.Path = f[0] + link.Text = strings.TrimSpace(l[3+len(f[0]):]) return link, nil } @@ -61,11 +61,13 @@ func ParseLink(l string) (GemtextObject, error) { // ParseHeading parses a gemtext heading, returns a HEADING GemtextObject if it is between levels 1-3 and TEXT otherwise. func ParseHeading(l string) (GemtextObject, error) { switch { - case strings.HasPrefix(l, "### "): + case strings.HasPrefix(l, "####"): // Fake headings + return GemtextObject{Type: TEXT, Text:l, Literal: l}, nil + case strings.HasPrefix(l, "###"): return GemtextObject{Type: HEADING, Level: 3, Text: strings.TrimSpace(l[3:]), Literal: l},nil - case strings.HasPrefix(l, "## "): + case strings.HasPrefix(l, "##"): return GemtextObject{Type: HEADING, Level: 2, Text: strings.TrimSpace(l[2:]), Literal: l},nil - case strings.HasPrefix(l, "# "): + case strings.HasPrefix(l, "#"): return GemtextObject{Type: HEADING, Level: 1, Text: strings.TrimSpace(l[1:]), Literal: l},nil } return GemtextObject{Type: TEXT, Text:l, Literal: l}, nil @@ -74,22 +76,24 @@ func ParseHeading(l string) (GemtextObject, error) { // ParseLine parses a gemtext line, and returns a GemtextObject representing it. // "isPreformatted" takes a true if the line is in a preformatted block, else otherwise. func ParseLine(line string, isPreformatted bool) (GemtextObject, error) { - l := strings.TrimSpace(line) - switch { - case strings.HasPrefix(l, "=>"): - return ParseLink(line) - case strings.HasPrefix(l, "```"): - return GemtextObject{Type: PREFORMATTED_TOGGLE, Literal: l}, nil - case strings.HasPrefix(l, "#"): - return ParseHeading(line) - case strings.HasPrefix(l, ">"): - return GemtextObject{Type: QUOTE, Text: strings.TrimSpace(l[1:]), Literal: l}, nil - case strings.HasPrefix(l, "*"): - return GemtextObject{Type: LIST, Text: strings.TrimSpace(l[1:]), Literal: l}, nil - case isPreformatted: - return GemtextObject{Type: PREFORMATTED_TEXT, Text: l, Literal: l}, nil - } - return GemtextObject{Type: TEXT, Text: l, Literal: l}, nil + if !isPreformatted { + switch { + case strings.HasPrefix(line, "=>"): + return ParseLink(line) + case strings.HasPrefix(line, "```"): + return GemtextObject{Type: PREFORMATTED_TOGGLE, Literal: line}, nil + case strings.HasPrefix(line, "#"): + return ParseHeading(line) + case strings.HasPrefix(line, ">"): + return GemtextObject{Type: QUOTE, Text: strings.TrimSpace(line[1:]), Literal: line}, nil + case strings.HasPrefix(line, "*"): + return GemtextObject{Type: LIST, Text: strings.TrimSpace(line[1:]), Literal: line}, nil + } + return GemtextObject{Type: TEXT, Text: line, Literal: line}, nil + } else { + return GemtextObject{Type: PREFORMATTED_TEXT, Text: line, Literal: line}, nil + } + } // ParsePage takes a string containing the contents of a gemtext page and returns a GemtextPage. diff --git a/parser_test.go b/parser_test.go index 08c9f39..ae0d419 100644 --- a/parser_test.go +++ b/parser_test.go @@ -7,7 +7,7 @@ type LineCase struct { Preformatted bool Want GemtextObject } -// These tests suck. They're not really tests. +// These tests suck. func TestParseLine(t *testing.T) { cases := []LineCase{ LineCase{Str: "```", Preformatted: false, Want: GemtextObject{Type: PREFORMATTED_TOGGLE, Literal: "```"}}, @@ -54,6 +54,24 @@ func TestParseLine(t *testing.T) { Text: "heading 3", Level: 3}, }, + LineCase{ + Str: "###heading 3", + Preformatted: false, + Want: GemtextObject{ + Type: HEADING, + Literal: "###heading 3", + Text: "heading 3", + Level: 3}, + }, + LineCase{ + Str: "### heading 3", + Preformatted: false, + Want: GemtextObject{ + Type: HEADING, + Literal: "### heading 3", + Text: "heading 3", + Level: 3}, + }, LineCase{ Str: "#### heading 4", Preformatted: false, @@ -78,6 +96,14 @@ func TestParseLine(t *testing.T) { Literal: "* list item", Text: "list item"}, }, + LineCase{ + Str: "* list item", + Preformatted: false, + Want: GemtextObject{ + Type: LIST, + Literal: "* list item", + Text: "list item"}, + }, LineCase{ Str: ">quote", Preformatted: false, @@ -94,6 +120,56 @@ func TestParseLine(t *testing.T) { Literal: "> quote", Text: "quote"}, }, + LineCase{ + Str: "> quote", + Preformatted: false, + Want: GemtextObject{ + Type: QUOTE, + Literal: "> quote", + Text: "quote"}, + }, + LineCase{ + Str: "> quote", + Preformatted: true, + Want: GemtextObject{ + Type: PREFORMATTED_TEXT, + Literal: "> quote", + Text: "> quote"}, + }, + LineCase{ + Str: "=> https://example.com link", + Preformatted: true, + Want: GemtextObject{ + Type: PREFORMATTED_TEXT, + Literal: "=> https://example.com link", + Text: "=> https://example.com link"}, + }, + LineCase{ + Str: "=> https://example.com link", + Preformatted: false, + Want: GemtextObject{ + Type: LINK, + Literal: "=> https://example.com link", + Text: "link", + Path: "https://example.com"}, + }, + LineCase{ + Str: "=>https://example.com link", + Preformatted: false, + Want: GemtextObject{ + Type: LINK, + Literal: "=>https://example.com link", + Text: "link", + Path: "https://example.com"}, + }, + LineCase{ + Str: "\n", + Preformatted: false, + Want: GemtextObject{ + Type: TEXT, + Literal: "\n", + Text: "\n"}, + }, } for _, c := range cases { got, _ := ParseLine(c.Str, c.Preformatted)