0 works both ways now

This commit is contained in:
2025-10-19 15:09:41 +01:00
parent 47aea08d49
commit 07f218f4dd
4 changed files with 99 additions and 89 deletions
+7 -6
View File
@@ -90,12 +90,13 @@ export type CursorManager = {
moveToTop: () => void; moveToTop: () => void;
moveToBottom: () => void; moveToBottom: () => void;
repeatLastMotion: () => void; repeatLastMotion: () => void;
resetCount: () => void; resetCount: () => void;
getCount: () => string; getCount: () => string;
setCount: (digit: string) => void; hasCount: () => boolean;
setLastKey: (key: string) => void; setCount: (digit: string) => void;
getLastKey: () => string; setLastKey: (key: string) => void;
hero?: UseHeroType; getLastKey: () => string;
hero?: UseHeroType;
} }
export type HeroManager = { export type HeroManager = {
+79 -74
View File
@@ -78,61 +78,61 @@ export function useCursor(board: BoardManager, gameStatusManager: GameStatusMana
move(0, 1, count); move(0, 1, count);
} }
function moveToAnchor(target: 'start' | 'end' | 'top' | 'bottom'): void { function moveToAnchor(target: 'start' | 'end' | 'top' | 'bottom'): void {
const currentPos = position.current; const currentPos = position.current;
const direction = target === 'start' ? 'left' : const direction = target === 'start' ? 'left' :
target === 'end' ? 'right' : target === 'end' ? 'right' :
target === 'top' ? 'top' : 'bottom'; target === 'top' ? 'top' : 'bottom';
const anchorTarget = navigator.findAnchorTarget(currentPos, direction); const anchorTarget = navigator.findAnchorTarget(currentPos, direction);
if (!anchorTarget) return; if (!anchorTarget) return;
const dr = anchorTarget.row > currentPos.row ? 1 : const dr = anchorTarget.row > currentPos.row ? 1 :
anchorTarget.row < currentPos.row ? -1 : 0; anchorTarget.row < currentPos.row ? -1 : 0;
const dc = anchorTarget.col > currentPos.col ? 1 : const dc = anchorTarget.col > currentPos.col ? 1 :
anchorTarget.col < currentPos.col ? -1 : 0; anchorTarget.col < currentPos.col ? -1 : 0;
const steps = Math.abs(anchorTarget.row - currentPos.row) + Math.abs(anchorTarget.col - currentPos.col); const steps = Math.abs(anchorTarget.row - currentPos.row) + Math.abs(anchorTarget.col - currentPos.col);
position.current = anchorTarget; position.current = anchorTarget;
if (hero && hero.heroPos) { if (hero && hero.heroPos) {
hero.moveTo(anchorTarget); hero.moveTo(anchorTarget);
if (steps > 0) { if (steps > 0) {
vimMotions.setLastMotion({ dr, dc, steps }); vimMotions.setLastMotion({ dr, dc, steps });
} }
} }
} }
function moveToStart(): void { function moveToStart(): void {
if (!validateAnchorMove('start', position.current, board)) { if (!validateAnchorMove('start', position.current, board)) {
window.dispatchEvent(new Event("maze-invalid")); window.dispatchEvent(new Event("maze-invalid"));
return; return;
} }
moveToAnchor('start'); moveToAnchor('start');
} }
function moveToEnd(): void { function moveToEnd(): void {
if (!validateAnchorMove('end', position.current, board)) { if (!validateAnchorMove('end', position.current, board)) {
window.dispatchEvent(new Event("maze-invalid")); window.dispatchEvent(new Event("maze-invalid"));
return; return;
} }
moveToAnchor('end'); moveToAnchor('end');
} }
function moveToTop(): void { function moveToTop(): void {
if (!validateAnchorMove('top', position.current, board)) { if (!validateAnchorMove('top', position.current, board)) {
window.dispatchEvent(new Event("maze-invalid")); window.dispatchEvent(new Event("maze-invalid"));
return; return;
} }
moveToAnchor('top'); moveToAnchor('top');
} }
function moveToBottom(): void { function moveToBottom(): void {
if (!validateAnchorMove('bottom', position.current, board)) { if (!validateAnchorMove('bottom', position.current, board)) {
window.dispatchEvent(new Event("maze-invalid")); window.dispatchEvent(new Event("maze-invalid"));
return; return;
} }
moveToAnchor('bottom'); moveToAnchor('bottom');
} }
function repeatLastMotion(): void { function repeatLastMotion(): void {
const motion = vimMotions.repeatLastMotion(); const motion = vimMotions.repeatLastMotion();
@@ -156,13 +156,17 @@ export function useCursor(board: BoardManager, gameStatusManager: GameStatusMana
vimMotions.resetCount(); vimMotions.resetCount();
} }
function getCount(): string { function getCount(): string {
return String(vimMotions.getCount()); return String(vimMotions.getCount());
} }
function setCount(digit: string): void { function hasCount(): boolean {
vimMotions.processKey(digit); return vimMotions.hasCount();
} }
function setCount(digit: string): void {
vimMotions.processKey(digit);
}
function setLastKey(key: string): void { function setLastKey(key: string): void {
lastKeyRef.current = key; lastKeyRef.current = key;
@@ -172,26 +176,27 @@ export function useCursor(board: BoardManager, gameStatusManager: GameStatusMana
return lastKeyRef.current; return lastKeyRef.current;
} }
const cursor = { const cursor = {
position: () => position.current, position: () => position.current,
mode: () => mode.current, mode: () => mode.current,
move, move,
moveLeft, moveLeft,
moveRight, moveRight,
moveUp, moveUp,
moveDown, moveDown,
moveToStart, moveToStart,
moveToEnd, moveToEnd,
moveToTop, moveToTop,
moveToBottom, moveToBottom,
repeatLastMotion, repeatLastMotion,
resetCount, resetCount,
getCount, getCount,
setCount, hasCount,
setLastKey, setCount,
getLastKey, setLastKey,
hero, getLastKey,
} hero,
}
const keyManager = useGameKeys({ cursor, gameStatusManager }); const keyManager = useGameKeys({ cursor, gameStatusManager });
+6 -8
View File
@@ -34,17 +34,15 @@ export const useGameKeys = (props: UseGameKeysParams) => {
const handler = (ev: KeyboardEvent) => { const handler = (ev: KeyboardEvent) => {
if (["waiting", "game-over", "game-won"].includes(gameStatus)) return; if (["waiting", "game-over", "game-won"].includes(gameStatus)) return;
// "0" behaves like Vim: beginning of line if (ev.key === "0" && !cursor.hasCount()) {
if (ev.key === "0" && cursor.getCount() === "") { recordKey("0");
recordKey("0"); cursor.resetCount();
cursor.resetCount(); cursor.moveToStart();
cursor.moveToStart(); return;
return; }
}
const isDigit = ev.key >= "0" && ev.key <= "9"; const isDigit = ev.key >= "0" && ev.key <= "9";
if (isDigit) { if (isDigit) {
if (ev.key === "0" && cursor.getCount() === "") return;
recordKey(ev.key); recordKey(ev.key);
cursor.setCount(ev.key); cursor.setCount(ev.key);
return; return;
+6
View File
@@ -6,6 +6,7 @@ export type VimMotionSystem = {
processKey: (key: string) => { type: 'move'|'anchor'|'repeat'|'count', data: any } | null; processKey: (key: string) => { type: 'move'|'anchor'|'repeat'|'count', data: any } | null;
resetCount: () => void; resetCount: () => void;
getCount: () => number; getCount: () => number;
hasCount: () => boolean;
setLastMotion: (motion: Motion) => void; setLastMotion: (motion: Motion) => void;
repeatLastMotion: () => Motion | null; repeatLastMotion: () => Motion | null;
}; };
@@ -98,10 +99,15 @@ export function useVimMotions(): VimMotionSystem {
return lastMotionRef.current; return lastMotionRef.current;
} }
function hasCount(): boolean {
return countRef.current !== '';
}
return { return {
processKey, processKey,
resetCount, resetCount,
getCount, getCount,
hasCount,
setLastMotion, setLastMotion,
repeatLastMotion repeatLastMotion
}; };