Improve virtual reference keyword handling and support line breaks (#16298)

* 🎨 Improve virtual reference keyword handling and support line breaks

https://ld246.com/article/1762474775795

* Update text
This commit is contained in:
Jeffrey Chen 2025-11-15 17:16:23 +08:00 committed by GitHub
parent 5ccb95ae4e
commit f35761c1ab
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 110 additions and 54 deletions

View file

@ -45,6 +45,9 @@ var virtualBlockRefCache, _ = ristretto.NewCache(&ristretto.Config{
BufferItems: 64,
})
// newlineRegexp 用于匹配连续或单个换行符的正则表达式
var newlineRegexp = regexp.MustCompile(`[\r\n]+`)
func getBlockVirtualRefKeywords(root *ast.Node) (ret []string) {
val, ok := virtualBlockRefCache.Get(root.ID)
if !ok {
@ -121,18 +124,54 @@ func ResetVirtualBlockRefCache() {
virtualBlockRefCache.Set("virtual_ref", keywords, 1)
}
// addNewKeywords 将新关键字添加到虚拟引用关键字列表中,如果不存在则追加,保留空白字符
func addNewKeywords(keywordsStr string, newKeywords []string) string {
keywordsStr = strings.TrimSpace(keywordsStr)
if 0 == len(newKeywords) {
return keywordsStr
}
var builder strings.Builder
if "" != keywordsStr {
if !strings.HasSuffix(keywordsStr, "\\,") {
keywordsStr = strings.TrimSuffix(keywordsStr, ",")
}
builder.WriteString(keywordsStr)
builder.WriteString(",")
}
keywords := gulu.Str.RemoveDuplicatedElem(parseKeywords(keywordsStr))
newKeywords = gulu.Str.RemoveDuplicatedElem(newKeywords)
allKeys := make(map[string]bool)
// 添加新关键字
for _, keyword := range newKeywords {
keywordTrimmed := strings.TrimSpace(keyword)
if "" == keywordTrimmed {
continue
}
if gulu.Str.Contains(keywordTrimmed, keywords) {
// 剔除已存在的关键字
continue
}
if _, value := allKeys[keywordTrimmed]; value {
// 剔除重复的关键字
continue
}
allKeys[keywordTrimmed] = true
builder.WriteString(strings.ReplaceAll(keyword, ",", "\\,")) // 字符串切片转换为字符串,需要转义逗号
builder.WriteString(",")
}
return strings.TrimSuffix(builder.String(), ",")
}
func AddVirtualBlockRefInclude(keyword []string) {
if 1 > len(keyword) {
return
}
include := strings.ReplaceAll(Conf.Editor.VirtualBlockRefInclude, "\\,", "__comma@sep__")
includes := strings.Split(include, ",")
includes = append(includes, keyword...)
includes = gulu.Str.RemoveDuplicatedElem(includes)
Conf.Editor.VirtualBlockRefInclude = strings.Join(includes, ",")
Conf.Editor.VirtualBlockRefInclude = addNewKeywords(Conf.Editor.VirtualBlockRefInclude, keyword)
Conf.Save()
ResetVirtualBlockRefCache()
}
@ -140,14 +179,8 @@ func AddVirtualBlockRefExclude(keyword []string) {
if 1 > len(keyword) {
return
}
exclude := strings.ReplaceAll(Conf.Editor.VirtualBlockRefExclude, "\\,", "__comma@sep__")
excludes := strings.Split(exclude, ",")
excludes = append(excludes, keyword...)
excludes = gulu.Str.RemoveDuplicatedElem(excludes)
Conf.Editor.VirtualBlockRefExclude = strings.Join(excludes, ",")
Conf.Editor.VirtualBlockRefExclude = addNewKeywords(Conf.Editor.VirtualBlockRefExclude, keyword)
Conf.Save()
ResetVirtualBlockRefCache()
}
@ -213,6 +246,30 @@ func processVirtualRef(n *ast.Node, unlinks *[]*ast.Node, virtualBlockRefKeyword
return false
}
// parseKeywords 将字符串转换为关键字切片,并剔除前后的空白字符
func parseKeywords(keywordsStr string) (keywords []string) {
keywords = []string{}
keywordsStr = strings.TrimSpace(keywordsStr)
if "" == keywordsStr {
return
}
// 先处理转义的逗号
keywordsStr = strings.ReplaceAll(keywordsStr, "\\,", "__comma@sep__")
// 再将连续或单个换行符替换为一个逗号,避免把 `\\\n` 转换为 `\,`
keywordsStr = newlineRegexp.ReplaceAllString(keywordsStr, ",")
// 按逗号分隔
for part := range strings.SplitSeq(keywordsStr, ",") {
part = strings.TrimSpace(part) // 剔除前后的空白字符
if "" == part {
continue
}
// 恢复转义的逗号
part = strings.ReplaceAll(part, "__comma@sep__", ",")
keywords = append(keywords, part)
}
return
}
func getVirtualRefKeywords(root *ast.Node) (ret []string) {
if !Conf.Editor.VirtualBlockRef {
return
@ -222,25 +279,16 @@ func getVirtualRefKeywords(root *ast.Node) (ret []string) {
ret = val.([]string)
}
if "" != strings.TrimSpace(Conf.Editor.VirtualBlockRefInclude) {
include := strings.ReplaceAll(Conf.Editor.VirtualBlockRefInclude, "\\,", "__comma@sep__")
includes := strings.Split(include, ",")
var tmp []string
for _, e := range includes {
e = strings.ReplaceAll(e, "__comma@sep__", ",")
tmp = append(tmp, e)
}
includes = tmp
includes := parseKeywords(Conf.Editor.VirtualBlockRefInclude)
if 0 < len(includes) {
ret = append(ret, includes...)
ret = gulu.Str.RemoveDuplicatedElem(ret)
}
if "" != strings.TrimSpace(Conf.Editor.VirtualBlockRefExclude) {
exclude := strings.ReplaceAll(Conf.Editor.VirtualBlockRefExclude, "\\,", "__comma@sep__")
excludes := strings.Split(exclude, ",")
excludes := parseKeywords(Conf.Editor.VirtualBlockRefExclude)
if 0 < len(excludes) {
var tmp, regexps []string
for _, e := range excludes {
e = strings.ReplaceAll(e, "__comma@sep__", ",")
if strings.HasPrefix(e, "/") && strings.HasSuffix(e, "/") {
regexps = append(regexps, e[1:len(e)-1])
} else {