From c30a6dd711bb294a7cb06ac5e89a5c8862cc853b Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Mon, 4 Nov 2024 09:12:42 +0800 Subject: [PATCH 1/3] :art: Dynamically loading graph nodes and edges https://github.com/siyuan-note/siyuan/issues/13014 --- app/src/layout/dock/Graph.ts | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/app/src/layout/dock/Graph.ts b/app/src/layout/dock/Graph.ts index 84729af24..8ce394454 100644 --- a/app/src/layout/dock/Graph.ts +++ b/app/src/layout/dock/Graph.ts @@ -619,37 +619,43 @@ export class Graph extends Model { iterations: 256, updateInterval: 64, onlyDynamicEdges: false, - fit: true + fit: false }, timestep: 0.5, adaptiveTimestep: true, wind: {x: 0, y: 0} }, }; - let j = Math.max(Math.ceil(this.graphData.nodes.length * 0.1), 128); - const nodes = new vis.DataSet(this.graphData.nodes.slice(0, j)); + let i = Math.max(Math.ceil(this.graphData.nodes.length * 0.1), 128); + const nodes = new vis.DataSet(this.graphData.nodes.slice(0, i)); const edges = new vis.DataSet(); const network = new vis.Network(this.graphElement, {nodes, edges}, options); const time = 256; + let intervalNodeTime = Math.max(Math.ceil(time / 8), 32); let batch = this.graphData.nodes.length / time / 2; - if (batch < 64) { - batch = 64; + if (batch < 32) { + batch = 32; } - if (batch > 256) { - batch = 256; + if (batch > 128) { + batch = 128; } - let i = 0; + let count = 0; const intervalNode = setInterval(() => { - const nodes = this.graphData.nodes.slice(j, j + batch); + const nodes = this.graphData.nodes.slice(i, i + batch); if (nodes.length === 0) { clearInterval(intervalNode); return; } network.body.data.nodes.add(nodes); - j += batch; - }, time / 8); + i += batch; + count++; + if (0 === count % (batch / 8)) { + network.fit({animation: false}); + } + }, intervalNodeTime); + let j = 0; const intervalId = setInterval(() => { - const edges = this.graphData.links.slice(i, i + batch); + const edges = this.graphData.links.slice(j, j + batch); if (edges.length === 0) { clearInterval(intervalId); network.fit({ @@ -658,7 +664,7 @@ export class Graph extends Model { return; } network.body.data.edges.add(edges); - i += batch; + j += batch; }, time); this.network = network; network.on("stabilizationIterationsDone", () => { @@ -670,7 +676,7 @@ export class Graph extends Model { network.on("dragEnd", () => { setTimeout(() => { network.physics.stopSimulation(); - }, 5000); + }, 3000); }); network.on("click", (params: any) => { if (params.nodes.length !== 1) { From 9c5a61016062193d19d95f44d9b0c6d797a70d0a Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Mon, 4 Nov 2024 09:36:56 +0800 Subject: [PATCH 2/3] :bug: Fix inline underscore element paste as plain text https://github.com/siyuan-note/siyuan/issues/13015 --- app/src/protyle/util/paste.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/protyle/util/paste.ts b/app/src/protyle/util/paste.ts index 689a59410..0b0669633 100644 --- a/app/src/protyle/util/paste.ts +++ b/app/src/protyle/util/paste.ts @@ -182,7 +182,7 @@ export const pasteAsPlainText = async (protyle: IProtyle) => { textPlain = textPlain.replace(/__@sub@__/g, "").replace(/__@\/sub@__/g, ""); textPlain = textPlain.replace(/__@sup@__/g, "").replace(/__@\/sup@__/g, ""); textPlain = textPlain.replace(/__@kbd@__/g, "").replace(/__@\/kbd@__/g, ""); - textPlain = textPlain.replace(/__@u@__/g, "").replace(/__@\/u@__/g, "").replace(/__@\/u@__/g, ""); const content = protyle.lute.BlockDOM2EscapeMarkerContent(protyle.lute.Md2BlockDOM(textPlain)); // insertHTML 会进行内部反转义 From 8b35367eb5fc1003768b04245feac50b4368a291 Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Mon, 4 Nov 2024 10:04:45 +0800 Subject: [PATCH 3/3] :bug: Fix find-replace for spaces https://github.com/siyuan-note/siyuan/issues/13010 Regexp compile error https://ld246.com/article/1730678393331 --- kernel/model/search.go | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/kernel/model/search.go b/kernel/model/search.go index c78cc0515..05a0d37e1 100644 --- a/kernel/model/search.go +++ b/kernel/model/search.go @@ -830,17 +830,19 @@ func replaceTextNode(text *ast.Node, method int, keyword string, replacement str newContent = bytes.ReplaceAll(text.Tokens, []byte(keyword), []byte(replacement)) } } else { - // 当搜索结果中的文本元素包含大小写混合时替换失败 - // Replace fails when search results contain mixed case in text elements https://github.com/siyuan-note/siyuan/issues/9171 - keywords := strings.Split(keyword, " ") - // keyword 可能是 "foo Foo" 使用空格分隔的大小写命中情况,这里统一转换小写后去重 - if 0 < len(keywords) { - var lowerKeywords []string - for _, k := range keywords { - lowerKeywords = append(lowerKeywords, strings.ToLower(k)) + if "" != strings.TrimSpace(keyword) { + // 当搜索结果中的文本元素包含大小写混合时替换失败 + // Replace fails when search results contain mixed case in text elements https://github.com/siyuan-note/siyuan/issues/9171 + keywords := strings.Split(keyword, " ") + // keyword 可能是 "foo Foo" 使用空格分隔的大小写命中情况,这里统一转换小写后去重 + if 0 < len(keywords) { + var lowerKeywords []string + for _, k := range keywords { + lowerKeywords = append(lowerKeywords, strings.ToLower(k)) + } + lowerKeywords = gulu.Str.RemoveDuplicatedElem(lowerKeywords) + keyword = strings.Join(lowerKeywords, " ") } - lowerKeywords = gulu.Str.RemoveDuplicatedElem(lowerKeywords) - keyword = strings.Join(lowerKeywords, " ") } if bytes.Contains(bytes.ToLower(text.Tokens), []byte(keyword)) { @@ -945,7 +947,7 @@ func FullTextSearchBlock(query string, boxes, paths []string, types map[string]b typeFilter := buildTypeFilter(types) boxFilter := buildBoxesFilter(boxes) pathFilter := buildPathsFilter(paths) - if 2 > len(strings.Split(query, " ")) { + if 2 > len(strings.Split(strings.TrimSpace(query), " ")) { blocks, matchedBlockCount, matchedRootCount = fullTextSearchByQuerySyntax(query, boxFilter, pathFilter, typeFilter, ignoreFilter, orderByClause, beforeLen, page, pageSize) } else { docMode = true // 文档全文搜索模式 https://github.com/siyuan-note/siyuan/issues/10584 @@ -1304,7 +1306,12 @@ func fullTextSearchByRegexp(exp, boxFilter, pathFilter, typeFilter, ignoreFilter fieldFilter := fieldRegexp(exp) stmt := "SELECT * FROM `blocks` WHERE " + fieldFilter + " AND type IN " + typeFilter stmt += boxFilter + pathFilter + ignoreFilter + " " + orderBy - regex := regexp.MustCompile(exp) + regex, err := regexp.Compile(exp) + if nil != err { + util.PushErrMsg(err.Error(), 5000) + return + } + blocks := sql.SelectBlocksRegex(stmt, regex, Conf.Search.Name, Conf.Search.Alias, Conf.Search.Memo, Conf.Search.IAL, page, pageSize) ret = fromSQLBlocks(&blocks, "", beforeLen) if 1 > len(ret) { @@ -1458,7 +1465,10 @@ func highlightByRegexp(query, typeFilter, id string) (ret []string) { fieldFilter := fieldRegexp(query) stmt := "SELECT * FROM `blocks` WHERE " + fieldFilter + " AND type IN " + typeFilter stmt += " AND root_id = '" + id + "'" - regex := regexp.MustCompile(query) + regex, _ := regexp.Compile(query) + if nil == regex { + return + } sqlBlocks := sql.SelectBlocksRegex(stmt, regex, Conf.Search.Name, Conf.Search.Alias, Conf.Search.Memo, Conf.Search.IAL, 1, 256) for _, block := range sqlBlocks { keyword := gulu.Str.SubstringsBetween(block.Content, search.SearchMarkLeft, search.SearchMarkRight)