aboutsummaryrefslogtreecommitdiffhomepage
path: root/docs/src/keymap-upgrade
diff options
context:
space:
mode:
authorJoel Spadin <[email protected]>2024-01-21 19:31:55 -0600
committerJoel Spadin <[email protected]>2024-01-25 18:03:37 -0600
commit37fcf190e682e1c3b72d9011dfb616268a649e5a (patch)
treeb6d9cb3ab964a32ddc114683722055c07f6f8dc0 /docs/src/keymap-upgrade
parent84e056793b7b1200f85317e97e9eaa527176633d (diff)
downloadzmk-37fcf190e682e1c3b72d9011dfb616268a649e5a.tar.gz
zmk-37fcf190e682e1c3b72d9011dfb616268a649e5a.zip
feat(keymap-upgrader): Highlight changes
Updated the keymap upgrader to highlight which lines it changed as well as indicate when nothing needed to be upgraded. Also adjusted the line highlight colors to be more readable in both light and dark color schemes.
Diffstat (limited to 'docs/src/keymap-upgrade')
-rw-r--r--docs/src/keymap-upgrade/index.ts36
-rw-r--r--docs/src/keymap-upgrade/keycodes.ts4
-rw-r--r--docs/src/keymap-upgrade/properties.ts4
-rw-r--r--docs/src/keymap-upgrade/textedit.ts85
4 files changed, 88 insertions, 41 deletions
diff --git a/docs/src/keymap-upgrade/index.ts b/docs/src/keymap-upgrade/index.ts
index 4d091e2376..3df9bb9df0 100644
--- a/docs/src/keymap-upgrade/index.ts
+++ b/docs/src/keymap-upgrade/index.ts
@@ -1,5 +1,5 @@
import { createParser } from "./parser";
-import { applyEdits } from "./textedit";
+import { applyEdits, Range } from "./textedit";
import { upgradeBehaviors } from "./behaviors";
import { upgradeHeaders } from "./headers";
@@ -23,3 +23,37 @@ export function upgradeKeymap(text: string) {
return applyEdits(text, edits);
}
+
+export function rangesToLineNumbers(
+ text: string,
+ changedRanges: Range[]
+): string {
+ const lineBreaks = getLineBreakPositions(text);
+
+ const changedLines = changedRanges.map((range) => {
+ const startLine = positionToLineNumber(range.startIndex, lineBreaks);
+ const endLine = positionToLineNumber(range.endIndex, lineBreaks);
+
+ return startLine === endLine ? `${startLine}` : `${startLine}-${endLine}`;
+ });
+
+ return `{${changedLines.join(",")}}`;
+}
+
+function getLineBreakPositions(text: string) {
+ const positions: number[] = [];
+ let index = 0;
+
+ while ((index = text.indexOf("\n", index)) >= 0) {
+ positions.push(index);
+ index++;
+ }
+
+ return positions;
+}
+
+function positionToLineNumber(position: number, lineBreaks: number[]) {
+ const line = lineBreaks.findIndex((lineBreak) => position <= lineBreak);
+
+ return line < 0 ? 0 : line + 1;
+}
diff --git a/docs/src/keymap-upgrade/keycodes.ts b/docs/src/keymap-upgrade/keycodes.ts
index 9a9ede667a..5069556c6e 100644
--- a/docs/src/keymap-upgrade/keycodes.ts
+++ b/docs/src/keymap-upgrade/keycodes.ts
@@ -101,7 +101,7 @@ export function upgradeKeycodes(tree: Tree) {
function keycodeReplaceHandler(node: SyntaxNode, replacement: string | null) {
if (replacement) {
- return [new TextEdit(node, replacement)];
+ return [TextEdit.fromNode(node, replacement)];
}
const nodes = findBehaviorNodes(node);
@@ -110,7 +110,7 @@ function keycodeReplaceHandler(node: SyntaxNode, replacement: string | null) {
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 */`)];
+ return [TextEdit.fromNode(node, `/* "${node.text}" no longer exists */`)];
}
const oldText = nodes.map((n) => n.text).join(" ");
diff --git a/docs/src/keymap-upgrade/properties.ts b/docs/src/keymap-upgrade/properties.ts
index 7edc555a9f..1cd3210fed 100644
--- a/docs/src/keymap-upgrade/properties.ts
+++ b/docs/src/keymap-upgrade/properties.ts
@@ -24,9 +24,9 @@ function removeLabels(tree: Tree) {
const node = findCapture("prop", captures);
if (name?.text === "label" && node) {
if (isLayerLabel(node)) {
- edits.push(new TextEdit(name, "display-name"));
+ edits.push(TextEdit.fromNode(name, "display-name"));
} else {
- edits.push(new TextEdit(node, ""));
+ edits.push(TextEdit.fromNode(node, ""));
}
}
}
diff --git a/docs/src/keymap-upgrade/textedit.ts b/docs/src/keymap-upgrade/textedit.ts
index a791c1a6cb..263b2ab815 100644
--- a/docs/src/keymap-upgrade/textedit.ts
+++ b/docs/src/keymap-upgrade/textedit.ts
@@ -1,40 +1,23 @@
import type { SyntaxNode } from "web-tree-sitter";
-export class TextEdit {
- startIndex: number;
- endIndex: number;
+export class Range {
+ constructor(public startIndex: number, public endIndex: number) {}
+}
+
+export class TextEdit extends Range {
newText: string;
/**
* Creates a text edit to replace a range with new text.
*/
- constructor(startIndex: number, endIndex: number, newText: string);
- /**
- * Creates a text edit to replace a node with new text.
- */
- constructor(node: SyntaxNode, newText: string);
- constructor(
- startIndex: number | SyntaxNode,
- endIndex: number | string,
- newText?: string
- ) {
- if (typeof startIndex !== "number") {
- if (typeof endIndex === "string") {
- const node = startIndex;
- newText = endIndex;
- startIndex = node.startIndex;
- endIndex = node.endIndex;
- } else {
- throw new TypeError();
- }
- } else if (typeof endIndex !== "number" || typeof newText !== "string") {
- throw new TypeError();
- }
-
- this.startIndex = startIndex;
- this.endIndex = endIndex;
+ constructor(startIndex: number, endIndex: number, newText: string) {
+ super(startIndex, endIndex);
this.newText = newText;
}
+
+ static fromNode(node: SyntaxNode | Range, newText: string) {
+ return new TextEdit(node.startIndex, node.endIndex, newText);
+ }
}
export type MatchFunc = (node: SyntaxNode, text: string) => boolean;
@@ -67,7 +50,7 @@ export function getUpgradeEdits(
isMatch?: MatchFunc
) {
const defaultReplace: ReplaceFunc = (node, replacement) => [
- new TextEdit(node, replacement ?? ""),
+ TextEdit.fromNode(node, replacement ?? ""),
];
const defaultMatch: MatchFunc = (node, text) => node.text === text;
@@ -89,16 +72,26 @@ function sortEdits(edits: TextEdit[]) {
return edits.sort((a, b) => a.startIndex - b.startIndex);
}
+export interface EditResult {
+ text: string;
+ changedRanges: Range[];
+}
+
+interface TextChunk {
+ text: string;
+ changed?: boolean;
+}
+
/**
- * Returns a string with text replacements applied.
+ * Returns a string with text replacements applied and a list of ranges within
+ * that string that were modified.
*/
export function applyEdits(text: string, edits: TextEdit[]) {
// If we are removing text and it's the only thing on a line, remove the whole line.
edits = edits.map((e) => (e.newText ? e : expandEditToLine(text, e)));
-
edits = sortEdits(edits);
- const chunks: string[] = [];
+ const chunks: TextChunk[] = [];
let currentIndex = 0;
for (let edit of edits) {
@@ -107,14 +100,34 @@ export function applyEdits(text: string, edits: TextEdit[]) {
continue;
}
- chunks.push(text.substring(currentIndex, edit.startIndex));
- chunks.push(edit.newText);
+ chunks.push({ text: text.substring(currentIndex, edit.startIndex) });
+ chunks.push({ text: edit.newText, changed: true });
currentIndex = edit.endIndex;
}
- chunks.push(text.substring(currentIndex));
+ chunks.push({ text: text.substring(currentIndex) });
+
+ // Join all of the text chunks while recording the ranges of any chunks that were changed.
+ return chunks.reduce<EditResult>(
+ (prev, current) => {
+ return {
+ text: prev.text + current.text,
+ changedRanges: reduceChangedRanges(prev, current),
+ };
+ },
+ { text: "", changedRanges: [] }
+ );
+}
+
+function reduceChangedRanges(prev: EditResult, current: TextChunk): Range[] {
+ if (current.changed) {
+ return [
+ ...prev.changedRanges,
+ new Range(prev.text.length, prev.text.length + current.text.length),
+ ];
+ }
- return chunks.join("");
+ return prev.changedRanges;
}
/**