mirror of
https://github.com/siyuan-note/siyuan.git
synced 2026-01-01 14:28:49 +01:00
Merge remote-tracking branch 'origin/dev' into dev
This commit is contained in:
commit
7ea6f08c21
7 changed files with 82 additions and 45 deletions
|
|
@ -1171,6 +1171,8 @@
|
|||
"202": "Cleaning data repo...",
|
||||
"203": "The data repo is purged, [%d] snapshots and [%d] data objects have been deleted, and a total of [%s] disk space has been released",
|
||||
"204": "The doc in the user guide does not support sharing to the community",
|
||||
"205": "The plugin is not supported in the current environment"
|
||||
"205": "The plugin is not supported in the current environment",
|
||||
"206": "Executing content replacement [%d/%d]",
|
||||
"207": "Executing path replacement [%d/%d]"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1171,6 +1171,8 @@
|
|||
"202": "Limpiando repositorio de datos...",
|
||||
"203": "El repositorio de datos se purgó, [%d] instantáneas y [%d] objetos de datos se eliminaron y se liberó un total de [%s] espacio en disco",
|
||||
"204": "La documentación en la guía del usuario no permite compartir con la comunidad",
|
||||
"205": "El complemento no es compatible con el entorno actual"
|
||||
"205": "El complemento no es compatible con el entorno actual",
|
||||
"206": "Ejecutando reemplazo de contenido [%d/%d]",
|
||||
"207": "Ejecutando reemplazo de ruta [%d/%d]"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1171,6 +1171,8 @@
|
|||
"202": "Nettoyage du référentiel de données...",
|
||||
"203": "Le référentiel de données est purgé, [%d] instantanés et [%d] objets de données ont été supprimés, et un total de [%s] espace disque a été libéré",
|
||||
"204": "La documentation du guide de l'utilisateur ne prend pas en charge le partage avec la communauté",
|
||||
"205": "Le plugin n'est pas pris en charge dans l'environnement actuel"
|
||||
"205": "Le plugin n'est pas pris en charge dans l'environnement actuel",
|
||||
"206": "Exécution du remplacement de contenu [%d/%d]",
|
||||
"207": "Exécution du remplacement de chemin [%d/%d]"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1171,6 +1171,8 @@
|
|||
"202": "正在清理數據倉庫...",
|
||||
"203": "數據倉庫清理完畢,已刪除 [%d] 個快照和 [%d] 個數據對象,共釋放 [%s] 磁盤空間",
|
||||
"204": "用戶指南中的文檔不支持分享到社區",
|
||||
"205": "該插件不支持在當前環境下使用"
|
||||
"205": "該插件不支持在當前環境下使用",
|
||||
"206": "正在執行內容替換 [%d/%d]",
|
||||
"207": "正在執行路徑替換 [%d/%d]"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1173,6 +1173,8 @@
|
|||
"202": "正在清理数据仓库...",
|
||||
"203": "数据仓库清理完毕,已删除 [%d] 个快照和 [%d] 个数据对象,共释放 [%s] 磁盘空间",
|
||||
"204": "用户指南中的文档不支持分享到社区",
|
||||
"205": "该插件不支持在当前环境下使用"
|
||||
"205": "该插件不支持在当前环境下使用",
|
||||
"206": "正在执行内容替换 [%d/%d]",
|
||||
"207": "正在执行路径替换 [%d/%d]"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,19 +35,16 @@ func findReplace(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
_, _, _, paths, boxes, types, method, orderBy, groupBy := parseSearchArgs(arg)
|
||||
|
||||
k := arg["k"].(string)
|
||||
r := arg["r"].(string)
|
||||
methodArg := arg["method"]
|
||||
var method int // 0:文本,1:查询语法,2:SQL,3:正则表达式
|
||||
if nil != methodArg {
|
||||
method = int(methodArg.(float64))
|
||||
}
|
||||
idsArg := arg["ids"].([]interface{})
|
||||
var ids []string
|
||||
for _, id := range idsArg {
|
||||
ids = append(ids, id.(string))
|
||||
}
|
||||
err := model.FindReplace(k, r, ids, method)
|
||||
err := model.FindReplace(k, r, ids, paths, boxes, types, method, orderBy, groupBy)
|
||||
if nil != err {
|
||||
ret.Code = -1
|
||||
ret.Msg = err.Error()
|
||||
|
|
@ -218,7 +215,18 @@ func fullTextSearchBlock(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
page := 1
|
||||
page, pageSize, query, paths, boxes, types, method, orderBy, groupBy := parseSearchArgs(arg)
|
||||
blocks, matchedBlockCount, matchedRootCount, pageCount := model.FullTextSearchBlock(query, boxes, paths, types, method, orderBy, groupBy, page, pageSize)
|
||||
ret.Data = map[string]interface{}{
|
||||
"blocks": blocks,
|
||||
"matchedBlockCount": matchedBlockCount,
|
||||
"matchedRootCount": matchedRootCount,
|
||||
"pageCount": pageCount,
|
||||
}
|
||||
}
|
||||
|
||||
func parseSearchArgs(arg map[string]interface{}) (page, pageSize int, query string, paths, boxes []string, types map[string]bool, method, orderBy, groupBy int) {
|
||||
page = 1
|
||||
if nil != arg["page"] {
|
||||
page = int(arg["page"].(float64))
|
||||
}
|
||||
|
|
@ -226,9 +234,20 @@ func fullTextSearchBlock(c *gin.Context) {
|
|||
page = 1
|
||||
}
|
||||
|
||||
query := arg["query"].(string)
|
||||
pageSize = 32
|
||||
if nil != arg["pageSize"] {
|
||||
pageSize = int(arg["pageSize"].(float64))
|
||||
}
|
||||
if 0 >= pageSize {
|
||||
pageSize = 32
|
||||
}
|
||||
|
||||
queryArg := arg["query"]
|
||||
if nil != queryArg {
|
||||
query = queryArg.(string)
|
||||
}
|
||||
|
||||
pathsArg := arg["paths"]
|
||||
var paths, boxes []string
|
||||
if nil != pathsArg {
|
||||
for _, p := range pathsArg.([]interface{}) {
|
||||
path := p.(string)
|
||||
|
|
@ -244,7 +263,7 @@ func fullTextSearchBlock(c *gin.Context) {
|
|||
paths = gulu.Str.RemoveDuplicatedElem(paths)
|
||||
boxes = gulu.Str.RemoveDuplicatedElem(boxes)
|
||||
}
|
||||
var types map[string]bool
|
||||
|
||||
if nil != arg["types"] {
|
||||
typesArg := arg["types"].(map[string]interface{})
|
||||
types = map[string]bool{}
|
||||
|
|
@ -252,26 +271,23 @@ func fullTextSearchBlock(c *gin.Context) {
|
|||
types[t] = b.(bool)
|
||||
}
|
||||
}
|
||||
|
||||
// method:0:关键字,1:查询语法,2:SQL,3:正则表达式
|
||||
methodArg := arg["method"]
|
||||
var method int // 0:关键字,1:查询语法,2:SQL,3:正则表达式
|
||||
if nil != methodArg {
|
||||
method = int(methodArg.(float64))
|
||||
}
|
||||
|
||||
// orderBy:0:按块类型(默认),1:按创建时间升序,2:按创建时间降序,3:按更新时间升序,4:按更新时间降序,5:按内容顺序(仅在按文档分组时),6:按相关度升序,7:按相关度降序
|
||||
orderByArg := arg["orderBy"]
|
||||
var orderBy int // 0:按块类型(默认),1:按创建时间升序,2:按创建时间降序,3:按更新时间升序,4:按更新时间降序,5:按内容顺序(仅在按文档分组时),6:按相关度升序,7:按相关度降序
|
||||
if nil != orderByArg {
|
||||
orderBy = int(orderByArg.(float64))
|
||||
}
|
||||
|
||||
// groupBy: 0:不分组,1:按文档分组
|
||||
groupByArg := arg["groupBy"]
|
||||
var groupBy int // 0:不分组,1:按文档分组
|
||||
if nil != groupByArg {
|
||||
groupBy = int(groupByArg.(float64))
|
||||
}
|
||||
blocks, matchedBlockCount, matchedRootCount, pageCount := model.FullTextSearchBlock(query, boxes, paths, types, method, orderBy, groupBy, page)
|
||||
ret.Data = map[string]interface{}{
|
||||
"blocks": blocks,
|
||||
"matchedBlockCount": matchedBlockCount,
|
||||
"matchedRootCount": matchedRootCount,
|
||||
"pageCount": pageCount,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import (
|
|||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
|
|
@ -207,7 +208,7 @@ func SearchRefBlock(id, rootID, keyword string, beforeLen int, isSquareBrackets
|
|||
return
|
||||
}
|
||||
|
||||
func FindReplace(keyword, replacement string, ids []string, method int) (err error) {
|
||||
func FindReplace(keyword, replacement string, ids []string, paths, boxes []string, types map[string]bool, method, orderBy, groupBy int) (err error) {
|
||||
// method:0:文本,1:查询语法,2:SQL,3:正则表达式
|
||||
if 1 == method || 2 == method {
|
||||
err = errors.New(Conf.Language(132))
|
||||
|
|
@ -232,6 +233,14 @@ func FindReplace(keyword, replacement string, ids []string, method int) (err err
|
|||
return
|
||||
}
|
||||
|
||||
if 1 > len(ids) {
|
||||
// `Replace All` is no longer affected by pagination https://github.com/siyuan-note/siyuan/issues/8265
|
||||
blocks, _, _, _ := FullTextSearchBlock(keyword, boxes, paths, types, method, orderBy, groupBy, 1, math.MaxInt)
|
||||
for _, block := range blocks {
|
||||
ids = append(ids, block.ID)
|
||||
}
|
||||
}
|
||||
|
||||
for _, id := range ids {
|
||||
bt := treenode.GetBlockTree(id)
|
||||
if nil == bt {
|
||||
|
|
@ -269,7 +278,7 @@ func FindReplace(keyword, replacement string, ids []string, method int) (err err
|
|||
}
|
||||
indexHistoryDir(filepath.Base(historyDir), util.NewLute())
|
||||
|
||||
for _, id := range ids {
|
||||
for i, id := range ids {
|
||||
bt := treenode.GetBlockTree(id)
|
||||
if nil == bt {
|
||||
continue
|
||||
|
|
@ -379,11 +388,15 @@ func FindReplace(keyword, replacement string, ids []string, method int) (err err
|
|||
if err = writeJSONQueue(tree); nil != err {
|
||||
return
|
||||
}
|
||||
|
||||
util.PushEndlessProgress(fmt.Sprintf(Conf.Language(206), i+1, len(ids)))
|
||||
}
|
||||
|
||||
for _, renameRoot := range renameRoots {
|
||||
for i, renameRoot := range renameRoots {
|
||||
newTitle := renameRootTitles[renameRoot.ID]
|
||||
RenameDoc(renameRoot.Box, renameRoot.Path, newTitle)
|
||||
|
||||
util.PushEndlessProgress(fmt.Sprintf(Conf.Language(207), i+1, len(ids)))
|
||||
}
|
||||
|
||||
WaitForWritingFiles()
|
||||
|
|
@ -396,14 +409,12 @@ func FindReplace(keyword, replacement string, ids []string, method int) (err err
|
|||
return
|
||||
}
|
||||
|
||||
const pageSize = 32
|
||||
|
||||
// FullTextSearchBlock 搜索内容块。
|
||||
//
|
||||
// method:0:关键字,1:查询语法,2:SQL,3:正则表达式
|
||||
// orderBy: 0:按块类型(默认),1:按创建时间升序,2:按创建时间降序,3:按更新时间升序,4:按更新时间降序,5:按内容顺序(仅在按文档分组时),6:按相关度升序,7:按相关度降序
|
||||
// groupBy:0:不分组,1:按文档分组
|
||||
func FullTextSearchBlock(query string, boxes, paths []string, types map[string]bool, method, orderBy, groupBy, page int) (ret []*Block, matchedBlockCount, matchedRootCount, pageCount int) {
|
||||
func FullTextSearchBlock(query string, boxes, paths []string, types map[string]bool, method, orderBy, groupBy, page, pageSize int) (ret []*Block, matchedBlockCount, matchedRootCount, pageCount int) {
|
||||
query = strings.TrimSpace(query)
|
||||
beforeLen := 36
|
||||
var blocks []*Block
|
||||
|
|
@ -413,19 +424,19 @@ func FullTextSearchBlock(query string, boxes, paths []string, types map[string]b
|
|||
filter := buildTypeFilter(types)
|
||||
boxFilter := buildBoxesFilter(boxes)
|
||||
pathFilter := buildPathsFilter(paths)
|
||||
blocks, matchedBlockCount, matchedRootCount = fullTextSearchByQuerySyntax(query, boxFilter, pathFilter, filter, orderByClause, beforeLen, page)
|
||||
blocks, matchedBlockCount, matchedRootCount = fullTextSearchByQuerySyntax(query, boxFilter, pathFilter, filter, orderByClause, beforeLen, page, pageSize)
|
||||
case 2: // SQL
|
||||
blocks, matchedBlockCount, matchedRootCount = searchBySQL(query, beforeLen, page)
|
||||
blocks, matchedBlockCount, matchedRootCount = searchBySQL(query, beforeLen, page, pageSize)
|
||||
case 3: // 正则表达式
|
||||
typeFilter := buildTypeFilter(types)
|
||||
boxFilter := buildBoxesFilter(boxes)
|
||||
pathFilter := buildPathsFilter(paths)
|
||||
blocks, matchedBlockCount, matchedRootCount = fullTextSearchByRegexp(query, boxFilter, pathFilter, typeFilter, orderByClause, beforeLen, page)
|
||||
blocks, matchedBlockCount, matchedRootCount = fullTextSearchByRegexp(query, boxFilter, pathFilter, typeFilter, orderByClause, beforeLen, page, pageSize)
|
||||
default: // 关键字
|
||||
filter := buildTypeFilter(types)
|
||||
boxFilter := buildBoxesFilter(boxes)
|
||||
pathFilter := buildPathsFilter(paths)
|
||||
blocks, matchedBlockCount, matchedRootCount = fullTextSearchByKeyword(query, boxFilter, pathFilter, filter, orderByClause, beforeLen, page)
|
||||
blocks, matchedBlockCount, matchedRootCount = fullTextSearchByKeyword(query, boxFilter, pathFilter, filter, orderByClause, beforeLen, page, pageSize)
|
||||
}
|
||||
pageCount = (matchedBlockCount + pageSize - 1) / pageSize
|
||||
|
||||
|
|
@ -607,7 +618,7 @@ func buildTypeFilter(types map[string]bool) string {
|
|||
return s.TypeFilter()
|
||||
}
|
||||
|
||||
func searchBySQL(stmt string, beforeLen, page int) (ret []*Block, matchedBlockCount, matchedRootCount int) {
|
||||
func searchBySQL(stmt string, beforeLen, page, pageSize int) (ret []*Block, matchedBlockCount, matchedRootCount int) {
|
||||
stmt = gulu.Str.RemoveInvisible(stmt)
|
||||
stmt = strings.TrimSpace(stmt)
|
||||
blocks := sql.SelectBlocksRawStmt(stmt, page, pageSize)
|
||||
|
|
@ -655,7 +666,7 @@ func fullTextSearchRefBlock(keyword string, beforeLen int, onlyDoc bool) (ret []
|
|||
keyword = gulu.Str.RemoveInvisible(keyword)
|
||||
|
||||
if ast.IsNodeIDPattern(keyword) {
|
||||
ret, _, _ = searchBySQL("SELECT * FROM `blocks` WHERE `id` = '"+keyword+"'", 36, 1)
|
||||
ret, _, _ = searchBySQL("SELECT * FROM `blocks` WHERE `id` = '"+keyword+"'", 36, 1, 32)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -704,26 +715,26 @@ func fullTextSearchRefBlock(keyword string, beforeLen int, onlyDoc bool) (ret []
|
|||
return
|
||||
}
|
||||
|
||||
func fullTextSearchByQuerySyntax(query, boxFilter, pathFilter, typeFilter, orderBy string, beforeLen, page int) (ret []*Block, matchedBlockCount, matchedRootCount int) {
|
||||
func fullTextSearchByQuerySyntax(query, boxFilter, pathFilter, typeFilter, orderBy string, beforeLen, page, pageSize int) (ret []*Block, matchedBlockCount, matchedRootCount int) {
|
||||
query = gulu.Str.RemoveInvisible(query)
|
||||
if ast.IsNodeIDPattern(query) {
|
||||
ret, matchedBlockCount, matchedRootCount = searchBySQL("SELECT * FROM `blocks` WHERE `id` = '"+query+"'", beforeLen, page)
|
||||
ret, matchedBlockCount, matchedRootCount = searchBySQL("SELECT * FROM `blocks` WHERE `id` = '"+query+"'", beforeLen, page, pageSize)
|
||||
return
|
||||
}
|
||||
return fullTextSearchByFTS(query, boxFilter, pathFilter, typeFilter, orderBy, beforeLen, page)
|
||||
return fullTextSearchByFTS(query, boxFilter, pathFilter, typeFilter, orderBy, beforeLen, page, pageSize)
|
||||
}
|
||||
|
||||
func fullTextSearchByKeyword(query, boxFilter, pathFilter, typeFilter string, orderBy string, beforeLen, page int) (ret []*Block, matchedBlockCount, matchedRootCount int) {
|
||||
func fullTextSearchByKeyword(query, boxFilter, pathFilter, typeFilter string, orderBy string, beforeLen, page, pageSize int) (ret []*Block, matchedBlockCount, matchedRootCount int) {
|
||||
query = gulu.Str.RemoveInvisible(query)
|
||||
if ast.IsNodeIDPattern(query) {
|
||||
ret, matchedBlockCount, matchedRootCount = searchBySQL("SELECT * FROM `blocks` WHERE `id` = '"+query+"'", beforeLen, page)
|
||||
ret, matchedBlockCount, matchedRootCount = searchBySQL("SELECT * FROM `blocks` WHERE `id` = '"+query+"'", beforeLen, page, pageSize)
|
||||
return
|
||||
}
|
||||
query = stringQuery(query)
|
||||
return fullTextSearchByFTS(query, boxFilter, pathFilter, typeFilter, orderBy, beforeLen, page)
|
||||
return fullTextSearchByFTS(query, boxFilter, pathFilter, typeFilter, orderBy, beforeLen, page, pageSize)
|
||||
}
|
||||
|
||||
func fullTextSearchByRegexp(exp, boxFilter, pathFilter, typeFilter, orderBy string, beforeLen, page int) (ret []*Block, matchedBlockCount, matchedRootCount int) {
|
||||
func fullTextSearchByRegexp(exp, boxFilter, pathFilter, typeFilter, orderBy string, beforeLen, page, pageSize int) (ret []*Block, matchedBlockCount, matchedRootCount int) {
|
||||
exp = gulu.Str.RemoveInvisible(exp)
|
||||
|
||||
fieldFilter := fieldRegexp(exp)
|
||||
|
|
@ -754,7 +765,7 @@ func fullTextSearchCountByRegexp(exp, boxFilter, pathFilter, typeFilter string)
|
|||
return
|
||||
}
|
||||
|
||||
func fullTextSearchByFTS(query, boxFilter, pathFilter, typeFilter, orderBy string, beforeLen, page int) (ret []*Block, matchedBlockCount, matchedRootCount int) {
|
||||
func fullTextSearchByFTS(query, boxFilter, pathFilter, typeFilter, orderBy string, beforeLen, page, pageSize int) (ret []*Block, matchedBlockCount, matchedRootCount int) {
|
||||
table := "blocks_fts" // 大小写敏感
|
||||
if !Conf.Search.CaseSensitive {
|
||||
table = "blocks_fts_case_insensitive"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue