Files
weatherreporter/internal/reporttemplate/plain_text.go

90 lines
1.7 KiB
Go

package reporttemplate
import (
"strings"
"unicode"
)
var inlineMarkdownReplacer = strings.NewReplacer(
`\`, `\\`,
"`", "\\`",
"*", "\\*",
"_", "\\_",
"[", "\\[",
"]", "\\]",
"(", "\\(",
")", "\\)",
"<", "\\<",
">", "\\>",
"!", "\\!",
"~", "\\~",
"|", "\\|",
"&", "\\&",
)
// plainText preserves prose and paragraph breaks while preventing dynamic
// values from creating Markdown structure owned by repository templates.
func plainText(value string) string {
value = strings.ReplaceAll(value, "\r\n", "\n")
value = strings.ReplaceAll(value, "\r", "\n")
lines := strings.Split(value, "\n")
for index, line := range lines {
lines[index] = escapeMarkdownLine(line)
}
return strings.Join(lines, "\n")
}
func escapeMarkdownLine(line string) string {
indentEnd := 0
spaces := 0
hasTab := false
for indentEnd < len(line) {
switch line[indentEnd] {
case ' ':
spaces++
indentEnd++
case '\t':
hasTab = true
indentEnd++
default:
goto escaped
}
}
escaped:
indent := line[:indentEnd]
if hasTab || spaces >= 4 {
indent = ""
}
return indent + escapeMarkdownBlockPrefix(escapeMarkdownInline(line[indentEnd:]))
}
func escapeMarkdownInline(value string) string {
value = inlineMarkdownReplacer.Replace(value)
return strings.Map(func(r rune) rune {
if unicode.IsControl(r) {
return ' '
}
return r
}, value)
}
func escapeMarkdownBlockPrefix(value string) string {
if value == "" {
return value
}
switch value[0] {
case '#', '+', '-', '>', '=':
return "\\" + value
}
index := 0
for index < len(value) && value[index] >= '0' && value[index] <= '9' {
index++
}
if index > 0 && index < len(value) && value[index] == '.' {
return value[:index] + "\\" + value[index:]
}
return value
}