2025-10-31 20:24:37 +01:00
|
|
|
package textfmt
|
|
|
|
|
|
2025-11-02 06:27:17 +01:00
|
|
|
import (
|
|
|
|
|
"code.squareroundforest.org/arpio/textedit"
|
|
|
|
|
"errors"
|
|
|
|
|
)
|
2025-10-31 20:24:37 +01:00
|
|
|
|
2025-11-02 06:27:17 +01:00
|
|
|
type mdEscapeState struct {
|
|
|
|
|
lineStarted bool
|
|
|
|
|
numberOnNewLine bool
|
|
|
|
|
linkValue bool
|
|
|
|
|
linkClosed bool
|
|
|
|
|
linkOpen bool
|
2025-10-31 20:24:37 +01:00
|
|
|
}
|
|
|
|
|
|
2025-11-02 06:27:17 +01:00
|
|
|
func escapeTeletypeEdit(r rune, s struct{}) ([]rune, struct{}) {
|
|
|
|
|
if r >= 0x00 && r <= 0x1f && r != '\n' && r != '\t' {
|
|
|
|
|
return []rune{0xb7}, s
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if r >= 0x7f && r <= 0x9f {
|
|
|
|
|
return []rune{0xb7}, s
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return []rune{r}, s
|
2025-10-31 20:24:37 +01:00
|
|
|
}
|
|
|
|
|
|
2025-11-02 06:27:17 +01:00
|
|
|
func escapeTeletype() wrapper {
|
|
|
|
|
return editor(
|
|
|
|
|
textedit.Func(
|
|
|
|
|
escapeTeletypeEdit,
|
|
|
|
|
func(struct{}) []rune { return nil },
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func escapeRoffEdit(additional ...string) func(rune, bool) ([]rune, bool) {
|
|
|
|
|
const invalidAdditional = "invalid additional escape definition"
|
|
|
|
|
if len(additional)%2 != 0 {
|
|
|
|
|
panic(errors.New(invalidAdditional))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
esc := map[rune][]rune{
|
|
|
|
|
'\\': []rune("\\\\"),
|
|
|
|
|
'\u00a0': []rune("\\~"),
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-02 22:15:31 +01:00
|
|
|
for i := 0; i < len(additional); i += 2 {
|
2025-11-02 06:27:17 +01:00
|
|
|
r := []rune(additional[i])
|
|
|
|
|
if len(r) != 1 {
|
|
|
|
|
panic(errors.New(invalidAdditional))
|
2025-10-31 20:24:37 +01:00
|
|
|
}
|
2025-11-02 06:27:17 +01:00
|
|
|
|
|
|
|
|
esc[r[0]] = []rune(additional[i+1])
|
2025-10-31 20:24:37 +01:00
|
|
|
}
|
|
|
|
|
|
2025-11-02 06:27:17 +01:00
|
|
|
lsEsc := map[rune][]rune{
|
|
|
|
|
'.': []rune("\\&."),
|
|
|
|
|
'\'': []rune("\\&'"),
|
|
|
|
|
}
|
2025-10-31 20:24:37 +01:00
|
|
|
|
2025-11-02 06:27:17 +01:00
|
|
|
return func(r rune, lineStarted bool) ([]rune, bool) {
|
|
|
|
|
if r == '\n' {
|
|
|
|
|
return []rune{'\n'}, false
|
|
|
|
|
}
|
2025-10-31 20:24:37 +01:00
|
|
|
|
2025-11-02 06:27:17 +01:00
|
|
|
replacement, replace := esc[r]
|
|
|
|
|
if replace {
|
|
|
|
|
return replacement, true
|
|
|
|
|
}
|
2025-10-31 20:24:37 +01:00
|
|
|
|
2025-11-02 06:27:17 +01:00
|
|
|
if lineStarted {
|
|
|
|
|
return []rune{r}, true
|
|
|
|
|
}
|
2025-10-31 20:24:37 +01:00
|
|
|
|
2025-11-02 06:27:17 +01:00
|
|
|
replacement, replace = lsEsc[r]
|
|
|
|
|
if replace {
|
|
|
|
|
return replacement, true
|
2025-10-31 20:24:37 +01:00
|
|
|
}
|
2025-11-02 06:27:17 +01:00
|
|
|
|
|
|
|
|
return []rune{r}, true
|
2025-10-31 20:24:37 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-02 06:27:17 +01:00
|
|
|
func escapeRoff(additional ...string) wrapper {
|
|
|
|
|
return editor(
|
|
|
|
|
textedit.Func(
|
|
|
|
|
escapeRoffEdit(additional...),
|
|
|
|
|
func(bool) []rune { return nil },
|
|
|
|
|
),
|
|
|
|
|
)
|
2025-10-31 20:24:37 +01:00
|
|
|
}
|
|
|
|
|
|
2025-11-02 06:27:17 +01:00
|
|
|
func escapeMarkdownEdit(r rune, s mdEscapeState) ([]rune, mdEscapeState) {
|
|
|
|
|
var ret []rune
|
|
|
|
|
switch r {
|
|
|
|
|
case '\\', '`', '*', '_', '[', ']', '#', '<', '>':
|
|
|
|
|
ret = append(ret, '\\', r)
|
|
|
|
|
default:
|
|
|
|
|
switch {
|
|
|
|
|
case !s.lineStarted:
|
|
|
|
|
switch r {
|
|
|
|
|
case '+', '-':
|
|
|
|
|
ret = append(ret, '\\', r)
|
|
|
|
|
default:
|
|
|
|
|
ret = append(ret, r)
|
|
|
|
|
}
|
|
|
|
|
case s.numberOnNewLine:
|
|
|
|
|
switch r {
|
|
|
|
|
case '.':
|
|
|
|
|
ret = append(ret, '\\', r)
|
|
|
|
|
default:
|
|
|
|
|
ret = append(ret, r)
|
|
|
|
|
}
|
|
|
|
|
case s.linkClosed:
|
|
|
|
|
switch r {
|
|
|
|
|
case '(':
|
|
|
|
|
ret = append(ret, '\\', r)
|
|
|
|
|
default:
|
|
|
|
|
ret = append(ret, r)
|
|
|
|
|
}
|
|
|
|
|
case s.linkValue:
|
|
|
|
|
switch r {
|
|
|
|
|
case ')':
|
|
|
|
|
ret = append(ret, '\\', r)
|
|
|
|
|
default:
|
|
|
|
|
ret = append(ret, r)
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
ret = append(ret, r)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s.numberOnNewLine = (!s.lineStarted || s.numberOnNewLine) && r >= '0' && r <= '9'
|
|
|
|
|
s.lineStarted = r != '\n'
|
|
|
|
|
s.linkValue = s.linkClosed && r == '(' || s.linkValue && r != ')'
|
|
|
|
|
s.linkClosed = s.linkOpen && r == ']'
|
|
|
|
|
s.linkOpen = !s.linkValue && r == '[' || s.linkOpen && r != ']'
|
|
|
|
|
return ret, s
|
2025-10-31 20:24:37 +01:00
|
|
|
}
|
|
|
|
|
|
2025-11-02 06:27:17 +01:00
|
|
|
func escapeMarkdown() wrapper {
|
|
|
|
|
return editor(
|
|
|
|
|
textedit.Func(
|
|
|
|
|
escapeMarkdownEdit,
|
|
|
|
|
func(mdEscapeState) []rune { return nil },
|
|
|
|
|
),
|
|
|
|
|
)
|
2025-10-31 20:24:37 +01:00
|
|
|
}
|