package textfmt import ( "code.squareroundforest.org/arpio/textedit" "errors" ) type mdEscapeState struct { lineStarted bool numberOnNewLine bool linkValue bool linkClosed bool linkOpen bool } 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 } 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("\\~"), } for i := 0; i < len(additional); i += 2 { r := []rune(additional[i]) if len(r) != 1 { panic(errors.New(invalidAdditional)) } esc[r[0]] = []rune(additional[i+1]) } lsEsc := map[rune][]rune{ '.': []rune("\\&."), '\'': []rune("\\&'"), } return func(r rune, lineStarted bool) ([]rune, bool) { if r == '\n' { return []rune{'\n'}, false } replacement, replace := esc[r] if replace { return replacement, true } if lineStarted { return []rune{r}, true } replacement, replace = lsEsc[r] if replace { return replacement, true } return []rune{r}, true } } func escapeRoff(additional ...string) wrapper { return editor( textedit.Func( escapeRoffEdit(additional...), func(bool) []rune { return nil }, ), ) } 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 } func escapeMarkdown() wrapper { return editor( textedit.Func( escapeMarkdownEdit, func(mdEscapeState) []rune { return nil }, ), ) }