forked from kofal.net/zmk
refactor: Improve keymap upgrader
Moved the keymap upgrader to a top-level page like the power profiler to make it more discoverable. It upgrades more things than key codes now, so putting it in the codes category doesn't make much sense. Converted the upgrader code to TypeScript and split it up into smaller files to make it easier to add new upgrade functions. Added upgrade functions to remove/replace "label" properties and rename matrix-transform.h to matrix_transform.h.
This commit is contained in:
150
docs/src/keymap-upgrade/keycodes.ts
Normal file
150
docs/src/keymap-upgrade/keycodes.ts
Normal file
@@ -0,0 +1,150 @@
|
||||
import type { SyntaxNode, Tree } from "web-tree-sitter";
|
||||
import { Devicetree, findCapture } from "./parser";
|
||||
import { getUpgradeEdits, TextEdit } from "./textedit";
|
||||
|
||||
// Map of { "DEPRECATED": "REPLACEMENT" } key codes.
|
||||
const CODES = {
|
||||
NUM_1: "N1",
|
||||
NUM_2: "N2",
|
||||
NUM_3: "N3",
|
||||
NUM_4: "N4",
|
||||
NUM_5: "N5",
|
||||
NUM_6: "N6",
|
||||
NUM_7: "N7",
|
||||
NUM_8: "N8",
|
||||
NUM_9: "N9",
|
||||
NUM_0: "N0",
|
||||
BKSP: "BSPC",
|
||||
SPC: "SPACE",
|
||||
EQL: "EQUAL",
|
||||
TILD: "TILDE",
|
||||
SCLN: "SEMI",
|
||||
QUOT: "SQT",
|
||||
GRAV: "GRAVE",
|
||||
CMMA: "COMMA",
|
||||
PRSC: "PSCRN",
|
||||
SCLK: "SLCK",
|
||||
PAUS: "PAUSE_BREAK",
|
||||
PGUP: "PG_UP",
|
||||
PGDN: "PG_DN",
|
||||
RARW: "RIGHT",
|
||||
LARW: "LEFT",
|
||||
DARW: "DOWN",
|
||||
UARW: "UP",
|
||||
KDIV: "KP_DIVIDE",
|
||||
KMLT: "KP_MULTIPLY",
|
||||
KMIN: "KP_MINUS",
|
||||
KPLS: "KP_PLUS",
|
||||
UNDO: "K_UNDO",
|
||||
CUT: "K_CUT",
|
||||
COPY: "K_COPY",
|
||||
PSTE: "K_PASTE",
|
||||
VOLU: "K_VOL_UP",
|
||||
VOLD: "K_VOL_DN",
|
||||
CURU: "DLLR",
|
||||
LPRN: "LPAR",
|
||||
RPRN: "RPAR",
|
||||
LCUR: "LBRC",
|
||||
RCUR: "RBRC",
|
||||
CRRT: "CARET",
|
||||
PRCT: "PRCNT",
|
||||
LABT: "LT",
|
||||
RABT: "GT",
|
||||
COLN: "COLON",
|
||||
KSPC: null,
|
||||
ATSN: "AT",
|
||||
BANG: "EXCL",
|
||||
LCTL: "LCTRL",
|
||||
LSFT: "LSHIFT",
|
||||
RCTL: "RCTRL",
|
||||
RSFT: "RSHIFT",
|
||||
M_NEXT: "C_NEXT",
|
||||
M_PREV: "C_PREV",
|
||||
M_STOP: "C_STOP",
|
||||
M_EJCT: "C_EJECT",
|
||||
M_PLAY: "C_PP",
|
||||
M_MUTE: "C_MUTE",
|
||||
M_VOLU: "C_VOL_UP",
|
||||
M_VOLD: "C_VOL_DN",
|
||||
GUI: "K_CMENU",
|
||||
MOD_LCTL: "LCTRL",
|
||||
MOD_LSFT: "LSHIFT",
|
||||
MOD_LALT: "LALT",
|
||||
MOD_LGUI: "LGUI",
|
||||
MOD_RCTL: "RCTRL",
|
||||
MOD_RSFT: "RSHIFT",
|
||||
MOD_RALT: "RALT",
|
||||
MOD_RGUI: "RGUI",
|
||||
};
|
||||
|
||||
/**
|
||||
* Upgrades deprecated key code identifiers.
|
||||
*/
|
||||
export function upgradeKeycodes(tree: Tree) {
|
||||
const edits: TextEdit[] = [];
|
||||
|
||||
// No need to filter to the bindings array. The C preprocessor would have
|
||||
// replaced identifiers anywhere, so upgrading all identifiers preserves the
|
||||
// original behavior of the keymap (even if that behavior wasn't intended).
|
||||
const query = Devicetree.query("(identifier) @name");
|
||||
const matches = query.matches(tree.rootNode);
|
||||
|
||||
for (const { captures } of matches) {
|
||||
const node = findCapture("name", captures);
|
||||
if (node) {
|
||||
edits.push(...getUpgradeEdits(node, CODES, keycodeReplaceHandler));
|
||||
}
|
||||
}
|
||||
|
||||
return edits;
|
||||
}
|
||||
|
||||
function keycodeReplaceHandler(node: SyntaxNode, replacement: string | null) {
|
||||
if (replacement) {
|
||||
return [new TextEdit(node, replacement)];
|
||||
}
|
||||
|
||||
const nodes = findBehaviorNodes(node);
|
||||
|
||||
if (nodes.length === 0) {
|
||||
console.warn(
|
||||
`Found deprecated code "${node.text}" but it is not a parameter to a behavior`
|
||||
);
|
||||
return [new TextEdit(node, `/* "${node.text}" no longer exists */`)];
|
||||
}
|
||||
|
||||
const oldText = nodes.map((n) => n.text).join(" ");
|
||||
const newText = `&none /* "${oldText}" no longer exists */`;
|
||||
|
||||
const startIndex = nodes[0].startIndex;
|
||||
const endIndex = nodes[nodes.length - 1].endIndex;
|
||||
|
||||
return [new TextEdit(startIndex, endIndex, newText)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a parameter to a keymap behavior, returns a list of nodes beginning
|
||||
* with the behavior and including all parameters.
|
||||
* Returns an empty array if no behavior was found.
|
||||
*/
|
||||
function findBehaviorNodes(paramNode: SyntaxNode) {
|
||||
// Walk backwards from the given parameter to find the behavior reference.
|
||||
let behavior = paramNode.previousNamedSibling;
|
||||
while (behavior && behavior.type !== "reference") {
|
||||
behavior = behavior.previousNamedSibling;
|
||||
}
|
||||
|
||||
if (!behavior) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Walk forward from the behavior to collect all its parameters.
|
||||
let nodes = [behavior];
|
||||
let param = behavior.nextNamedSibling;
|
||||
while (param && param.type !== "reference") {
|
||||
nodes.push(param);
|
||||
param = param.nextNamedSibling;
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
Reference in New Issue
Block a user