import { keymap } from '@codemirror/view' import { Prec } from '@codemirror/state' import { indentMore } from '../commands/indent' import { indentLess, redo, deleteLine, toggleLineComment, cursorLineBoundaryBackward, selectLineBoundaryBackward, cursorLineBoundaryForward, selectLineBoundaryForward, cursorSyntaxLeft, selectSyntaxLeft, cursorSyntaxRight, selectSyntaxRight, } from '@codemirror/commands' import { changeCase, duplicateSelection } from '../commands/ranges' import { selectNextOccurrence, selectPrevOccurrence } from '../commands/select' import { cloneSelectionVertically } from '../commands/cursor' import { deleteToVisualLineEnd, deleteToVisualLineStart, } from './visual-line-selection' import { emitShortcutEvent } from '@/features/source-editor/extensions/toolbar/utils/analytics' import { sendMB } from '@/infrastructure/event-tracking' const toggleReviewPanel = () => { window.dispatchEvent(new Event('ui.toggle-review-panel')) return true } const addNewCommentFromKbdShortcut = () => { sendMB('add-comment', { location: 'shortcut', }) window.dispatchEvent(new Event('add-new-review-comment')) return true } const toggleTrackChangesFromKbdShortcut = () => { window.dispatchEvent(new Event('toggle-track-changes')) return true } /** * Custom key bindings for motion, transformation, selection, history, etc. */ export const shortcuts = Prec.high( keymap.of([ { key: 'Tab', run: indentMore, // note: not using indentWithTab as the user may want to insert tab spaces within a line }, { key: 'Shift-Tab', run: indentLess, // note: not using indentWithTab as the user may want to insert tab spaces within a line }, { key: 'Mod-y', preventDefault: true, run: redo, }, { key: 'Mod-Shift-z', preventDefault: true, run: redo, }, // defaultKeymap maps Mod-/ to toggleLineComment, but // w3c-keyname has a hard-coded mapping of Shift+key => character // which uses a US keyboard layout, so we need to add more mappings. // Mod-/, but Spanish, Portuguese, German and Swedish keyboard layouts have / at Shift+7 // (keyCode 55, mapped with Shift to &) { key: 'Mod-&', preventDefault: true, run: toggleLineComment, }, // Mod-/, but German keyboard layouts have / at Cmd+Shift+ß // Mod-/, but Czech keyboard layouts have / at Shift-ú // (keyCode 191, mapped with Shift to ?) { key: 'Mod-?', preventDefault: true, run: toggleLineComment, }, // German keyboard layouts map 0xBF to #, // so VS Code on Windows/Linux uses Ctrl-# to toggle line comments. // This is an additional, undocumented shortcut for compatibility. { key: 'Ctrl-#', preventDefault: true, run: toggleLineComment, }, { key: 'Ctrl-u', preventDefault: true, run: changeCase(true), // uppercase }, { key: 'Ctrl-Shift-u', preventDefault: true, run: changeCase(false), // lowercase }, { key: 'Mod-d', preventDefault: true, run(view) { emitShortcutEvent(view, 'delete-line') return deleteLine(view) }, }, { key: 'Mod-j', preventDefault: true, run: toggleReviewPanel, }, { key: 'Ctrl-Shift-c', preventDefault: true, run: addNewCommentFromKbdShortcut, }, { key: 'Cmd-Shift-c', preventDefault: true, run: addNewCommentFromKbdShortcut, }, { key: 'Mod-Shift-a', preventDefault: true, run: toggleTrackChangesFromKbdShortcut, }, { key: 'Cmd-Alt-ArrowUp', preventDefault: true, run: cloneSelectionVertically(false, true, 'cmd'), }, { key: 'Cmd-Alt-ArrowDown', preventDefault: true, run: cloneSelectionVertically(true, true, 'cmd'), }, { key: 'Cmd-Alt-Shift-ArrowUp', preventDefault: true, run: cloneSelectionVertically(false, false, 'cmd'), }, { key: 'Cmd-Alt-Shift-ArrowDown', preventDefault: true, run: cloneSelectionVertically(true, false, 'cmd'), }, // Duplicates of the above commands, // allowing Ctrl instead of Command (but still tracking the events separately). // Note: both Ctrl and Commmand versions need to work on macOS, for backwards compatibility, // so the duplicates shouldn't simply be combined to use `Mod-`. { key: 'Ctrl-Alt-ArrowUp', preventDefault: true, run: cloneSelectionVertically(false, true, 'ctrl'), }, { key: 'Ctrl-Alt-ArrowDown', preventDefault: true, run: cloneSelectionVertically(true, true, 'ctrl'), }, { key: 'Ctrl-Alt-Shift-ArrowUp', preventDefault: true, run: cloneSelectionVertically(false, false, 'ctrl'), }, { key: 'Ctrl-Alt-Shift-ArrowDown', preventDefault: true, run: cloneSelectionVertically(true, false, 'ctrl'), }, { key: 'Ctrl-Alt-ArrowLeft', preventDefault: true, run(view) { emitShortcutEvent(view, 'select-prev-occurrence') return selectPrevOccurrence(view) }, }, { key: 'Ctrl-Alt-ArrowRight', preventDefault: true, run(view) { emitShortcutEvent(view, 'select-next-occurrence') return selectNextOccurrence(view) }, }, { key: 'Mod-Shift-d', run: duplicateSelection, }, { win: 'Alt-ArrowLeft', linux: 'Alt-ArrowLeft', run: cursorLineBoundaryBackward, shift: selectLineBoundaryBackward, preventDefault: true, }, { win: 'Alt-ArrowRight', linux: 'Alt-ArrowRight', run: cursorLineBoundaryForward, shift: selectLineBoundaryForward, preventDefault: true, }, { mac: 'Ctrl-ArrowLeft', run: cursorSyntaxLeft, shift: selectSyntaxLeft, }, { mac: 'Ctrl-ArrowRight', run: cursorSyntaxRight, shift: selectSyntaxRight, }, { mac: 'Cmd-Backspace', run: deleteToVisualLineStart, }, { mac: 'Cmd-Delete', run: deleteToVisualLineEnd, }, ]) )