Skip to content

Commit

Permalink
Added branch navigation shortcuts
Browse files Browse the repository at this point in the history
Fixed starting pos bugs + added tests
  • Loading branch information
Cankyre committed Apr 19, 2024
1 parent 75f93b5 commit b18e29c
Show file tree
Hide file tree
Showing 4 changed files with 163 additions and 2 deletions.
9 changes: 9 additions & 0 deletions src/components/common/MoveControls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,22 @@ function MoveControls({
const start = useStore(store, (s) => s.goToStart);
const end = useStore(store, (s) => s.goToEnd);
const deleteMove = useStore(store, (s) => s.deleteMove);
const startBranch = useStore(store, (s) => s.goToBranchStart);
const endBranch = useStore(store, (s) => s.goToBranchEnd);
const nextBranch = useStore(store, (s) => s.nextBranch);
const previousBranch = useStore(store, (s) => s.previousBranch);

const keyMap = useAtomValue(keyMapAtom);
useHotkeys(keyMap.PREVIOUS_MOVE.keys, previous);
useHotkeys(keyMap.NEXT_MOVE.keys, next);
useHotkeys(keyMap.GO_TO_START.keys, start);
useHotkeys(keyMap.GO_TO_END.keys, end);
useHotkeys(keyMap.DELETE_MOVE.keys, readOnly ? () => {} : () => deleteMove());
useHotkeys(keyMap.GO_TO_BRANCH_START.keys, startBranch);
useHotkeys(keyMap.GO_TO_BRANCH_END.keys, endBranch);
useHotkeys(keyMap.NEXT_BRANCH.keys, nextBranch);
useHotkeys(keyMap.PREVIOUS_BRANCH.keys, previousBranch);

return (
<Group grow gap="xs">
<ActionIcon variant="default" size="lg" onClick={start}>
Expand Down
8 changes: 6 additions & 2 deletions src/state/keybinds.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,12 @@ const keys = {
CLEAR_SHAPES: { name: "Clear shapes", keys: "ctrl+l" },
NEXT_MOVE: { name: "Next move", keys: "arrowright" },
PREVIOUS_MOVE: { name: "Previous move", keys: "arrowleft" },
GO_TO_START: { name: "Go to start of game", keys: "arrowup" },
GO_TO_END: { name: "Go to end of game", keys: "arrowdown" },
GO_TO_BRANCH_START: { name: "Go to start of branch", keys: "arrowup" },
GO_TO_BRANCH_END: { name: "Go to end of branch", keys: "arrowdown" },
GO_TO_START: { name: "Go to start of game", keys: "shift+arrowup" },
GO_TO_END: { name: "Go to end of game", keys: "shift+arrowdown" },
NEXT_BRANCH: { name: "Next branch", keys: "shift+arrowright" },
PREVIOUS_BRANCH: { name: "Previous branch", keys: "shift+arrowleft" },
DELETE_MOVE: { name: "Delete move", keys: "delete" },
CYCLE_TABS: { name: "Cycle tabs", keys: "ctrl+tab" },
REVERSE_CYCLE_TABS: { name: "Reverse cycle tabs", keys: "ctrl+shift+tab" },
Expand Down
80 changes: 80 additions & 0 deletions src/state/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ export interface TreeStoreState {
goToStart: () => void;
goToEnd: () => void;
goToMove: (move: number[]) => void;
goToBranchStart: () => void;
goToBranchEnd: () => void;
nextBranch: () => void;
previousBranch: () => void;

goToAnnotation: (annotation: Annotation, color: "white" | "black") => void;

Expand Down Expand Up @@ -245,6 +249,82 @@ export const createTreeStore = (id?: string, initialTree?: TreeState) => {
...state,
position: move,
})),
goToBranchStart: () => {
set(
produce((state) => {
if (
state.position.length > 0 &&
state.position[state.position.length - 1] !== 0
) {
state.position = state.position.slice(0, -1);
}

while (
state.position.length > 0 &&
state.position[state.position.length - 1] === 0
) {
state.position = state.position.slice(0, -1);
}
}),
);
},

goToBranchEnd: () => {
set(
produce((state) => {
let currentNode = getNodeAtPath(state.root, state.position);
while (currentNode.children.length > 0) {
state.position.push(0);
currentNode = currentNode.children[0];
}
}),
);
},

nextBranch: () =>
set(
produce((state) => {
if (state.position.length === 0) return state;

let branchIndex = state.position[state.position.length - 1];
let branchCount = getNodeAtPath(state.root, state.position).children
.length;

while (state.position.length > 0 && branchCount <= 1) {
branchIndex = state.position[state.position.length - 1];
state.position = state.position.slice(0, -1);
branchCount = getNodeAtPath(state.root, state.position).children
.length;
}

const currentNode = getNodeAtPath(state.root, state.position);
state.position.push((branchIndex + 1) % currentNode.children.length);
}),
),
previousBranch: () =>
set(
produce((state) => {
if (state.position.length === 0) return state;

let branchIndex = state.position[state.position.length - 1];
let branchCount = getNodeAtPath(state.root, state.position).children
.length;

while (state.position.length > 0 && branchCount <= 1) {
branchIndex = state.position[state.position.length - 1];
state.position = state.position.slice(0, -1);
branchCount = getNodeAtPath(state.root, state.position).children
.length;
}

const currentNode = getNodeAtPath(state.root, state.position);
state.position.push(
(branchIndex + currentNode.children.length - 1) %
currentNode.children.length,
);
}),
),

deleteMove: (path) =>
set(
produce((state) => {
Expand Down
68 changes: 68 additions & 0 deletions src/utils/tests/store.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,74 @@ test("should handle goToPrevious", () => {
});
});

test("should handle nextBranch", () => {
store.setState({ ...treeE4D5Nf3(), position: [] });
store.getState().nextBranch();

expect(getNewState()).toStrictEqual({
...treeE4D5Nf3(),
position: [],
});

store.setState({ ...treeE4D5Nf3(), position: [0, 0] });

store.getState().nextBranch();
expect(getNewState()).toStrictEqual({
...treeE4D5Nf3(),
position: [1],
});

store.getState().nextBranch();

expect(getNewState()).toStrictEqual({
...treeE4D5Nf3(),
position: [0],
});
});

test("should handle previousBranch", () => {
store.setState({ ...treeE4D5Nf3(), position: [] });
store.getState().previousBranch();

expect(getNewState()).toStrictEqual({
...treeE4D5Nf3(),
position: [],
});

store.setState({ ...treeE4D5Nf3(), position: [0, 0] });
store.getState().previousBranch();
expect(getNewState()).toStrictEqual({
...treeE4D5Nf3(),
position: [1],
});

store.getState().previousBranch();
expect(getNewState()).toStrictEqual({
...treeE4D5Nf3(),
position: [0],
});
});

test("should handle goToBranchEnd", () => {
store.setState({ ...treeE4D5(), position: [] });
store.getState().goToBranchEnd();

expect(getNewState()).toStrictEqual({
...treeE4D5(),
position: [0, 0],
});
});

test("should handle goToBranchStart", () => {
store.setState({ ...treeE4D5(), position: [0, 0] });
store.getState().goToBranchStart();

expect(getNewState()).toStrictEqual({
...treeE4D5(),
position: [],
});
});

test("should handle goToMove", () => {
store.setState({ ...treeE4D5(), position: [] });
store.getState().goToMove([0]);
Expand Down

0 comments on commit b18e29c

Please sign in to comment.