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:
Joel Spadin
2024-01-21 17:15:58 -06:00
parent 1a3529a3e6
commit a0465391be
14 changed files with 528 additions and 337 deletions

View 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;
}