Skip to content

Support "instance" scope type #1490

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ export type SimpleScopeTypeType =
| "identifier"
| "nonWhitespaceSequence"
| "boundedNonWhitespaceSequence"
| "instance"
| "url";

export interface SimpleScopeType {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ function usesScopeType(
);
}

export async function checkForOldInference(
export function checkForOldInference(
partialTargets: PartialTargetDescriptor[],
) {
const hasOldInference = partialTargets.some((target) => {
Expand All @@ -136,16 +136,16 @@ export async function checkForOldInference(
const hideInferenceWarning = globalState.get("hideInferenceWarning");

if (!hideInferenceWarning) {
const pressed = await showWarning(
showWarning(
messages,
"deprecatedPositionInference",
'The "past start of" / "past end of" form has changed behavior. For the old behavior, update cursorless-talon (https://www.cursorless.org/docs/user/updating/), and then you can now say "past start of its" / "past end of its". For example, "take air past end of its line". You may also consider using "head" / "tail" instead; see https://www.cursorless.org/docs/#head-and-tail',
"Don't show again",
);

if (pressed) {
globalState.set("hideInferenceWarning", true);
}
).then((pressed) => {
if (pressed) {
globalState.set("hideInferenceWarning", true);
}
});
}
}
}
48 changes: 27 additions & 21 deletions packages/cursorless-engine/src/core/inferFullTargets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,13 @@ import {
PartialTargetDescriptor,
PositionModifier,
} from "@cursorless/common";
import { findLastIndex } from "lodash";
import {
EveryRangeTargetDescriptor,
PrimitiveTargetDescriptor,
RangeTargetDescriptor,
TargetDescriptor,
} from "../typings/TargetDescriptor";
import { findLastIndex } from "lodash";
import produce from "immer";

/**
* Performs inference on the partial targets provided by the user, using
Expand Down Expand Up @@ -90,13 +89,11 @@ function inferRangeTarget(
active: inferPrimitiveTarget(
target.active,
previousTargets.concat(target.anchor),
true,
),
};

const isAnchorMarkImplicit =
target.anchor.type === "implicit" || target.anchor.mark == null;

return handleEveryRangeTarget(fullTarget, isAnchorMarkImplicit) ?? fullTarget;
return handleEveryRangeTarget(fullTarget) ?? fullTarget;
}

/**
Expand Down Expand Up @@ -127,12 +124,9 @@ function inferRangeTarget(
* resulting range.
*
* @param fullTarget The full range target, post-inference
* @param isAnchorMarkImplicit `true` if the anchor mark was implicit on the
* original partial target
*/
function handleEveryRangeTarget(
fullTarget: RangeTargetDescriptor,
isAnchorMarkImplicit: boolean,
): EveryRangeTargetDescriptor | null {
const { anchor, rangeType, active, excludeAnchor, excludeActive } =
fullTarget;
Expand All @@ -154,6 +148,10 @@ function handleEveryRangeTarget(
anchor.modifiers[everyScopeModifierIndex] as EveryScopeModifier
).scopeType;

if (scopeType.type === "instance") {
return null;
}

const [beforeEveryModifiers, afterEveryModifiers] = [
anchor.modifiers.slice(0, everyScopeModifierIndex),
anchor.modifiers.slice(everyScopeModifierIndex + 1),
Expand All @@ -167,24 +165,15 @@ function handleEveryRangeTarget(
// If they say "every line past bat", the anchor is implicit, even though
// it comes across the wire as a primitive target due to the "every line",
// which we've now removed
afterEveryModifiers.length === 0 && isAnchorMarkImplicit
afterEveryModifiers.length === 0 && anchor.mark == null
? { type: "implicit" }
: {
type: "primitive",
mark: anchor.mark,
positionModifier: undefined,
modifiers: afterEveryModifiers,
},
// Remove the "every" (and everything before it) from the active if it
// ended up there from inference
active: produce(active, (draft) => {
draft.modifiers = draft.modifiers.slice(
findLastIndex(
draft.modifiers,
(modifier) => modifier.type === "everyScope",
) + 1,
);
}),
active,
modifiers: beforeEveryModifiers,
positionModifier: anchor.positionModifier,
excludeAnchor,
Expand All @@ -206,6 +195,7 @@ function inferPossiblyImplicitTarget(
function inferPrimitiveTarget(
target: PartialPrimitiveTargetDescriptor,
previousTargets: PartialTargetDescriptor[],
isActive: boolean = false,
): PrimitiveTargetDescriptor {
const ownPositionModifier = getPositionModifier(target);
const ownModifiers = getPreservedModifiers(target);
Expand All @@ -217,9 +207,25 @@ function inferPrimitiveTarget(
: null) ??
undefined;

const modifiers =
let modifiers =
ownModifiers ?? getPreviousPreservedModifiers(previousTargets) ?? [];

if (isActive) {
// If we're inferring the active end of a range target, we don't want any
// every or instance modifiers, because those will be handled by rewrites,
// because "past" binds more tightly than "every" or "instance"
modifiers = modifiers.slice(
findLastIndex(
modifiers,
(modifier) =>
modifier.type === "everyScope" ||
((modifier.type === "relativeScope" ||
modifier.type === "ordinalScope") &&
modifier.scopeType.type === "instance"),
) + 1,
);
}

const positionModifier =
ownPositionModifier ?? getPreviousPositionModifier(previousTargets);

Expand Down
4 changes: 1 addition & 3 deletions packages/cursorless-engine/src/testCaseRecorder/TestCase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,7 @@ export class TestCase {
visibleRanges: !visibleRangeActions.includes(this.command.action.name),
};

return Object.keys(excludedFields).filter(
(field) => excludedFields[field],
);
return Object.keys(excludedFields).filter((field) => excludedFields[field]);
}

toYaml() {
Expand Down