diff --git a/packages/cursorless-engine/src/actions/InsertEmptyLines.ts b/packages/cursorless-engine/src/actions/InsertEmptyLines.ts index 9f2607a292..94b1824d46 100644 --- a/packages/cursorless-engine/src/actions/InsertEmptyLines.ts +++ b/packages/cursorless-engine/src/actions/InsertEmptyLines.ts @@ -142,6 +142,6 @@ function constructChangeEdit( ): EditWithFlashType { return { ...target.toDestination(insertionMode).constructChangeEdit("", true), - isLine: target.isLine, + isLine: target.textualType === "line", }; } diff --git a/packages/cursorless-engine/src/actions/JoinLines.ts b/packages/cursorless-engine/src/actions/JoinLines.ts index 89950e2868..f5b20936a8 100644 --- a/packages/cursorless-engine/src/actions/JoinLines.ts +++ b/packages/cursorless-engine/src/actions/JoinLines.ts @@ -61,9 +61,9 @@ function getEdits(editor: TextEditor, targets: Target[]): Edit[] { for (const target of targets) { const targetsEdits = - target.joinAs === "line" - ? getLineTargetEdits(target) - : getTokenTargetEdits(target); + target.textualType === "token" + ? getTokenTargetEdits(target) + : getLineTargetEdits(target); edits.push(...targetsEdits); } diff --git a/packages/cursorless-engine/src/processTargets/createContinuousRangeTarget.ts b/packages/cursorless-engine/src/processTargets/createContinuousRangeTarget.ts index abb2daa7b9..a358621f0b 100644 --- a/packages/cursorless-engine/src/processTargets/createContinuousRangeTarget.ts +++ b/packages/cursorless-engine/src/processTargets/createContinuousRangeTarget.ts @@ -1,10 +1,10 @@ import type { Target } from "../typings/target.types"; import { isSameType } from "../util/typeUtils"; +import { LineTarget, UntypedTarget } from "./targets"; import { createContinuousLineRange, createContinuousRange, } from "./targets/util/createContinuousRange"; -import { LineTarget, UntypedTarget } from "./targets"; /** * Creates a target consisting of a range between two targets. If the targets @@ -48,7 +48,7 @@ export function createContinuousRangeTarget( } } - if (startTarget.isLine && endTarget.isLine) { + if (startTarget.textualType === "line" && endTarget.textualType === "line") { return new LineTarget({ editor: startTarget.editor, isReversed, @@ -71,7 +71,12 @@ export function createContinuousRangeTarget( includeStart, includeEnd, ), - isToken: - includeStart && includeEnd && startTarget.isToken && endTarget.isToken, + textualType: + includeStart && + includeEnd && + startTarget.textualType === "token" && + endTarget.textualType === "token" + ? "token" + : "character", }); } diff --git a/packages/cursorless-engine/src/processTargets/marks/CursorStage.ts b/packages/cursorless-engine/src/processTargets/marks/CursorStage.ts index 10c96d22f7..fe47a94be1 100644 --- a/packages/cursorless-engine/src/processTargets/marks/CursorStage.ts +++ b/packages/cursorless-engine/src/processTargets/marks/CursorStage.ts @@ -13,7 +13,7 @@ export class CursorStage implements MarkStage { isReversed: selection.selection.isReversed, contentRange: selection.selection, hasExplicitRange: !selection.selection.isEmpty, - isToken: false, + textualType: "character", }), ); } diff --git a/packages/cursorless-engine/src/processTargets/modifiers/InstanceStage.ts b/packages/cursorless-engine/src/processTargets/modifiers/InstanceStage.ts index 26fc8b4c4b..2572aa864a 100644 --- a/packages/cursorless-engine/src/processTargets/modifiers/InstanceStage.ts +++ b/packages/cursorless-engine/src/processTargets/modifiers/InstanceStage.ts @@ -135,7 +135,7 @@ export class InstanceStage implements ModifierStage { contentRange: range, editor, isReversed: false, - isToken: false, + textualType: "character", }), ); @@ -182,19 +182,14 @@ export class InstanceStage implements ModifierStage { } function getFilterScopeType(target: Target): ScopeType | null { - if (target.isLine) { - return { type: "line" }; + switch (target.textualType) { + case "line": + case "token": + case "word": + return { type: target.textualType }; + default: + return null; } - - if (target.isToken) { - return { type: "token" }; - } - - if (target.isWord) { - return { type: "word" }; - } - - return null; } /** diff --git a/packages/cursorless-engine/src/processTargets/modifiers/PositionStage.ts b/packages/cursorless-engine/src/processTargets/modifiers/PositionStage.ts index 875c2fc037..07bd43c0bd 100644 --- a/packages/cursorless-engine/src/processTargets/modifiers/PositionStage.ts +++ b/packages/cursorless-engine/src/processTargets/modifiers/PositionStage.ts @@ -15,7 +15,7 @@ abstract class PositionStage implements ModifierStage { return [ target.isRaw ? new RawSelectionTarget(parameters) - : new PlainTarget({ ...parameters, isToken: false }), + : new PlainTarget({ ...parameters, textualType: "character" }), ]; } diff --git a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/CharacterScopeHandler.ts b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/CharacterScopeHandler.ts index 2fd80d0189..de20d3b4e2 100644 --- a/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/CharacterScopeHandler.ts +++ b/packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/CharacterScopeHandler.ts @@ -39,7 +39,7 @@ export class CharacterScopeHandler extends NestedScopeHandler { editor, contentRange: range, isReversed, - isToken: false, + textualType: "character", }), ], }), diff --git a/packages/cursorless-engine/src/processTargets/targets/BaseTarget.ts b/packages/cursorless-engine/src/processTargets/targets/BaseTarget.ts index 3b8e5f99f8..78820bc874 100644 --- a/packages/cursorless-engine/src/processTargets/targets/BaseTarget.ts +++ b/packages/cursorless-engine/src/processTargets/targets/BaseTarget.ts @@ -12,8 +12,8 @@ import { isEqual } from "lodash-es"; import type { EditWithRangeUpdater } from "../../typings/Types"; import type { Destination, - JoinAsType, Target, + TextualType, } from "../../typings/target.types"; import { toGeneralizedRange } from "../../util/targetUtils"; import { DestinationImpl } from "./DestinationImpl"; @@ -47,15 +47,12 @@ export abstract class BaseTarget< { protected abstract readonly type: string; protected readonly state: EnforceUndefined; - isLine = false; - isToken = true; hasExplicitScopeType = true; hasExplicitRange = true; isRaw = false; isImplicit = false; isNotebookCell = false; - isWord = false; - joinAs: JoinAsType = "line"; + textualType: TextualType = "token"; constructor(parameters: TParameters & CommonTargetParameters) { this.state = { @@ -69,6 +66,7 @@ export abstract class BaseTarget< get editor() { return this.state.editor; } + get isReversed() { return this.state.isReversed; } diff --git a/packages/cursorless-engine/src/processTargets/targets/BoundedParagraphTarget.ts b/packages/cursorless-engine/src/processTargets/targets/BoundedParagraphTarget.ts index 24cc2ba49b..291249c197 100644 --- a/packages/cursorless-engine/src/processTargets/targets/BoundedParagraphTarget.ts +++ b/packages/cursorless-engine/src/processTargets/targets/BoundedParagraphTarget.ts @@ -1,5 +1,6 @@ import { toLineRange, type Range } from "@cursorless/common"; import type { InteriorTarget, ParagraphTarget } from "."; +import type { TextualType } from "../../typings/target.types"; import { expandToFullLine } from "../../util/rangeUtils"; import type { MinimumTargetParameters } from "./BaseTarget"; import { BaseTarget } from "./BaseTarget"; @@ -12,8 +13,8 @@ interface BoundedParagraphTargetParameters extends MinimumTargetParameters { export class BoundedParagraphTarget extends BaseTarget { readonly type = "BoundedParagraphTarget"; + readonly textualType: TextualType = "line"; readonly insertionDelimiter = "\n\n"; - readonly isLine = true; private containingInterior: InteriorTarget; private paragraphTarget: ParagraphTarget; private startLineGap: number; diff --git a/packages/cursorless-engine/src/processTargets/targets/DocumentTarget.ts b/packages/cursorless-engine/src/processTargets/targets/DocumentTarget.ts index 7773de4afe..201f292676 100644 --- a/packages/cursorless-engine/src/processTargets/targets/DocumentTarget.ts +++ b/packages/cursorless-engine/src/processTargets/targets/DocumentTarget.ts @@ -1,4 +1,5 @@ import type { Range } from "@cursorless/common"; +import type { TextualType } from "../../typings/target.types"; import { shrinkRangeToFitContent } from "../../util/selectionUtils"; import type { CommonTargetParameters } from "./BaseTarget"; import { BaseTarget } from "./BaseTarget"; @@ -6,8 +7,8 @@ import { PlainTarget } from "./PlainTarget"; export class DocumentTarget extends BaseTarget { type = "DocumentTarget"; + textualType: TextualType = "line"; insertionDelimiter = "\n"; - isLine = true; constructor(parameters: CommonTargetParameters) { super(parameters); diff --git a/packages/cursorless-engine/src/processTargets/targets/ImplicitTarget.ts b/packages/cursorless-engine/src/processTargets/targets/ImplicitTarget.ts index f88fabfc08..7b7589ea81 100644 --- a/packages/cursorless-engine/src/processTargets/targets/ImplicitTarget.ts +++ b/packages/cursorless-engine/src/processTargets/targets/ImplicitTarget.ts @@ -1,4 +1,5 @@ import type { EnforceUndefined } from "@cursorless/common"; +import type { TextualType } from "../../typings/target.types"; import type { CommonTargetParameters } from "./BaseTarget"; import { BaseTarget } from "./BaseTarget"; @@ -10,11 +11,11 @@ import { BaseTarget } from "./BaseTarget"; */ export class ImplicitTarget extends BaseTarget { type = "ImplicitTarget"; + textualType: TextualType = "character"; insertionDelimiter = ""; isRaw = true; hasExplicitScopeType = false; isImplicit = true; - isToken = false; getLeadingDelimiterTarget = () => undefined; getTrailingDelimiterTarget = () => undefined; diff --git a/packages/cursorless-engine/src/processTargets/targets/LineTarget.ts b/packages/cursorless-engine/src/processTargets/targets/LineTarget.ts index 6dd5d4258a..a34c8be7af 100644 --- a/packages/cursorless-engine/src/processTargets/targets/LineTarget.ts +++ b/packages/cursorless-engine/src/processTargets/targets/LineTarget.ts @@ -1,5 +1,6 @@ import type { TextEditor } from "@cursorless/common"; import { Position, Range, toLineRange } from "@cursorless/common"; +import type { TextualType } from "../../typings/target.types"; import { expandToFullLine } from "../../util/rangeUtils"; import { tryConstructTarget } from "../../util/tryConstructTarget"; import type { CommonTargetParameters } from "./BaseTarget"; @@ -9,8 +10,8 @@ import { createContinuousLineRange } from "./util/createContinuousRange"; export class LineTarget extends BaseTarget { type = "LineTarget"; + textualType: TextualType = "line"; insertionDelimiter = "\n"; - isLine = true; private get fullLineContentRange() { return expandToFullLine(this.editor, this.contentRange); diff --git a/packages/cursorless-engine/src/processTargets/targets/ParagraphTarget.ts b/packages/cursorless-engine/src/processTargets/targets/ParagraphTarget.ts index 76c492cf5e..affb0a87a6 100644 --- a/packages/cursorless-engine/src/processTargets/targets/ParagraphTarget.ts +++ b/packages/cursorless-engine/src/processTargets/targets/ParagraphTarget.ts @@ -5,6 +5,7 @@ import type { TextLine, } from "@cursorless/common"; import { Position, Range, toLineRange } from "@cursorless/common"; +import type { TextualType } from "../../typings/target.types"; import { expandToFullLine } from "../../util/rangeUtils"; import type { CommonTargetParameters } from "./BaseTarget"; import { BaseTarget } from "./BaseTarget"; @@ -13,8 +14,8 @@ import { createContinuousLineRange } from "./util/createContinuousRange"; export class ParagraphTarget extends BaseTarget { type = "ParagraphTarget"; + textualType: TextualType = "line"; insertionDelimiter = "\n\n"; - isLine = true; getLeadingDelimiterTarget() { return constructLineTarget( diff --git a/packages/cursorless-engine/src/processTargets/targets/PlainTarget.ts b/packages/cursorless-engine/src/processTargets/targets/PlainTarget.ts index 48576bd438..4ecc394ee1 100644 --- a/packages/cursorless-engine/src/processTargets/targets/PlainTarget.ts +++ b/packages/cursorless-engine/src/processTargets/targets/PlainTarget.ts @@ -1,10 +1,11 @@ +import type { Range, TextEditor } from "@cursorless/common"; +import type { TextualType } from "../../typings/target.types"; import { tryConstructTarget } from "../../util/tryConstructTarget"; -import type { TextEditor, Range } from "@cursorless/common"; import type { CommonTargetParameters } from "./BaseTarget"; import { BaseTarget } from "./BaseTarget"; interface PlainTargetParameters extends CommonTargetParameters { - readonly isToken?: boolean; + readonly textualType?: TextualType; readonly insertionDelimiter?: string; } @@ -19,7 +20,7 @@ export class PlainTarget extends BaseTarget { constructor(parameters: PlainTargetParameters) { super(parameters); - this.isToken = parameters.isToken ?? true; + this.textualType = parameters.textualType ?? "token"; this.insertionDelimiter = parameters.insertionDelimiter ?? ""; } @@ -30,7 +31,7 @@ export class PlainTarget extends BaseTarget { protected getCloneParameters() { return { ...this.state, - isToken: this.isToken, + textualType: this.textualType, insertionDelimiter: this.insertionDelimiter, }; } diff --git a/packages/cursorless-engine/src/processTargets/targets/RawSelectionTarget.ts b/packages/cursorless-engine/src/processTargets/targets/RawSelectionTarget.ts index 16f4478f24..3fd3b593a7 100644 --- a/packages/cursorless-engine/src/processTargets/targets/RawSelectionTarget.ts +++ b/packages/cursorless-engine/src/processTargets/targets/RawSelectionTarget.ts @@ -1,4 +1,5 @@ import type { EnforceUndefined } from "@cursorless/common"; +import type { TextualType } from "../../typings/target.types"; import type { CommonTargetParameters } from "./BaseTarget"; import { BaseTarget } from "./BaseTarget"; @@ -9,9 +10,9 @@ import { BaseTarget } from "./BaseTarget"; */ export class RawSelectionTarget extends BaseTarget { type = "RawSelectionTarget"; + textualType: TextualType = "character"; insertionDelimiter = ""; isRaw = true; - isToken = false; getLeadingDelimiterTarget = () => undefined; getTrailingDelimiterTarget = () => undefined; diff --git a/packages/cursorless-engine/src/processTargets/targets/SubTokenWordTarget.ts b/packages/cursorless-engine/src/processTargets/targets/SubTokenWordTarget.ts index 15123e330f..24023d97e7 100644 --- a/packages/cursorless-engine/src/processTargets/targets/SubTokenWordTarget.ts +++ b/packages/cursorless-engine/src/processTargets/targets/SubTokenWordTarget.ts @@ -1,4 +1,5 @@ import type { Range } from "@cursorless/common"; +import type { TextualType } from "../../typings/target.types"; import type { CommonTargetParameters } from "./BaseTarget"; import { BaseTarget } from "./BaseTarget"; import { tryConstructPlainTarget } from "./PlainTarget"; @@ -13,11 +14,10 @@ export interface SubTokenTargetParameters extends CommonTargetParameters { export class SubTokenWordTarget extends BaseTarget { type = "SubTokenWordTarget"; + textualType: TextualType = "word"; private leadingDelimiterRange_?: Range; private trailingDelimiterRange_?: Range; insertionDelimiter: string; - isToken = false; - isWord = true; constructor(parameters: SubTokenTargetParameters) { super(parameters); diff --git a/packages/cursorless-engine/src/processTargets/targets/TokenTarget.ts b/packages/cursorless-engine/src/processTargets/targets/TokenTarget.ts index fb1faf16e3..3784597a96 100644 --- a/packages/cursorless-engine/src/processTargets/targets/TokenTarget.ts +++ b/packages/cursorless-engine/src/processTargets/targets/TokenTarget.ts @@ -1,5 +1,5 @@ import type { Range } from "@cursorless/common"; -import type { JoinAsType, Target } from "../../typings/target.types"; +import type { Target, TextualType } from "../../typings/target.types"; import type { CommonTargetParameters } from "./BaseTarget"; import { BaseTarget } from "./BaseTarget"; import { @@ -10,8 +10,8 @@ import { export class TokenTarget extends BaseTarget { type = "TokenTarget"; + textualType: TextualType = "token"; insertionDelimiter = " "; - joinAs: JoinAsType = "token"; getLeadingDelimiterTarget(): Target | undefined { return getTokenLeadingDelimiterTarget(this); diff --git a/packages/cursorless-engine/src/processTargets/targets/UntypedTarget.ts b/packages/cursorless-engine/src/processTargets/targets/UntypedTarget.ts index 2a5ef3a45b..32130e3da1 100644 --- a/packages/cursorless-engine/src/processTargets/targets/UntypedTarget.ts +++ b/packages/cursorless-engine/src/processTargets/targets/UntypedTarget.ts @@ -1,7 +1,7 @@ import type { Range } from "@cursorless/common"; +import type { Target, TextualType } from "../../typings/target.types"; import type { CommonTargetParameters } from "./BaseTarget"; import { BaseTarget } from "./BaseTarget"; -import type { Target } from "../../typings/target.types"; import { getTokenLeadingDelimiterTarget, getTokenRemovalRange, @@ -10,7 +10,7 @@ import { interface UntypedTargetParameters extends CommonTargetParameters { readonly hasExplicitRange: boolean; - readonly isToken?: boolean; + readonly textualType?: TextualType; } /** @@ -26,7 +26,7 @@ export class UntypedTarget extends BaseTarget { constructor(parameters: UntypedTargetParameters) { super(parameters); this.hasExplicitRange = parameters.hasExplicitRange; - this.isToken = parameters.isToken ?? true; + this.textualType = parameters.textualType ?? "token"; } getLeadingDelimiterTarget(): Target | undefined { @@ -52,7 +52,7 @@ export class UntypedTarget extends BaseTarget { protected getCloneParameters() { return { ...this.state, - isToken: this.isToken, + textualType: this.textualType, hasExplicitRange: this.hasExplicitRange, }; } diff --git a/packages/cursorless-engine/src/typings/target.types.ts b/packages/cursorless-engine/src/typings/target.types.ts index 8e44d3da5d..6a62e682f7 100644 --- a/packages/cursorless-engine/src/typings/target.types.ts +++ b/packages/cursorless-engine/src/typings/target.types.ts @@ -29,7 +29,8 @@ import type { import type { EditWithRangeUpdater } from "./Types"; export type EditNewActionType = "edit" | "insertLineAfter"; -export type JoinAsType = "line" | "token"; + +export type TextualType = "character" | "word" | "token" | "line"; export interface Target { /** The text editor used for all ranges */ @@ -47,17 +48,8 @@ export interface Target { /** Optional prefix. For example, dash or asterisk for a markdown item */ readonly prefixRange?: Range; - /** If true this target should be treated as a line */ - readonly isLine: boolean; - - /** If true this target should be treated as a token */ - readonly isToken: boolean; - - /** If true this target should be treated as a word */ - readonly isWord: boolean; - - /** Specifies how a target should be joined */ - readonly joinAs: JoinAsType; + /** Targets textual type. Is this target a line, a token, etc... */ + readonly textualType: TextualType; /** * If `true`, then this target has an explicit scope type, and so should never diff --git a/packages/cursorless-engine/src/util/targetUtils.ts b/packages/cursorless-engine/src/util/targetUtils.ts index c57e8d5e4b..eeccb188a5 100644 --- a/packages/cursorless-engine/src/util/targetUtils.ts +++ b/packages/cursorless-engine/src/util/targetUtils.ts @@ -113,7 +113,9 @@ export function toGeneralizedRange( target: Target, range: Range, ): GeneralizedRange { - return target.isLine ? toLineRange(range) : toCharacterRange(range); + return target.textualType === "line" + ? toLineRange(range) + : toCharacterRange(range); } function toGeneralizedContentRange(target: Target): GeneralizedRange {