diff --git a/tools/cli/markup/prettify.go b/tools/cli/markup/prettify.go index 506cc3e90..b5a6c44e5 100644 --- a/tools/cli/markup/prettify.go +++ b/tools/cli/markup/prettify.go @@ -6,7 +6,6 @@ import ( "fmt" "os" "path/filepath" - "regexp" "strings" "kitty" @@ -51,39 +50,13 @@ func New(allow_escape_codes bool) *Context { } func replace_all_rst_roles(str string, repl func(rst_format_match) string) string { - result := strings.Builder{} - result.Grow(len(str) + 256) - last_index := 0 - - matches := prettify_pat().FindAllStringSubmatchIndex(str, -1) - for _, v := range matches { - match_start, match_end := v[0], v[1] - m := rst_format_match{} - if v[2] > -1 && v[3] > -1 { - m.role = str[v[2]:v[3]] - } - if v[4] > -1 && v[5] > -1 { - m.payload = str[v[4]:v[5]] - } else if v[6] > -1 && v[7] > -1 { - m.payload = str[v[6]:v[7]] - } - - result.WriteString(str[last_index:match_start]) - result.WriteString(repl(m)) - last_index = match_end + var m rst_format_match + rf := func(full_match string, groupdict map[string]string) string { + m.payload = groupdict["payload"] + m.role = groupdict["role"] + return repl(m) } - - result.WriteString(str[last_index:]) - return result.String() -} - -var _prettify_pat *regexp.Regexp - -func prettify_pat() *regexp.Regexp { - if _prettify_pat == nil { - _prettify_pat = regexp.MustCompile(":([a-z]+):(?:(?:`([^`]+)`)|(?:'([^']+)'))") - } - return _prettify_pat + return utils.ReplaceAll(":(?P[a-z]+):(?:(?:`(?P[^`]+)`)|(?:'(?P[^']+)'))", str, rf) } func (self *Context) hyperlink_for_url(url string, text string) string { diff --git a/tools/utils/regexp.go b/tools/utils/regexp.go new file mode 100644 index 000000000..893ba732b --- /dev/null +++ b/tools/utils/regexp.go @@ -0,0 +1,51 @@ +// License: GPLv3 Copyright: 2022, Kovid Goyal, + +package utils + +import ( + "fmt" + "regexp" + "strings" + "sync" +) + +var _ = fmt.Print + +var pat_cache = map[string]*regexp.Regexp{} +var pat_cache_lock = sync.RWMutex{} + +func ReplaceAll(pat, str string, repl func(full_match string, groupdict map[string]string) string) string { + pat_cache_lock.RLock() + cpat := pat_cache[pat] + pat_cache_lock.RUnlock() + if cpat == nil { + cpat = regexp.MustCompile(pat) + pat_cache_lock.Lock() + pat_cache[pat] = cpat + pat_cache_lock.Unlock() + } + result := strings.Builder{} + result.Grow(len(str) + 256) + last_index := 0 + matches := cpat.FindAllStringSubmatchIndex(str, -1) + names := cpat.SubexpNames() + for _, v := range matches { + match_start, match_end := v[0], v[1] + full_match := str[match_start:match_end] + groupdict := make(map[string]string, len(names)) + for i, name := range names { + if i == 0 { + continue + } + idx := 2 * i + if v[idx] > -1 && v[idx+1] > -1 { + groupdict[name] = str[v[idx]:v[idx+1]] + } + } + result.WriteString(str[last_index:match_start]) + result.WriteString(repl(full_match, groupdict)) + last_index = match_end + } + result.WriteString(str[last_index:]) + return result.String() +}