🐛 fix(vscode): 代码阅读按 ⌘↓ 跳高亮不再来回闪,筛选栏加上上一处、下一处

This commit is contained in:
cruldra committed 2026-10-03 03:11:46 +08:00
1 parent 70a53e5a68
commit b16cc6409e
8 files changed
+221 -36

No files matched your search

@@ -129,31 +129,55 @@ export const KEY_SCROLL_MS = 500
export interface ScrollPosition { x: number, y: number }
/**
* 跳到下一处 / 上一处的命令由 VS Code 的快捷键系统触发,页面不知道绑的是哪个键,浏览器对这个键自己的动作(⌘↓ 滚到底)拦不住;
* 它还可能早于命令开始,也可能晚于命令(实测命令十几毫秒就到,滚动动画再过一帧才开始)。所以不管哪个键:
* 默认的「下一处 / 上一处」快捷键:mac 是 ⌘↓ / ⌘↑,别的系统是 ctrl。
* 只用来取消浏览器滚到底 / 滚到顶,不拿它判断命令到了没有(命令是 VS Code 发来的)。
*/
export function occurrenceJumpKey(
event: { key: string, metaKey: boolean, ctrlKey: boolean, altKey: boolean, shiftKey: boolean },
mac: boolean,
): boolean {
if (event.altKey || event.shiftKey || (event.key !== 'ArrowDown' && event.key !== 'ArrowUp'))
return false
return mac ? event.metaKey && !event.ctrlKey : event.ctrlKey && !event.metaKey
}
/**
* 跳到下一处 / 上一处的命令由 VS Code 的快捷键系统触发。默认的 ⌘↓ / ⌘↑(Windows 是 ctrl)在能跳的时候会取消浏览器滚到底 / 滚到顶,
* 但用户改过快捷键时别的键仍会自己滚,而且可能早于或晚于命令。所以任何键:
* 按键那一刻记下页面滚在哪(press);命令发来时先回到那里(take)再滚到目标;跳完守住跳到的位置(hold),
* 按键后 KEY_SCROLL_MS 内浏览器自己滚走了就拉回来(scrolled)。
* 按键后点了鼠标、滚了滚轮、又按了键,或跳转隔了 KEY_TO_COMMAND_MS 以上才来(从命令面板运行),都不算这个键触发的。
* 我们自己滚到的位置用 own 记下(拉回时差的那一像素、滚进视口),对应的滚动事件不算浏览器滚走;事件可能晚于滚动调用才到。
* 按键后点了鼠标、滚了滚轮、又按了键,或跳转隔了 KEY_TO_COMMAND_MS 以上才来(从命令面板运行),都不算这个键触发的。筛选栏上的按钮另走,不经过这里。
*/
export class KeyScroll {
private pressed: { position: ScrollPosition, at: number } | undefined
private held: { position: ScrollPosition, until: number } | undefined
/** 我们自己滚到的位置。守着的这段时间里,落到这里不算浏览器把页面滚走。 */
private owned: ScrollPosition[] = []
/** 按下任何键(照常交给浏览器和 VS Code 处理)时记下页面滚在哪。 */
press(position: ScrollPosition, at: number): void {
this.pressed = { position, at }
this.held = undefined
this.owned = []
}
forget(): void {
this.pressed = undefined
this.held = undefined
this.owned = []
}
/** 记下我们马上要滚到的位置。滚动事件晚到也认。 */
own(position: ScrollPosition): void {
this.owned.push(position)
}
/** 跳转发来时:刚按过键就交出按键那一刻的位置(只交一次),从这时起守住它,直到跳完换成跳到的位置。 */
take(now: number): ScrollPosition | undefined {
const pressed = this.pressed
this.pressed = undefined
this.owned = []
this.held = pressed && now - pressed.at <= KEY_TO_COMMAND_MS ? { position: pressed.position, until: pressed.at + KEY_SCROLL_MS } : undefined
return this.held?.position
}
@@ -164,13 +188,16 @@ export class KeyScroll {
this.held = { ...this.held, position }
}
/** 页面滚动了:还在守着、又被浏览器滚走了,给出要拉回的位置。 */
/** 页面滚动了:还在守着、又被浏览器滚走了,给出要拉回的位置。我们自己滚到的位置不算。 */
scrolled(position: ScrollPosition, now: number): ScrollPosition | undefined {
const held = this.held
if (!held || now > held.until) {
this.held = undefined
this.owned = []
return undefined
}
if (this.owned.some(item => item.x === position.x && item.y === position.y))
return undefined
return held.position.x === position.x && held.position.y === position.y ? undefined : held.position
}
}