Skip to content

Commit

Permalink
Working version
Browse files Browse the repository at this point in the history
  • Loading branch information
pokey committed Nov 8, 2021
1 parent d346f5a commit c06bcec
Show file tree
Hide file tree
Showing 9 changed files with 102 additions and 24 deletions.
11 changes: 4 additions & 7 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import canonicalizeActionName from "./util/canonicalizeActionName";
import { mkdir, stat } from "fs/promises";
import { join } from "path";
import { getPrimitiveTargets } from "./util/targetUtils";
import { doTargetsUseSnapshot } from "./util/doTargetsRequireSnapshot";

export async function activate(context: vscode.ExtensionContext) {
const fontMeasurements = new FontMeasurements(context);
Expand Down Expand Up @@ -124,13 +125,8 @@ export async function activate(context: vscode.ExtensionContext) {
inputExtraArgs
);

if (
getPrimitiveTargets(partialTargets).some(
(partialTarget) =>
partialTarget.mark?.type === "decoratedSymbol" &&
partialTarget.mark.useSnapshot
)
) {
const useSnapshot = doTargetsUseSnapshot(partialTargets);
if (useSnapshot) {
await graph.navigationMap.maybeTakeSnapshot();
}

Expand Down Expand Up @@ -175,6 +171,7 @@ export async function activate(context: vscode.ExtensionContext) {
sourceMark,
navigationMap: graph.navigationMap!,
spokenForm,
useSnapshot,
};
await testCaseRecorder.preCommandHook(command, context);
}
Expand Down
26 changes: 26 additions & 0 deletions src/test/suite/fixtures/recorded/navigationMap/takeHarp.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
spokenForm: take harp
languageId: plaintext
command:
actionName: setSelection
partialTargets:
- type: primitive
mark: {type: decoratedSymbol, symbolColor: default, character: h, useSnapshot: true}
extraArgs: []
initialState:
documentContents: hello world
selections:
- anchor: {line: 0, character: 11}
active: {line: 0, character: 11}
marks:
default.h:
start: {line: 0, character: 0}
end: {line: 0, character: 5}
finalState:
documentContents: hello world
selections:
- anchor: {line: 0, character: 0}
active: {line: 0, character: 5}
thatMark:
- anchor: {line: 0, character: 0}
active: {line: 0, character: 5}
fullTargets: [{type: primitive, mark: {type: decoratedSymbol, symbolColor: default, character: h, useSnapshot: true}, selectionType: token, position: contents, insideOutsideType: inside, modifier: {type: identity}}]
7 changes: 6 additions & 1 deletion src/test/suite/recorded.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
} from "../../util/getExtensionApi";
import { enableDebugLog } from "../../util/debug";
import { extractTargetedMarks } from "../../testUtil/extractTargetedMarks";
import { doTargetsUseSnapshot } from "../../util/doTargetsRequireSnapshot";

