From b26698797e90f9e659905731472330f609dfaf2e Mon Sep 17 00:00:00 2001 From: Liang Ding Date: Tue, 6 Sep 2022 23:06:17 +0800 Subject: [PATCH] =?UTF-8?q?:bug:=20=E6=97=A0=E6=B3=95=E5=AF=BC=E5=87=BA?= =?UTF-8?q?=E6=9F=90=E4=BA=9B=E5=AE=8F=E5=AE=9A=E4=B9=89=E5=85=AC=E5=BC=8F?= =?UTF-8?q?=20https://github.com/siyuan-note/siyuan/issues/5831?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/model/export.go | 75 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 61 insertions(+), 14 deletions(-) diff --git a/kernel/model/export.go b/kernel/model/export.go index 75da2873b..d124c788e 100644 --- a/kernel/model/export.go +++ b/kernel/model/export.go @@ -985,7 +985,7 @@ func processKaTexMacros(n *ast.Node) { return } - mathContent := n.Tokens + mathContent := string(n.Tokens) macros := map[string]string{} if err := gulu.JSON.UnmarshalJSON([]byte(Conf.Editor.KaTexMacros), ¯os); nil != err { logging.LogWarnf("parse katex macros failed: %s", err) @@ -993,13 +993,12 @@ func processKaTexMacros(n *ast.Node) { } var keys []string - for k, _ := range macros { + for k := range macros { keys = append(keys, k) } - useMacro := false - for k, _ := range macros { - if bytes.Contains(mathContent, []byte(k)) { + for k := range macros { + if strings.Contains(mathContent, k) { useMacro = true break } @@ -1007,38 +1006,86 @@ func processKaTexMacros(n *ast.Node) { if !useMacro { return } + sort.Slice(keys, func(i, j int) bool { return len(keys[i]) > len(keys[j]) }) - usedMacros := extractUsedMacros(mathContent, macros) + mathContent = escapeKaTexSupportedFunctions(mathContent) + usedMacros := extractUsedMacros(mathContent, &keys) newcommandBuf := bytes.Buffer{} + for _, usedMacro := range usedMacros { expanded := resolveKaTexMacro(usedMacro, ¯os, &keys) + expanded = unescapeKaTexSupportedFunctions(expanded) newcommandBuf.WriteString("\\newcommand" + usedMacro + "{" + expanded + "}\n") } newcommandBuf.WriteString("\n") - mathContent = append(newcommandBuf.Bytes(), mathContent...) - n.Tokens = mathContent + mathContent = newcommandBuf.String() + mathContent + n.Tokens = []byte(mathContent) } -func extractUsedMacros(mathContent []byte, macros map[string]string) (ret []string) { - for macro, _ := range macros { - if bytes.Contains(mathContent, []byte(macro)) { - ret = append(ret, macro) +func extractUsedMacros(mathContent string, macrosKeys *[]string) (ret []string) { +Next: + for { + for _, k := range *macrosKeys { + if idx := strings.Index(mathContent, k); -1 < idx { + mathContent = strings.Replace(mathContent, k, "__@"+k[1:]+"@__", 1) + ret = append(ret, k) + goto Next + } } + break } return } +var katexSupportedFunctions = []string{ // https://katex.org/docs/supported.html + + // Delimiters + "\\downarrow", +} + +func init() { + sort.Slice(katexSupportedFunctions, func(i, j int) bool { return len(katexSupportedFunctions[i]) > len(katexSupportedFunctions[j]) }) +} + func resolveKaTexMacro(macroName string, macros *map[string]string, keys *[]string) string { v := (*macros)[macroName] + sort.Slice(*keys, func(i, j int) bool { return len((*keys)[i]) > len((*keys)[j]) }) for _, k := range *keys { - if strings.Contains(v, k) { - v = strings.ReplaceAll(v, k, resolveKaTexMacro(k, macros, keys)) + escaped := escapeKaTexSupportedFunctions(v) + if strings.Contains(escaped, k) { + escaped = strings.ReplaceAll(escaped, k, resolveKaTexMacro(k, macros, keys)) + v = unescapeKaTexSupportedFunctions(escaped) (*macros)[macroName] = v } } return v } +func escapeKaTexSupportedFunctions(macroVal string) string { +Next: + for { + for _, f := range katexSupportedFunctions { + if idx := strings.Index(macroVal, f); -1 < idx { + macroVal = strings.Replace(macroVal, f, "__@"+f[1:]+"@__", 1) + goto Next + } + } + break + } + return macroVal +} + +func unescapeKaTexSupportedFunctions(macroVal string) string { + if !strings.Contains(macroVal, "__@") { + return macroVal + } + + for _, f := range katexSupportedFunctions { + macroVal = strings.ReplaceAll(macroVal, "__@"+f[1:]+"@__", f) + } + return macroVal +} + func renderExportMdParagraph(r *render.FormatRenderer, node *ast.Node, entering bool) ast.WalkStatus { if entering { if r.Options.ChineseParagraphBeginningSpace && ast.NodeDocument == node.Parent.Type {