Keybindings
Register editing and indentation keymaps, use feature shortcuts, and add your own bindings.
Two extensions provide general editing shortcuts. DefaultKeymapExtension adds standard editing
and search bindings. KeybindExtension adds Tab indentation using the editor’s tabSize option.
Setup
Import both extensions from the keybinds subpath and register them with the editor:
import { Editor } from "@inksane/core";
import { DefaultKeymapExtension, KeybindExtension } from "@inksane/core/extensions/keybinds";
const editor = new Editor({
element: document.getElementById("editor")!,
tabSize: 4,
extensions: [KeybindExtension, DefaultKeymapExtension],
});Create the mount element before this code runs. Register only KeybindExtension if you want Tab
indentation without the standard editing keymap. BaseKit includes both extensions.
The default keymap
The default keymap is composed from CodeMirror’s defaultKeymap, searchKeymap, and
indentWithTab. Register DefaultKeymapExtension to enable it.
Standard editing keys include:
- Word and line deletion, such as
Mod-BackspaceandShift-Mod-k. - Line movement and selection, such as
Alt-ArrowUp,Mod-], andMod-/. - Home, End, page, and arrow navigation, with the usual
Shiftvariants for selection. - Select all on
Mod-a.
Enter inserts a plain newline and Backspace deletes a character. Core leaves out the Markdown language keymap so it does not override registered editing shortcuts with list or quote continuation.
Search keys include:
Mod-fopens the Find panel.Mod-gandF3find the next match, withShiftfor the previous one.Mod-dselects the next occurrence.Mod-Alt-gjumps to a line.
Indentation
Tab indents the selected lines, or the current line when nothing is selected. Shift+Tab dedents. The
KeybindExtension owns these bindings and honors the tabSize option, which defaults to 2.
The commands return false when there is nothing to indent, for example when a dedent would go past
the start of a line, and the key is left to the browser. indentWithTab from the default keymap
is a fallback when DefaultKeymapExtension is also registered. It uses CodeMirror’s language
indentation rather than the editor’s tabSize.
Precedence
Within BaseKit, feature bindings precede the default keymap. When registering individual
extensions, put feature keymaps before DefaultKeymapExtension or give them a higher priority.
Undo and redo (Mod-z, Mod-y, Mod-Shift-z) come from the history
extension, which owns its own keymap.
Bindings inksane adds
Each binding is active only when its extension is registered. Mod is Cmd on macOS and Ctrl on
Windows and Linux.
| Keys | Action | From |
|---|---|---|
Mod-b | Bold | Bold |
Mod-i | Italic | Italic |
Mod-Shift-x | Strikethrough | Strikethrough |
Mod-k | Link, when onLinkRequest is set | Link |
Mod-. | Inline code | Code |
Mod-Shift-. | Code block | Code |
Mod-Shift-> | Code block | Code |
Mod-Shift-- | Horizontal rule | Horizontal rule |
Mod-z | Undo | History |
Mod-y | Redo | History |
Mod-Shift-z | Redo | History |
Tab | Indent the selection or the line | keybinds |
Shift-Tab | Dedent the selection or the line | keybinds |
ArrowUp | Move into an adjacent HTML block | HTML |
ArrowDown | Move into an adjacent HTML block | HTML |
The arrow keys only take over when the cursor would otherwise skip past an HTML block. Everything
else, such as Mod-a, Mod-f, or Mod-d, comes from the default keymap described above.
Opt out
The editor no longer has a defaultKeymap option. Disable that feature in BaseKit:
import { Editor } from "@inksane/core";
import { BaseKit } from "@inksane/core/extensions/base-kit";
const editor = new Editor({
element: document.getElementById("editor")!,
extensions: [BaseKit({ defaultKeymap: false })],
});The kit’s Tab indentation stays enabled. Pass BaseKit({ defaultKeymap: false, keybinds: false })
to disable both general keymap extensions. Individually registered editors can simply omit them.
Replace or extend
Disable the kit’s keymap before registering a replacement. An extension with the same name does not replace it automatically:
import { Editor } from "@inksane/core";
import { BaseKit } from "@inksane/core/extensions/base-kit";
import { defaultKeymap, selectAll } from "@codemirror/commands";
const editor = new Editor({
element: document.getElementById("editor")!,
extensions: [
BaseKit({ defaultKeymap: false }),
{
name: "defaultKeymap",
addKeybinds: () => [...defaultKeymap, { key: "Mod-Shift-a", run: selectAll }],
},
],
});The replacement defines the complete keymap. Add searchKeymap from @codemirror/search if you
want to retain the standard search shortcuts.
Add your own
Return CodeMirror KeyBinding objects from addKeybinds. The callback returns whether it handled
the key. This example inserts a timestamp using a core document command:
import { Editor, type Extension } from "@inksane/core";
import { BaseKit } from "@inksane/core/extensions/base-kit";
const TimestampShortcut: Extension = {
name: "timestamp-shortcut",
priority: 10,
addKeybinds({ editor }) {
return [
{
key: "Mod-Shift-t",
run() {
const { from, to } = editor.state.selection.main;
return editor.commands.insertContent({
content: new Date().toISOString(),
from,
to,
});
},
},
];
},
};
const editor = new Editor({
element: document.getElementById("editor")!,
extensions: [BaseKit(), TimestampShortcut],
});See write your own extension for the full pattern.