diff --git a/packages/cursorless-engine/src/processTargets/createContinuousRangeTarget.ts b/packages/cursorless-engine/src/processTargets/createContinuousRangeTarget.ts index be1c6d914e..993a4b0b8e 100644 --- a/packages/cursorless-engine/src/processTargets/createContinuousRangeTarget.ts +++ b/packages/cursorless-engine/src/processTargets/createContinuousRangeTarget.ts @@ -1,6 +1,10 @@ import { Target } from "../typings/target.types"; -import { createContinuousRange } from "./targetUtil/createContinuousRange"; -import { PlainTarget, UntypedTarget } from "./targets"; +import { isSameType } from "../util/typeUtils"; +import { + createContinuousLineRange, + createContinuousRange, +} from "./targetUtil/createContinuousRange"; +import { LineTarget, UntypedTarget } from "./targets"; export function createContinuousRangeTarget( isReversed: boolean, @@ -9,28 +13,27 @@ export function createContinuousRangeTarget( includeStart: boolean, includeEnd: boolean, ): Target { - const richTarget = startTarget.maybeCreateRichRangeTarget( - isReversed, - endTarget, - includeStart, - includeEnd, - ); + if (includeStart && includeEnd && isSameType(startTarget, endTarget)) { + const richTarget = startTarget.maybeCreateRichRangeTarget( + isReversed, + endTarget, + ); - if (richTarget != null) { - return richTarget; + if (richTarget != null) { + return richTarget; + } } - if (!includeStart || !includeEnd) { - return new PlainTarget({ + if (startTarget.isLine && endTarget.isLine) { + return new LineTarget({ editor: startTarget.editor, - contentRange: createContinuousRange( + isReversed, + contentRange: createContinuousLineRange( startTarget, endTarget, includeStart, includeEnd, ), - isReversed, - isToken: false, }); } @@ -44,6 +47,7 @@ export function createContinuousRangeTarget( includeStart, includeEnd, ), - isToken: startTarget.isToken && endTarget.isToken, + isToken: + includeStart && includeEnd && startTarget.isToken && endTarget.isToken, }); } diff --git a/packages/cursorless-engine/src/processTargets/targets/BaseTarget.ts b/packages/cursorless-engine/src/processTargets/targets/BaseTarget.ts index 23c87c9ce2..20307fbbfe 100644 --- a/packages/cursorless-engine/src/processTargets/targets/BaseTarget.ts +++ b/packages/cursorless-engine/src/processTargets/targets/BaseTarget.ts @@ -13,9 +13,8 @@ import { import { isEqual } from "lodash"; import type { EditWithRangeUpdater } from "../../typings/Types"; import type { Destination, Target } from "../../typings/target.types"; -import { isSameType } from "../../util/typeUtils"; -import { createContinuousRange } from "../targetUtil/createContinuousRange"; import { DestinationImpl } from "./DestinationImpl"; +import { createContinuousRange } from "../targetUtil/createContinuousRange"; /** Parameters supported by all target classes */ export interface MinimumTargetParameters { @@ -127,22 +126,9 @@ export abstract class BaseTarget< protected abstract getCloneParameters(): EnforceUndefined; maybeCreateRichRangeTarget( - isReversed: boolean, - endTarget: Target, - includeStart: boolean, - includeEnd: boolean, - ): Target | undefined { - if (!includeStart || !includeEnd || !isSameType(this, endTarget)) { - return undefined; - } - - return this.createRichRangeTarget(isReversed, endTarget); - } - - protected createRichRangeTarget( isReversed: boolean, endTarget: ThisType & Target, - ): ThisType & Target { + ): (ThisType & Target) | null { const { constructor } = Object.getPrototypeOf(this); return new constructor({ diff --git a/packages/cursorless-engine/src/processTargets/targets/InteriorTarget.ts b/packages/cursorless-engine/src/processTargets/targets/InteriorTarget.ts index 97c88535a4..f220a81276 100644 --- a/packages/cursorless-engine/src/processTargets/targets/InteriorTarget.ts +++ b/packages/cursorless-engine/src/processTargets/targets/InteriorTarget.ts @@ -34,7 +34,7 @@ export class InteriorTarget extends BaseTarget { }; } - createRichRangeTarget( + maybeCreateRichRangeTarget( isReversed: boolean, endTarget: InteriorTarget, ): InteriorTarget { diff --git a/packages/cursorless-engine/src/processTargets/targets/LineTarget.ts b/packages/cursorless-engine/src/processTargets/targets/LineTarget.ts index 7907f54ad8..862868dfa6 100644 --- a/packages/cursorless-engine/src/processTargets/targets/LineTarget.ts +++ b/packages/cursorless-engine/src/processTargets/targets/LineTarget.ts @@ -1,6 +1,5 @@ import { Position, Range, TextEditor } from "@cursorless/common"; import { BaseTarget, CommonTargetParameters } from "."; -import { Target } from "../../typings/target.types"; import { expandToFullLine } from "../../util/rangeUtils"; import { tryConstructPlainTarget } from "../../util/tryConstructTarget"; import { createContinuousLineRange } from "../targetUtil/createContinuousRange"; @@ -44,24 +43,13 @@ export class LineTarget extends BaseTarget { maybeCreateRichRangeTarget( isReversed: boolean, - endTarget: Target, - includeStart: boolean, - includeEnd: boolean, - ): Target | undefined { - if (endTarget.isLine) { - return new LineTarget({ - editor: this.editor, - isReversed, - contentRange: createContinuousLineRange( - this, - endTarget, - includeStart, - includeEnd, - ), - }); - } - - return undefined; + endTarget: LineTarget, + ): LineTarget { + return new LineTarget({ + editor: this.editor, + isReversed, + contentRange: createContinuousLineRange(this, endTarget, true, true), + }); } protected getCloneParameters() { diff --git a/packages/cursorless-engine/src/processTargets/targets/ParagraphTarget.ts b/packages/cursorless-engine/src/processTargets/targets/ParagraphTarget.ts index b2392bd496..d6cd18f25b 100644 --- a/packages/cursorless-engine/src/processTargets/targets/ParagraphTarget.ts +++ b/packages/cursorless-engine/src/processTargets/targets/ParagraphTarget.ts @@ -6,10 +6,8 @@ import { TextLine, } from "@cursorless/common"; import { BaseTarget, CommonTargetParameters, LineTarget } from "."; -import { Target } from "../../typings/target.types"; import { expandToFullLine } from "../../util/rangeUtils"; import { constructLineTarget } from "../../util/tryConstructTarget"; -import { isSameType } from "../../util/typeUtils"; import { createContinuousLineRange } from "../targetUtil/createContinuousRange"; export class ParagraphTarget extends BaseTarget { @@ -75,37 +73,13 @@ export class ParagraphTarget extends BaseTarget { maybeCreateRichRangeTarget( isReversed: boolean, - endTarget: Target, - includeStart: boolean, - includeEnd: boolean, - ): Target | undefined { - if (isSameType(this, endTarget)) { - return new ParagraphTarget({ - ...this.getCloneParameters(), - isReversed, - contentRange: createContinuousLineRange( - this, - endTarget, - includeStart, - includeEnd, - ), - }); - } - - if (endTarget.isLine) { - return new LineTarget({ - editor: this.editor, - isReversed, - contentRange: createContinuousLineRange( - this, - endTarget, - includeStart, - includeEnd, - ), - }); - } - - return undefined; + endTarget: ParagraphTarget, + ): ParagraphTarget { + return new ParagraphTarget({ + ...this.getCloneParameters(), + isReversed, + contentRange: createContinuousLineRange(this, endTarget, true, true), + }); } protected getCloneParameters() { diff --git a/packages/cursorless-engine/src/processTargets/targets/ScopeTypeTarget.ts b/packages/cursorless-engine/src/processTargets/targets/ScopeTypeTarget.ts index 50cf6e316e..1a724e2377 100644 --- a/packages/cursorless-engine/src/processTargets/targets/ScopeTypeTarget.ts +++ b/packages/cursorless-engine/src/processTargets/targets/ScopeTypeTarget.ts @@ -6,7 +6,6 @@ import { PlainTarget, } from "."; import { Target } from "../../typings/target.types"; -import { isSameType } from "../../util/typeUtils"; import { createContinuousRange, createContinuousRangeFromRanges, @@ -101,17 +100,10 @@ export class ScopeTypeTarget extends BaseTarget { maybeCreateRichRangeTarget( isReversed: boolean, - endTarget: Target, - includeStart: boolean, - includeEnd: boolean, - ): Target | undefined { - if ( - !includeStart || - !includeEnd || - !isSameType(this, endTarget) || - this.scopeTypeType_ !== endTarget.scopeTypeType_ - ) { - return undefined; + endTarget: ScopeTypeTarget, + ): ScopeTypeTarget | null { + if (this.scopeTypeType_ !== endTarget.scopeTypeType_) { + return null; } const contentRemovalRange = @@ -119,8 +111,8 @@ export class ScopeTypeTarget extends BaseTarget { ? createContinuousRangeFromRanges( this.removalRange_ ?? this.contentRange, endTarget.removalRange_ ?? endTarget.contentRange, - includeStart, - includeEnd, + true, + true, ) : undefined; @@ -130,12 +122,7 @@ export class ScopeTypeTarget extends BaseTarget { leadingDelimiterRange: this.leadingDelimiterRange_, trailingDelimiterRange: endTarget.trailingDelimiterRange_, removalRange: contentRemovalRange, - contentRange: createContinuousRange( - this, - endTarget, - includeStart, - includeEnd, - ), + contentRange: createContinuousRange(this, endTarget, true, true), }); } diff --git a/packages/cursorless-engine/src/processTargets/targets/SubTokenWordTarget.ts b/packages/cursorless-engine/src/processTargets/targets/SubTokenWordTarget.ts index 224b4d3628..9659edc11a 100644 --- a/packages/cursorless-engine/src/processTargets/targets/SubTokenWordTarget.ts +++ b/packages/cursorless-engine/src/processTargets/targets/SubTokenWordTarget.ts @@ -45,7 +45,7 @@ export class SubTokenWordTarget extends BaseTarget { return getDelimitedSequenceRemovalRange(this); } - createRichRangeTarget( + maybeCreateRichRangeTarget( isReversed: boolean, endTarget: SubTokenWordTarget, ): SubTokenWordTarget { diff --git a/packages/cursorless-engine/src/processTargets/targets/UntypedTarget.ts b/packages/cursorless-engine/src/processTargets/targets/UntypedTarget.ts index 187609e027..547e6bdf29 100644 --- a/packages/cursorless-engine/src/processTargets/targets/UntypedTarget.ts +++ b/packages/cursorless-engine/src/processTargets/targets/UntypedTarget.ts @@ -41,8 +41,8 @@ export class UntypedTarget extends BaseTarget { : getTokenRemovalRange(this); } - maybeCreateRichRangeTarget(): undefined { - return undefined; + maybeCreateRichRangeTarget(): null { + return null; } protected getCloneParameters() { diff --git a/packages/cursorless-engine/src/typings/target.types.ts b/packages/cursorless-engine/src/typings/target.types.ts index 5eaaa0ed78..7f4042cb36 100644 --- a/packages/cursorless-engine/src/typings/target.types.ts +++ b/packages/cursorless-engine/src/typings/target.types.ts @@ -152,24 +152,33 @@ export interface Target { getRemovalHighlightRange(): Range; withThatTarget(thatTarget: Target): Target; withContentRange(contentRange: Range): Target; + /** - * Attempt to create a range target that preserves some of the semantics of - * this target. Most targets will return `undefined` for targets not of the - * same type, and for targets of the same type, inherit some of the args from - * the two targets. Trailing delimiter should come from end target, leading - * from start target, etc. + * Targets use this function to determine what happens when a range target is + * created from two targets of the same type. This function is called by + * {@link createContinuousRangeTarget} to create the range target if both + * sides of the range are included and are of the same type. + * + * The newly created range target can inherit some of the args from the two + * targets. Trailing delimiter should come from end target, leading from start + * target, etc. * - * Note that you likely don't want to call this function directly; it is - * designed to be used by {@link createContinuousRangeTarget}. - * @param isReversed - * @param endTarget + * If for whatever reason it doesn't make sense to create a rich range target + * from the two targets, this function should return null. For example, + * {@link ScopeTypeTarget} returns null if the two targets have different + * scope types, and {@link UntypedTarget} returns null because it never makes + * sense to create a rich range target from two untyped targets. + * + * @param isReversed Indicates whether the range is reversed. + * @param endTarget The end target of the range. + * @returns The new target of the same type as the two targets, corresponding + * to an inclusive range between the two targets. */ maybeCreateRichRangeTarget( isReversed: boolean, - endTarget: Target, - includeStart: boolean, - includeEnd: boolean, - ): Target | undefined; + endTarget: ThisType & Target, + ): (ThisType & Target) | null; + /** Constructs removal edit */ constructRemovalEdit(): EditWithRangeUpdater; isEqual(target: Target): boolean;