feat(shortcuts): adopt Typora defaults for supported actions
This commit is contained in:
1 parent
830fabaa2d
commit
2b8f18f0db
14 files changed
+145
-37
No files matched your search
@@ -1,4 +1,4 @@
|
||||
import { defaultKeymap, history, selectAll } from '@codemirror/commands'
|
||||
import { defaultKeymap, history, indentLess, indentMore, selectAll, selectParentSyntax, toggleComment } from '@codemirror/commands'
|
||||
import { markdownKeymap, markdownLanguage } from '@codemirror/lang-markdown'
|
||||
import { Language } from '@codemirror/language'
|
||||
import { Compartment, EditorState, Prec, type Extension } from '@codemirror/state'
|
||||
@@ -64,7 +64,7 @@ export function createEditorState(opts: EditorStateOptions): EditorState {
|
||||
editorFocus,
|
||||
previewCompartment.of(previewExtensions(opts.sourceMode ?? false)),
|
||||
// 可配置操作不再通过 CM 的默认绑定重复注册。
|
||||
keymap.of(defaultKeymap.filter((binding) => binding.run !== selectAll)),
|
||||
keymap.of(defaultKeymap.filter((binding) => binding.run !== selectAll && binding.run !== indentLess && binding.run !== indentMore && binding.run !== selectParentSyntax && binding.run !== toggleComment)),
|
||||
preferencesCompartment.of([
|
||||
EditorState.tabSize.of(opts.tabSize ?? 4),
|
||||
EditorView.contentAttributes.of({ spellcheck: String(opts.spellcheck ?? false) }),
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
describe('快捷键', () => {
|
||||
it('Windows 上 Ctrl+Shift+Z 为重做', async () => {
|
||||
it('Windows 上 Ctrl+Y 为重做', async () => {
|
||||
// CodeMirror 在模块加载时读取平台,需先设置再导入
|
||||
Object.defineProperty(navigator, 'platform', { value: 'Win32', configurable: true })
|
||||
const { undo } = await import('@codemirror/commands')
|
||||
@@ -12,9 +12,20 @@ describe('快捷键', () => {
|
||||
view.dispatch({ changes: { from: 0, insert: 'abc' } })
|
||||
undo(view)
|
||||
expect(view.state.doc.toString()).toBe('')
|
||||
const event = new KeyboardEvent('keydown', { key: 'Z', code: 'KeyZ', keyCode: 90, ctrlKey: true, shiftKey: true })
|
||||
const event = new KeyboardEvent('keydown', { key: 'y', code: 'KeyY', keyCode: 89, ctrlKey: true })
|
||||
expect(runScopeHandlers(view, event, 'editor')).toBe(true)
|
||||
expect(view.state.doc.toString()).toBe('abc')
|
||||
view.destroy()
|
||||
})
|
||||
it('工作区自定义快捷键清空后,不回落到 CM 的缩进或其他冲突绑定', async () => {
|
||||
const { EditorView, runScopeHandlers } = await import('@codemirror/view')
|
||||
const { createEditorState } = await import('./index')
|
||||
const view = new EditorView({ parent: document.body, state: createEditorState({ doc: 'text', shortcuts: [] }) })
|
||||
try {
|
||||
for (const [key, code] of [['[', 'BracketLeft'], [']', 'BracketRight'], ['i', 'KeyI'], ['/', 'Slash']]) {
|
||||
expect(runScopeHandlers(view, new KeyboardEvent('keydown', { key, code, ctrlKey: true }), 'editor')).toBe(false)
|
||||
}
|
||||
expect(view.state.doc.toString()).toBe('text')
|
||||
} finally { view.destroy() }
|
||||
})
|
||||
})
|
||||
+17
-10
@@ -1,18 +1,25 @@
|
||||
import { indentLess, indentMore, redo, selectAll, undo } from '@codemirror/commands'
|
||||
import type { Command, KeyBinding } from '@codemirror/view'
|
||||
import { selectCodeBlock } from './codeblocks'
|
||||
import { insertLink, toggleBold, toggleHeading, toggleItalic } from './format'
|
||||
import { insertLink, toggleBlock, toggleBold, toggleCode, toggleHeading, toggleItalic } from './format'
|
||||
import { toggleSelectionMark, toggleUnderline } from './inlineStyles'
|
||||
import { typoraKeys } from '../typoraKeys'
|
||||
|
||||
export const editorCommands: { id: string; title: string; keys: string[]; run: Command }[] = [
|
||||
{ id: 'editor.bold', title: '粗体', keys: ['Mod+B'], run: toggleBold },
|
||||
{ id: 'editor.italic', title: '斜体', keys: ['Mod+I'], run: toggleItalic },
|
||||
{ id: 'editor.link', title: '插入链接', keys: ['Mod+K'], run: insertLink },
|
||||
{ id: 'editor.undo', title: '撤销', keys: ['Mod+Z'], run: undo },
|
||||
{ id: 'editor.redo', title: '重做', keys: ['Mod+Shift+Z', 'Mod+Y'], run: redo },
|
||||
{ id: 'editor.indent', title: '增加缩进', keys: ['Tab'], run: indentMore },
|
||||
{ id: 'editor.outdent', title: '减少缩进', keys: ['Shift+Tab'], run: indentLess },
|
||||
{ id: 'editor.selectAll', title: '全选(代码块内优先选中代码块)', keys: ['Mod+A'], run: (view) => selectCodeBlock(view) || selectAll(view) },
|
||||
...Array.from({ length: 6 }, (_, i) => ({ id: `editor.heading${i + 1}`, title: `设置 ${i + 1} 级标题`, keys: [`Ctrl+Alt+${i + 1}`], run: toggleHeading(i + 1) })),
|
||||
{ id: 'editor.bold', title: '粗体', keys: typoraKeys('editor.bold'), run: toggleBold },
|
||||
{ id: 'editor.italic', title: '斜体', keys: typoraKeys('editor.italic'), run: toggleItalic },
|
||||
{ id: 'editor.underline', title: '下划线', keys: typoraKeys('editor.underline'), run: toggleUnderline },
|
||||
{ id: 'editor.strike', title: '删除线', keys: typoraKeys('editor.strike'), run: toggleSelectionMark('Strikethrough') },
|
||||
{ id: 'editor.highlight', title: '高亮', keys: [], run: toggleSelectionMark('Highlight') },
|
||||
{ id: 'editor.code', title: '行内代码', keys: typoraKeys('editor.code'), run: toggleCode },
|
||||
...(['task', 'bullet', 'ordered', 'quote'] as const).map(kind => ({ id: `editor.${kind}`, title: { task: '任务列表', bullet: '无序列表', ordered: '有序列表', quote: '引用' }[kind], keys: typoraKeys(`editor.${kind}`), run: toggleBlock(kind) })),
|
||||
{ id: 'editor.link', title: '插入链接', keys: typoraKeys('editor.link'), run: insertLink },
|
||||
{ id: 'editor.undo', title: '撤销', keys: typoraKeys('editor.undo'), run: undo },
|
||||
{ id: 'editor.redo', title: '重做', keys: typoraKeys('editor.redo'), run: redo },
|
||||
{ id: 'editor.indent', title: '增加缩进', keys: typoraKeys('editor.indent'), run: indentMore },
|
||||
{ id: 'editor.outdent', title: '减少缩进', keys: typoraKeys('editor.outdent'), run: indentLess },
|
||||
{ id: 'editor.selectAll', title: '全选(代码块内优先选中代码块)', keys: typoraKeys('editor.selectAll'), run: (view) => selectCodeBlock(view) || selectAll(view) },
|
||||
...Array.from({ length: 6 }, (_, i) => ({ id: `editor.heading${i + 1}`, title: `设置 ${i + 1} 级标题`, keys: typoraKeys(`editor.heading${i + 1}`), run: toggleHeading(i + 1) })),
|
||||
]
|
||||
|
||||
export const defaultEditorKeys: KeyBinding[] = editorCommands.flatMap((command) => command.keys.map((key) => ({ key: key.replaceAll('+', '-').replace(/-[A-Z]$/, (letter) => letter.toLowerCase()), run: command.run, preventDefault: true })))
|
||||
Reference in new issue
Block a user