思源笔记 v3.1.22 版本技术详解:行级标记开关、编辑体验与开发者 API 改进
【免费下载链接】siyuanAn open-source, privacy-first, self-hosted knowledge workspace where humans and AI agents work together 开源、隐私优先、自托管的知识工作空间,让人与智能体在此协作项目地址: https://gitcode.com/GitHub_Trending/si/siyuan
本篇文章基于思源笔记(SiYuan)v3.1.22 的官方繁体中文更新日志(app/changelogs/v3.1.x/v3.1.22/v3.1.22_zh_CHT.md),逐一解析该版本的改进细节,并结合仓库源码说明其底层实现。读完本文,你将了解如何关闭==foo==行级标记语法、理解虚拟引用粘贴与退出聚焦定位的改进原理、掌握数据库日期字段相对过滤与 S3 同步的配置要点,并能利用新增的nodeElement参数扩展插件斜杠菜单回调。
一、版本概览:一次面向细节的「打磨」更新
v3.1.22 延续思源笔记「小版本持续打磨」的节奏,官方将其概述为「此版本改进了一些细节」。从变更记录看,本版本共包含10 项功能改进与1 项面向开发者的 API 变更,覆盖范围包括:
- 编辑体验:行级标记语法开关、虚拟引用内容粘贴、文本外观设置、本地文件链接粘贴;
- 界面交互:停靠面板弹出、退出聚焦定位、块自定义属性搜索预览区域定位;
- 兼容性与数据:Firefox 浏览器兼容性、数据库日期字段相对过滤、S3 提供商兼容性;
- 开发者 API:
protyleSlash.callback新增nodeElement参数。
这些改进虽「小」,却都落在编辑器的日常使用高频路径上,下文将逐项结合源码深入分析。
二、核心新功能:支持停用==foo==行级标记语法
本版本最重要的新增能力,是允许用户在设置中关闭 Markdown 行级标记(inline mark)语法。在此之前,==文字==是思源内置的「标记/高亮」行级语法,其解析由思源的 Markdown 引擎 Lute 负责,且默认开启;现在用户可以按需关闭,避免在粘贴或输入含==符号的文本(例如代码片段、等式)时被意外解析。
2.1 设置入口与配置项
在「设置 → 编辑器 → Markdown 行级语法」分组中,新增了「行级标记」开关。对应的前端 UI 构建位于 app/src/config/tabs/editorTab.ts,该分组registerEditorMarkdownInlineGroup中共有 7 个开关,本次新增的是最后一个:
group.switch("editor.markdown.inlineMark", { title: window.siyuan.languages.editorMarkdownInlineMark, desc: window.siyuan.languages.editorMarkdownInlineMarkTip, });该配置项的完整类型定义位于 app/src/types/config.d.ts,IMarkdown接口将行级语法配置统一收敛在editor.markdown下:
interface IMarkdown { inlineAsterisk: boolean; // *斜体* 星号语法 inlineUnderscore: boolean; // _斜体_ 下划线语法 inlineSup: boolean; // ^上标^ inlineSub: boolean; // ~下标~ inlineTag: boolean; // #标签# inlineMath: boolean; // $行内公式$ inlineStrikethrough: boolean; // ~~删除线~~ inlineMark: boolean; // ==行级标记== }2.2 前端与内核的双重解析开关
关闭开关后,前后端两个层面的 Lute 实例都会同步关闭该语法:
- 前端渲染:在 app/src/protyle/render/setLute.ts 中,编辑器初始化 Lute 时会逐一读取这些配置:
lute.SetGFMStrikethrough(window.siyuan.config.editor.markdown.inlineStrikethrough); lute.SetMark(window.siyuan.config.editor.markdown.inlineMark);- 内核解析:在 kernel/util/lute.go 中,
MarkdownSettings定义了运行时默认值,InlineMark默认开启(true),随后通过ret.SetMark(MarkdownSettings.InlineMark)应用到内核 Lute 实例,保证导入、导出与索引等内核侧操作与前端行为一致。
由此可以看出,==标记的「开关」并不是简单的 CSS 隐藏,而是从前端编辑器到内核解析器全链路禁用了该语法,因此关闭后文档中的==foo==会按普通文本对待,不会再被解析为高亮标记。
提示:
==foo==与思源的行内公式$...$、标签#...#等同属「Markdown 行级语法」分组,如需更精细地控制解析行为,可一并调整该分组下的其他开关。
三、编辑体验改进
3.1 改进虚拟引用内容粘贴
虚拟引用(virtual block ref)是思源中不依赖 ID 的引用方式,粘贴其内容时,如果正文中包含 Markdown 特殊字符,可能会被 Lute 二次解析而产生与源内容不一致的结果。本版本对此进行了改进。
相关实现位于 app/src/protyle/util/paste.ts。该文件采用了一个值得注意的设计——Lute 单例临界区:
// 临界区:Lute 已是所有编辑器共享的单例,此处临时把 inline-syntax 标志置 true 再恢复。 enableLuteMarkdownSyntax(protyle); const content = protyle.lute.BlockDOM2EscapeMarkerContent(protyle.lute.Md2BlockDOM(textPlain)); restoreLuteMarkdownSyntax(protyle);其中enableLuteMarkdownSyntax会临时开启全部行级语法,restoreLuteMarkdownSyntax再按用户配置恢复。源码注释特别强调:enable/transform/restore必须保持同步执行,中间不得插入await,否则并发编辑器的转换调用(如实时输入的SpinBlockDOM)会读到被改写的标志而产生错误输出。这正是本版本「改进虚拟引用内容粘贴」所涉及的底层机制——它保证了粘贴内容先以完整语法解析、再按用户配置还原,从而避免粘贴结果与源内容不一致。
3.2 改进退出聚焦定位
「退出聚焦」是指从聚焦(focus)模式返回文档视图时,光标/选中块的定位问题。此前在退出聚焦后,若目标块处于折叠状态或位于被隐藏元素中,定位可能失败或跳转错误。
在 app/src/menus/protyle.ts 中可以看到对这类问题的既有处理逻辑:
if (options.focusId) { let focusElement = options.protyle.wysiwyg.element.querySelector(`[data-node-id="${options.focusId}"]`); if (!focusElement) { const unfoldResponse = await fetchSyncPost("/api/block/getUnfoldedParentID", {id: options.focusId}); options.focusId = unfoldResponse.data.parentID; focusElement = ...; } if (focusElement) { // 退出聚焦后块在折叠中 https://github.com/siyuan-note/siyuan/issues/10746 let showElement = focusElement; while (showElement.getBoundingClientRect().height === 0) { showElement = showElement.parentElement; } ... focusBlock(showElement); } }从代码可以看出,退出聚焦后的定位逻辑会:先按块 ID 查找目标元素;若不存在则通过/api/block/getUnfoldedParentID回溯到已展开的父块;随后向上遍历,跳过所有高度为 0 的折叠父级,最终定位到可见块。v3.1.22 在此基础上进一步改进了定位的稳定性和准确性,使退出聚焦后视图能可靠回到正确位置。
3.3 改进文本外观设置
「文本外观设置」指编辑器中对字体、字号、行高等外观相关配置的即时生效能力。本版本改进了该设置的更新路径,确保修改后能立即反映到编辑区。该功能与外观运行时配置相关,前端配置逻辑位于 app/src/config/tabs/appearanceRuntime.ts 与 app/src/config/render/render.ts 等文件中,涉及的配置项包括appearance下的字体与排版参数,读者可结合「设置 → 外观」面板实际体验。
3.4 改进本地文件链接粘贴
当从系统文件管理器复制本地文件路径并在编辑器内粘贴时,思源需要将其转换为符合其资产(asset)管理规范的内链格式。本版本改进了该转换流程,使本地文件链接的粘贴结果更符合预期、路径处理更健壮。相关粘贴处理逻辑位于 app/src/protyle/util/paste.ts 中的本地文件读取与资产处理分支(readLocalFile等函数)。
四、界面与兼容性改进
4.1 改进停靠面板弹出
停靠(dock)面板是思源左右侧边栏的统称,包含文件树、大纲、反向链接等面板。「改进停靠面板弹出」主要针对面板展开时的定位、层级与交互细节进行优化,使面板弹出行为更平滑。停靠面板的布局与弹出逻辑集中在 app/src/layout/dock/ 目录下,其中 app/src/layout/dock/index.ts 负责面板的注册与组织,app/src/layout/dock/Backlink.ts、app/src/layout/dock/Outline.ts 等文件实现了各具体面板。
4.2 改进 Firefox 浏览器兼容性
思源在桌面端基于 Electron,在 Web 端则需要在各主流浏览器中运行。本版本修复了 Firefox 下若干兼容性问题(例如部分样式或事件处理在 Firefox 中的差异表现),提升了 Web 版在 Firefox 中的可用性。此类兼容性修复通常涉及 app/src/protyle/util/compatibility.ts 等兼容性适配文件,读者可在 Firefox 中打开思源 Web 版实际验证。
4.3 改进块自定义属性搜索预览区域定位
「块自定义属性」允许用户为块附加键值对属性,并可在搜索中按属性检索。本版本改进了属性搜索结果在预览区域中的定位行为,使命中结果在预览面板中能被准确定位与高亮显示。搜索结果的高亮与定位逻辑与搜索模块相关,可参考 app/src/search/ 目录下的实现。
五、数据与同步改进
5.1 改进数据库日期字段相对过滤
思源数据库(属性视图)的日期字段支持「相对过滤」,即按「当前时间 ± 偏移」进行动态过滤(例如「近 7 天」「前 30 天」)。本版本改进了相对过滤在「介于(between)」条件下的判断逻辑。
前端实现位于 app/src/protyle/render/av/filter.ts,该文件中的genInlineDateHTML函数负责生成日期类型的内联筛选控件,支持绝对/相对切换以及「Is between 结束日期」的组合;代码注释表明日期类型切换(绝对/相对)、日期方向切换(当前/前/后)等状态变化会触发筛选条件的保存。结合本版本改进,相对过滤在 between 区间下的计算边界更加准确。
5.2 某些 S3 提供商不可用
S3 协议对象存储(如 MinIO、Cloudflare R2、Backblaze B2 等)是思源「云端同步」的三种可选提供商之一(另两种为思源内置云与 WebDAV)。不同 S3 提供商在端点(Endpoint)、路径风格(Path Style)、TLS 校验等方面的实现存在差异,部分提供商此前无法正常同步,本版本对此进行了兼容性修复。
S3 同步配置的结构体定义位于 kernel/conf/sync.go:
type S3 struct { Endpoint string `json:"endpoint"` // 服务端点 AccessKey string `json:"accessKey"` // Access Key SecretKey string `json:"secretKey"` // Secret Key Bucket string `json:"bucket"` // 存储空间 Region string `json:"region"` // 存储区域 PathStyle bool `json:"pathStyle"` // 是否使用路径风格 SkipTlsVerify bool `json:"skipTlsVerify"` // 是否跳过 TLS 验证 Timeout int `json:"timeout"` // 超时时间,单位:秒 ConcurrentReqs int `json:"concurrentReqs"` // 并发请求数 }其中PathStyle(路径风格)与SkipTlsVerify(跳过 TLS 校验)是影响不同提供商兼容性的两个关键字段:部分兼容 S3 的私有服务要求使用http://host/bucket/key的路径风格访问,而云厂商默认使用https://bucket.host/key的虚拟主机风格;自建端点若使用自签名证书,则需要SkipTlsVerify。值得注意的是,思源在初始化默认配置时已将这两项预设为开启状态(kernel/model/conf.go:Conf.Sync.S3 = &conf.S3{PathStyle: true, SkipTlsVerify: true}),并在同步仓库提交时随配置一并传递(kernel/model/repository.go)。
S3 提供商的配置与导入导出通过 API 完成,对应路由在 kernel/api/router.go 中注册:
POST /api/sync/setSyncProviderS3—— 设置 S3 同步提供商(含管理员角色校验,参见 kernel/api/sync.go);POST /api/sync/exportSyncProviderS3/POST /api/sync/importSyncProviderS3—— 导出/导入 S3 提供商配置包。
实操建议:若使用自建 S3 或小众兼容服务时同步失败,可优先检查 Endpoint 地址是否含路径前缀、
PathStyle是否符合服务商要求、证书是否可信,必要时开启「跳过 TLS 校验」。
六、开发者 API:protyleSlash.callback新增nodeElement参数
本版本面向插件开发者提供了一项 API 变更:protyleSlash.callback回调新增nodeElement参数。
插件通过plugin.protyleSlash注册自定义斜杠菜单项,其类型定义位于 app/src/plugin/index.ts:
public protyleSlash: { filter: string[], html: string, id: string, callback: (protyle: import("../protyle").Protyle, nodeElement: HTMLElement) => void }[] = [];可见callback的签名已从单个protyle参数扩展为(protyle, nodeElement)两个参数。nodeElement是触发斜杠菜单时所操作的 DOM 节点元素,它由斜杠菜单的触发流程传入——在 app/src/protyle/hint/index.ts 中,当用户选择plugin__xxx类型的斜杠菜单项时:
} else if (value.startsWith("plugin")) { protyle.app.plugins.find((plugin) => { const ids = value.split(Constants.ZWSP); if (ids[1] === plugin.name) { plugin.protyleSlash.find((slash) => { if (slash.id === ids[2]) { slash.callback(protyle.getInstance(), nodeElement); return true; } }); return true; } }); return; }对插件开发者的影响:此前回调只能拿到protyle实例,需要自行通过选区或 DOM 查询定位当前操作节点;现在可以直接使用nodeElement参数,简化了「在光标处插入内容 / 替换文本」类插件的实现。旧插件若回调仍声明为单参数,在 TypeScript 下并不会报错(JS 允许少传参),但将无法使用该新参数,建议升级签名以充分利用新能力。
七、下载与升级
v3.1.22 属于思源笔记 3.1.x 稳定分支的维护版本,可通过官方提供的桌面端(Windows / macOS / Linux)与移动端安装包进行升级。升级前建议:
- 备份工作空间(默认目录包含
data数据目录,见 docs/WORKSPACE.zh-CN.md); - 关注版本间的数据格式兼容性,思源会为数据格式变更提供自动迁移;
- 插件用户升级前确认所用插件是否依赖
protyleSlash.callback的旧签名。
本版本的完整变更记录可在 app/changelogs/v3.1.x/v3.1.22/v3.1.22_zh_CHT.md(繁体中文)、app/changelogs/v3.1.x/v3.1.22/v3.1.22_zh_CN.md(简体中文)与 app/changelogs/v3.1.x/v3.1.22/v3.1.22.md(英文)中查看。
总结
v3.1.22 是一个典型的「细节打磨」版本,但其中的每一项改进都直接作用于日常编辑路径:==行级标记==语法开关让 Markdown 解析行为可控(前端 setLute.ts 与内核 lute.go 双重生效);虚拟引用粘贴通过 Lute 单例临界区保证解析一致性;S3 同步通过PathStyle、SkipTlsVerify等字段提升了不同提供商的兼容性;protyleSlash.callback的nodeElement参数则为插件开发提供了更便捷的节点访问能力。对于使用思源进行日常记录、或基于其开发插件的用户而言,理解这些改进背后的实现细节,将有助于更精准地使用和扩展这个开源知识工作空间。
【免费下载链接】siyuanAn open-source, privacy-first, self-hosted knowledge workspace where humans and AI agents work together 开源、隐私优先、自托管的知识工作空间,让人与智能体在此协作项目地址: https://gitcode.com/GitHub_Trending/si/siyuan
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考