♻️ refactor(vscode): 代码阅读不再在页面里拦 ⌘↓ / ⌘↑,快捷键只在「键盘快捷方式」里绑;跳到下一处时把浏览器自己的滚动拉回来,页面不再先滚到底

This commit is contained in:
cruldra committed 2026-09-27 00:33:18 +08:00
1 parent 0cad5722bb
commit 1b1299dc1f
10 files changed
+157 -165

No files matched your search

@@ -1,5 +1,3 @@
import type { KeyCombo } from './messages'
/** 在高亮着的名字的各处出现之间跳:两条命令、快捷键的 when 子句用的上下文键。 */
export const NEXT_OCCURRENCE = 'superpowers.codeReader.nextOccurrence'
@@ -7,54 +5,6 @@ export const PREVIOUS_OCCURRENCE = 'superpowers.codeReader.previousOccurrence'
/** 活动的预览里能用键盘跳(有高亮、页面有焦点、焦点不在输入框里)。 */
export const OCCURRENCES_CONTEXT = 'superpowers.codeReader.hasOccurrences'
/** VS Code 快捷键写法里的键名 → KeyboardEvent.key;单个字母、数字照写。 */
const KEY_NAMES: Record<string, string> = {
up: 'ArrowUp',
down: 'ArrowDown',
left: 'ArrowLeft',
right: 'ArrowRight',
home: 'Home',
end: 'End',
pageup: 'PageUp',
pagedown: 'PageDown',
}
/** `cmd+down` 这种一下按完的组合 → KeyCombo;`ctrl+k ctrl+x` 这种分两下按的、认不得的键名没有。 */
export function parseKey(text: string): KeyCombo | undefined {
const parts = text.trim().toLowerCase().split('+')
if (parts.some(part => part === '' || /\s/.test(part)))
return undefined
const name = parts.pop() ?? ''
const key = KEY_NAMES[name] ?? (/^[a-z0-9]$/.test(name) ? name : undefined)
const modifiers = new Set(parts)
if (!key || [...modifiers].some(modifier => !['ctrl', 'shift', 'alt', 'cmd', 'meta', 'win'].includes(modifier)))
return undefined
return {
key,
ctrl: modifiers.has('ctrl'),
shift: modifiers.has('shift'),
alt: modifiers.has('alt'),
meta: modifiers.has('cmd') || modifiers.has('meta') || modifiers.has('win'),
}
}
interface Keybinding { command?: unknown, key?: unknown, mac?: unknown, linux?: unknown, win?: unknown }
/**
* package.json 给这两条命令默认绑的键,各平台的都算(扩展可能跑在远程机器上,看不出界面在哪个系统)。
* 用户在「键盘快捷方式」里改绑的读不到:VS Code 没有给扩展查快捷键的接口。
*/
export function navigationKeys(manifest: unknown): KeyCombo[] {
const bindings = (manifest as { contributes?: { keybindings?: Keybinding[] } } | undefined)?.contributes?.keybindings ?? []
const combos = bindings
.filter(binding => binding.command === NEXT_OCCURRENCE || binding.command === PREVIOUS_OCCURRENCE)
.flatMap(binding => [binding.key, binding.mac, binding.linux, binding.win])
.filter((text): text is string => typeof text === 'string')
.map(parseKey)
.filter((combo): combo is KeyCombo => combo !== undefined)
return combos.filter((combo, i) => combos.findIndex(other => JSON.stringify(other) === JSON.stringify(combo)) === i)
}
/**
* 上下文键跟着各预览报来的状态走:有一个预览能跳就是真(同一时刻只有一个页面有焦点),变了才设。
* 预览关掉、页面被销毁(标签页切走)时当它不能跳。