1. 背景
Obsidian-Query-Control(后面简称为 OQC 插件) 是Obsidian 中一个非常有用的插件。一说到它我就赞不绝口。原因是:这个插件做了一件 Obsidian 本来就可以做,但是却没有做的事情:对搜索结果的 markdown 语法进行二次渲染。而且,完成度非常高:不仅针对搜索面板,内嵌搜索,后向连接内的显示结果markdown 全部进行了渲染,更加感人的是,还把原本只在搜索面板中的搜索控制和排序功能,完整地移植到了内嵌搜索和后向连接面板。我实在想不出,为啥 Obsidian 的作者不把这个功能直接写进 Obsidian,而且还是在这个插件存在了好几年的今天。
Obsidian-Query-Control 对我来说,做大的作用在于随时按需动态检索待办事项,并且可以直接将任务“原封不动”地呈现在任意的笔记里,然后可以打印成 PDF共享给别人。估计你已经看出来了,这个在做任务分解和工作分配的时候,简直是 must-have。即便是安排自己的工作,有了动态检索和结果 markdown 渲染,几乎可以按需地组织呈现 Obsidian 内存储的一切笔记的内容了。
然而,遗憾的是,由于插件所实现的功能,基于对整个 Obsidian 的非常精巧的“拦截”+“替换” + “移植”操作,因此,在Obsidian 更新到 1.2.x之后,插件突然不能工作了。在 0.16版本升级的时候,也出现过类似的情况。不过作者在 1 个多月后,还是给出了 bug 修复。但是这次,插件作者托人放话了:太忙了,估计一段时间内都没法更新。
于是,自从 Obsidian 内侧版本更新到 1.2.x之后,我就通过版本回滚,一直使用1.1.15的老版本,原因只有一个:用 Obsidian-Query-Control。但是,这显然不是办法:Obsidian 早晚都是要再升级的。这种“伸手”和“等别人解决”的懒散方式,迟早有一天要破产的。所以,我决定从零开始,在不会 typescript 的前提下,也完全不会前端开发调试的前提下,直接上术台,调试和修复这个 bug。
2. 先说“手术”结果
手术之后,功能恢复了 70%,现在你可以:
- 让搜索面板,嵌入搜索,后向连接窗体,显示渲染后的结果
- backlink 界面的搜索能力恢复情况是 100%
- 可以用插件原作者提供的 query 语句中的参数配置命令(这里要再膜拜一下,原作者太 NB,太贴心了)控制嵌入搜索结果的呈现方式:
- 搜索的题目
- 折叠/展开
- 是否扩展
- 是否markdown渲染
- 搜索结果的三种结果排序依据的正序,倒序排序
没有恢复的功能
- 搜索面板的控制按钮,全都去掉了。 这也是这次出现问题的原因:Obsidian 的搜索视图变了,而且是外表和内心一起变了。
- 好消息是:搜索面板的控制,可以通过调整Obsidian-Query-Control 设置界面中配置参数来调整,无法随时更改。
- 坏消息是:改完设置,如果要生效,需要重启 Obsidian
- 内嵌搜索
- 坏消息是:控制按钮全都被砍掉了。原因同上。
- 好消息是:内嵌搜索的控制,可以通过搜索命令来实现。 其实,我个人更喜欢这个方式。我发现,针对特定用途的检索,向排序啊,渲染啊这些配置都是相对比较固定的。因此可以把常用的几种搜索配置,全部固化在笔记模板中,需要的时候按需插入模板就好了,灵活方便。
- 内嵌搜索的控制语法,详见 https://github.com/nothingislost/obsidian-query-control 的说明,把常用的控制选项直接写进模板,事半功倍。
我目前的配置是:我会把Obsidian-Query-Control 配置中的“默认渲染”的选项关闭,来确保搜索面板能够呈现比较原始的文本信息结果。如果需要渲染后的结果,可以直接新建一个临时笔记,然后用 query 命令构建一个完成了 markdown 解析的结果。如果你没有用过 query命令,告诉你一个好消息:query 的检索命令是与搜索面板完全一样的,一样灵活,快捷,一样地对笔记本身没有影响,而且还能渲染成原来笔记中的样子。这也是我为什么没有用 DataView 插件的原因。
改好的插件的下载地址:
https://github.com/zhao414/obsidian-query-control/releases/tag/0.5_fix_fix_for_Obsidian_1.2.5
在 Obsidian 的插件目录中,用上述 main.js 替换 OCQ 插件原始的main.js即可。
3. 调试过程
3.1. 搭建调试环境
我是路人直接上到手术台主刀的位置。站定低头一看,我靠,不仅是个外星生物(Type Script, OMG,没用过),手术所需条件也是“全都没有”(好吧,VSCode 好歹还是装了的),所以,这个过程也就从最基本的搭建调试环境开始(基于 MacOS,姑且算是开局选了个 Easy 模式吧)。
- 搭建JS 和 TS 的调试环境。在 MacOS 下面,参照 https://github.com/obsidianmd/obsidian-sample-plugin 中的说您,利用 NPM,这个配置过程几乎是全自动化的。
- 安装一个 VS Code和 Github Desktop。后者比较傻瓜,适合没有什么特殊需求的初学者。
- 用 Github Desktop 从 Github 上把插件的代码库拖下来。
- 按照 https://github.com/obsidianmd/obsidian-sample-plugin 中 First time developing plugins? 中说明的步骤,在本地完成对插件的编译。
- 按照说明,运行
npm run dev
后,就会开始第一次编译,在代码库目录里生成 dist 目录:./dist
,以及编译好的 js 文件:./dist/main.js
。这个终端窗口不要关闭,npm 会自动检查后继的代码变动并自动完成编译。 - 如果没有生成编译好的js 文件,也不用着急,用 VS Code 打开插件代码库中src目录下的 main.ts
- 随便改动点什么,例如加个空格,npm 变回自动完成编译
- 如果还是没有编译,检查联网(编译过程需要解决 depency,下载必要的包),停止当前的
npm run dev
,返回步骤 1 重新开始。
- 按照说明,运行
- 重要: 将编译好的 main.js 放入 Obsidian 的对应的插件目录,替换掉原有的。这个操作还是很有必要的,虽然不清楚原理,但是这样操作之后,在 Obsidian Developer Tool里调试的时候,就能直接看到和跟踪编译前的TS代码了。这会必直接跟踪编译后的 js 代码方便太多了。
3.2. 出现问题的原因
Obsidian 1.2.x之后,SearchView 中似乎去掉了原本包含在其中的 searchHeaderDOM。
OQC 插件的一个操作就是拦截这个searchHeaderDOM,然后生成一个新的 DOM,并在其中插入搜索控制的 UI以及对应的调用,然后再将这个改好的 DOM“缝合”回去,从而实现“无缝插入全新控制界面”的结果。
这是一个我看来非常巧妙的外科手术操作,原作者一看就知道是大牛。并且,这样一番操作之后,相当于直接给 Obsidian 本体做了增强,所以我一直认为,OB 的作者应该考虑把这个功能收编进基本功能里。当然,也可以能 OB 的作者,比较反感这种产品发布之后再“开刀”的情况,所以,迟迟不给出积极的回应。
言归正传,这个searchHeaderDOM被 Obsidian 拿掉之后,这个手术就做不成了,自然就运行不下去了。
但是,经过单步调试和分析原始的 TS 可以发现,受影响的仅仅是植入UI这个环节。 OQC 针对 Search/Qurey 的其他几个核心功能,虽然也是通过精确的外科手术,在巧妙的时机抓住拦截对象并完成“改造”,但是这些操作本身和 UI 的改造过程是并行的,并且涉及的 SearchResultDOM 对象仍然有效(没有被 OB 作者干掉),因此,可以判断这些实际功能应该是仍然可以工作的。
通过分析代码发现,OQC对于 Backlink的其改造方法与 OQC 对 Search/Query 过程的改造类似,而这种改造并没有因为这次 OB 升级发生影响,因此可以进一步判断,如果把对搜索 UI 的部分的“手术”停掉,大概率核心功能的代码应该还可以重用。
3.3. 解题
问题定位清楚了,解决问题的思路就成型了
- 清理掉所有 searchHeaderDOM 对象以及其成员对象的实例
- 清理掉所有与上述实例相关的引用。
Bingo!
3.4. “手术”结果
请参见 先说“手术”结果 部分。
4. 下一步计划(留给高人)
目前的“手术”,屏蔽掉了有问题的部分而已,相当于给一个病人做了成功的止血手术,把命保住了。
如果需要重建对 Search/Query 的控制界面,目前看到有几个可能的思路:
- 从 Backlink 实例中复制一个 HeaderDOM,然后移植到 searchView 中,看看能不能 work
- 参照新的 Native Search Pane 中的模式,重构一个类似的基于菜单的全新控制面板。
- 完全 out-of-scratch,自己写一套 UI(其实,这个和第一个有点类似,因为原本 Backlink中的 DOM 的内容,就是插件原作者“自造”的)
本人水平有限,要实现上述任意一个思路,都得从 0 开始学起,估计都得猴年马月了。因此,如果有高人有兴趣,欢迎 fork,欢迎改造,欢迎一起把这个 NB 的插件做好。
最后,向原作者致敬,经过我这么一番野路子折腾,代码依然健壮,太厉害了。