mirror of
https://github.com/siyuan-note/siyuan.git
synced 2026-01-28 03:06:10 +01:00
Merge branch 'dev' into master
This commit is contained in:
commit
c3cd6e3b8a
409 changed files with 5557 additions and 1327 deletions
|
|
@ -28,6 +28,7 @@ import (
|
|||
"github.com/siyuan-note/logging"
|
||||
"github.com/siyuan-note/siyuan/kernel/filesys"
|
||||
"github.com/siyuan-note/siyuan/kernel/model"
|
||||
"github.com/siyuan-note/siyuan/kernel/treenode"
|
||||
"github.com/siyuan-note/siyuan/kernel/util"
|
||||
)
|
||||
|
||||
|
|
@ -660,6 +661,10 @@ func getBlockInfo(c *gin.Context) {
|
|||
ret.Code = 3
|
||||
ret.Msg = model.Conf.Language(56)
|
||||
return
|
||||
} else if errors.Is(err, treenode.ErrSpecTooNew) {
|
||||
ret.Code = -1
|
||||
ret.Msg = model.Conf.Language(275)
|
||||
return
|
||||
}
|
||||
|
||||
block, _ := model.GetBlock(id, tree)
|
||||
|
|
|
|||
|
|
@ -903,7 +903,6 @@ func batchUpdateBlock(c *gin.Context) {
|
|||
|
||||
ret.Data = transactions
|
||||
broadcastTransactions(transactions)
|
||||
|
||||
}
|
||||
|
||||
func deleteBlock(c *gin.Context) {
|
||||
|
|
|
|||
|
|
@ -733,7 +733,7 @@ func exportPreview(c *gin.Context) {
|
|||
}
|
||||
}
|
||||
|
||||
stdHTML := model.Preview(id, fillCSSVar)
|
||||
stdHTML := model.ExportPreview(id, fillCSSVar)
|
||||
ret.Data = map[string]interface{}{
|
||||
"html": stdHTML,
|
||||
"fillCSSVar": fillCSSVar,
|
||||
|
|
|
|||
|
|
@ -380,10 +380,13 @@ func putFile(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
if !util.IsValidUploadFileName(filepath.Base(fileAbsPath)) { // Improve kernel API `/api/file/putFile` parameter validation https://github.com/siyuan-note/siyuan/issues/14658
|
||||
ret.Code = http.StatusBadRequest
|
||||
ret.Msg = "invalid file path, please check https://github.com/siyuan-note/siyuan/issues/14658 for more details"
|
||||
return
|
||||
fileExists := filelock.IsExist(fileAbsPath)
|
||||
if !fileExists {
|
||||
if !util.IsValidUploadFileName(filepath.Base(fileAbsPath)) { // Improve kernel API `/api/file/putFile` parameter validation https://github.com/siyuan-note/siyuan/issues/14658
|
||||
ret.Code = http.StatusBadRequest
|
||||
ret.Msg = "invalid file path, please check https://github.com/siyuan-note/siyuan/issues/14658 for more details"
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
isDirStr := c.PostForm("isDir")
|
||||
|
|
|
|||
|
|
@ -68,9 +68,9 @@ func setPetalEnabled(c *gin.Context) {
|
|||
}
|
||||
if enabled {
|
||||
upsertPluginCodeSet := hashset.New(packageName)
|
||||
model.PushReloadPlugin(upsertPluginCodeSet, nil, nil, app)
|
||||
model.PushReloadPlugin(upsertPluginCodeSet, nil, nil, nil, app)
|
||||
} else {
|
||||
removePluginSet := hashset.New(packageName)
|
||||
model.PushReloadPlugin(nil, nil, removePluginSet, app)
|
||||
unloadPluginSet := hashset.New(packageName)
|
||||
model.PushReloadPlugin(nil, nil, unloadPluginSet, nil, app)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -326,6 +326,7 @@ func setEditor(c *gin.Context) {
|
|||
model.Conf.Save()
|
||||
|
||||
if oldGenerateHistoryInterval != model.Conf.Editor.GenerateHistoryInterval {
|
||||
model.GenerateFileHistory()
|
||||
model.ChangeHistoryTick(editor.GenerateHistoryInterval)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -785,7 +785,13 @@ func exit(c *gin.Context) {
|
|||
execInstallPkg = int(execInstallPkgArg.(float64))
|
||||
}
|
||||
|
||||
exitCode := model.Close(force, true, execInstallPkg)
|
||||
setCurrentWorkspaceArg := arg["setCurrentWorkspace"]
|
||||
setCurrentWorkspace := true
|
||||
if nil != setCurrentWorkspaceArg {
|
||||
setCurrentWorkspace = setCurrentWorkspaceArg.(bool)
|
||||
}
|
||||
|
||||
exitCode := model.Close(force, setCurrentWorkspace, execInstallPkg)
|
||||
ret.Code = exitCode
|
||||
switch exitCode {
|
||||
case 0:
|
||||
|
|
|
|||
|
|
@ -330,9 +330,7 @@ func setWorkspaceDir(c *gin.Context) {
|
|||
|
||||
if util.ContainerAndroid == util.Container || util.ContainerIOS == util.Container || util.ContainerHarmony == util.Container {
|
||||
util.PushMsg(model.Conf.Language(42), 1000*15)
|
||||
time.Sleep(time.Second * 1)
|
||||
model.Close(false, false, 1)
|
||||
time.Sleep(time.Second * 1)
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -169,9 +169,9 @@ func InstalledIcons() (ret []*Icon) {
|
|||
icon.PreferredFunding = getPreferredFunding(icon.Funding)
|
||||
icon.PreferredName = GetPreferredName(icon.Package)
|
||||
icon.PreferredDesc = getPreferredDesc(icon.Description)
|
||||
info, statErr := os.Stat(filepath.Join(installPath, "README.md"))
|
||||
info, statErr := os.Stat(filepath.Join(installPath, "icon.json"))
|
||||
if nil != statErr {
|
||||
logging.LogWarnf("stat install theme README.md failed: %s", statErr)
|
||||
logging.LogWarnf("stat install icon.json failed: %s", statErr)
|
||||
continue
|
||||
}
|
||||
icon.HInstallDate = info.ModTime().Format("2006-01-02")
|
||||
|
|
@ -183,14 +183,7 @@ func InstalledIcons() (ret []*Icon) {
|
|||
packageInstallSizeCache.SetDefault(icon.RepoURL, is)
|
||||
}
|
||||
icon.HInstallSize = humanize.BytesCustomCeil(uint64(icon.InstallSize), 2)
|
||||
readmeFilename := getPreferredReadme(icon.Readme)
|
||||
readme, readErr := os.ReadFile(filepath.Join(installPath, readmeFilename))
|
||||
if nil != readErr {
|
||||
logging.LogWarnf("read installed README.md failed: %s", readErr)
|
||||
continue
|
||||
}
|
||||
|
||||
icon.PreferredReadme, _ = renderLocalREADME("/appearance/icons/"+dirName+"/", readme)
|
||||
icon.PreferredReadme = loadInstalledReadme(installPath, "/appearance/icons/"+dirName+"/", icon.Readme)
|
||||
icon.Outdated = isOutdatedIcon(icon, bazaarIcons)
|
||||
ret = append(ret, icon)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ type DisplayName struct {
|
|||
HeIL string `json:"he_IL"`
|
||||
ItIT string `json:"it_IT"`
|
||||
JaJP string `json:"ja_JP"`
|
||||
KoKR string `json:"ko_KR"`
|
||||
PlPL string `json:"pl_PL"`
|
||||
PtBR string `json:"pt_BR"`
|
||||
RuRU string `json:"ru_RU"`
|
||||
|
|
@ -68,6 +69,7 @@ type Description struct {
|
|||
HeIL string `json:"he_IL"`
|
||||
ItIT string `json:"it_IT"`
|
||||
JaJP string `json:"ja_JP"`
|
||||
KoKR string `json:"ko_KR"`
|
||||
PlPL string `json:"pl_PL"`
|
||||
PtBR string `json:"pt_BR"`
|
||||
RuRU string `json:"ru_RU"`
|
||||
|
|
@ -86,6 +88,7 @@ type Readme struct {
|
|||
HeIL string `json:"he_IL"`
|
||||
ItIT string `json:"it_IT"`
|
||||
JaJP string `json:"ja_JP"`
|
||||
KoKR string `json:"ko_KR"`
|
||||
PlPL string `json:"pl_PL"`
|
||||
PtBR string `json:"pt_BR"`
|
||||
RuRU string `json:"ru_RU"`
|
||||
|
|
@ -174,7 +177,7 @@ func getPreferredReadme(readme *Readme) string {
|
|||
return "README.md"
|
||||
}
|
||||
|
||||
ret := readme.Default
|
||||
var ret string
|
||||
switch util.Lang {
|
||||
case "ar_SA":
|
||||
if "" != readme.ArSA {
|
||||
|
|
@ -208,6 +211,10 @@ func getPreferredReadme(readme *Readme) string {
|
|||
if "" != readme.JaJP {
|
||||
ret = readme.JaJP
|
||||
}
|
||||
case "ko_KR":
|
||||
if "" != readme.KoKR {
|
||||
ret = readme.KoKR
|
||||
}
|
||||
case "pl_PL":
|
||||
if "" != readme.PlPL {
|
||||
ret = readme.PlPL
|
||||
|
|
@ -232,13 +239,14 @@ func getPreferredReadme(readme *Readme) string {
|
|||
if "" != readme.ZhCN {
|
||||
ret = readme.ZhCN
|
||||
}
|
||||
default:
|
||||
if "" != readme.EnUS {
|
||||
ret = readme.EnUS
|
||||
}
|
||||
}
|
||||
if "" == ret {
|
||||
ret = "README.md"
|
||||
if "" == strings.TrimSpace(ret) {
|
||||
defaultReadme := strings.TrimSpace(readme.Default)
|
||||
if defaultReadme != "" {
|
||||
ret = defaultReadme
|
||||
} else {
|
||||
ret = "README.md"
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
|
@ -248,7 +256,7 @@ func GetPreferredName(pkg *Package) string {
|
|||
return pkg.Name
|
||||
}
|
||||
|
||||
ret := pkg.DisplayName.Default
|
||||
var ret string
|
||||
switch util.Lang {
|
||||
case "ar_SA":
|
||||
if "" != pkg.DisplayName.ArSA {
|
||||
|
|
@ -282,6 +290,10 @@ func GetPreferredName(pkg *Package) string {
|
|||
if "" != pkg.DisplayName.JaJP {
|
||||
ret = pkg.DisplayName.JaJP
|
||||
}
|
||||
case "ko_KR":
|
||||
if "" != pkg.DisplayName.KoKR {
|
||||
ret = pkg.DisplayName.KoKR
|
||||
}
|
||||
case "pl_PL":
|
||||
if "" != pkg.DisplayName.PlPL {
|
||||
ret = pkg.DisplayName.PlPL
|
||||
|
|
@ -306,13 +318,14 @@ func GetPreferredName(pkg *Package) string {
|
|||
if "" != pkg.DisplayName.ZhCN {
|
||||
ret = pkg.DisplayName.ZhCN
|
||||
}
|
||||
default:
|
||||
if "" != pkg.DisplayName.EnUS {
|
||||
ret = pkg.DisplayName.EnUS
|
||||
}
|
||||
}
|
||||
if "" == ret {
|
||||
ret = pkg.Name
|
||||
if "" == strings.TrimSpace(ret) {
|
||||
defaultName := strings.TrimSpace(pkg.DisplayName.Default)
|
||||
if defaultName != "" {
|
||||
ret = defaultName
|
||||
} else {
|
||||
ret = pkg.Name
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
|
@ -322,7 +335,7 @@ func getPreferredDesc(desc *Description) string {
|
|||
return ""
|
||||
}
|
||||
|
||||
ret := desc.Default
|
||||
var ret string
|
||||
switch util.Lang {
|
||||
case "ar_SA":
|
||||
if "" != desc.ArSA {
|
||||
|
|
@ -356,6 +369,10 @@ func getPreferredDesc(desc *Description) string {
|
|||
if "" != desc.JaJP {
|
||||
ret = desc.JaJP
|
||||
}
|
||||
case "ko_KR":
|
||||
if "" != desc.KoKR {
|
||||
ret = desc.KoKR
|
||||
}
|
||||
case "pl_PL":
|
||||
if "" != desc.PlPL {
|
||||
ret = desc.PlPL
|
||||
|
|
@ -380,13 +397,12 @@ func getPreferredDesc(desc *Description) string {
|
|||
if "" != desc.ZhCN {
|
||||
ret = desc.ZhCN
|
||||
}
|
||||
default:
|
||||
if "" != desc.EnUS {
|
||||
ret = desc.EnUS
|
||||
}
|
||||
}
|
||||
if "" == ret {
|
||||
ret = desc.EnUS
|
||||
if "" == strings.TrimSpace(ret) {
|
||||
defaultDesc := strings.TrimSpace(desc.Default)
|
||||
if defaultDesc != "" {
|
||||
ret = defaultDesc
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
|
@ -397,12 +413,21 @@ func getPreferredFunding(funding *Funding) string {
|
|||
}
|
||||
|
||||
if "" != funding.OpenCollective {
|
||||
if strings.HasPrefix(funding.OpenCollective, "http://") || strings.HasPrefix(funding.OpenCollective, "https://") {
|
||||
return funding.OpenCollective
|
||||
}
|
||||
return "https://opencollective.com/" + funding.OpenCollective
|
||||
}
|
||||
if "" != funding.Patreon {
|
||||
if strings.HasPrefix(funding.Patreon, "http://") || strings.HasPrefix(funding.Patreon, "https://") {
|
||||
return funding.Patreon
|
||||
}
|
||||
return "https://www.patreon.com/" + funding.Patreon
|
||||
}
|
||||
if "" != funding.GitHub {
|
||||
if strings.HasPrefix(funding.GitHub, "http://") || strings.HasPrefix(funding.GitHub, "https://") {
|
||||
return funding.GitHub
|
||||
}
|
||||
return "https://github.com/sponsors/" + funding.GitHub
|
||||
}
|
||||
if 0 < len(funding.Custom) {
|
||||
|
|
@ -684,14 +709,29 @@ func GetPackageREADME(repoURL, repoHash, packageType string) (ret string) {
|
|||
|
||||
data, err := downloadPackage(repoURLHash+"/"+readme, false, "")
|
||||
if err != nil {
|
||||
ret = fmt.Sprintf("Load bazaar package's README.md(%s) failed: %s", readme, err.Error())
|
||||
if readme == repo.Package.Readme.Default || "" == strings.TrimSpace(repo.Package.Readme.Default) {
|
||||
return
|
||||
ret = fmt.Sprintf("Load bazaar package's preferred README(%s) failed: %s", readme, err.Error())
|
||||
// 回退到 Default README
|
||||
var defaultReadme string
|
||||
if nil != repo.Package.Readme {
|
||||
defaultReadme = repo.Package.Readme.Default
|
||||
}
|
||||
readme = repo.Package.Readme.Default
|
||||
data, err = downloadPackage(repoURLHash+"/"+readme, false, "")
|
||||
if err != nil {
|
||||
ret += fmt.Sprintf("<br>Load bazaar package's README.md(%s) failed: %s", readme, err.Error())
|
||||
if "" == strings.TrimSpace(defaultReadme) {
|
||||
defaultReadme = "README.md"
|
||||
}
|
||||
if readme != defaultReadme {
|
||||
data, err = downloadPackage(repoURLHash+"/"+defaultReadme, false, "")
|
||||
if err != nil {
|
||||
ret += fmt.Sprintf("<br>Load bazaar package's default README(%s) failed: %s", defaultReadme, err.Error())
|
||||
}
|
||||
}
|
||||
// 回退到 README.md
|
||||
if err != nil && readme != "README.md" && defaultReadme != "README.md" {
|
||||
data, err = downloadPackage(repoURLHash+"/README.md", false, "")
|
||||
if err != nil {
|
||||
ret += fmt.Sprintf("<br>Load bazaar package's README.md failed: %s", err.Error())
|
||||
return
|
||||
}
|
||||
} else if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
@ -708,6 +748,46 @@ func GetPackageREADME(repoURL, repoHash, packageType string) (ret string) {
|
|||
return
|
||||
}
|
||||
|
||||
func loadInstalledReadme(installPath, basePath string, readme *Readme) (ret string) {
|
||||
readmeFilename := getPreferredReadme(readme)
|
||||
readmeData, readErr := os.ReadFile(filepath.Join(installPath, readmeFilename))
|
||||
if nil == readErr {
|
||||
ret, _ = renderLocalREADME(basePath, readmeData)
|
||||
return
|
||||
}
|
||||
|
||||
logging.LogWarnf("read installed %s failed: %s", readmeFilename, readErr)
|
||||
ret = fmt.Sprintf("File %s not found", readmeFilename)
|
||||
// 回退到 Default README
|
||||
var defaultReadme string
|
||||
if nil != readme {
|
||||
defaultReadme = strings.TrimSpace(readme.Default)
|
||||
}
|
||||
if "" == defaultReadme {
|
||||
defaultReadme = "README.md"
|
||||
}
|
||||
if readmeFilename != defaultReadme {
|
||||
readmeData, readErr = os.ReadFile(filepath.Join(installPath, defaultReadme))
|
||||
if nil == readErr {
|
||||
ret, _ = renderLocalREADME(basePath, readmeData)
|
||||
return
|
||||
}
|
||||
logging.LogWarnf("read installed %s failed: %s", defaultReadme, readErr)
|
||||
ret += fmt.Sprintf("<br>File %s not found", defaultReadme)
|
||||
}
|
||||
// 回退到 README.md
|
||||
if nil != readErr && readmeFilename != "README.md" && defaultReadme != "README.md" {
|
||||
readmeData, readErr = os.ReadFile(filepath.Join(installPath, "README.md"))
|
||||
if nil == readErr {
|
||||
ret, _ = renderLocalREADME(basePath, readmeData)
|
||||
return
|
||||
}
|
||||
logging.LogWarnf("read installed README.md failed: %s", readErr)
|
||||
ret += "<br>File README.md not found"
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func renderREADME(repoURL string, mdData []byte) (ret string, err error) {
|
||||
luteEngine := lute.New()
|
||||
luteEngine.SetSoftBreak2HardBreak(false)
|
||||
|
|
|
|||
|
|
@ -207,9 +207,9 @@ func InstalledPlugins(frontend string, checkUpdate bool) (ret []*Plugin) {
|
|||
plugin.PreferredFunding = getPreferredFunding(plugin.Funding)
|
||||
plugin.PreferredName = GetPreferredName(plugin.Package)
|
||||
plugin.PreferredDesc = getPreferredDesc(plugin.Description)
|
||||
info, statErr := os.Stat(filepath.Join(installPath, "README.md"))
|
||||
info, statErr := os.Stat(filepath.Join(installPath, "plugin.json"))
|
||||
if nil != statErr {
|
||||
logging.LogWarnf("stat install theme README.md failed: %s", statErr)
|
||||
logging.LogWarnf("stat install plugin.json failed: %s", statErr)
|
||||
continue
|
||||
}
|
||||
plugin.HInstallDate = info.ModTime().Format("2006-01-02")
|
||||
|
|
@ -221,14 +221,7 @@ func InstalledPlugins(frontend string, checkUpdate bool) (ret []*Plugin) {
|
|||
packageInstallSizeCache.SetDefault(plugin.RepoURL, is)
|
||||
}
|
||||
plugin.HInstallSize = humanize.BytesCustomCeil(uint64(plugin.InstallSize), 2)
|
||||
readmeFilename := getPreferredReadme(plugin.Readme)
|
||||
readme, readErr := os.ReadFile(filepath.Join(installPath, readmeFilename))
|
||||
if nil != readErr {
|
||||
logging.LogWarnf("read installed README.md failed: %s", readErr)
|
||||
continue
|
||||
}
|
||||
|
||||
plugin.PreferredReadme, _ = renderLocalREADME("/plugins/"+dirName+"/", readme)
|
||||
plugin.PreferredReadme = loadInstalledReadme(installPath, "/plugins/"+dirName+"/", plugin.Readme)
|
||||
plugin.Outdated = isOutdatedPlugin(plugin, bazaarPlugins)
|
||||
plugin.Incompatible = isIncompatiblePlugin(plugin, frontend)
|
||||
ret = append(ret, plugin)
|
||||
|
|
|
|||
|
|
@ -170,9 +170,9 @@ func InstalledTemplates() (ret []*Template) {
|
|||
template.PreferredFunding = getPreferredFunding(template.Funding)
|
||||
template.PreferredName = GetPreferredName(template.Package)
|
||||
template.PreferredDesc = getPreferredDesc(template.Description)
|
||||
info, statErr := os.Stat(filepath.Join(installPath, "README.md"))
|
||||
info, statErr := os.Stat(filepath.Join(installPath, "template.json"))
|
||||
if nil != statErr {
|
||||
logging.LogWarnf("stat install theme README.md failed: %s", statErr)
|
||||
logging.LogWarnf("stat install template.json failed: %s", statErr)
|
||||
continue
|
||||
}
|
||||
template.HInstallDate = info.ModTime().Format("2006-01-02")
|
||||
|
|
@ -184,14 +184,7 @@ func InstalledTemplates() (ret []*Template) {
|
|||
packageInstallSizeCache.SetDefault(template.RepoURL, is)
|
||||
}
|
||||
template.HInstallSize = humanize.BytesCustomCeil(uint64(template.InstallSize), 2)
|
||||
readmeFilename := getPreferredReadme(template.Readme)
|
||||
readme, readErr := os.ReadFile(filepath.Join(installPath, readmeFilename))
|
||||
if nil != readErr {
|
||||
logging.LogWarnf("read installed README.md failed: %s", readErr)
|
||||
continue
|
||||
}
|
||||
|
||||
template.PreferredReadme, _ = renderLocalREADME("/templates/"+dirName+"/", readme)
|
||||
template.PreferredReadme = loadInstalledReadme(installPath, "/templates/"+dirName+"/", template.Readme)
|
||||
template.Outdated = isOutdatedTemplate(template, bazaarTemplates)
|
||||
ret = append(ret, template)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -171,9 +171,9 @@ func InstalledThemes() (ret []*Theme) {
|
|||
theme.PreferredFunding = getPreferredFunding(theme.Funding)
|
||||
theme.PreferredName = GetPreferredName(theme.Package)
|
||||
theme.PreferredDesc = getPreferredDesc(theme.Description)
|
||||
info, statErr := os.Stat(filepath.Join(installPath, "README.md"))
|
||||
info, statErr := os.Stat(filepath.Join(installPath, "theme.json"))
|
||||
if nil != statErr {
|
||||
logging.LogWarnf("stat install theme README.md failed: %s", statErr)
|
||||
logging.LogWarnf("stat install theme.json failed: %s", statErr)
|
||||
continue
|
||||
}
|
||||
theme.HInstallDate = info.ModTime().Format("2006-01-02")
|
||||
|
|
@ -185,14 +185,7 @@ func InstalledThemes() (ret []*Theme) {
|
|||
packageInstallSizeCache.SetDefault(theme.RepoURL, is)
|
||||
}
|
||||
theme.HInstallSize = humanize.BytesCustomCeil(uint64(theme.InstallSize), 2)
|
||||
readmeFilename := getPreferredReadme(theme.Readme)
|
||||
readme, readErr := os.ReadFile(filepath.Join(installPath, readmeFilename))
|
||||
if nil != readErr {
|
||||
logging.LogWarnf("read installed README.md failed: %s", readErr)
|
||||
continue
|
||||
}
|
||||
|
||||
theme.PreferredReadme, _ = renderLocalREADME("/appearance/themes/"+dirName+"/", readme)
|
||||
theme.PreferredReadme = loadInstalledReadme(installPath, "/appearance/themes/"+dirName+"/", theme.Readme)
|
||||
theme.Outdated = isOutdatedTheme(theme, bazaarThemes)
|
||||
ret = append(ret, theme)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -167,9 +167,9 @@ func InstalledWidgets() (ret []*Widget) {
|
|||
widget.PreferredFunding = getPreferredFunding(widget.Funding)
|
||||
widget.PreferredName = GetPreferredName(widget.Package)
|
||||
widget.PreferredDesc = getPreferredDesc(widget.Description)
|
||||
info, statErr := os.Stat(filepath.Join(installPath, "README.md"))
|
||||
info, statErr := os.Stat(filepath.Join(installPath, "widget.json"))
|
||||
if nil != statErr {
|
||||
logging.LogWarnf("stat install theme README.md failed: %s", statErr)
|
||||
logging.LogWarnf("stat install widget.json failed: %s", statErr)
|
||||
continue
|
||||
}
|
||||
widget.HInstallDate = info.ModTime().Format("2006-01-02")
|
||||
|
|
@ -181,14 +181,7 @@ func InstalledWidgets() (ret []*Widget) {
|
|||
packageInstallSizeCache.SetDefault(widget.RepoURL, is)
|
||||
}
|
||||
widget.HInstallSize = humanize.BytesCustomCeil(uint64(widget.InstallSize), 2)
|
||||
readmeFilename := getPreferredReadme(widget.Readme)
|
||||
readme, readErr := os.ReadFile(filepath.Join(installPath, readmeFilename))
|
||||
if nil != readErr {
|
||||
logging.LogWarnf("read installed README.md failed: %s", readErr)
|
||||
continue
|
||||
}
|
||||
|
||||
widget.PreferredReadme, _ = renderLocalREADME("/widgets/"+dirName+"/", readme)
|
||||
widget.PreferredReadme = loadInstalledReadme(installPath, "/widgets/"+dirName+"/", widget.Readme)
|
||||
widget.Outdated = isOutdatedWidget(widget, bazaarWidgets)
|
||||
ret = append(ret, widget)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ type Editor struct {
|
|||
Justify bool `json:"justify"` // 是否两端对齐
|
||||
RTL bool `json:"rtl"` // 是否从右到左显示
|
||||
Spellcheck bool `json:"spellcheck"` // 是否启用拼写检查
|
||||
SpellcheckLanguages []string `json:"spellcheckLanguages"` // 拼写检查语言
|
||||
OnlySearchForDoc bool `json:"onlySearchForDoc"` // 是否启用 [[ 仅搜索文档块
|
||||
BacklinkExpandCount int `json:"backlinkExpandCount"` // 反向链接默认展开数量
|
||||
BackmentionExpandCount int `json:"backmentionExpandCount"` // 反链提及默认展开数量
|
||||
|
|
@ -88,6 +89,8 @@ func NewEditor() *Editor {
|
|||
DynamicLoadBlocks: 192,
|
||||
Justify: false,
|
||||
RTL: false,
|
||||
Spellcheck: false,
|
||||
SpellcheckLanguages: []string{"en-US"},
|
||||
BacklinkExpandCount: 8,
|
||||
BackmentionExpandCount: -1,
|
||||
BacklinkContainChildren: true,
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ type TypeFilter struct {
|
|||
ListItem bool `json:"listItem"`
|
||||
Blockquote bool `json:"blockquote"`
|
||||
Super bool `json:"super"`
|
||||
Callout bool `json:"callout"`
|
||||
}
|
||||
|
||||
type D3 struct {
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ type Search struct {
|
|||
VideoBlock bool `json:"videoBlock"`
|
||||
IFrameBlock bool `json:"iframeBlock"`
|
||||
WidgetBlock bool `json:"widgetBlock"`
|
||||
Callout bool `json:"callout"`
|
||||
|
||||
Limit int `json:"limit"`
|
||||
CaseSensitive bool `json:"caseSensitive"`
|
||||
|
|
@ -84,6 +85,7 @@ func NewSearch() *Search {
|
|||
VideoBlock: false,
|
||||
IFrameBlock: false,
|
||||
WidgetBlock: false,
|
||||
Callout: false,
|
||||
|
||||
Limit: 64,
|
||||
CaseSensitive: false,
|
||||
|
|
@ -227,6 +229,12 @@ func (s *Search) TypeFilter() string {
|
|||
buf.WriteByte('\'')
|
||||
buf.WriteString(",")
|
||||
}
|
||||
if s.Callout {
|
||||
buf.WriteByte('\'')
|
||||
buf.WriteString(treenode.TypeAbbr(ast.NodeCallout.String()))
|
||||
buf.WriteByte('\'')
|
||||
buf.WriteString(",")
|
||||
}
|
||||
|
||||
ret := buf.String()
|
||||
if "" == ret {
|
||||
|
|
|
|||
|
|
@ -125,10 +125,9 @@ func LoadTree(boxID, p string, luteEngine *lute.Lute) (ret *parse.Tree, err erro
|
|||
}
|
||||
|
||||
func LoadTreeByData(data []byte, boxID, p string, luteEngine *lute.Lute) (ret *parse.Tree, err error) {
|
||||
ret = parseJSON2Tree(boxID, p, data, luteEngine)
|
||||
if nil == ret {
|
||||
logging.LogErrorf("parse tree [%s] failed", p)
|
||||
err = errors.New("parse tree failed")
|
||||
ret, err = parseJSON2Tree(boxID, p, data, luteEngine)
|
||||
if nil != err {
|
||||
logging.LogErrorf("parse tree [%s] failed: %s", p, err)
|
||||
return
|
||||
}
|
||||
ret.Path = p
|
||||
|
|
@ -245,12 +244,9 @@ func prepareWriteTree(tree *parse.Tree) (data []byte, filePath string, err error
|
|||
treenode.UpsertBlockTree(tree)
|
||||
}
|
||||
|
||||
treenode.UpgradeSpec(tree)
|
||||
|
||||
filePath = filepath.Join(util.DataDir, tree.Box, tree.Path)
|
||||
if oldSpec := tree.Root.Spec; "" == oldSpec {
|
||||
parse.NestedInlines2FlattedSpans(tree, false)
|
||||
tree.Root.Spec = "1"
|
||||
logging.LogInfof("migrated tree [%s] from spec [%s] to [%s]", filePath, oldSpec, tree.Root.Spec)
|
||||
}
|
||||
tree.Root.SetIALAttr("type", "doc")
|
||||
renderer := render.NewJSONRenderer(tree, luteEngine.RenderOptions)
|
||||
data = renderer.Render()
|
||||
|
|
@ -277,8 +273,7 @@ func afterWriteTree(tree *parse.Tree) {
|
|||
cache.PutDocIAL(tree.Path, docIAL)
|
||||
}
|
||||
|
||||
func parseJSON2Tree(boxID, p string, jsonData []byte, luteEngine *lute.Lute) (ret *parse.Tree) {
|
||||
var err error
|
||||
func parseJSON2Tree(boxID, p string, jsonData []byte, luteEngine *lute.Lute) (ret *parse.Tree, err error) {
|
||||
var needFix bool
|
||||
ret, needFix, err = dataparser.ParseJSON(jsonData, luteEngine.ParseOptions)
|
||||
if err != nil {
|
||||
|
|
@ -289,12 +284,12 @@ func parseJSON2Tree(boxID, p string, jsonData []byte, luteEngine *lute.Lute) (re
|
|||
ret.Box = boxID
|
||||
ret.Path = p
|
||||
|
||||
filePath := filepath.Join(util.DataDir, ret.Box, ret.Path)
|
||||
if oldSpec := ret.Root.Spec; "" == oldSpec {
|
||||
parse.NestedInlines2FlattedSpans(ret, false)
|
||||
ret.Root.Spec = "1"
|
||||
if err = treenode.CheckSpec(ret); errors.Is(err, treenode.ErrSpecTooNew) {
|
||||
return
|
||||
}
|
||||
|
||||
if treenode.UpgradeSpec(ret) {
|
||||
needFix = true
|
||||
logging.LogInfof("migrated tree [%s] from spec [%s] to [%s]", filePath, oldSpec, ret.Root.Spec)
|
||||
}
|
||||
|
||||
if pathID := util.GetTreeID(p); pathID != ret.Root.ID {
|
||||
|
|
@ -318,6 +313,7 @@ func parseJSON2Tree(boxID, p string, jsonData []byte, luteEngine *lute.Lute) (re
|
|||
data = buf.Bytes()
|
||||
}
|
||||
|
||||
filePath := filepath.Join(util.DataDir, ret.Box, ret.Path)
|
||||
if err = os.MkdirAll(filepath.Dir(filePath), 0755); err != nil {
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ require (
|
|||
github.com/88250/clipboard v0.1.5
|
||||
github.com/88250/epub v0.0.0-20230830085737-c19055cd1f48
|
||||
github.com/88250/go-humanize v0.0.0-20240424102817-4f78fac47ea7
|
||||
github.com/88250/gulu v1.2.3-0.20251119142510-7b1583ab4aa0
|
||||
github.com/88250/lute v1.7.7-0.20251201033723-6a6624a61082
|
||||
github.com/88250/gulu v1.2.3-0.20251208021445-f93f2666eaac
|
||||
github.com/88250/lute v1.7.7-0.20251212092708-7bcfc87de402
|
||||
github.com/88250/vitess-sqlparser v0.0.0-20210205111146-56a2ded2aba1
|
||||
github.com/ClarkThan/ahocorasick v0.0.0-20231011042242-30d1ef1347f4
|
||||
github.com/ConradIrwin/font v0.2.1
|
||||
|
|
@ -29,8 +29,8 @@ require (
|
|||
github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb
|
||||
github.com/flopp/go-findfont v0.1.0
|
||||
github.com/fsnotify/fsnotify v1.9.0
|
||||
github.com/gabriel-vasile/mimetype v1.4.10
|
||||
github.com/gin-contrib/gzip v1.2.3
|
||||
github.com/gabriel-vasile/mimetype v1.4.11
|
||||
github.com/gin-contrib/gzip v1.2.5
|
||||
github.com/gin-contrib/sessions v1.0.4
|
||||
github.com/gin-contrib/sse v1.1.0
|
||||
github.com/gin-gonic/gin v1.11.0
|
||||
|
|
@ -53,17 +53,17 @@ require (
|
|||
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||
github.com/pdfcpu/pdfcpu v0.11.0
|
||||
github.com/radovskyb/watcher v1.0.7
|
||||
github.com/rqlite/sql v0.0.0-20251114131613-ef07423e7137
|
||||
github.com/rqlite/sql v0.0.0-20251204023435-65660522892e
|
||||
github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06
|
||||
github.com/sashabaranov/go-openai v1.41.2
|
||||
github.com/shirou/gopsutil/v4 v4.25.11
|
||||
github.com/siyuan-note/dataparser v0.0.0-20250804100744-b41253b236f3
|
||||
github.com/siyuan-note/dejavu v0.0.0-20251202041457-7402b7c625c5
|
||||
github.com/siyuan-note/dataparser v0.0.0-20251203120213-59c16535cb56
|
||||
github.com/siyuan-note/dejavu v0.0.0-20251206130752-28126fa5ecd1
|
||||
github.com/siyuan-note/encryption v0.0.0-20251120032857-3ddc3c2cc49f
|
||||
github.com/siyuan-note/eventbus v0.0.0-20240627125516-396fdb0f0f97
|
||||
github.com/siyuan-note/filelock v0.0.0-20251107023958-207cad31f0dd
|
||||
github.com/siyuan-note/filelock v0.0.0-20251212095217-08318833e008
|
||||
github.com/siyuan-note/httpclient v0.0.0-20251119144307-63b815d7d198
|
||||
github.com/siyuan-note/logging v0.0.0-20251107023700-cd4339891032
|
||||
github.com/siyuan-note/logging v0.0.0-20251209020516-52f1a2f65ec5
|
||||
github.com/siyuan-note/riff v0.0.0-20251022131846-228528e70754
|
||||
github.com/spf13/cast v1.10.0
|
||||
github.com/steambap/captcha v1.4.1
|
||||
|
|
@ -72,12 +72,12 @@ require (
|
|||
github.com/vmihailenco/msgpack/v5 v5.4.1
|
||||
github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342
|
||||
github.com/xuri/excelize/v2 v2.9.0
|
||||
golang.org/x/image v0.32.0
|
||||
golang.org/x/mobile v0.0.0-20251009145931-8baca8bf4eeb
|
||||
golang.org/x/mod v0.29.0
|
||||
golang.org/x/net v0.47.0
|
||||
golang.org/x/sys v0.38.0
|
||||
golang.org/x/text v0.31.0
|
||||
golang.org/x/image v0.33.0
|
||||
golang.org/x/mobile v0.0.0-20251126181937-5c265dc024c4
|
||||
golang.org/x/mod v0.30.0
|
||||
golang.org/x/net v0.48.0
|
||||
golang.org/x/sys v0.39.0
|
||||
golang.org/x/text v0.32.0
|
||||
golang.org/x/time v0.14.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
|
@ -94,24 +94,24 @@ require (
|
|||
github.com/alex-ant/gomath v0.0.0-20160516115720-89013a210a82 // indirect
|
||||
github.com/andybalholm/brotli v1.2.0 // indirect
|
||||
github.com/andybalholm/cascadia v1.3.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.40.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.14 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.14 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.14 // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.40.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.15 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.15 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.15 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.14 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.14 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.14 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.92.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.0.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.10 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.41.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.15 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.6 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.15 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.15 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.93.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.0.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.6 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.11 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.41.3 // indirect
|
||||
github.com/aws/smithy-go v1.24.0 // indirect
|
||||
github.com/bytedance/gopkg v0.1.3 // indirect
|
||||
github.com/bytedance/sonic v1.14.1 // indirect
|
||||
|
|
@ -183,10 +183,10 @@ require (
|
|||
github.com/xuri/efp v0.0.1 // indirect
|
||||
github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||
golang.org/x/arch v0.22.0 // indirect
|
||||
golang.org/x/crypto v0.45.0 // indirect
|
||||
golang.org/x/sync v0.18.0 // indirect
|
||||
golang.org/x/tools v0.38.0 // indirect
|
||||
golang.org/x/arch v0.23.0 // indirect
|
||||
golang.org/x/crypto v0.46.0 // indirect
|
||||
golang.org/x/sync v0.19.0 // indirect
|
||||
golang.org/x/tools v0.39.0 // indirect
|
||||
google.golang.org/protobuf v1.36.10 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
modernc.org/fileutil v1.3.40 // indirect
|
||||
|
|
|
|||
144
kernel/go.sum
144
kernel/go.sum
|
|
@ -12,10 +12,10 @@ github.com/88250/go-humanize v0.0.0-20240424102817-4f78fac47ea7 h1:MafIFwSS0x6A4
|
|||
github.com/88250/go-humanize v0.0.0-20240424102817-4f78fac47ea7/go.mod h1:HrKCCTin3YNDSLBD02K0AOljjV6eNwc3/zyEI+xyV1I=
|
||||
github.com/88250/go-sqlite3 v1.14.13-0.20231214121541-e7f54c482950 h1:Pa5hMiBceTVVqrYaDlLio2QSKbXMUmAZPbzCwT5eNCw=
|
||||
github.com/88250/go-sqlite3 v1.14.13-0.20231214121541-e7f54c482950/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/88250/gulu v1.2.3-0.20251119142510-7b1583ab4aa0 h1:ip0IQCJCLtJEDHil+2XSnh3NP39i98SYV5qhWoUeMnA=
|
||||
github.com/88250/gulu v1.2.3-0.20251119142510-7b1583ab4aa0/go.mod h1:IQ5dXW9CjVmx6B7OfK1Y4ZBKTPMe9q1AkVoLGGzRbS8=
|
||||
github.com/88250/lute v1.7.7-0.20251201033723-6a6624a61082 h1:iKn0t9LqKcVFl8CUlxiOIuf8t/4guLvaFFTHQ4IgZd4=
|
||||
github.com/88250/lute v1.7.7-0.20251201033723-6a6624a61082/go.mod h1:WYyUw//5yVw9BJnoVjx7rI/3szsISxNZCYGOqTIrV0o=
|
||||
github.com/88250/gulu v1.2.3-0.20251208021445-f93f2666eaac h1:EC80pY8zyR0gbL8ZLIBB4IPG/ia3ZHScrR/xt8zU8qU=
|
||||
github.com/88250/gulu v1.2.3-0.20251208021445-f93f2666eaac/go.mod h1:IQ5dXW9CjVmx6B7OfK1Y4ZBKTPMe9q1AkVoLGGzRbS8=
|
||||
github.com/88250/lute v1.7.7-0.20251212092708-7bcfc87de402 h1:Z+WVdMJVUAkwydjaavh22rLp/ODzdm+5jzYx037y3SA=
|
||||
github.com/88250/lute v1.7.7-0.20251212092708-7bcfc87de402/go.mod h1:WYyUw//5yVw9BJnoVjx7rI/3szsISxNZCYGOqTIrV0o=
|
||||
github.com/88250/pdfcpu v0.3.14-0.20250424122812-f10e8d9d8d46 h1:Bq1JsDfVbHKUxNL/B2JXd8cC/1h6aFjrlXpGycnh0Hk=
|
||||
github.com/88250/pdfcpu v0.3.14-0.20250424122812-f10e8d9d8d46/go.mod h1:fVfOloBzs2+W2VJCCbq60XIxc3yJHAZ0Gahv1oO0gyI=
|
||||
github.com/88250/vitess-sqlparser v0.0.0-20210205111146-56a2ded2aba1 h1:48T899JQDwyyRu9yXHePYlPdHtpJfrJEUGBMH3SMBWY=
|
||||
|
|
@ -56,42 +56,42 @@ github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de h1:FxWPpzIjnTlhP
|
|||
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de/go.mod h1:DCaWoUhZrYW9p1lxo/cm8EmUOOzAPSEZNGF2DK1dJgw=
|
||||
github.com/asaskevich/EventBus v0.0.0-20200907212545-49d423059eef h1:2JGTg6JapxP9/R33ZaagQtAM4EkkSYnIAlOG5EI8gkM=
|
||||
github.com/asaskevich/EventBus v0.0.0-20200907212545-49d423059eef/go.mod h1:JS7hed4L1fj0hXcyEejnW57/7LCetXggd+vwrRnYeII=
|
||||
github.com/aws/aws-sdk-go-v2 v1.40.0 h1:/WMUA0kjhZExjOQN2z3oLALDREea1A7TobfuiBrKlwc=
|
||||
github.com/aws/aws-sdk-go-v2 v1.40.0/go.mod h1:c9pm7VwuW0UPxAEYGyTmyurVcNrbF6Rt/wixFqDhcjE=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.3 h1:DHctwEM8P8iTXFxC/QK0MRjwEpWQeM9yzidCRjldUz0=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.3/go.mod h1:xdCzcZEtnSTKVDOmUZs4l/j3pSV6rpo1WXl5ugNsL8Y=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.2 h1:4liUsdEpUUPZs5WVapsJLx5NPmQhQdez7nYFcovrytk=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.2/go.mod h1:l0hs06IFz1eCT+jTacU/qZtC33nvcnLADAPL/XyrkZI=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.2 h1:qZry8VUyTK4VIo5aEdUcBjPZHL2v4FyQ3QEOaWcFLu4=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.2/go.mod h1:YUqm5a1/kBnoK+/NY5WEiMocZihKSo15/tJdmdXnM5g=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.14 h1:WZVR5DbDgxzA0BJeudId89Kmgy6DIU4ORpxwsVHz0qA=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.14/go.mod h1:Dadl9QO0kHgbrH1GRqGiZdYtW5w+IXXaBNCHTIaheM4=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.14 h1:PZHqQACxYb8mYgms4RZbhZG0a7dPW06xOjmaH0EJC/I=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.14/go.mod h1:VymhrMJUWs69D8u0/lZ7jSB6WgaG/NqHi3gX0aYf6U0=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.14 h1:bOS19y6zlJwagBfHxs0ESzr1XCOU2KXJCWcq3E2vfjY=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.14/go.mod h1:1ipeGBMAxZ0xcTm6y6paC2C/J6f6OO7LBODV9afuAyM=
|
||||
github.com/aws/aws-sdk-go-v2 v1.40.1 h1:difXb4maDZkRH0x//Qkwcfpdg1XQVXEAEs2DdXldFFc=
|
||||
github.com/aws/aws-sdk-go-v2 v1.40.1/go.mod h1:MayyLB8y+buD9hZqkCW3kX1AKq07Y5pXxtgB+rRFhz0=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 h1:489krEF9xIGkOaaX3CE/Be2uWjiXrkCH6gUX+bZA/BU=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4/go.mod h1:IOAPF6oT9KCsceNTvvYMNHy0+kMF8akOjeDvPENWxp4=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.3 h1:cpz7H2uMNTDa0h/5CYL5dLUEzPSLo2g0NkbxTRJtSSU=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.3/go.mod h1:srtPKaJJe3McW6T/+GMBZyIPc+SeqJsNPJsd4mOYZ6s=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.3 h1:01Ym72hK43hjwDeJUfi1l2oYLXBAOR8gNSZNmXmvuas=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.3/go.mod h1:55nWF/Sr9Zvls0bGnWkRxUdhzKqj9uRNlPvgV1vgxKc=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.15 h1:utxLraaifrSBkeyII9mIbVwXXWrZdlPO7FIKmyLCEcY=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.15/go.mod h1:hW6zjYUDQwfz3icf4g2O41PHi77u10oAzJ84iSzR/lo=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.15 h1:Y5YXgygXwDI5P4RkteB5yF7v35neH7LfJKBG+hzIons=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.15/go.mod h1:K+/1EpG42dFSY7CBj+Fruzm8PsCGWTXJ3jdeJ659oGQ=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.15 h1:AvltKnW9ewxX2hFmQS0FyJH93aSvJVUEFvXfU+HWtSE=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.15/go.mod h1:3I4oCdZdmgrREhU74qS1dK9yZ62yumob+58AbFR4cQA=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 h1:WKuaxf++XKWlHWu9ECbMlha8WOEGm0OUEZqm4K/Gcfk=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4/go.mod h1:ZWy7j6v1vWGmPReu0iSGvRiise4YI5SkR3OHKTZ6Wuc=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.14 h1:ITi7qiDSv/mSGDSWNpZ4k4Ve0DQR6Ug2SJQ8zEHoDXg=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.14/go.mod h1:k1xtME53H1b6YpZt74YmwlONMWf4ecM+lut1WQLAF/U=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3 h1:x2Ibm/Af8Fi+BH+Hsn9TXGdT+hKbDd5XOTZxTMxDk7o=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3/go.mod h1:IW1jwyrQgMdhisceG8fQLmQIydcT/jWY21rFhzgaKwo=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.5 h1:Hjkh7kE6D81PgrHlE/m9gx+4TyyeLHuY8xJs7yXN5C4=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.5/go.mod h1:nPRXgyCfAurhyaTMoBMwRBYBhaHI4lNPAnJmjM0Tslc=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.14 h1:FIouAnCE46kyYqyhs0XEBDFFSREtdnr8HQuLPQPLCrY=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.14/go.mod h1:UTwDc5COa5+guonQU8qBikJo1ZJ4ln2r1MkF7Dqag1E=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.14 h1:FzQE21lNtUor0Fb7QNgnEyiRCBlolLTX/Z1j65S7teM=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.14/go.mod h1:s1ydyWG9pm3ZwmmYN21HKyG9WzAZhYVW85wMHs5FV6w=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.92.1 h1:OgQy/+0+Kc3khtqiEOk23xQAglXi3Tj0y5doOxbi5tg=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.92.1/go.mod h1:wYNqY3L02Z3IgRYxOBPH9I1zD9Cjh9hI5QOy/eOjQvw=
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.0.2 h1:MxMBdKTYBjPQChlJhi4qlEueqB1p1KcbTEa7tD5aqPs=
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.0.2/go.mod h1:iS6EPmNeqCsGo+xQmXv0jIMjyYtQfnwg36zl2FwEouk=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.5 h1:ksUT5KtgpZd3SAiFJNJ0AFEJVva3gjBmN7eXUZjzUwQ=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.5/go.mod h1:av+ArJpoYf3pgyrj6tcehSFW+y9/QvAY8kMooR9bZCw=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.10 h1:GtsxyiF3Nd3JahRBJbxLCCdYW9ltGQYrFWg8XdkGDd8=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.10/go.mod h1:/j67Z5XBVDx8nZVp9EuFM9/BS5dvBznbqILGuu73hug=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.41.2 h1:a5UTtD4mHBU3t0o6aHQZFJTNKVfxFWfPX7J0Lr7G+uY=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.41.2/go.mod h1:6TxbXoDSgBQ225Qd8Q+MbxUxUh6TtNKwbRt/EPS9xso=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.15 h1:NLYTEyZmVZo0Qh183sC8nC+ydJXOOeIL/qI/sS3PdLY=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.15/go.mod h1:Z803iB3B0bc8oJV8zH2PERLRfQUJ2n2BXISpsA4+O1M=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 h1:0ryTNEdJbzUCEWkVXEXoqlXV72J5keC1GvILMOuD00E=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4/go.mod h1:HQ4qwNZh32C3CBeO6iJLQlgtMzqeG17ziAA/3KDJFow=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.6 h1:P1MU/SuhadGvg2jtviDXPEejU3jBNhoeeAlRadHzvHI=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.6/go.mod h1:5KYaMG6wmVKMFBSfWoyG/zH8pWwzQFnKgpoSRlXHKdQ=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.15 h1:3/u/4yZOffg5jdNk1sDpOQ4Y+R6Xbh+GzpDrSZjuy3U=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.15/go.mod h1:4Zkjq0FKjE78NKjabuM4tRXKFzUJWXgP0ItEZK8l7JU=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.15 h1:wsSQ4SVz5YE1crz0Ap7VBZrV4nNqZt4CIBBT8mnwoNc=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.15/go.mod h1:I7sditnFGtYMIqPRU1QoHZAUrXkGp4SczmlLwrNPlD0=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.93.0 h1:IrbE3B8O9pm3lsg96AXIN5MXX4pECEuExh/A0Du3AuI=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.93.0/go.mod h1:/sJLzHtiiZvs6C1RbxS/anSAFwZD6oC6M/kotQzOiLw=
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.0.3 h1:d/6xOGIllc/XW1lzG9a4AUBMmpLA9PXcQnVPTuHHcik=
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.0.3/go.mod h1:fQ7E7Qj9GiW8y0ClD7cUJk3Bz5Iw8wZkWDHsTe8vDKs=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.6 h1:8sTTiw+9yuNXcfWeqKF2x01GqCF49CpP4Z9nKrrk/ts=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.6/go.mod h1:8WYg+Y40Sn3X2hioaaWAAIngndR8n1XFdRPPX+7QBaM=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.11 h1:E+KqWoVsSrj1tJ6I/fjDIu5xoS2Zacuu1zT+H7KtiIk=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.11/go.mod h1:qyWHz+4lvkXcr3+PoGlGHEI+3DLLiU6/GdrFfMaAhB0=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.41.3 h1:tzMkjh0yTChUqJDgGkcDdxvZDSrJ/WB6R6ymI5ehqJI=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.41.3/go.mod h1:T270C0R5sZNLbWUe8ueiAF42XSZxxPocTaGSgs5c/60=
|
||||
github.com/aws/smithy-go v1.24.0 h1:LpilSUItNPFr1eY85RYgTIg5eIEPtvFbskaFcmmIUnk=
|
||||
github.com/aws/smithy-go v1.24.0/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0=
|
||||
github.com/bytedance/gopkg v0.1.3 h1:TPBSwH8RsouGCBcMBktLt1AymVo2TVsBVCY4b6TnZ/M=
|
||||
|
|
@ -155,14 +155,14 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk
|
|||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
||||
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/gabriel-vasile/mimetype v1.4.10 h1:zyueNbySn/z8mJZHLt6IPw0KoZsiQNszIpU+bX4+ZK0=
|
||||
github.com/gabriel-vasile/mimetype v1.4.10/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
|
||||
github.com/gabriel-vasile/mimetype v1.4.11 h1:AQvxbp830wPhHTqc1u7nzoLT+ZFxGY7emj5DR5DYFik=
|
||||
github.com/gabriel-vasile/mimetype v1.4.11/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
|
||||
github.com/gammazero/toposort v0.1.1 h1:OivGxsWxF3U3+U80VoLJ+f50HcPU1MIqE1JlKzoJ2Eg=
|
||||
github.com/gammazero/toposort v0.1.1/go.mod h1:H2cozTnNpMw0hg2VHAYsAxmkHXBYroNangj2NTBQDvw=
|
||||
github.com/gigawattio/window v0.0.0-20180317192513-0f5467e35573 h1:u8AQ9bPa9oC+8/A/jlWouakhIvkFfuxgIIRjiy8av7I=
|
||||
github.com/gigawattio/window v0.0.0-20180317192513-0f5467e35573/go.mod h1:eBvb3i++NHDH4Ugo9qCvMw8t0mTSctaEa5blJbWcNxs=
|
||||
github.com/gin-contrib/gzip v1.2.3 h1:dAhT722RuEG330ce2agAs75z7yB+NKvX/ZM1r8w0u2U=
|
||||
github.com/gin-contrib/gzip v1.2.3/go.mod h1:ad72i4Bzmaypk8M762gNXa2wkxxjbz0icRNnuLJ9a/c=
|
||||
github.com/gin-contrib/gzip v1.2.5 h1:fIZs0S+l17pIu1P5XRJOo/YNqfIuPCrZZ3TWB7pjckI=
|
||||
github.com/gin-contrib/gzip v1.2.5/go.mod h1:aomRgR7ftdZV3uWY0gW/m8rChfxau0n8YVvwlOHONzw=
|
||||
github.com/gin-contrib/sessions v1.0.4 h1:ha6CNdpYiTOK/hTp05miJLbpTSNfOnFg5Jm2kbcqy8U=
|
||||
github.com/gin-contrib/sessions v1.0.4/go.mod h1:ccmkrb2z6iU2osiAHZG3x3J4suJK+OU27oqzlWOqQgs=
|
||||
github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w=
|
||||
|
|
@ -360,8 +360,8 @@ github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTE
|
|||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
||||
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
|
||||
github.com/rqlite/sql v0.0.0-20251114131613-ef07423e7137 h1:OG5MfYAA0yaWgllfPdOq9Xa2bo1vpurCNx1LWz7+Zh0=
|
||||
github.com/rqlite/sql v0.0.0-20251114131613-ef07423e7137/go.mod h1:ib9zVtNgRKiGuoMyUqqL5aNpk+r+++YlyiVIkclVqPg=
|
||||
github.com/rqlite/sql v0.0.0-20251204023435-65660522892e h1:ccOm5zC6YqJtBrMmtiNcLPjFyWzB+TDY+fDIlQNsIFw=
|
||||
github.com/rqlite/sql v0.0.0-20251204023435-65660522892e/go.mod h1:ib9zVtNgRKiGuoMyUqqL5aNpk+r+++YlyiVIkclVqPg=
|
||||
github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06 h1:OkMGxebDjyw0ULyrTYWeN0UNCCkmCWfjPnIA2W6oviI=
|
||||
github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06/go.mod h1:+ePHsJ1keEjQtpvf9HHw0f4ZeJ0TLRsxhunSI2hYJSs=
|
||||
github.com/sashabaranov/go-openai v1.41.2 h1:vfPRBZNMpnqu8ELsclWcAvF19lDNgh1t6TVfFFOPiSM=
|
||||
|
|
@ -374,20 +374,20 @@ github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+D
|
|||
github.com/shurcooL/gofontwoff v0.0.0-20181114050219-180f79e6909d h1:lvCTyBbr36+tqMccdGMwuEU+hjux/zL6xSmf5S9ITaA=
|
||||
github.com/shurcooL/gofontwoff v0.0.0-20181114050219-180f79e6909d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw=
|
||||
github.com/simplereach/timeutils v1.2.0/go.mod h1:VVbQDfN/FHRZa1LSqcwo4kNZ62OOyqLLGQKYB3pB0Q8=
|
||||
github.com/siyuan-note/dataparser v0.0.0-20250804100744-b41253b236f3 h1:EH063L0HD1f82DvddurUmEXS0obXypv8pQrcaC/zNgI=
|
||||
github.com/siyuan-note/dataparser v0.0.0-20250804100744-b41253b236f3/go.mod h1:8lb+SsWAPQblGbjmwEBsBdJszMCcLeECtB95fv6mReg=
|
||||
github.com/siyuan-note/dejavu v0.0.0-20251202041457-7402b7c625c5 h1:KZ+l6WeLmdGobI193Ty/cqA15QOCOPBxvgKP9thFQf8=
|
||||
github.com/siyuan-note/dejavu v0.0.0-20251202041457-7402b7c625c5/go.mod h1:NiyGdfe/v4QzmlCA9NLNfzkwHijB+Fr208f7WVOtMUE=
|
||||
github.com/siyuan-note/dataparser v0.0.0-20251203120213-59c16535cb56 h1:aKzEVlOOSwvYqpbWTAQpGrpAZT8JrpAvaY9ek4PXIAQ=
|
||||
github.com/siyuan-note/dataparser v0.0.0-20251203120213-59c16535cb56/go.mod h1:UGIytXL3Ge9iFj9RVDNAnfEOCPmzMPzpYTZyLtGC6tQ=
|
||||
github.com/siyuan-note/dejavu v0.0.0-20251206130752-28126fa5ecd1 h1:lbHYhcOzS+WhfuCCmKgBt4erBM/RGemFtqVbSc52a7A=
|
||||
github.com/siyuan-note/dejavu v0.0.0-20251206130752-28126fa5ecd1/go.mod h1:B+A9rUy7CTvf8ZvgHfAkI9oFuZY7Nk9DE5xm0sXrJ5g=
|
||||
github.com/siyuan-note/encryption v0.0.0-20251120032857-3ddc3c2cc49f h1:HSgJKIAMgokJDAvBBfRj47SzRSm6mNGssY0Wv7rcEtg=
|
||||
github.com/siyuan-note/encryption v0.0.0-20251120032857-3ddc3c2cc49f/go.mod h1:JE3S9VuJqTggyfhjesNDuqvqrRvwG3IctFjXXchLx1M=
|
||||
github.com/siyuan-note/eventbus v0.0.0-20240627125516-396fdb0f0f97 h1:lM5v8BfNtbOL5jYwhCdMYBcYtr06IYBKjjSLAPMKTM8=
|
||||
github.com/siyuan-note/eventbus v0.0.0-20240627125516-396fdb0f0f97/go.mod h1:1/nGgthl89FPA7GzAcEWKl6zRRnfgyTjzLZj9bW7kuw=
|
||||
github.com/siyuan-note/filelock v0.0.0-20251107023958-207cad31f0dd h1:7Rr+wH2hy/goTMe5EAZHjpfEudZZXVVaZOkhs/xzX+I=
|
||||
github.com/siyuan-note/filelock v0.0.0-20251107023958-207cad31f0dd/go.mod h1:jFSEENJoE+SRZ7xtSpiflL3RMfnxE6CAJFUfBuuGs1A=
|
||||
github.com/siyuan-note/filelock v0.0.0-20251212095217-08318833e008 h1:3wEmNS4eZkxwm1rhXDhVK5Y0o/GKAZtfe1VV584BF+A=
|
||||
github.com/siyuan-note/filelock v0.0.0-20251212095217-08318833e008/go.mod h1:9OhXAyOkSXwuLvNCZk2aFMo0nOldyO3f2hMJEnkuT30=
|
||||
github.com/siyuan-note/httpclient v0.0.0-20251119144307-63b815d7d198 h1:NCFtk65n+a6oo+nIXnYPx3jCgs3O2uvvihnD7aRy/ZE=
|
||||
github.com/siyuan-note/httpclient v0.0.0-20251119144307-63b815d7d198/go.mod h1:w8ZKhKvcOr6lXsfxGmXQQTcIlVYWKhesB5IaXC+3OkA=
|
||||
github.com/siyuan-note/logging v0.0.0-20251107023700-cd4339891032 h1:z1r9ZhSTISDom1lvqKuiykfI7YtPCIELABj8onc0n3A=
|
||||
github.com/siyuan-note/logging v0.0.0-20251107023700-cd4339891032/go.mod h1:UVFePdmdasN+fLDEYFr2X734G2AIJb6nYS9WcWK5740=
|
||||
github.com/siyuan-note/logging v0.0.0-20251209020516-52f1a2f65ec5 h1:bIMoJAAf3tV0xYcN+N2Vw7Ot/LbVxuz715o1rn1GDto=
|
||||
github.com/siyuan-note/logging v0.0.0-20251209020516-52f1a2f65ec5/go.mod h1:U6DyWKvtIPW9WrUoUikPCwFUzUoHGtEJjjeLNYae1nc=
|
||||
github.com/siyuan-note/riff v0.0.0-20251022131846-228528e70754 h1:6QYpy7s5HlRSge09TyM/mT0vz1RDcWYZdkxEh7hmbH4=
|
||||
github.com/siyuan-note/riff v0.0.0-20251022131846-228528e70754/go.mod h1:/N7+N2CsZ0nleNPpP3b+06Bzqvuhy6GUmLY7Kug/zT0=
|
||||
github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY=
|
||||
|
|
@ -451,8 +451,8 @@ go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
|
|||
go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
|
||||
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
||||
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||
golang.org/x/arch v0.22.0 h1:c/Zle32i5ttqRXjdLyyHZESLD/bB90DCU1g9l/0YBDI=
|
||||
golang.org/x/arch v0.22.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A=
|
||||
golang.org/x/arch v0.23.0 h1:lKF64A2jF6Zd8L0knGltUnegD62JMFBiCPBmQpToHhg=
|
||||
golang.org/x/arch v0.23.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
|
|
@ -461,21 +461,21 @@ golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf
|
|||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
|
||||
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
|
||||
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
|
||||
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
|
||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
|
||||
golang.org/x/image v0.32.0 h1:6lZQWq75h7L5IWNk0r+SCpUJ6tUVd3v4ZHnbRKLkUDQ=
|
||||
golang.org/x/image v0.32.0/go.mod h1:/R37rrQmKXtO6tYXAjtDLwQgFLHmhW+V6ayXlxzP2Pc=
|
||||
golang.org/x/mobile v0.0.0-20251009145931-8baca8bf4eeb h1:6lzmAebw71+I8PM7W9A/VomU3XWEwZkkwp9Jh4XJX7c=
|
||||
golang.org/x/mobile v0.0.0-20251009145931-8baca8bf4eeb/go.mod h1:3QSlP0AtP6HPTLbsxfgfefGN76jpIB9yBsMqB8UY37I=
|
||||
golang.org/x/image v0.33.0 h1:LXRZRnv1+zGd5XBUVRFmYEphyyKJjQjCRiOuAP3sZfQ=
|
||||
golang.org/x/image v0.33.0/go.mod h1:DD3OsTYT9chzuzTQt+zMcOlBHgfoKQb1gry8p76Y1sc=
|
||||
golang.org/x/mobile v0.0.0-20251126181937-5c265dc024c4 h1:lZKReZrCBTDNaVewUp31194cua6qf65/tYg3mq1KUU0=
|
||||
golang.org/x/mobile v0.0.0-20251126181937-5c265dc024c4/go.mod h1:Eq3Nh/5pFSWug2ohiudJ1iyU59SO78QFuh4qTTN++I0=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
|
||||
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
|
||||
golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk=
|
||||
golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc=
|
||||
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
|
|
@ -490,8 +490,8 @@ golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
|||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
|
||||
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
|
||||
golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
|
||||
golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
|
|
@ -499,8 +499,8 @@ golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
|||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
|
||||
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
|
||||
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
|
@ -519,8 +519,8 @@ golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
|
||||
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
|
||||
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
|
|
@ -544,8 +544,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
|||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
|
||||
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
|
||||
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
|
||||
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
|
||||
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
|
||||
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
|
|
@ -554,8 +554,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
|
|||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
|
||||
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
|
||||
golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ=
|
||||
golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
|
||||
|
|
|
|||
|
|
@ -680,8 +680,10 @@ func RemoveUnusedAssets() (ret []string) {
|
|||
}
|
||||
}
|
||||
|
||||
if err := filelock.Remove(absPath); err != nil {
|
||||
logging.LogErrorf("remove unused asset [%s] failed: %s", absPath, err)
|
||||
if removeErr := filelock.RemoveWithoutFatal(absPath); removeErr != nil {
|
||||
logging.LogErrorf("remove unused asset [%s] failed: %s", absPath, removeErr)
|
||||
util.PushErrMsg(fmt.Sprintf("%s", removeErr), 7000)
|
||||
return
|
||||
}
|
||||
util.RemoveAssetText(unusedAsset)
|
||||
}
|
||||
|
|
@ -720,8 +722,10 @@ func RemoveUnusedAsset(p string) (ret string) {
|
|||
cache.RemoveAssetHash(hash)
|
||||
}
|
||||
|
||||
if err = filelock.Remove(absPath); err != nil {
|
||||
if err = filelock.RemoveWithoutFatal(absPath); err != nil {
|
||||
logging.LogErrorf("remove unused asset [%s] failed: %s", absPath, err)
|
||||
util.PushErrMsg(fmt.Sprintf("%s", err), 7000)
|
||||
return
|
||||
}
|
||||
ret = absPath
|
||||
|
||||
|
|
|
|||
|
|
@ -241,6 +241,8 @@ func getAttrViewAddingBlockDefaultValues(attrView *av.AttributeView, view, group
|
|||
if !av.MSelectExistOption(newValue.MSelect, groupView.GetGroupValue()) {
|
||||
if 1 > len(newValue.MSelect) || av.KeyTypeMSelect == groupKey.Type {
|
||||
newValue.MSelect = append(newValue.MSelect, &av.ValueSelect{Content: opt.Name, Color: opt.Color})
|
||||
} else {
|
||||
newValue.MSelect = []*av.ValueSelect{{Content: opt.Name, Color: opt.Color}}
|
||||
}
|
||||
} else {
|
||||
var vals []*av.ValueSelect
|
||||
|
|
@ -3987,11 +3989,18 @@ func sortAttributeViewRow(operation *Operation) (err error) {
|
|||
if targetGroupView := view.GetGroupByID(operation.TargetGroupID); nil != targetGroupView && !gulu.Str.Contains(itemID, targetGroupView.GroupItemIDs) {
|
||||
fillDefaultValue(attrView, view, targetGroupView, operation.PreviousID, itemID, false)
|
||||
|
||||
// 移除旧分组的值
|
||||
if val := attrView.GetValue(groupKey.ID, itemID); nil != val {
|
||||
if av.MSelectExistOption(val.MSelect, groupView.GetGroupValue()) {
|
||||
// 移除旧分组的值
|
||||
val.MSelect = av.MSelectRemoveOption(val.MSelect, groupView.GetGroupValue())
|
||||
}
|
||||
|
||||
now := time.Now().UnixMilli()
|
||||
val.SetUpdatedAt(now)
|
||||
if blockVal := attrView.GetBlockValue(itemID); nil != blockVal {
|
||||
blockVal.Block.Updated = now
|
||||
blockVal.SetUpdatedAt(now)
|
||||
}
|
||||
}
|
||||
|
||||
for i, r := range targetGroupView.GroupItemIDs {
|
||||
|
|
|
|||
|
|
@ -256,8 +256,8 @@ func UninstallBazaarPlugin(pluginName, frontend string) error {
|
|||
petals = tmp
|
||||
savePetals(petals)
|
||||
|
||||
removePluginSet := hashset.New(pluginName)
|
||||
PushReloadPlugin(nil, nil, removePluginSet, "")
|
||||
uninstallPluginSet := hashset.New(pluginName)
|
||||
PushReloadPlugin(nil, nil, nil, uninstallPluginSet, "")
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -212,7 +212,7 @@ func GetBlockSiblingID(id string) (parent, previous, next string) {
|
|||
|
||||
parent = parentBlock.ID
|
||||
if ast.NodeDocument == parentBlock.Type {
|
||||
parent = parentBlock.ID
|
||||
parent = treenode.FirstLeafBlock(parentBlock).ID
|
||||
|
||||
if nil != current.Previous && current.Previous.IsBlock() {
|
||||
previous = current.Previous.ID
|
||||
|
|
@ -230,24 +230,37 @@ func GetBlockSiblingID(id string) (parent, previous, next string) {
|
|||
return
|
||||
}
|
||||
|
||||
parentCount := 0
|
||||
for ; nil != parentBlock; parentBlock = treenode.ParentBlock(parentBlock) {
|
||||
if nil != parentBlock.Previous && parentBlock.Previous.IsBlock() {
|
||||
previous = parentBlock.Previous.ID
|
||||
if flb := treenode.FirstChildBlock(parentBlock.Previous); nil != flb {
|
||||
previous = flb.ID
|
||||
}
|
||||
if ast.NodeDocument == parentBlock.Type {
|
||||
break
|
||||
}
|
||||
|
||||
if ast.NodeList == parentBlock.Type || ast.NodeBlockquote == parentBlock.Type || ast.NodeSuperBlock == parentBlock.Type || ast.NodeCallout == parentBlock.Type {
|
||||
parentCount++
|
||||
continue
|
||||
}
|
||||
|
||||
if ast.NodeListItem == parentBlock.Type {
|
||||
if 1 > parentCount {
|
||||
parentBlock = treenode.ParentBlock(parentBlock)
|
||||
}
|
||||
parentBlock = treenode.ParentBlock(parentBlock)
|
||||
}
|
||||
break
|
||||
}
|
||||
parentBlock = treenode.ParentBlock(current)
|
||||
for ; nil != parentBlock; parentBlock = treenode.ParentBlock(parentBlock) {
|
||||
if nil != parentBlock.Next && parentBlock.Next.IsBlock() {
|
||||
next = parentBlock.Next.ID
|
||||
if flb := treenode.FirstChildBlock(parentBlock.Next); nil != flb {
|
||||
next = flb.ID
|
||||
}
|
||||
break
|
||||
}
|
||||
if ast.NodeDocument == parentBlock.Type {
|
||||
parentBlock = treenode.FirstLeafBlock(parentBlock)
|
||||
parent = parentBlock.ID
|
||||
} else {
|
||||
parent = parentBlock.ID
|
||||
}
|
||||
|
||||
if nil != parentBlock.Previous {
|
||||
previous = parentBlock.Previous.ID
|
||||
}
|
||||
if nil != parentBlock.Next {
|
||||
next = parentBlock.Next.ID
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -532,7 +532,7 @@ func buildBlockBreadcrumb(node *ast.Node, excludeTypes []string, isEmbedBlock bo
|
|||
name, _ = av.GetAttributeViewName(parent.AttributeViewID)
|
||||
} else {
|
||||
if "" == name {
|
||||
if ast.NodeListItem == parent.Type || ast.NodeList == parent.Type || ast.NodeSuperBlock == parent.Type || ast.NodeBlockquote == parent.Type {
|
||||
if ast.NodeListItem == parent.Type || ast.NodeList == parent.Type || ast.NodeSuperBlock == parent.Type || ast.NodeBlockquote == parent.Type || ast.NodeCallout == parent.Type {
|
||||
name = gulu.Str.SubStr(renderBlockText(fc, excludeTypes, true), maxNameLen)
|
||||
} else {
|
||||
name = gulu.Str.SubStr(renderBlockText(parent, excludeTypes, true), maxNameLen)
|
||||
|
|
@ -544,7 +544,7 @@ func buildBlockBreadcrumb(node *ast.Node, excludeTypes []string, isEmbedBlock bo
|
|||
}
|
||||
|
||||
add := true
|
||||
if ast.NodeList == parent.Type || ast.NodeSuperBlock == parent.Type || ast.NodeBlockquote == parent.Type {
|
||||
if ast.NodeList == parent.Type || ast.NodeSuperBlock == parent.Type || ast.NodeBlockquote == parent.Type || ast.NodeCallout == parent.Type {
|
||||
add = false
|
||||
if parent == node {
|
||||
// https://github.com/siyuan-note/siyuan/issues/13141#issuecomment-2476789553
|
||||
|
|
|
|||
|
|
@ -539,7 +539,7 @@ func normalizeTree(tree *parse.Tree) (yfmRootID, yfmTitle, yfmUpdated string) {
|
|||
if "" == n.IALAttr("id") && (ast.NodeParagraph == n.Type || ast.NodeList == n.Type || ast.NodeListItem == n.Type || ast.NodeBlockquote == n.Type ||
|
||||
ast.NodeMathBlock == n.Type || ast.NodeCodeBlock == n.Type || ast.NodeHeading == n.Type || ast.NodeTable == n.Type || ast.NodeThematicBreak == n.Type ||
|
||||
ast.NodeYamlFrontMatter == n.Type || ast.NodeBlockQueryEmbed == n.Type || ast.NodeSuperBlock == n.Type || ast.NodeAttributeView == n.Type ||
|
||||
ast.NodeHTMLBlock == n.Type || ast.NodeIFrame == n.Type || ast.NodeWidget == n.Type || ast.NodeAudio == n.Type || ast.NodeVideo == n.Type) {
|
||||
ast.NodeHTMLBlock == n.Type || ast.NodeIFrame == n.Type || ast.NodeWidget == n.Type || ast.NodeAudio == n.Type || ast.NodeVideo == n.Type || ast.NodeCallout == n.Type) {
|
||||
n.ID = ast.NewNodeID()
|
||||
n.KramdownIAL = [][]string{{"id", n.ID}}
|
||||
n.InsertAfter(&ast.Node{Type: ast.NodeKramdownBlockIAL, Tokens: []byte("{: id=\"" + n.ID + "\"}")})
|
||||
|
|
|
|||
|
|
@ -240,8 +240,8 @@ func InitConf() {
|
|||
if nil == Conf.Editor {
|
||||
Conf.Editor = defaultEditor
|
||||
}
|
||||
// 新增字段的默认值
|
||||
// 使用指针类型来区分字段不存在(nil)和用户设置为 0(非 nil)
|
||||
|
||||
// 新增字段的默认值,使用指针类型来区分字段不存在(nil)和用户设置为 0(非 nil)
|
||||
if nil == Conf.Editor.BacklinkSort {
|
||||
Conf.Editor.BacklinkSort = defaultEditor.BacklinkSort
|
||||
}
|
||||
|
|
@ -282,6 +282,9 @@ func InitConf() {
|
|||
if conf.MinDynamicLoadBlocks > Conf.Editor.DynamicLoadBlocks {
|
||||
Conf.Editor.DynamicLoadBlocks = conf.MinDynamicLoadBlocks
|
||||
}
|
||||
if 1 > len(Conf.Editor.SpellcheckLanguages) {
|
||||
Conf.Editor.SpellcheckLanguages = []string{"en-US"}
|
||||
}
|
||||
if 0 > Conf.Editor.BacklinkExpandCount {
|
||||
Conf.Editor.BacklinkExpandCount = 0
|
||||
}
|
||||
|
|
@ -742,7 +745,15 @@ func Close(force, setCurrentWorkspace bool, execInstallPkg int) (exitCode int) {
|
|||
if nil != util.WebSocketServer {
|
||||
util.WebSocketServer.Close()
|
||||
}
|
||||
if nil != util.HttpServer {
|
||||
util.HttpServer.Close()
|
||||
}
|
||||
util.HttpServing = false
|
||||
|
||||
if util.ContainerAndroid == util.Container || util.ContainerIOS == util.Container || util.ContainerHarmony == util.Container {
|
||||
return
|
||||
}
|
||||
|
||||
os.Exit(logging.ExitCodeOk)
|
||||
}()
|
||||
return
|
||||
|
|
|
|||
|
|
@ -586,7 +586,7 @@ func ExportResources(resourcePaths []string, mainName string) (exportFilePath st
|
|||
return
|
||||
}
|
||||
|
||||
func Preview(id string, fillCSSVar bool) (retStdHTML string) {
|
||||
func ExportPreview(id string, fillCSSVar bool) (retStdHTML string) {
|
||||
blockRefMode := Conf.Export.BlockRefMode
|
||||
bt := treenode.GetBlockTree(id)
|
||||
if nil == bt {
|
||||
|
|
@ -891,6 +891,9 @@ func ExportHTML(id, savePath string, pdf, image, keepFold, merge bool) (name, do
|
|||
|
||||
tree := prepareExportTree(bt)
|
||||
node = treenode.GetNodeInTree(tree, id)
|
||||
if ast.NodeDocument == node.Type {
|
||||
node.RemoveIALAttr("style")
|
||||
}
|
||||
|
||||
if merge {
|
||||
var mergeErr error
|
||||
|
|
@ -905,7 +908,7 @@ func ExportHTML(id, savePath string, pdf, image, keepFold, merge bool) (name, do
|
|||
var headings []*ast.Node
|
||||
if pdf { // 导出 PDF 需要标记目录书签
|
||||
ast.Walk(tree.Root, func(n *ast.Node, entering bool) ast.WalkStatus {
|
||||
if entering && ast.NodeHeading == n.Type && !n.ParentIs(ast.NodeBlockquote) {
|
||||
if entering && ast.NodeHeading == n.Type && !n.ParentIs(ast.NodeBlockquote) && !n.ParentIs(ast.NodeCallout) {
|
||||
headings = append(headings, n)
|
||||
return ast.WalkSkipChildren
|
||||
}
|
||||
|
|
@ -1128,7 +1131,7 @@ func ProcessPDF(id, p string, merge, removeAssets, watermark bool) (err error) {
|
|||
return ast.WalkContinue
|
||||
}
|
||||
|
||||
if ast.NodeHeading == n.Type && !n.ParentIs(ast.NodeBlockquote) {
|
||||
if ast.NodeHeading == n.Type && !n.ParentIs(ast.NodeBlockquote) && !n.ParentIs(ast.NodeCallout) {
|
||||
headings = append(headings, n)
|
||||
return ast.WalkSkipChildren
|
||||
}
|
||||
|
|
@ -2442,7 +2445,7 @@ func exportTree(tree *parse.Tree, wysiwyg, keepFold, avHiddenCol bool,
|
|||
root.IAL["type"] = "doc"
|
||||
title := &ast.Node{Type: ast.NodeHeading, HeadingLevel: 1}
|
||||
for k, v := range root.IAL {
|
||||
if "type" == k {
|
||||
if "type" == k || "style" == k {
|
||||
continue
|
||||
}
|
||||
title.SetIALAttr(k, v)
|
||||
|
|
@ -3557,14 +3560,14 @@ func adjustHeadingLevel(bt *treenode.BlockTree, tree *parse.Tree) {
|
|||
var firstHeading *ast.Node
|
||||
if !Conf.Export.AddTitle {
|
||||
for n := tree.Root.FirstChild; nil != n; n = n.Next {
|
||||
if ast.NodeHeading == n.Type && !n.ParentIs(ast.NodeBlockquote) {
|
||||
if ast.NodeHeading == n.Type && !n.ParentIs(ast.NodeBlockquote) && !n.ParentIs(ast.NodeCallout) {
|
||||
firstHeading = n
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for n := tree.Root.FirstChild.Next; nil != n; n = n.Next {
|
||||
if ast.NodeHeading == n.Type && !n.ParentIs(ast.NodeBlockquote) {
|
||||
if ast.NodeHeading == n.Type && !n.ParentIs(ast.NodeBlockquote) && !n.ParentIs(ast.NodeCallout) {
|
||||
firstHeading = n
|
||||
break
|
||||
}
|
||||
|
|
|
|||
|
|
@ -187,8 +187,8 @@ func SearchDocsByKeyword(keyword string, flashcard bool, excludeIDs []string) (r
|
|||
}
|
||||
}
|
||||
|
||||
if 0 < len(excludeIDs) {
|
||||
condition += fmt.Sprintf(" AND root_id NOT IN ('%s')", strings.Join(excludeIDs, "', '"))
|
||||
for _, excludeID := range excludeIDs {
|
||||
condition += fmt.Sprintf(" AND path NOT LIKE '%%%s%%' ", excludeID)
|
||||
}
|
||||
|
||||
rootBlocks = sql.QueryRootBlockByCondition(condition, Conf.Search.Limit)
|
||||
|
|
@ -978,12 +978,6 @@ func DuplicateDoc(tree *parse.Tree) {
|
|||
|
||||
previousPath := tree.Path
|
||||
resetTree(tree, "Duplicated", false)
|
||||
createTreeTx(tree)
|
||||
box := Conf.Box(tree.Box)
|
||||
if nil != box {
|
||||
box.addSort(previousPath, tree.ID)
|
||||
}
|
||||
FlushTxQueue()
|
||||
|
||||
// 复制为副本时移除数据库绑定状态 https://github.com/siyuan-note/siyuan/issues/12294
|
||||
ast.Walk(tree.Root, func(n *ast.Node, entering bool) ast.WalkStatus {
|
||||
|
|
@ -996,6 +990,13 @@ func DuplicateDoc(tree *parse.Tree) {
|
|||
n.RemoveIALAttrsByPrefix(av.NodeAttrViewStaticText)
|
||||
return ast.WalkContinue
|
||||
})
|
||||
|
||||
createTreeTx(tree)
|
||||
box := Conf.Box(tree.Box)
|
||||
if nil != box {
|
||||
box.addSort(previousPath, tree.ID)
|
||||
}
|
||||
FlushTxQueue()
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -1748,7 +1749,7 @@ func createDoc(boxID, p, title, dom string) (tree *parse.Tree, err error) {
|
|||
tree.HPath = hPath
|
||||
tree.ID = id
|
||||
tree.Root.ID = id
|
||||
tree.Root.Spec = "1"
|
||||
tree.Root.Spec = treenode.CurrentSpec
|
||||
updated := util.TimeFromID(id)
|
||||
tree.Root.KramdownIAL = [][]string{{"id", id}, {"title", html.EscapeAttrVal(title)}, {"updated", updated}}
|
||||
if nil == tree.Root.FirstChild {
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import (
|
|||
"github.com/88250/lute/editor"
|
||||
"github.com/88250/lute/render"
|
||||
"github.com/siyuan-note/logging"
|
||||
"github.com/siyuan-note/siyuan/kernel/treenode"
|
||||
"github.com/siyuan-note/siyuan/kernel/util"
|
||||
)
|
||||
|
||||
|
|
@ -63,13 +64,13 @@ func AutoSpace(rootID string) (err error) {
|
|||
formatRenderer := render.NewFormatRenderer(tree, luteEngine.RenderOptions)
|
||||
md := formatRenderer.Render()
|
||||
newTree := parseKTree(md)
|
||||
newTree.Root.Spec = "1"
|
||||
newTree.Root.Spec = treenode.CurrentSpec
|
||||
// 第二次格式化启用自动空格
|
||||
luteEngine.SetAutoSpace(true)
|
||||
formatRenderer = render.NewFormatRenderer(newTree, luteEngine.RenderOptions)
|
||||
md = formatRenderer.Render()
|
||||
newTree = parseKTree(md)
|
||||
newTree.Root.Spec = "1"
|
||||
newTree.Root.Spec = treenode.CurrentSpec
|
||||
newTree.Root.ID = tree.ID
|
||||
newTree.Root.KramdownIAL = rootIAL
|
||||
newTree.ID = tree.ID
|
||||
|
|
|
|||
|
|
@ -596,6 +596,14 @@ func graphTypeFilter(local bool) string {
|
|||
inList = append(inList, "'s'")
|
||||
}
|
||||
|
||||
callout := Conf.Graph.Local.Callout
|
||||
if !local {
|
||||
callout = Conf.Graph.Global.Callout
|
||||
}
|
||||
if callout {
|
||||
inList = append(inList, "'callout'")
|
||||
}
|
||||
|
||||
inList = append(inList, "'d'")
|
||||
return " AND ref.type IN (" + strings.Join(inList, ",") + ")"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -427,7 +427,7 @@ func Heading2Doc(srcHeadingID, targetBoxID, targetPath, previousPath string) (sr
|
|||
|
||||
newTree.Box, newTree.Path = targetBoxID, newTargetPath
|
||||
newTree.Root.SetIALAttr("updated", util.CurrentTimeSecondsStr())
|
||||
newTree.Root.Spec = "1"
|
||||
newTree.Root.Spec = treenode.CurrentSpec
|
||||
if "" != previousPath {
|
||||
box.addSort(previousPath, newTree.ID)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -54,11 +54,11 @@ func AutoGenerateFileHistory() {
|
|||
ChangeHistoryTick(Conf.Editor.GenerateHistoryInterval)
|
||||
for {
|
||||
<-historyTicker.C
|
||||
task.AppendTask(task.HistoryGenerateFile, generateFileHistory)
|
||||
task.AppendTask(task.HistoryGenerateFile, GenerateFileHistory)
|
||||
}
|
||||
}
|
||||
|
||||
func generateFileHistory() {
|
||||
func GenerateFileHistory() {
|
||||
defer logging.Recover()
|
||||
|
||||
if 1 > Conf.Editor.GenerateHistoryInterval {
|
||||
|
|
|
|||
|
|
@ -418,10 +418,7 @@ func ImportSY(zipPath, boxID, toPath string) (err error) {
|
|||
for _, tree := range trees {
|
||||
util.PushEndlessProgress(Conf.language(73) + " " + fmt.Sprintf(Conf.language(70), tree.Root.IALAttr("title")))
|
||||
syPath := filepath.Join(unzipRootPath, tree.Path)
|
||||
if "" == tree.Root.Spec {
|
||||
parse.NestedInlines2FlattedSpans(tree, false)
|
||||
tree.Root.Spec = "1"
|
||||
}
|
||||
treenode.UpgradeSpec(tree)
|
||||
renderer := render.NewJSONRenderer(tree, luteEngine.RenderOptions)
|
||||
data := renderer.Render()
|
||||
|
||||
|
|
@ -943,7 +940,7 @@ func ImportFromLocalPath(boxID, localPath string, toPath string) (err error) {
|
|||
tree.Path = targetPath
|
||||
targetPaths[curRelPath] = targetPath
|
||||
tree.HPath = hPath
|
||||
tree.Root.Spec = "1"
|
||||
tree.Root.Spec = treenode.CurrentSpec
|
||||
|
||||
docDirLocalPath := filepath.Dir(filepath.Join(boxLocalPath, targetPath))
|
||||
assetDirPath := getAssetsDir(boxLocalPath, docDirLocalPath)
|
||||
|
|
@ -1075,7 +1072,7 @@ func ImportFromLocalPath(boxID, localPath string, toPath string) (err error) {
|
|||
tree.Box = boxID
|
||||
tree.Path = targetPath
|
||||
tree.HPath = path.Join(baseHPath, title)
|
||||
tree.Root.Spec = "1"
|
||||
tree.Root.Spec = treenode.CurrentSpec
|
||||
|
||||
docDirLocalPath := filepath.Dir(filepath.Join(boxLocalPath, targetPath))
|
||||
assetDirPath := getAssetsDir(boxLocalPath, docDirLocalPath)
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ func ListItem2Doc(srcListItemID, targetBoxID, targetPath, previousPath string) (
|
|||
|
||||
newTree.Box, newTree.Path = targetBoxID, newTargetPath
|
||||
newTree.Root.SetIALAttr("updated", util.CurrentTimeSecondsStr())
|
||||
newTree.Root.Spec = "1"
|
||||
newTree.Root.Spec = treenode.CurrentSpec
|
||||
if "" != previousPath {
|
||||
box.addSort(previousPath, newTree.ID)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ func (tx *Transaction) doMoveOutlineHeading(operation *Operation) (ret *TxErr) {
|
|||
|
||||
headings := []*ast.Node{}
|
||||
ast.Walk(tree.Root, func(n *ast.Node, entering bool) ast.WalkStatus {
|
||||
if entering && ast.NodeHeading == n.Type && !n.ParentIs(ast.NodeBlockquote) {
|
||||
if entering && ast.NodeHeading == n.Type && !n.ParentIs(ast.NodeBlockquote) && !n.ParentIs(ast.NodeCallout) {
|
||||
headings = append(headings, n)
|
||||
}
|
||||
return ast.WalkContinue
|
||||
|
|
@ -305,7 +305,7 @@ func outline(tree *parse.Tree) (ret []*Path) {
|
|||
luteEngine := NewLute()
|
||||
var headings []*Block
|
||||
ast.Walk(tree.Root, func(n *ast.Node, entering bool) ast.WalkStatus {
|
||||
if entering && ast.NodeHeading == n.Type && !n.ParentIs(ast.NodeBlockquote) {
|
||||
if entering && ast.NodeHeading == n.Type && !n.ParentIs(ast.NodeBlockquote) && !n.ParentIs(ast.NodeCallout) {
|
||||
n.Box, n.Path = tree.Box, tree.Path
|
||||
block := &Block{
|
||||
RootID: tree.Root.ID,
|
||||
|
|
|
|||
|
|
@ -38,11 +38,25 @@ import (
|
|||
"github.com/siyuan-note/siyuan/kernel/util"
|
||||
)
|
||||
|
||||
func PushReloadPlugin(upsertCodePluginSet, upsertDataPluginSet, removePluginNameSet *hashset.Set, excludeApp string) {
|
||||
if nil != removePluginNameSet {
|
||||
for _, n := range removePluginNameSet.Values() {
|
||||
func PushReloadPlugin(upsertCodePluginSet, upsertDataPluginSet, unloadPluginNameSet, uninstallPluginNameSet *hashset.Set, excludeApp string) {
|
||||
// 集合去重
|
||||
if nil != uninstallPluginNameSet {
|
||||
for _, n := range uninstallPluginNameSet.Values() {
|
||||
pluginName := n.(string)
|
||||
if nil != upsertCodePluginSet {
|
||||
upsertCodePluginSet.Remove(pluginName)
|
||||
}
|
||||
if nil != upsertDataPluginSet {
|
||||
upsertDataPluginSet.Remove(pluginName)
|
||||
}
|
||||
if nil != unloadPluginNameSet {
|
||||
unloadPluginNameSet.Remove(pluginName)
|
||||
}
|
||||
}
|
||||
}
|
||||
if nil != unloadPluginNameSet {
|
||||
for _, n := range unloadPluginNameSet.Values() {
|
||||
pluginName := n.(string)
|
||||
// 如果插件在 removePluginSet 中,从其他集合中移除
|
||||
if nil != upsertCodePluginSet {
|
||||
upsertCodePluginSet.Remove(pluginName)
|
||||
}
|
||||
|
|
@ -54,14 +68,13 @@ func PushReloadPlugin(upsertCodePluginSet, upsertDataPluginSet, removePluginName
|
|||
if nil != upsertCodePluginSet {
|
||||
for _, n := range upsertCodePluginSet.Values() {
|
||||
pluginName := n.(string)
|
||||
// 如果插件在 upsertCodePluginSet 中,从 upsertDataPluginSet 中移除
|
||||
if nil != upsertDataPluginSet {
|
||||
upsertDataPluginSet.Remove(pluginName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
upsertCodePlugins, upsertDataPlugins, removePlugins := []string{}, []string{}, []string{}
|
||||
upsertCodePlugins, upsertDataPlugins, unloadPlugins, uninstallPlugins := []string{}, []string{}, []string{}, []string{}
|
||||
if nil != upsertCodePluginSet {
|
||||
for _, n := range upsertCodePluginSet.Values() {
|
||||
upsertCodePlugins = append(upsertCodePlugins, n.(string))
|
||||
|
|
@ -72,22 +85,28 @@ func PushReloadPlugin(upsertCodePluginSet, upsertDataPluginSet, removePluginName
|
|||
upsertDataPlugins = append(upsertDataPlugins, n.(string))
|
||||
}
|
||||
}
|
||||
if nil != removePluginNameSet {
|
||||
for _, n := range removePluginNameSet.Values() {
|
||||
removePlugins = append(removePlugins, n.(string))
|
||||
if nil != unloadPluginNameSet {
|
||||
for _, n := range unloadPluginNameSet.Values() {
|
||||
unloadPlugins = append(unloadPlugins, n.(string))
|
||||
}
|
||||
}
|
||||
if nil != uninstallPluginNameSet {
|
||||
for _, n := range uninstallPluginNameSet.Values() {
|
||||
uninstallPlugins = append(uninstallPlugins, n.(string))
|
||||
}
|
||||
}
|
||||
|
||||
pushReloadPlugin0(upsertCodePlugins, upsertDataPlugins, removePlugins, excludeApp)
|
||||
pushReloadPlugin0(upsertCodePlugins, upsertDataPlugins, unloadPlugins, uninstallPlugins, excludeApp)
|
||||
}
|
||||
|
||||
func pushReloadPlugin0(upsertCodePlugins, upsertDataPlugins, removePlugins []string, excludeApp string) {
|
||||
logging.LogInfof("reload plugins [codeChanges=%v, dataChanges=%v, removes=%v]", upsertCodePlugins, upsertDataPlugins, removePlugins)
|
||||
func pushReloadPlugin0(upsertCodePlugins, upsertDataPlugins, unloadPlugins, uninstallPlugins []string, excludeApp string) {
|
||||
logging.LogInfof("reload plugins [codeChanges=%v, dataChanges=%v, unloads=%v, uninstalls=%v]", upsertCodePlugins, upsertDataPlugins, unloadPlugins, uninstallPlugins)
|
||||
if "" == excludeApp {
|
||||
util.BroadcastByType("main", "reloadPlugin", 0, "", map[string]interface{}{
|
||||
"upsertCodePlugins": upsertCodePlugins,
|
||||
"upsertDataPlugins": upsertDataPlugins,
|
||||
"removePlugins": removePlugins,
|
||||
"unloadPlugins": unloadPlugins,
|
||||
"uninstallPlugins": uninstallPlugins,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
|
@ -95,7 +114,8 @@ func pushReloadPlugin0(upsertCodePlugins, upsertDataPlugins, removePlugins []str
|
|||
util.BroadcastByTypeAndExcludeApp(excludeApp, "main", "reloadPlugin", 0, "", map[string]interface{}{
|
||||
"upsertCodePlugins": upsertCodePlugins,
|
||||
"upsertDataPlugins": upsertDataPlugins,
|
||||
"removePlugins": removePlugins,
|
||||
"unloadPlugins": unloadPlugins,
|
||||
"uninstallPlugins": uninstallPlugins,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -256,165 +256,168 @@ func resolveEmbedR(n *ast.Node, blockEmbedMode int, luteEngine *lute.Lute, resol
|
|||
return ast.WalkContinue
|
||||
}
|
||||
|
||||
if ast.NodeBlockQueryEmbed == n.Type {
|
||||
if gulu.Str.Contains(n.ID, *resolved) {
|
||||
return ast.WalkContinue
|
||||
if ast.NodeBlockQueryEmbed != n.Type {
|
||||
return ast.WalkContinue
|
||||
}
|
||||
|
||||
if gulu.Str.Contains(n.ID, *resolved) {
|
||||
return ast.WalkContinue
|
||||
}
|
||||
*resolved = append(*resolved, n.ID)
|
||||
|
||||
stmt := n.ChildByType(ast.NodeBlockQueryEmbedScript).TokensStr()
|
||||
stmt = html.UnescapeString(stmt)
|
||||
stmt = strings.ReplaceAll(stmt, editor.IALValEscNewLine, "\n")
|
||||
sqlBlocks := sql.SelectBlocksRawStmt(stmt, 1, Conf.Search.Limit)
|
||||
for _, sqlBlock := range sqlBlocks {
|
||||
if "query_embed" == sqlBlock.Type {
|
||||
continue
|
||||
}
|
||||
*resolved = append(*resolved, n.ID)
|
||||
|
||||
stmt := n.ChildByType(ast.NodeBlockQueryEmbedScript).TokensStr()
|
||||
stmt = html.UnescapeString(stmt)
|
||||
stmt = strings.ReplaceAll(stmt, editor.IALValEscNewLine, "\n")
|
||||
sqlBlocks := sql.SelectBlocksRawStmt(stmt, 1, Conf.Search.Limit)
|
||||
for _, sqlBlock := range sqlBlocks {
|
||||
if "query_embed" == sqlBlock.Type {
|
||||
continue
|
||||
}
|
||||
subTree, _ := LoadTreeByBlockID(sqlBlock.ID)
|
||||
if nil == subTree {
|
||||
continue
|
||||
}
|
||||
|
||||
subTree, _ := LoadTreeByBlockID(sqlBlock.ID)
|
||||
if nil == subTree {
|
||||
continue
|
||||
}
|
||||
|
||||
var md string
|
||||
if "d" == sqlBlock.Type {
|
||||
if 0 == blockEmbedMode {
|
||||
// 嵌入块中出现了大于等于上方非嵌入块的标题时需要降低嵌入块中的标题级别
|
||||
// Improve export of heading levels in embedded blocks https://github.com/siyuan-note/siyuan/issues/12233 https://github.com/siyuan-note/siyuan/issues/12741
|
||||
embedTopLevel := 0
|
||||
ast.Walk(subTree.Root, func(n *ast.Node, entering bool) ast.WalkStatus {
|
||||
if !entering || ast.NodeHeading != n.Type {
|
||||
return ast.WalkContinue
|
||||
}
|
||||
|
||||
embedTopLevel = n.HeadingLevel
|
||||
if parentHeadingLevel >= embedTopLevel {
|
||||
n.HeadingLevel += parentHeadingLevel - embedTopLevel + 1
|
||||
if 6 < n.HeadingLevel {
|
||||
n.HeadingLevel = 6
|
||||
}
|
||||
}
|
||||
var md string
|
||||
if "d" == sqlBlock.Type {
|
||||
if 0 == blockEmbedMode {
|
||||
// 嵌入块中出现了大于等于上方非嵌入块的标题时需要降低嵌入块中的标题级别
|
||||
// Improve export of heading levels in embedded blocks https://github.com/siyuan-note/siyuan/issues/12233 https://github.com/siyuan-note/siyuan/issues/12741
|
||||
embedTopLevel := 0
|
||||
ast.Walk(subTree.Root, func(n *ast.Node, entering bool) ast.WalkStatus {
|
||||
if !entering || ast.NodeHeading != n.Type {
|
||||
return ast.WalkContinue
|
||||
})
|
||||
}
|
||||
|
||||
md, _ = lute.FormatNodeSync(subTree.Root, luteEngine.ParseOptions, luteEngine.RenderOptions)
|
||||
} else if "h" == sqlBlock.Type {
|
||||
h := treenode.GetNodeInTree(subTree, sqlBlock.ID)
|
||||
var hChildren []*ast.Node
|
||||
|
||||
// 从嵌入块的 IAL 属性中解析 custom-heading-mode,使用全局配置作为默认值
|
||||
blockHeadingMode := Conf.Editor.HeadingEmbedMode
|
||||
if customHeadingMode := n.IALAttr("custom-heading-mode"); "" != customHeadingMode {
|
||||
if mode, err := strconv.Atoi(customHeadingMode); nil == err && (mode == 0 || mode == 1 || mode == 2) {
|
||||
blockHeadingMode = mode
|
||||
}
|
||||
}
|
||||
|
||||
// 根据 blockHeadingMode 处理标题块的显示
|
||||
// blockHeadingMode: 0=显示标题与下方的块,1=仅显示标题,2=仅显示标题下方的块
|
||||
if 1 == blockHeadingMode {
|
||||
// 仅显示标题
|
||||
hChildren = append(hChildren, h)
|
||||
} else if 2 == blockHeadingMode {
|
||||
// 仅显示标题下方的块(默认行为)
|
||||
if "1" != h.IALAttr("fold") {
|
||||
children := treenode.HeadingChildren(h)
|
||||
for _, c := range children {
|
||||
if "1" == c.IALAttr("heading-fold") {
|
||||
// 嵌入块包含折叠标题时不应该显示其下方块 https://github.com/siyuan-note/siyuan/issues/4765
|
||||
continue
|
||||
}
|
||||
hChildren = append(hChildren, c)
|
||||
embedTopLevel = n.HeadingLevel
|
||||
if parentHeadingLevel >= embedTopLevel {
|
||||
n.HeadingLevel += parentHeadingLevel - embedTopLevel + 1
|
||||
if 6 < n.HeadingLevel {
|
||||
n.HeadingLevel = 6
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 0: 显示标题与下方的块
|
||||
hChildren = append(hChildren, h)
|
||||
hChildren = append(hChildren, treenode.HeadingChildren(h)...)
|
||||
return ast.WalkContinue
|
||||
})
|
||||
}
|
||||
|
||||
md, _ = lute.FormatNodeSync(subTree.Root, luteEngine.ParseOptions, luteEngine.RenderOptions)
|
||||
} else if "h" == sqlBlock.Type {
|
||||
h := treenode.GetNodeInTree(subTree, sqlBlock.ID)
|
||||
var hChildren []*ast.Node
|
||||
|
||||
// 从嵌入块的 IAL 属性中解析 custom-heading-mode,使用全局配置作为默认值
|
||||
blockHeadingMode := Conf.Editor.HeadingEmbedMode
|
||||
if customHeadingMode := n.IALAttr("custom-heading-mode"); "" != customHeadingMode {
|
||||
if mode, err := strconv.Atoi(customHeadingMode); nil == err && (mode == 0 || mode == 1 || mode == 2) {
|
||||
blockHeadingMode = mode
|
||||
}
|
||||
if 0 == blockEmbedMode {
|
||||
embedTopLevel := 0
|
||||
}
|
||||
|
||||
// 根据 blockHeadingMode 处理标题块的显示
|
||||
// blockHeadingMode: 0=显示标题与下方的块,1=仅显示标题,2=仅显示标题下方的块
|
||||
if 1 == blockHeadingMode {
|
||||
// 仅显示标题
|
||||
hChildren = append(hChildren, h)
|
||||
} else if 2 == blockHeadingMode {
|
||||
// 仅显示标题下方的块(默认行为)
|
||||
if "1" != h.IALAttr("fold") {
|
||||
children := treenode.HeadingChildren(h)
|
||||
for _, c := range children {
|
||||
if "1" == c.IALAttr("heading-fold") {
|
||||
// 嵌入块包含折叠标题时不应该显示其下方块 https://github.com/siyuan-note/siyuan/issues/4765
|
||||
continue
|
||||
}
|
||||
hChildren = append(hChildren, c)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 0: 显示标题与下方的块
|
||||
hChildren = append(hChildren, h)
|
||||
hChildren = append(hChildren, treenode.HeadingChildren(h)...)
|
||||
}
|
||||
if 0 == blockEmbedMode {
|
||||
embedTopLevel := 0
|
||||
for _, hChild := range hChildren {
|
||||
if ast.NodeHeading == hChild.Type {
|
||||
embedTopLevel = hChild.HeadingLevel
|
||||
break
|
||||
}
|
||||
}
|
||||
if parentHeadingLevel >= embedTopLevel {
|
||||
for _, hChild := range hChildren {
|
||||
if ast.NodeHeading == hChild.Type {
|
||||
embedTopLevel = hChild.HeadingLevel
|
||||
break
|
||||
}
|
||||
}
|
||||
if parentHeadingLevel >= embedTopLevel {
|
||||
for _, hChild := range hChildren {
|
||||
if ast.NodeHeading == hChild.Type {
|
||||
hChild.HeadingLevel += parentHeadingLevel - embedTopLevel + 1
|
||||
if 6 < hChild.HeadingLevel {
|
||||
hChild.HeadingLevel = 6
|
||||
}
|
||||
hChild.HeadingLevel += parentHeadingLevel - embedTopLevel + 1
|
||||
if 6 < hChild.HeadingLevel {
|
||||
hChild.HeadingLevel = 6
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mdBuf := &bytes.Buffer{}
|
||||
for _, hChild := range hChildren {
|
||||
md, _ = lute.FormatNodeSync(hChild, luteEngine.ParseOptions, luteEngine.RenderOptions)
|
||||
mdBuf.WriteString(md)
|
||||
mdBuf.WriteString("\n\n")
|
||||
}
|
||||
md = mdBuf.String()
|
||||
} else {
|
||||
node := treenode.GetNodeInTree(subTree, sqlBlock.ID)
|
||||
md, _ = lute.FormatNodeSync(node, luteEngine.ParseOptions, luteEngine.RenderOptions)
|
||||
}
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
lines := strings.Split(md, "\n")
|
||||
for i, line := range lines {
|
||||
if 0 == blockEmbedMode { // 使用原始文本
|
||||
buf.WriteString(line)
|
||||
} else { // 使用引述块
|
||||
buf.WriteString("> " + line)
|
||||
}
|
||||
if i < len(lines)-1 {
|
||||
buf.WriteString("\n")
|
||||
}
|
||||
mdBuf := &bytes.Buffer{}
|
||||
for _, hChild := range hChildren {
|
||||
md, _ = lute.FormatNodeSync(hChild, luteEngine.ParseOptions, luteEngine.RenderOptions)
|
||||
mdBuf.WriteString(md)
|
||||
mdBuf.WriteString("\n\n")
|
||||
}
|
||||
buf.WriteString("\n\n")
|
||||
md = mdBuf.String()
|
||||
} else {
|
||||
node := treenode.GetNodeInTree(subTree, sqlBlock.ID)
|
||||
md, _ = lute.FormatNodeSync(node, luteEngine.ParseOptions, luteEngine.RenderOptions)
|
||||
}
|
||||
|
||||
subTree = parse.Parse("", buf.Bytes(), luteEngine.ParseOptions)
|
||||
var inserts []*ast.Node
|
||||
for subNode := subTree.Root.FirstChild; nil != subNode; subNode = subNode.Next {
|
||||
if ast.NodeKramdownBlockIAL != subNode.Type {
|
||||
inserts = append(inserts, subNode)
|
||||
}
|
||||
buf := &bytes.Buffer{}
|
||||
lines := strings.Split(md, "\n")
|
||||
for i, line := range lines {
|
||||
if 0 == blockEmbedMode { // 使用原始文本
|
||||
buf.WriteString(line)
|
||||
} else { // 使用引述块
|
||||
buf.WriteString("> " + line)
|
||||
}
|
||||
if 2 < len(n.KramdownIAL) && 0 < len(inserts) {
|
||||
if bookmark := n.IALAttr("bookmark"); "" != bookmark {
|
||||
inserts[0].SetIALAttr("bookmark", bookmark)
|
||||
}
|
||||
if name := n.IALAttr("name"); "" != name {
|
||||
inserts[0].SetIALAttr("name", name)
|
||||
}
|
||||
if alias := n.IALAttr("alias"); "" != alias {
|
||||
inserts[0].SetIALAttr("alias", alias)
|
||||
}
|
||||
if memo := n.IALAttr("memo"); "" != memo {
|
||||
inserts[0].SetIALAttr("memo", memo)
|
||||
}
|
||||
}
|
||||
for _, insert := range inserts {
|
||||
n.InsertBefore(insert)
|
||||
|
||||
if gulu.Str.Contains(sqlBlock.ID, *resolved) {
|
||||
return ast.WalkContinue
|
||||
}
|
||||
|
||||
resolveEmbedR(insert, blockEmbedMode, luteEngine, resolved, depth)
|
||||
if i < len(lines)-1 {
|
||||
buf.WriteString("\n")
|
||||
}
|
||||
}
|
||||
unlinks = append(unlinks, n)
|
||||
return ast.WalkSkipChildren
|
||||
buf.WriteString("\n\n")
|
||||
|
||||
subTree = parse.Parse("", buf.Bytes(), luteEngine.ParseOptions)
|
||||
var inserts []*ast.Node
|
||||
for subNode := subTree.Root.FirstChild; nil != subNode; subNode = subNode.Next {
|
||||
if ast.NodeKramdownBlockIAL != subNode.Type {
|
||||
inserts = append(inserts, subNode)
|
||||
}
|
||||
}
|
||||
if 2 < len(n.KramdownIAL) && 0 < len(inserts) {
|
||||
if bookmark := n.IALAttr("bookmark"); "" != bookmark {
|
||||
inserts[0].SetIALAttr("bookmark", bookmark)
|
||||
}
|
||||
if name := n.IALAttr("name"); "" != name {
|
||||
inserts[0].SetIALAttr("name", name)
|
||||
}
|
||||
if alias := n.IALAttr("alias"); "" != alias {
|
||||
inserts[0].SetIALAttr("alias", alias)
|
||||
}
|
||||
if memo := n.IALAttr("memo"); "" != memo {
|
||||
inserts[0].SetIALAttr("memo", memo)
|
||||
}
|
||||
}
|
||||
for _, insert := range inserts {
|
||||
n.InsertBefore(insert)
|
||||
|
||||
if gulu.Str.Contains(sqlBlock.ID, *resolved) {
|
||||
return ast.WalkContinue
|
||||
}
|
||||
|
||||
resolveEmbedR(insert, blockEmbedMode, luteEngine, resolved, depth)
|
||||
*depth--
|
||||
}
|
||||
}
|
||||
return ast.WalkContinue
|
||||
unlinks = append(unlinks, n)
|
||||
return ast.WalkSkipChildren
|
||||
})
|
||||
|
||||
for _, unlink := range unlinks {
|
||||
unlink.Unlink()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1635,7 +1635,7 @@ func processSyncMergeResult(exit, byHand bool, mergeResult *dejavu.MergeResult,
|
|||
}
|
||||
}
|
||||
|
||||
removeWidgetDirSet, removePluginSet := hashset.New(), hashset.New()
|
||||
removeWidgetDirSet, unloadPluginSet, uninstallPluginSet := hashset.New(), hashset.New(), hashset.New()
|
||||
for _, file := range mergeResult.Removes {
|
||||
removes = append(removes, file.Path)
|
||||
if strings.HasPrefix(file.Path, "/storage/riff/") {
|
||||
|
|
@ -1664,7 +1664,8 @@ func processSyncMergeResult(exit, byHand bool, mergeResult *dejavu.MergeResult,
|
|||
if strings.HasPrefix(file.Path, "/plugins/") {
|
||||
if parts := strings.Split(file.Path, "/"); 2 < len(parts) {
|
||||
needReloadPlugin = true
|
||||
removePluginSet.Add(parts[2])
|
||||
// 删除插件目录:卸载
|
||||
uninstallPluginSet.Add(parts[2])
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1681,7 +1682,8 @@ func processSyncMergeResult(exit, byHand bool, mergeResult *dejavu.MergeResult,
|
|||
}
|
||||
for _, removePetal := range mergeResult.RemovePetals {
|
||||
needReloadPlugin = true
|
||||
removePluginSet.Add(removePetal)
|
||||
// Petal 中删除插件:卸载
|
||||
uninstallPluginSet.Add(removePetal)
|
||||
}
|
||||
|
||||
if needReloadFlashcard {
|
||||
|
|
@ -1693,7 +1695,7 @@ func processSyncMergeResult(exit, byHand bool, mergeResult *dejavu.MergeResult,
|
|||
}
|
||||
|
||||
if needReloadPlugin {
|
||||
PushReloadPlugin(upsertCodePluginSet, upsertDataPluginSet, removePluginSet, "")
|
||||
PushReloadPlugin(upsertCodePluginSet, upsertDataPluginSet, unloadPluginSet, uninstallPluginSet, "")
|
||||
}
|
||||
|
||||
for _, widgetDir := range removeWidgetDirSet.Values() {
|
||||
|
|
|
|||
|
|
@ -1433,6 +1433,7 @@ func buildTypeFilter(types map[string]bool) string {
|
|||
s.VideoBlock = types["videoBlock"]
|
||||
s.IFrameBlock = types["iframeBlock"]
|
||||
s.WidgetBlock = types["widgetBlock"]
|
||||
s.Callout = types["callout"]
|
||||
} else {
|
||||
s.Document = Conf.Search.Document
|
||||
s.Heading = Conf.Search.Heading
|
||||
|
|
@ -1451,6 +1452,7 @@ func buildTypeFilter(types map[string]bool) string {
|
|||
s.VideoBlock = Conf.Search.VideoBlock
|
||||
s.IFrameBlock = Conf.Search.IFrameBlock
|
||||
s.WidgetBlock = Conf.Search.WidgetBlock
|
||||
s.Callout = Conf.Search.Callout
|
||||
}
|
||||
return s.TypeFilter()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -338,6 +338,7 @@ type CriterionTypes struct {
|
|||
VideoBlock bool `json:"videoBlock"`
|
||||
IFrameBlock bool `json:"iframeBlock"`
|
||||
WidgetBlock bool `json:"widgetBlock"`
|
||||
Callout bool `json:"callout"`
|
||||
}
|
||||
|
||||
type CriterionReplaceTypes struct {
|
||||
|
|
|
|||
|
|
@ -373,7 +373,8 @@ func RenderTemplate(p, id string, preview bool) (tree *parse.Tree, dom string, e
|
|||
|
||||
if (ast.NodeListItem == n.Type && (nil == n.FirstChild ||
|
||||
(3 == n.ListData.Typ && (nil == n.FirstChild.Next || ast.NodeKramdownBlockIAL == n.FirstChild.Next.Type)))) ||
|
||||
(ast.NodeBlockquote == n.Type && nil != n.FirstChild && nil != n.FirstChild.Next && ast.NodeKramdownBlockIAL == n.FirstChild.Next.Type) {
|
||||
(ast.NodeBlockquote == n.Type && nil != n.FirstChild && nil != n.FirstChild.Next && ast.NodeKramdownBlockIAL == n.FirstChild.Next.Type) ||
|
||||
(ast.NodeCallout == n.Type && nil != n.FirstChild && ast.NodeKramdownBlockIAL == n.FirstChild.Next.Type) {
|
||||
nodesNeedAppendChild = append(nodesNeedAppendChild, n)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1612,6 +1612,16 @@ func (tx *Transaction) doUpdate(operation *Operation) (ret *TxErr) {
|
|||
util.PushEvent(evt)
|
||||
}
|
||||
|
||||
if avNames := getAvNames(updatedNode.IALAttr(av.NodeAttrNameAvs)); "" != avNames {
|
||||
// updateBlock 会清空数据库角标 https://github.com/siyuan-note/siyuan/issues/16549
|
||||
go func() {
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
oldAttrs := parse.IAL2Map(updatedNode.KramdownIAL)
|
||||
updatedNode.SetIALAttr(av.NodeAttrViewNames, avNames)
|
||||
pushBroadcastAttrTransactions(oldAttrs, updatedNode)
|
||||
}()
|
||||
}
|
||||
|
||||
createdUpdated(updatedNode)
|
||||
tx.nodes[updatedNode.ID] = updatedNode
|
||||
if err = tx.writeTree(tree); err != nil {
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ package server
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"mime"
|
||||
|
|
@ -217,7 +218,15 @@ func Serve(fastMode bool) {
|
|||
// 反代服务器启动失败不影响核心服务器启动
|
||||
}()
|
||||
|
||||
if err = http.Serve(ln, ginServer.Handler()); err != nil {
|
||||
util.HttpServer = &http.Server{
|
||||
Handler: ginServer,
|
||||
}
|
||||
|
||||
if err = util.HttpServer.Serve(ln); err != nil {
|
||||
if errors.Is(err, http.ErrServerClosed) {
|
||||
return
|
||||
}
|
||||
|
||||
if !fastMode {
|
||||
logging.LogErrorf("boot kernel failed: %s", err)
|
||||
os.Exit(logging.ExitCodeUnavailablePort)
|
||||
|
|
@ -562,6 +571,7 @@ func serveDebug(ginServer *gin.Engine) {
|
|||
}
|
||||
|
||||
func serveWebSocket(ginServer *gin.Engine) {
|
||||
util.WebSocketServer = melody.New()
|
||||
util.WebSocketServer.Config.MaxMessageSize = 1024 * 1024 * 8
|
||||
|
||||
ginServer.GET("/ws", func(c *gin.Context) {
|
||||
|
|
|
|||
|
|
@ -565,6 +565,10 @@ func GetFurtherCollections(attrView *av.AttributeView, cachedAttrViews map[strin
|
|||
continue
|
||||
}
|
||||
|
||||
if nil == kv.Key.Rollup {
|
||||
continue
|
||||
}
|
||||
|
||||
relKey, _ := attrView.GetKey(kv.Key.Rollup.RelationKeyID)
|
||||
if nil == relKey {
|
||||
continue
|
||||
|
|
|
|||
|
|
@ -1358,6 +1358,8 @@ func commitTx(tx *sql.Tx) (err error) {
|
|||
if err = tx.Commit(); err != nil {
|
||||
logging.LogErrorf("commit tx failed: %s\n %s", err, logging.ShortStack())
|
||||
}
|
||||
|
||||
closeTxPreparedStmts(tx)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -1380,6 +1382,8 @@ func commitHistoryTx(tx *sql.Tx) (err error) {
|
|||
if err = tx.Commit(); err != nil {
|
||||
logging.LogErrorf("commit tx failed: %s\n %s", err, logging.ShortStack())
|
||||
}
|
||||
|
||||
closeTxPreparedStmts(tx)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -1402,16 +1406,80 @@ func commitAssetContentTx(tx *sql.Tx) (err error) {
|
|||
if err = tx.Commit(); err != nil {
|
||||
logging.LogErrorf("commit tx failed: %s\n %s", err, logging.ShortStack())
|
||||
}
|
||||
|
||||
closeTxPreparedStmts(tx)
|
||||
return
|
||||
}
|
||||
|
||||
func prepareExecInsertTx(tx *sql.Tx, stmtSQL string, args []interface{}) (err error) {
|
||||
stmt, err := tx.Prepare(stmtSQL)
|
||||
if err != nil {
|
||||
func closeTxPreparedStmts(tx *sql.Tx) {
|
||||
if tx == nil {
|
||||
return
|
||||
}
|
||||
cacheKey := txCacheKey(tx)
|
||||
|
||||
txStmtCacheLock.Lock()
|
||||
stmtMap, ok := txStmtCache[cacheKey]
|
||||
if ok {
|
||||
delete(txStmtCache, cacheKey)
|
||||
}
|
||||
txStmtCacheLock.Unlock()
|
||||
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
for _, stmt := range stmtMap {
|
||||
_ = stmt.Close()
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
txStmtCache = make(map[string]map[string]*sql.Stmt)
|
||||
txStmtCacheLock = sync.Mutex{}
|
||||
)
|
||||
|
||||
func txCacheKey(tx *sql.Tx) string {
|
||||
return fmt.Sprintf("%p", tx)
|
||||
}
|
||||
|
||||
func prepareExecInsertTx(tx *sql.Tx, stmtSQL string, args []interface{}) (err error) {
|
||||
if tx == nil {
|
||||
return fmt.Errorf("tx is nil")
|
||||
}
|
||||
|
||||
cacheKey := txCacheKey(tx)
|
||||
|
||||
txStmtCacheLock.Lock()
|
||||
stmtMap, ok := txStmtCache[cacheKey]
|
||||
if !ok {
|
||||
stmtMap = make(map[string]*sql.Stmt)
|
||||
txStmtCache[cacheKey] = stmtMap
|
||||
}
|
||||
stmt, ok := stmtMap[stmtSQL]
|
||||
txStmtCacheLock.Unlock()
|
||||
|
||||
if !ok {
|
||||
stmt, err = tx.Prepare(stmtSQL)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
txStmtCacheLock.Lock()
|
||||
if existing, exists := txStmtCache[cacheKey][stmtSQL]; exists {
|
||||
stmt.Close()
|
||||
stmt = existing
|
||||
} else {
|
||||
txStmtCache[cacheKey][stmtSQL] = stmt
|
||||
}
|
||||
txStmtCacheLock.Unlock()
|
||||
}
|
||||
|
||||
if _, err = stmt.Exec(args...); err != nil {
|
||||
logging.LogErrorf("exec database stmt [%s] failed: %s", stmtSQL, err)
|
||||
if strings.Contains(err.Error(), "database disk image is malformed") {
|
||||
tx.Rollback()
|
||||
closeDatabase()
|
||||
removeDatabaseFile()
|
||||
logging.LogFatalf(logging.ExitCodeReadOnlyDatabase, "database disk image [%s] is malformed, please restart SiYuan kernel to rebuild it", util.DBPath)
|
||||
}
|
||||
logging.LogErrorf("exec database stmt [%s] failed: %s\n %s", stmtSQL, err, logging.ShortStack())
|
||||
return
|
||||
}
|
||||
return
|
||||
|
|
@ -1433,7 +1501,6 @@ func execStmtTx(tx *sql.Tx, stmt string, args ...interface{}) (err error) {
|
|||
|
||||
func nSort(n *ast.Node) int {
|
||||
switch n.Type {
|
||||
// 以下为块级元素
|
||||
case ast.NodeHeading:
|
||||
return 5
|
||||
case ast.NodeParagraph:
|
||||
|
|
@ -1452,6 +1519,8 @@ func nSort(n *ast.Node) int {
|
|||
return 20
|
||||
case ast.NodeBlockquote:
|
||||
return 20
|
||||
case ast.NodeCallout:
|
||||
return 20
|
||||
case ast.NodeSuperBlock:
|
||||
return 30
|
||||
case ast.NodeAttributeView:
|
||||
|
|
|
|||
|
|
@ -224,7 +224,7 @@ func FirstLeafBlock(node *ast.Node) (ret *ast.Node) {
|
|||
|
||||
func CountBlockNodes(node *ast.Node) (ret int) {
|
||||
ast.Walk(node, func(n *ast.Node, entering bool) ast.WalkStatus {
|
||||
if !entering || !n.IsBlock() || ast.NodeList == n.Type || ast.NodeBlockquote == n.Type || ast.NodeSuperBlock == n.Type {
|
||||
if !entering || !n.IsBlock() || ast.NodeList == n.Type || ast.NodeBlockquote == n.Type || ast.NodeSuperBlock == n.Type || ast.NodeCallout == n.Type {
|
||||
return ast.WalkContinue
|
||||
}
|
||||
|
||||
|
|
@ -403,6 +403,7 @@ var typeAbbrMap = map[string]string{
|
|||
"NodeThematicBreak": "tb",
|
||||
"NodeVideo": "video",
|
||||
"NodeAudio": "audio",
|
||||
"NodeCallout": "callout",
|
||||
// 行级元素
|
||||
"NodeText": "text",
|
||||
"NodeImage": "img",
|
||||
|
|
@ -458,6 +459,8 @@ func SubTypeAbbr(n *ast.Node) string {
|
|||
if 6 == n.HeadingLevel {
|
||||
return "h6"
|
||||
}
|
||||
case ast.NodeCallout:
|
||||
return n.CalloutType
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import (
|
|||
"io/fs"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/88250/gulu"
|
||||
|
|
@ -29,6 +30,7 @@ import (
|
|||
"github.com/88250/lute/ast"
|
||||
"github.com/88250/lute/parse"
|
||||
"github.com/siyuan-note/filelock"
|
||||
"github.com/siyuan-note/logging"
|
||||
"github.com/siyuan-note/siyuan/kernel/util"
|
||||
)
|
||||
|
||||
|
|
@ -71,7 +73,7 @@ func NewTree(boxID, p, hp, title string) *parse.Tree {
|
|||
root.SetIALAttr("id", id)
|
||||
root.SetIALAttr("updated", util.TimeFromID(id))
|
||||
ret := &parse.Tree{Root: root, ID: id, Box: boxID, Path: p, HPath: hp}
|
||||
ret.Root.Spec = "1"
|
||||
ret.Root.Spec = CurrentSpec
|
||||
newPara := &ast.Node{Type: ast.NodeParagraph, ID: ast.NewNodeID(), Box: boxID, Path: p}
|
||||
newPara.SetIALAttr("id", newPara.ID)
|
||||
newPara.SetIALAttr("updated", util.TimeFromID(newPara.ID))
|
||||
|
|
@ -129,3 +131,62 @@ func NewSpanAnchor(id string) (ret *ast.Node) {
|
|||
func ContainOnlyDefaultIAL(tree *parse.Tree) bool {
|
||||
return 5 > len(tree.Root.KramdownIAL)
|
||||
}
|
||||
|
||||
var CurrentSpec = "2"
|
||||
|
||||
var ErrSpecTooNew = fmt.Errorf("the document spec is too new")
|
||||
|
||||
func CheckSpec(tree *parse.Tree) (err error) {
|
||||
if CurrentSpec == tree.Root.Spec || "" == tree.Root.Spec {
|
||||
return
|
||||
}
|
||||
|
||||
spec, err := strconv.Atoi(tree.Root.Spec)
|
||||
if nil != err {
|
||||
logging.LogErrorf("parse spec [%s] failed: %s", tree.Root.Spec, err)
|
||||
return
|
||||
}
|
||||
|
||||
currentSpec, _ := strconv.Atoi(CurrentSpec)
|
||||
if spec > currentSpec {
|
||||
logging.LogErrorf("tree spec [%s] is newer than current spec [%s]", tree.Root.Spec, CurrentSpec)
|
||||
return ErrSpecTooNew
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func UpgradeSpec(tree *parse.Tree) (upgraded bool) {
|
||||
if CurrentSpec == tree.Root.Spec {
|
||||
return
|
||||
}
|
||||
|
||||
upgradeSpec1(tree)
|
||||
upgradeSpec2(tree)
|
||||
return true
|
||||
}
|
||||
|
||||
func upgradeSpec2(tree *parse.Tree) {
|
||||
oldSpec, err := strconv.Atoi(tree.Root.Spec)
|
||||
if nil != err {
|
||||
logging.LogErrorf("parse spec [%s] failed: %s", tree.Root.Spec, err)
|
||||
return
|
||||
}
|
||||
|
||||
if 2 <= oldSpec {
|
||||
return
|
||||
}
|
||||
|
||||
// 增加了 Callout
|
||||
|
||||
tree.Root.Spec = "2"
|
||||
}
|
||||
|
||||
func upgradeSpec1(tree *parse.Tree) {
|
||||
if "" != tree.Root.Spec {
|
||||
return
|
||||
}
|
||||
|
||||
parse.NestedInlines2FlattedSpans(tree, false)
|
||||
tree.Root.Spec = "1"
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -211,6 +211,71 @@ func IsValidPandocBin(binPath string) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// 解析符号链接
|
||||
if real, err := filepath.EvalSymlinks(binPath); err == nil {
|
||||
binPath = real
|
||||
}
|
||||
|
||||
// 文件信息检查
|
||||
fi, err := os.Stat(binPath)
|
||||
if err != nil || fi.IsDir() || !fi.Mode().IsRegular() {
|
||||
return false
|
||||
}
|
||||
|
||||
// 在 Unix 上要求拥有可执行权限
|
||||
if !gulu.OS.IsWindows() {
|
||||
if fi.Mode().Perm()&0111 == 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// 读取文件头判断是否为二进制并排除脚本(#!)
|
||||
f, err := os.Open(binPath)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
header := make([]byte, 16)
|
||||
n, _ := f.Read(header)
|
||||
header = header[:n]
|
||||
|
||||
// 拒绝以 shebang 开头的脚本
|
||||
if bytes.HasPrefix(header, []byte("#!")) {
|
||||
return false
|
||||
}
|
||||
|
||||
isBin := false
|
||||
// 常见二进制魔数:ELF, PE("MZ"), Mach-O/FAT
|
||||
if len(header) >= 4 {
|
||||
switch {
|
||||
case bytes.Equal(header[:4], []byte{0x7f, 'E', 'L', 'F'}):
|
||||
isBin = true // ELF
|
||||
case bytes.Equal(header[:4], []byte{0xfe, 0xed, 0xfa, 0xce}):
|
||||
isBin = true // Mach-O
|
||||
case bytes.Equal(header[:4], []byte{0xce, 0xfa, 0xed, 0xfe}):
|
||||
isBin = true // Mach-O (swapped)
|
||||
case bytes.Equal(header[:4], []byte{0xca, 0xfe, 0xba, 0xbe}):
|
||||
isBin = true // FAT
|
||||
}
|
||||
}
|
||||
// PE only needs first 2 bytes "MZ"
|
||||
if !isBin && len(header) >= 2 && bytes.Equal(header[:2], []byte{'M', 'Z'}) {
|
||||
isBin = true
|
||||
}
|
||||
|
||||
// Windows 上允许 .exe 文件(作为补充判断)
|
||||
if !isBin && gulu.OS.IsWindows() {
|
||||
ext := strings.ToLower(filepath.Ext(binPath))
|
||||
if ext == ".exe" {
|
||||
isBin = true
|
||||
}
|
||||
}
|
||||
|
||||
if !isBin {
|
||||
return false
|
||||
}
|
||||
|
||||
cmd := exec.Command(binPath, "--version")
|
||||
gulu.CmdAttr(cmd)
|
||||
data, err := cmd.CombinedOutput()
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
WebSocketServer = melody.New()
|
||||
WebSocketServer *melody.Melody
|
||||
|
||||
// map[string]map[string]*melody.Session{}
|
||||
sessions = sync.Map{} // {appId, {sessionId, session}}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import (
|
|||
"fmt"
|
||||
"math/rand"
|
||||
"mime"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
|
@ -72,6 +73,7 @@ func initEnvVars() {
|
|||
var (
|
||||
bootProgress = atomic.Int32{} // 启动进度,从 0 到 100
|
||||
bootDetails string // 启动细节描述
|
||||
HttpServer *http.Server // HTTP 伺服器实例
|
||||
HttpServing = false // 是否 HTTP 伺服已经可用
|
||||
)
|
||||
|
||||
|
|
@ -101,7 +103,7 @@ func Boot() {
|
|||
readOnly := flag.String("readonly", "false", "read-only mode")
|
||||
accessAuthCode := flag.String("accessAuthCode", "", "access auth code")
|
||||
ssl := flag.Bool("ssl", false, "for https and wss")
|
||||
lang := flag.String("lang", "", "ar_SA/de_DE/en_US/es_ES/fr_FR/he_IL/it_IT/ja_JP/pl_PL/pt_BR/ru_RU/tr_TR/zh_CHT/zh_CN")
|
||||
lang := flag.String("lang", "", "ar_SA/de_DE/en_US/es_ES/fr_FR/he_IL/it_IT/ja_JP/ko_KR/pl_PL/pt_BR/ru_RU/tr_TR/zh_CHT/zh_CN")
|
||||
mode := flag.String("mode", "prod", "dev/prod")
|
||||
flag.Parse()
|
||||
|
||||
|
|
@ -140,7 +142,7 @@ func Boot() {
|
|||
// The access authorization code command line parameter must be set when deploying via Docker https://github.com/siyuan-note/siyuan/issues/9328
|
||||
fmt.Printf("the access authorization code command line parameter (--accessAuthCode) must be set when deploying via Docker\n")
|
||||
fmt.Printf("or you can set the SIYUAN_ACCESS_AUTH_CODE env var")
|
||||
os.Exit(1)
|
||||
os.Exit(logging.ExitCodeSecurityRisk)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -345,10 +347,19 @@ func ReadWorkspacePaths() (ret []string, err error) {
|
|||
}
|
||||
|
||||
var tmp []string
|
||||
workspaceBaseDir := filepath.Dir(HomeDir)
|
||||
for _, d := range ret {
|
||||
if ContainerIOS == Container && strings.Contains(d, "/Documents/") {
|
||||
// iOS 端沙箱路径会变化,需要转换为相对路径再拼接当前沙箱中的工作空间基路径
|
||||
d = d[strings.Index(d, "/Documents/")+len("/Documents/"):]
|
||||
d = filepath.Join(workspaceBaseDir, d)
|
||||
}
|
||||
|
||||
d = strings.TrimRight(d, " \t\n") // 去掉工作空间路径尾部空格 https://github.com/siyuan-note/siyuan/issues/6353
|
||||
if gulu.File.IsDir(d) {
|
||||
tmp = append(tmp, d)
|
||||
} else {
|
||||
logging.LogWarnf("workspace path [%s] is not a dir", d)
|
||||
}
|
||||
}
|
||||
ret = tmp
|
||||
|
|
|
|||
|
|
@ -117,6 +117,7 @@ func initWorkspaceDirMobile(workspaceBaseDir string) {
|
|||
|
||||
var workspacePaths []string
|
||||
if !gulu.File.IsExist(workspaceConf) {
|
||||
logging.LogInfof("workspace conf [%s] not exist, use the default workspace [%s]", workspaceConf, defaultWorkspaceDir)
|
||||
WorkspaceDir = defaultWorkspaceDir
|
||||
if !gulu.File.IsDir(WorkspaceDir) {
|
||||
logging.LogWarnf("use the default workspace [%s] since the specified workspace [%s] is not a dir", WorkspaceDir, defaultWorkspaceDir)
|
||||
|
|
@ -125,6 +126,7 @@ func initWorkspaceDirMobile(workspaceBaseDir string) {
|
|||
workspacePaths = append(workspacePaths, WorkspaceDir)
|
||||
} else {
|
||||
workspacePaths, _ = ReadWorkspacePaths()
|
||||
|
||||
if 0 < len(workspacePaths) {
|
||||
WorkspaceDir = workspacePaths[len(workspacePaths)-1]
|
||||
if !gulu.File.IsDir(WorkspaceDir) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue