2020-07-04 17:17:08 +00:00
|
|
|
package parser
|
|
|
|
|
2020-07-05 14:56:03 +00:00
|
|
|
import (
|
2020-07-14 13:46:49 +00:00
|
|
|
"bufio"
|
2020-07-05 14:56:03 +00:00
|
|
|
"bytes"
|
2020-07-14 13:46:49 +00:00
|
|
|
"fmt"
|
2020-07-05 14:56:03 +00:00
|
|
|
"strings"
|
|
|
|
|
|
|
|
"github.com/bouncepaw/mycorrhiza/util"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
linkToken = "=>"
|
|
|
|
headerToken = "#"
|
|
|
|
quoteToken = ">"
|
|
|
|
preformattedToken = "```"
|
|
|
|
listItemToken = "*"
|
|
|
|
)
|
2020-07-04 17:17:08 +00:00
|
|
|
|
2020-07-14 13:46:49 +00:00
|
|
|
var preState bool
|
|
|
|
var listState bool
|
|
|
|
|
2020-07-04 17:17:08 +00:00
|
|
|
func GeminiToHtml(gemini []byte) string {
|
2020-07-05 14:56:03 +00:00
|
|
|
lines, _ := StringToLines(string(util.NormalizeEOL(gemini)))
|
|
|
|
var html []string
|
2020-07-14 13:46:49 +00:00
|
|
|
|
2020-07-05 14:56:03 +00:00
|
|
|
for _, line := range lines {
|
|
|
|
html = append(html, geminiLineToHtml(line))
|
|
|
|
}
|
2020-07-14 13:46:49 +00:00
|
|
|
|
2020-07-05 14:56:03 +00:00
|
|
|
buffer := bytes.Buffer{}
|
|
|
|
for _, line := range html {
|
|
|
|
buffer.WriteString(line)
|
|
|
|
}
|
|
|
|
return buffer.String()
|
|
|
|
}
|
|
|
|
|
|
|
|
func geminiLineToHtml(line string) (res string) {
|
|
|
|
arr := strings.Fields(line)
|
2020-07-14 13:46:49 +00:00
|
|
|
token := checkLineType(arr)
|
2020-07-05 14:56:03 +00:00
|
|
|
|
|
|
|
switch token {
|
2020-07-14 13:46:49 +00:00
|
|
|
case headerToken:
|
|
|
|
level, content := makeOutHeader(arr)
|
|
|
|
res = fmt.Sprintf("<h%v>%v</h%v>", level, content, level)
|
2020-07-05 14:56:03 +00:00
|
|
|
case linkToken:
|
2020-07-14 13:46:49 +00:00
|
|
|
source, content := makeOutLink(arr[1:])
|
|
|
|
res = fmt.Sprintf(`<a href="%v">%v</a>`, source, content)
|
2020-07-05 14:56:03 +00:00
|
|
|
case quoteToken:
|
2020-07-14 13:46:49 +00:00
|
|
|
res = "<blockquote>" + LinesToString(arr[1:], " ") + "</blockquote>"
|
2020-07-05 14:56:03 +00:00
|
|
|
case preformattedToken:
|
2020-07-14 13:46:49 +00:00
|
|
|
preState = true
|
|
|
|
res = fmt.Sprintf(`<pre alt="%v">`, LinesToString(arr[1:], " "))
|
|
|
|
case "pre/empty":
|
|
|
|
res = "\n"
|
|
|
|
case "pre/text":
|
|
|
|
res = line + "\n"
|
|
|
|
case "pre/end":
|
|
|
|
preState = false
|
|
|
|
res = "</pre>"
|
|
|
|
case "list/begin":
|
|
|
|
res = "<ul><li>" + LinesToString(arr[1:], " ") + "</li>"
|
2020-07-05 14:56:03 +00:00
|
|
|
case listItemToken:
|
2020-07-14 13:46:49 +00:00
|
|
|
res = "<li>" + LinesToString(arr[1:], " ") + "</li>"
|
|
|
|
case "list/end":
|
|
|
|
listState = false
|
|
|
|
res = "</ul>" + geminiLineToHtml(line)
|
|
|
|
case "linebreak":
|
|
|
|
res = "<br>"
|
2020-07-05 14:56:03 +00:00
|
|
|
default:
|
2020-07-14 13:46:49 +00:00
|
|
|
res = "<p>" + line + "</p>"
|
2020-07-05 14:56:03 +00:00
|
|
|
}
|
2020-07-14 13:46:49 +00:00
|
|
|
return
|
2020-07-05 14:56:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func makeOutLink(arr []string) (source, content string) {
|
|
|
|
switch len(arr) {
|
|
|
|
case 0:
|
|
|
|
return "", ""
|
|
|
|
case 1:
|
|
|
|
return arr[0], arr[0]
|
|
|
|
default:
|
|
|
|
return arr[0], LinesToString(arr[1:], " ")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func makeOutHeader(arr []string) (level int, content string) {
|
|
|
|
level = len(arr[0])
|
|
|
|
content = LinesToString(arr[1:], " ")
|
|
|
|
return
|
2020-07-04 17:17:08 +00:00
|
|
|
}
|
2020-07-14 13:46:49 +00:00
|
|
|
|
|
|
|
func checkLineType(arr []string) (res string) {
|
|
|
|
isEmpty := len(arr) == 0
|
|
|
|
if preState {
|
|
|
|
if isEmpty {
|
|
|
|
res = "pre/empty"
|
|
|
|
} else if arr[0] == preformattedToken {
|
|
|
|
res = "pre/end"
|
|
|
|
} else {
|
|
|
|
res = "pre/text"
|
|
|
|
}
|
|
|
|
} else if listState {
|
|
|
|
if arr[0] == listItemToken {
|
|
|
|
res = listItemToken
|
|
|
|
} else {
|
|
|
|
res = "list/end"
|
|
|
|
}
|
|
|
|
} else if isEmpty {
|
|
|
|
res = "linebreak"
|
|
|
|
} else if arr[0][0] == headerToken[0] {
|
|
|
|
res = headerToken
|
|
|
|
} else {
|
|
|
|
return arr[0]
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func StringToLines(s string) (lines []string, err error) {
|
|
|
|
scanner := bufio.NewScanner(strings.NewReader(s))
|
|
|
|
for scanner.Scan() {
|
|
|
|
lines = append(lines, scanner.Text())
|
|
|
|
}
|
|
|
|
err = scanner.Err()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func LinesToString(lines []string, separator string) string {
|
|
|
|
buffer := bytes.Buffer{}
|
|
|
|
for _, line := range lines {
|
|
|
|
buffer.WriteString(line + separator)
|
|
|
|
}
|
|
|
|
return buffer.String()
|
|
|
|
}
|