A privacy-first, self-hosted, fully open source personal knowledge management software, written in typescript and golang. (PERSONAL FORK)
at lambda-fork/main 86 lines 2.8 kB view raw
1// SiYuan - Refactor your thinking 2// Copyright (c) 2020-present, b3log.org 3// 4// This program is free software: you can redistribute it and/or modify 5// it under the terms of the GNU Affero General Public License as published by 6// the Free Software Foundation, either version 3 of the License, or 7// (at your option) any later version. 8// 9// This program is distributed in the hope that it will be useful, 10// but WITHOUT ANY WARRANTY; without even the implied warranty of 11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12// GNU Affero General Public License for more details. 13// 14// You should have received a copy of the GNU Affero General Public License 15// along with this program. If not, see <https://www.gnu.org/licenses/>. 16 17package model 18 19import ( 20 "bytes" 21 22 "github.com/88250/lute/ast" 23 "github.com/88250/lute/editor" 24 "github.com/88250/lute/render" 25 "github.com/siyuan-note/logging" 26 "github.com/siyuan-note/siyuan/kernel/util" 27) 28 29func AutoSpace(rootID string) (err error) { 30 tree, err := LoadTreeByBlockID(rootID) 31 if err != nil { 32 return 33 } 34 35 logging.LogInfof("formatting tree [%s]...", rootID) 36 util.PushProtyleLoading(rootID, Conf.Language(116)) 37 defer ReloadProtyle(rootID) 38 39 FlushTxQueue() 40 41 generateOpTypeHistory(tree, HistoryOpFormat) 42 luteEngine := NewLute() 43 ast.Walk(tree.Root, func(n *ast.Node, entering bool) ast.WalkStatus { 44 if !entering { 45 return ast.WalkContinue 46 } 47 48 switch n.Type { 49 case ast.NodeTextMark: 50 luteEngine.MergeSameTextMark(n) // 合并相邻的同类行级节点 51 case ast.NodeCodeBlockCode: 52 // 代码块中包含 ``` 时 `优化排版` 异常 `Optimize typography` exception when code block contains ``` https://github.com/siyuan-note/siyuan/issues/15843 53 n.Tokens = bytes.ReplaceAll(n.Tokens, []byte(editor.Zwj+"```"), []byte("```")) 54 n.Tokens = bytes.ReplaceAll(n.Tokens, []byte("```"), []byte(editor.Zwj+"```")) 55 } 56 return ast.WalkContinue 57 }) 58 59 rootIAL := tree.Root.KramdownIAL 60 addBlockIALNodes(tree, false) 61 62 // 第一次格式化为了合并相邻的文本节点 63 formatRenderer := render.NewFormatRenderer(tree, luteEngine.RenderOptions) 64 md := formatRenderer.Render() 65 newTree := parseKTree(md) 66 newTree.Root.Spec = "1" 67 // 第二次格式化启用自动空格 68 luteEngine.SetAutoSpace(true) 69 formatRenderer = render.NewFormatRenderer(newTree, luteEngine.RenderOptions) 70 md = formatRenderer.Render() 71 newTree = parseKTree(md) 72 newTree.Root.Spec = "1" 73 newTree.Root.ID = tree.ID 74 newTree.Root.KramdownIAL = rootIAL 75 newTree.ID = tree.ID 76 newTree.Path = tree.Path 77 newTree.HPath = tree.HPath 78 newTree.Box = tree.Box 79 err = writeTreeUpsertQueue(newTree) 80 if err != nil { 81 return 82 } 83 logging.LogInfof("formatted tree [%s]", rootID) 84 util.RandomSleep(500, 700) 85 return 86}