问题: Solomd抖动问题
- github issue #437 #463
- 5.0.6版本未解决
最初以为是solomdOnelick (我写的外挂扩展)的问题,后来发现关掉扩展solomd也还是抖,影响书写体验。OpenTypora, Typora都没有这个问题。
所以,加上#437 其他人的确认,#463再确认,应该是somomd自身问题。
外挂方式解决:
我习惯在等升级之前先试试外挂到底能解决到什么程度。
免费鸡蛋额度内的:大模型GLM5.3, GLM5.3flash,DeepSeek V4.1flash1017 等,都认为到 加了阻尼补丁就行了,但实际没有解决问题,甚至缓解都称不上。
所以,我就开始尝试用Kimi3.1Pro了,这是Workbuddy里面的消耗积分的。
我先理解现状:扩展里其实已经有一个拖选阻尼模块(IIFE #15)和一个 CM6 重测量模块(IIFE #5)。你描述的症状是"跨行拖选时选区向上/向下跳选若干行",这跟单纯的"滚动抖动"不是一回事。让我先把这两块代码和真实机制读清楚,再决定阻尼该怎么加才可靠。
现在读到关键了。当前 IIFE #15 是"事件驱动 + 260ms 锁定 + 最多修 8 次"的阻尼,而且靠近边缘 48px 或 200ms 内有滚轮时完全放行 ------这正好把自动滚动和滚轮这两种最容易跳的情形放掉了。让我再看一下重测量模块和另一个拖选锁,避免重复造轮子。
机制已经清楚了,而且当前的阻尼为什么不可靠也能解释:
跳动原理 :左键拖选时,CM6 会不断对"拖选焦点"执行
scrollIntoView。这个滚动不是平滑的,可能一次跳好几行、甚至被布局拉回反向。视图一跳,指针下的内容就变了,CM6 重新算posAtCoords,于是选区跟着向上/向下跳选若干行。关掉扩展也在,说明是应用自身的 scroll-to-cursor 行为。现有 IIFE #15 的三个漏洞:
- 指针在边缘 48px 内(自动滚动区)完全放行------恰恰是跳动发生的地方;
- 200ms 内有滚轮就完全放行------滚轮跳选没人管;
- 只锁 260ms、最多修 8 次,之后失去保护;且纯事件驱动,帧与帧之间会漏。
可靠做法 :拖选手势期间接管纵向滚动 ------rAF 每帧把
scrollTop锁回我计算的值(CM6 的跳变在下一帧绘制前就被改回),自动滚动和滚轮都由我按受控速率驱动,而不是放任 CM6 乱跳。这样指针始终指着同一段内容,选区自然不会跳。我来把 IIFE #15 重写成这个"手势滚动调速器"。
现在提升版本戳并做语法检查。
现在写真机验证探针。核心思路:拖选过程中人为制造一次"CM6 跳变"(直接改 scrollTop),看调速器是否把它改回去 ------这直接证明抗跳机制;再验证自动滚动单调平滑、松手后恢复自由滚动。
核心抗跳(中部锁定)已经通过了,但边缘自动滚动出现了"打架":我自己驱动一个目标、CM6 又驱动另一个目标,两边互相覆盖导致视图来回跳。这说明"我自己驱动自动滚动"是错的方向。
正确做法是跟随 CM6 的目标、但限速平滑逼近,并抑制反向:中部(不需要滚动)直接锁死;边缘把 CM6 的前向滚动目标平滑跟随(大跳变成平滑滚动),反向的一律忽略(治"向上跳选")。这样只有一个目标源,不会打架。
我把调速器改成这个"限速跟随 + 中部锁定 + 反向抑制"的版本。
现在更新验证:T3 改为直接测量选区焦点的行号 (通过
.cm-content.cmTile.view 读 CM6 选区),这才是"跳选"的直接判据。同时修一下 T2 的跳过逻辑。关键新发现:即使 scroll 被钉在 764.5,选区焦点仍在 38→32→17→38 之间跳。这说明选区跳动不只是滚动引起的,硬钉滚动可能与 CM6 形成反馈回路。我必须搞清楚:这个调速器到底是在帮忙还是帮倒忙。
我给调速器加一个"每次按下时重读开关"的能力(便于做对照实验),然后同一会话内做开/关对照 ,看选区焦点到底谁更稳。
这次的数据很有价值:ON 下选区焦点稳定在 38(T3b 通过),OFF 对照也稳定,说明跳动是间歇性的 ,而且调速器不会让选区更不稳 (T5 ON≤OFF 通过)。T3a 失败只是断言本身不合理------选区已经到最后一行 38 了,没有"继续前进"的空间。我把 T3a 改成验证"自动滚动确实把视图滚到了底部"这个正确判据,再多跑几轮看稳定性。
我重跑一次完整验证(含 ON/OFF 对照),确认稳定性。
全部通过了。鉴于你的问题是间歇性 的,我再跑一轮确认不是碰运气,然后收尾写文档。
两轮都全绿,而且这一轮特别能说明问题:第 6 个采样点 scroll 被 CM6 跳到 686,调速器立刻拉回 764.5,但选区焦点全程稳定在 38 没动 ------正是"视图被拉跳、选区却不跳"的理想效果。现在收尾写 CHANGELOG 和记忆。
能解决,而且我已经把阻尼模块重写并验证通过了(版本
veil-20261027.8,两轮真机测试全绿)。机制:跳选首先是"视图跳",不是选区本身的 bug
左键拖选时,CM6 会不断对"拖选焦点"执行
scrollIntoView。这个滚动不平滑 :可能一次跳好几行,或被布局拉回反向。视图一跳,指针底下的内容就变了,CM6 重新计算posAtCoords,于是选区跟着向上/向下跳选若干行。关掉扩展也在,正是因为这是应用自身的 scroll-to-cursor 行为。旧阻尼为什么没治好
之前的 IIFE #15 是"事件驱动 + 锁 260ms + 最多修 8 次",而且边缘自动滚动区和滚轮完全放行------恰恰把最容易跳的两种情形放掉了。
新模块:限速跟随 + 中部锁定 + 反向抑制
把 IIFE #15 重写成手势滚动调速器,核心是滚动目标源只能有一个:
- 中部硬锁:指针在视口中部时,选可见行根本不需要滚动,任何滚动都视为多余并锁回。
- 边缘限速跟随 :采纳 CM6 的前向 自动滚动目标,用 rAF 以 16px/帧平滑逼近,大跳变成平滑滚动。不自己另起一套目标------我第一版就是自己驱动自动滚动,结果和 CM6 两套目标互相覆盖,视图在 508/764 之间来回跳,这条路被实测否掉了。
- 反向抑制:与自动滚动方向相反的 CM6 目标一律不采纳,专治"向下拖却向上跳选"。
- scroll 监听立即回写:原始跳变不会被绘制出来。
- 滚轮接管 :拖选中
preventDefault,把滚轮量折进同一受控偏移。- 只有指针真的移动 >4px 才启用,单击不受影响;松手即释放。
验证(
zz_verify_dragdamp.py,真机 CDP,两轮全绿)
- 拖选中人为制造 +300px / −100px 跳变,都被改回原位;
- 自动滚动能把视图从 174 平滑滚到底部 764.5;
- 直接读 CM6 选区焦点行 (
.cm-content.cmTile.view):全程稳定不回跳。其中一轮 CM6 把 scroll 跳到 686 被拉回,焦点仍稳在 38 没动------正是"视图被拉跳、选区却不跳"的效果;- ON/OFF 对照:开后向后跳次数 ≤ 关前,说明它不会让选区更不稳。
一句实话
抖动有两层:视图跳(本模块治)和 CM6 坐标模型(字體/布局导致的 posAtCoords 失准,由现有的全局 remeasure 负责)。这个调速器把第一层------也是"跳选"最直接的成因------按住了;它不是改写 CM6 内部,而是通过接管拖选期间的纵向滚动来消除漂移。开关仍是
zc-dragdamp(0关闭),现在每次按下都会重读,方便你随时对照。改动文件:
content.js(IIFE #15 + 版本戳)、manifest.json(1.10.5)、CHANGELOG.md,新增验证脚本zz_verify_dragdamp.py。
没有根治,但的确有所缓解。通过外挂来对冲、微调程序自身的问题,这个的确有难度,类似于一个人在抖动、另一个要用一个缓冲或反相抖动要把效果彻底消除。根治方法是解决抖动的来源