function createPosition(position: PositionPlainObject) {
return new vscode.Position(position.line, position.character);
Expand Down Expand Up @@ -108,6 +109,9 @@ async function runTest(file: string) {
// Assert that recorded decorations are present
checkMarks(fixture.initialState.marks, cursorlessApi.navigationMap);

const useSnapshot = doTargetsUseSnapshot(fixture.command.partialTargets);
// TODO: Issue the barrier if we need to

const returnValue = await vscode.commands.executeCommand(
"cursorless.command",
fixture.spokenForm,
Expand All @@ -122,7 +126,8 @@ async function runTest(file: string) {
: marksToPlainObject(
extractTargetedMarks(
Object.keys(fixture.finalState.marks) as string[],
cursorlessApi.navigationMap
cursorlessApi.navigationMap,
useSnapshot
)
);

Expand Down
5 changes: 3 additions & 2 deletions src/testUtil/TestCase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export type TestCaseContext = {
sourceMark: ThatMark;
targets: Target[];
navigationMap: NavigationMap;
useSnapshot: boolean;
};

export type TestCaseFixture = {
Expand Down Expand Up @@ -73,15 +74,15 @@ export class TestCase {
private getMarks() {
let marks: Record<string, Token>;

const { navigationMap } = this.context;
const { navigationMap, useSnapshot } = this.context;

if (this.isNavigationMapTest) {
// If we're doing a navigation map test, then we grab the entire
// navigation map because we'll filter it later based on the marks
// referenced in the expected follow up command
marks = Object.fromEntries(navigationMap.getEntries());
} else {
marks = extractTargetedMarks(this.targetKeys, navigationMap);
marks = extractTargetedMarks(this.targetKeys, navigationMap, useSnapshot);
}

return marksToPlainObject(marks);
Expand Down
9 changes: 7 additions & 2 deletions src/testUtil/extractTargetedMarks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,18 @@ export function extractTargetKeys(target: Target): string[] {

export function extractTargetedMarks(
targetKeys: string[],
navigationMap: NavigationMap
navigationMap: NavigationMap,
useSnapshot: boolean
) {
const targetedMarks: { [decoratedCharacter: string]: Token } = {};

targetKeys.forEach((key) => {
const { hatStyle, character } = NavigationMap.splitKey(key);
targetedMarks[key] = navigationMap.getToken(hatStyle, character);
targetedMarks[key] = navigationMap.getToken(
hatStyle,
character,
useSnapshot
);
});

return targetedMarks;
Expand Down
4 changes: 2 additions & 2 deletions src/util/canonicalizeAndValidateCommand.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import canonicalizeActionName from "./canonicalizeActionName";
import canonicalizeTargets from "./canonicalizeTargets";
import { ActionType, PartialTarget, SelectionType } from "../typings/Types";
import { getPrimitiveTargets } from "./targetUtils";
import { getPartialPrimitiveTargets } from "./targetUtils";

export function canonicalizeAndValidateCommand(
inputActionName: string,
Expand Down Expand Up @@ -40,7 +40,7 @@ function usesSelectionType(
selectionType: SelectionType,
partialTargets: PartialTarget[]
) {
return getPrimitiveTargets(partialTargets).some(
return getPartialPrimitiveTargets(partialTargets).some(
(partialTarget) => partialTarget.selectionType === selectionType
);
}
4 changes: 2 additions & 2 deletions src/util/canonicalizeTargets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
ScopeType,
} from "../typings/Types";
import update from "immutability-helper";
import { transformPrimitiveTargets } from "./targetUtils";
import { transformPartialPrimitiveTargets } from "./targetUtils";
import { HatStyleName } from "../core/constants";
import { flow } from "lodash";

Expand Down Expand Up @@ -43,7 +43,7 @@ const canonicalizeColors = (
: target;

export default function canonicalizeTargets(partialTargets: PartialTarget[]) {
return transformPrimitiveTargets(
return transformPartialPrimitiveTargets(
partialTargets,
flow(canonicalizeScopeTypes, canonicalizeColors)
);
Expand Down
19 changes: 19 additions & 0 deletions src/util/doTargetsRequireSnapshot.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { PartialTarget } from "../typings/Types";
import { uniq } from "lodash";
import { getPartialPrimitiveTargets } from "./targetUtils";

export function doTargetsUseSnapshot(targets: PartialTarget[]): boolean {
const snapshotIds = getPartialPrimitiveTargets(targets).map((target) =>
target.mark?.type === "decoratedSymbol"
? target.mark.useSnapshot
: undefined
);

const uniqueSnapshotIds = uniq(snapshotIds);

if (uniqueSnapshotIds.length !== 1) {
throw new Error("Must use the same snapshot id for all targets");
}

return uniqueSnapshotIds[0] ?? false;
}
41 changes: 33 additions & 8 deletions src/util/targetUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import {
PartialPrimitiveTarget,
PartialRangeTarget,
PartialTarget,
PrimitiveTarget,
Target,
TypedSelection,
} from "../typings/Types";

Expand Down Expand Up @@ -99,22 +101,43 @@ function createTypeSelection(
* @param targets The targets to extract from
* @returns A list of primitive targets
*/
export function getPrimitiveTargets(targets: PartialTarget[]) {
return targets.flatMap(getPrimitiveTargetsHelper);
export function getPartialPrimitiveTargets(targets: PartialTarget[]) {
return targets.flatMap(getPartialPrimitiveTargetsHelper);
}

function getPrimitiveTargetsHelper(
function getPartialPrimitiveTargetsHelper(
target: PartialTarget
): PartialPrimitiveTarget[] {
switch (target.type) {
case "primitive":
return [target];
case "list":
return target.elements.flatMap(getPrimitiveTargetsHelper);
return target.elements.flatMap(getPartialPrimitiveTargetsHelper);
case "range":
return [target.start, target.end];
}
}
/**
* Given a list of targets, recursively descends all targets and returns every
* contained primitive target.
*
* @param targets The targets to extract from
* @returns A list of primitive targets
*/
export function getPrimitiveTargets(targets: Target[]) {
return targets.flatMap(getPrimitiveTargetsHelper);
}

function getPrimitiveTargetsHelper(target: Target): PrimitiveTarget[] {
switch (target.type) {
case "primitive":
return [target];
case "list":
return target.elements.flatMap(getPrimitiveTargetsHelper);
case "range":
return [target.anchor, target.active];
}
}

/**
* Given a list of targets, recursively descends all targets and applies `func`
Expand All @@ -123,14 +146,16 @@ function getPrimitiveTargetsHelper(
* @param targets The targets to extract from
* @returns A list of primitive targets
*/
export function transformPrimitiveTargets(
export function transformPartialPrimitiveTargets(
targets: PartialTarget[],
func: (target: PartialPrimitiveTarget) => PartialPrimitiveTarget
) {
return targets.map((target) => transformPrimitiveTargetsHelper(target, func));
return targets.map((target) =>
transformPartialPrimitiveTargetsHelper(target, func)
);
}

function transformPrimitiveTargetsHelper(
function transformPartialPrimitiveTargetsHelper(
target: PartialTarget,
func: (target: PartialPrimitiveTarget) => PartialPrimitiveTarget
): PartialTarget {
Expand All @@ -142,7 +167,7 @@ function transformPrimitiveTargetsHelper(
...target,
elements: target.elements.map(
(element) =>
transformPrimitiveTargetsHelper(element, func) as
transformPartialPrimitiveTargetsHelper(element, func) as
| PartialPrimitiveTarget
| PartialRangeTarget
),
Expand Down

0 comments on commit c06bcec

Please sign in to comment.